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_conspeed = {CVAR_SAVE, "scr_conspeed","900", "speed of console open/close"}; // LordHavoc: quake used 300
12 cvar_t scr_conalpha = {CVAR_SAVE, "scr_conalpha", "1", "opacity of console background"};
13 cvar_t scr_conbrightness = {CVAR_SAVE, "scr_conbrightness", "0.2", "brightness of console background (0 = black, 1 = image)"};
14 cvar_t scr_conforcewhiledisconnected = {0, "scr_conforcewhiledisconnected", "1", "forces fullscreen console while disconnected"};
15 cvar_t scr_menuforcewhiledisconnected = {0, "scr_menuforcewhiledisconnected", "0", "forces menu while disconnected"};
16 cvar_t scr_centertime = {0, "scr_centertime","2", "how long centerprint messages show"};
17 cvar_t scr_showram = {CVAR_SAVE, "showram","1", "show ram icon if low on surface cache memory (not used)"};
18 cvar_t scr_showturtle = {CVAR_SAVE, "showturtle","0", "show turtle icon when framerate is too low (not used)"};
19 cvar_t scr_showpause = {CVAR_SAVE, "showpause","1", "show pause icon when game is paused"};
20 cvar_t scr_showbrand = {0, "showbrand","0", "shows gfx/brand.tga in a corner of the screen (different values select different positions, including centered)"};
21 cvar_t scr_printspeed = {0, "scr_printspeed","8", "speed of intermission printing (episode end texts)"};
22 cvar_t vid_conwidth = {CVAR_SAVE, "vid_conwidth", "640", "virtual width of 2D graphics system"};
23 cvar_t vid_conheight = {CVAR_SAVE, "vid_conheight", "480", "virtual height of 2D graphics system"};
24 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)"};
25 cvar_t scr_screenshot_jpeg = {CVAR_SAVE, "scr_screenshot_jpeg","1", "save jpeg instead of targa"};
26 cvar_t scr_screenshot_jpeg_quality = {CVAR_SAVE, "scr_screenshot_jpeg_quality","0.9", "image quality of saved jpeg"};
27 cvar_t scr_screenshot_gamma = {CVAR_SAVE, "scr_screenshot_gamma","2.2", "gamma correction on saved screenshots and videos, 1.0 saves unmodified images"};
28 // scr_screenshot_name is defined in fs.c
29 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)"};
30 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)"};
31 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)"};
32 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)"};
33 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)"};
34 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 cvar_t r_stereo_separation = {0, "r_stereo_separation", "4", "separation of eyes in the world (try negative values too)"};
36 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)"};
37 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)"};
38 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"};
39 cvar_t r_stereo_redgreen = {0, "r_stereo_redgreen", "0", "red/green anaglyph stereo glasses (for those who don't mind yellow)"};
40 cvar_t scr_zoomwindow = {CVAR_SAVE, "scr_zoomwindow", "0", "displays a zoomed in overlay window"};
41 cvar_t scr_zoomwindow_viewsizex = {CVAR_SAVE, "scr_zoomwindow_viewsizex", "20", "horizontal viewsize of zoom window"};
42 cvar_t scr_zoomwindow_viewsizey = {CVAR_SAVE, "scr_zoomwindow_viewsizey", "20", "vertical viewsize of zoom window"};
43 cvar_t scr_zoomwindow_fov = {CVAR_SAVE, "scr_zoomwindow_fov", "20", "fov of zoom window"};
46 int jpeg_supported = false;
48 qboolean scr_initialized; // ready to draw
50 float scr_con_current;
52 extern int con_vislines;
54 void DrawCrosshair(int num);
55 static void SCR_ScreenShot_f (void);
56 static void R_Envmap_f (void);
59 void R_ClearScreen(void);
62 ===============================================================================
66 ===============================================================================
69 char scr_centerstring[MAX_INPUTLINE];
70 float scr_centertime_start; // for slow victory printing
71 float scr_centertime_off;
80 Called for important messages that should stay in the center of the screen
84 void SCR_CenterPrint(char *str)
86 strlcpy (scr_centerstring, str, sizeof (scr_centerstring));
87 scr_centertime_off = scr_centertime.value;
88 scr_centertime_start = cl.time;
90 // count the number of lines for centering
101 void SCR_DrawCenterString (void)
109 // the finale prints the characters one at a time
111 remaining = (int)(scr_printspeed.value * (cl.time - scr_centertime_start));
115 scr_erase_center = 0;
116 start = scr_centerstring;
121 if (scr_center_lines <= 4)
122 y = (int)(vid_conheight.integer*0.35);
129 // scan the width of the line
130 for (l=0 ; l<vid_conwidth.integer/8 ; l++)
131 if (start[l] == '\n' || !start[l])
133 x = (vid_conwidth.integer - l*8)/2;
138 DrawQ_ColoredString(x, y, start, l, 8, 8, 1, 1, 1, 1, 0, &color);
146 while (*start && *start != '\n')
151 start++; // skip the \n
155 void SCR_CheckDrawCenterString (void)
157 if (scr_center_lines > scr_erase_lines)
158 scr_erase_lines = scr_center_lines;
160 scr_centertime_off -= cl.realframetime;
162 // don't draw if this is a normal stats-screen intermission,
163 // only if it is not an intermission, or a finale intermission
164 if (cl.intermission == 1)
166 if (scr_centertime_off <= 0 && !cl.intermission)
168 if (key_dest != key_game)
171 SCR_DrawCenterString ();
179 void SCR_DrawTurtle (void)
183 if (cls.state != ca_connected)
186 if (!scr_showturtle.integer)
189 if (cl.realframetime < 0.1)
199 DrawQ_Pic (0, 0, Draw_CachePic("gfx/turtle", true), 0, 0, 1, 1, 1, 1, 0);
207 void SCR_DrawNet (void)
209 if (cls.state != ca_connected)
211 if (realtime - cl.last_received_message < 0.3)
213 if (cls.demoplayback)
216 DrawQ_Pic (64, 0, Draw_CachePic("gfx/net", true), 0, 0, 1, 1, 1, 1, 0);
224 void SCR_DrawPause (void)
228 if (cls.state != ca_connected)
231 if (!scr_showpause.integer) // turn off for screenshots
237 pic = Draw_CachePic ("gfx/pause", true);
238 DrawQ_Pic ((vid_conwidth.integer - pic->width)/2, (vid_conheight.integer - pic->height)/2, pic, 0, 0, 1, 1, 1, 1, 0);
246 void SCR_DrawBrand (void)
251 if (!scr_showbrand.value)
254 pic = Draw_CachePic ("gfx/brand", true);
256 switch ((int)scr_showbrand.value)
258 case 1: // bottom left
260 y = vid_conheight.integer - pic->height;
262 case 2: // bottom centre
263 x = (vid_conwidth.integer - pic->width) / 2;
264 y = vid_conheight.integer - pic->height;
266 case 3: // bottom right
267 x = vid_conwidth.integer - pic->width;
268 y = vid_conheight.integer - pic->height;
270 case 4: // centre right
271 x = vid_conwidth.integer - pic->width;
272 y = (vid_conheight.integer - pic->height) / 2;
275 x = vid_conwidth.integer - pic->width;
278 case 6: // top centre
279 x = (vid_conwidth.integer - pic->width) / 2;
286 case 8: // centre left
288 y = (vid_conheight.integer - pic->height) / 2;
294 DrawQ_Pic (x, y, pic, 0, 0, 1, 1, 1, 1, 0);
302 static void SCR_DrawDownload(void)
308 if (!cls.qw_downloadname[0])
310 dpsnprintf(temp, sizeof(temp), "Downloading %s ... %3i%%\n", cls.qw_downloadname, cls.qw_downloadpercent);
311 len = (int)strlen(temp);
312 x = (vid_conwidth.integer - len*size) / 2;
313 y = vid_conheight.integer - size;
314 DrawQ_Pic(0, y, NULL, vid_conwidth.integer, size, 0, 0, 0, 0.5, 0);
315 DrawQ_String(x, y, temp, len, size, size, 1, 1, 1, 1, 0);
318 //=============================================================================
323 SCR_SetUpToDrawConsole
326 void SCR_SetUpToDrawConsole (void)
328 // lines of console to display
330 static int framecounter = 0;
334 if (scr_menuforcewhiledisconnected.integer && key_dest == key_game && cls.state == ca_disconnected)
336 if (framecounter >= 2)
344 if (scr_conforcewhiledisconnected.integer && key_dest == key_game && cls.signon != SIGNONS)
345 key_consoleactive |= KEY_CONSOLEACTIVE_FORCED;
347 key_consoleactive &= ~KEY_CONSOLEACTIVE_FORCED;
349 // decide on the height of the console
350 if (key_consoleactive & KEY_CONSOLEACTIVE_USER)
351 conlines = vid_conheight.integer/2; // half screen
353 conlines = 0; // none visible
355 if (scr_conspeed.value)
357 if (scr_con_current > conlines)
359 scr_con_current -= scr_conspeed.value*cl.realframetime;
360 if (scr_con_current < conlines)
361 scr_con_current = conlines;
363 else if (scr_con_current < conlines)
365 scr_con_current += scr_conspeed.value*cl.realframetime;
366 if (scr_con_current > conlines)
367 scr_con_current = conlines;
371 scr_con_current = conlines;
379 void SCR_DrawConsole (void)
381 if (key_consoleactive & KEY_CONSOLEACTIVE_FORCED)
384 Con_DrawConsole (vid_conheight.integer);
386 else if (scr_con_current)
387 Con_DrawConsole ((int)scr_con_current);
391 if (key_dest == key_game || key_dest == key_message)
392 Con_DrawNotify (); // only draw notify in game
398 SCR_BeginLoadingPlaque
402 void SCR_BeginLoadingPlaque (void)
404 // save console log up to this point to log_file if it was set by configs
409 SCR_UpdateLoadingScreen();
412 //=============================================================================
414 char r_speeds_string[1024];
415 int speedstringcount, r_timereport_active;
416 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
418 void R_TimeReport(char *desc)
424 if (r_speeds.integer < 2 || !r_timereport_active)
428 r_timereport_temp = r_timereport_current;
429 r_timereport_current = Sys_DoubleTime();
430 t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0 + 0.5);
432 dpsnprintf(tempbuf, sizeof(tempbuf), "%8i %-11s", t, desc);
433 length = (int)strlen(tempbuf);
434 if (speedstringcount + length > (vid_conwidth.integer / 8))
436 strlcat(r_speeds_string, "\n", sizeof(r_speeds_string));
437 speedstringcount = 0;
439 strlcat(r_speeds_string, tempbuf, sizeof(r_speeds_string));
440 speedstringcount += length;
443 void R_TimeReport_Frame(void)
447 if (r_speeds_string[0])
449 if (r_timereport_active)
451 r_timereport_current = r_timereport_start;
452 R_TimeReport("total");
455 if (r_speeds_string[strlen(r_speeds_string)-1] == '\n')
456 r_speeds_string[strlen(r_speeds_string)-1] = 0;
458 for (i = 0;r_speeds_string[i];i++)
459 if (r_speeds_string[i] == '\n')
461 y = vid_conheight.integer - sb_lines - lines * 8;
463 DrawQ_Pic(0, y, NULL, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0);
464 while (r_speeds_string[i])
467 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
470 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
471 if (r_speeds_string[i] == '\n')
475 r_speeds_string[0] = 0;
476 r_timereport_active = false;
478 if (r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected)
480 speedstringcount = 0;
481 r_speeds_string[0] = 0;
482 r_timereport_active = false;
483 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]);
484 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);
485 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);
486 if (renderstats.bloom)
487 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);
489 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles\n", renderstats.meshes, renderstats.meshes_elements / 3);
491 memset(&renderstats, 0, sizeof(renderstats));
493 if (r_speeds.integer >= 2)
495 r_timereport_active = true;
496 r_timereport_start = r_timereport_current = Sys_DoubleTime();
508 void SCR_SizeUp_f (void)
510 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
521 void SCR_SizeDown_f (void)
523 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
526 void CL_Screen_Init(void)
528 Cvar_RegisterVariable (&scr_fov);
529 Cvar_RegisterVariable (&scr_viewsize);
530 Cvar_RegisterVariable (&scr_conspeed);
531 Cvar_RegisterVariable (&scr_conalpha);
532 Cvar_RegisterVariable (&scr_conbrightness);
533 Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
534 Cvar_RegisterVariable (&scr_menuforcewhiledisconnected);
535 Cvar_RegisterVariable (&scr_showram);
536 Cvar_RegisterVariable (&scr_showturtle);
537 Cvar_RegisterVariable (&scr_showpause);
538 Cvar_RegisterVariable (&scr_showbrand);
539 Cvar_RegisterVariable (&scr_centertime);
540 Cvar_RegisterVariable (&scr_printspeed);
541 Cvar_RegisterVariable (&vid_conwidth);
542 Cvar_RegisterVariable (&vid_conheight);
543 Cvar_RegisterVariable (&vid_pixelheight);
544 Cvar_RegisterVariable (&scr_screenshot_jpeg);
545 Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
546 Cvar_RegisterVariable (&scr_screenshot_gamma);
547 Cvar_RegisterVariable (&cl_capturevideo);
548 Cvar_RegisterVariable (&cl_capturevideo_sound);
549 Cvar_RegisterVariable (&cl_capturevideo_fps);
550 Cvar_RegisterVariable (&cl_capturevideo_rawrgb);
551 Cvar_RegisterVariable (&cl_capturevideo_rawyv12);
552 Cvar_RegisterVariable (&r_letterbox);
553 Cvar_RegisterVariable(&r_stereo_separation);
554 Cvar_RegisterVariable(&r_stereo_sidebyside);
555 Cvar_RegisterVariable(&r_stereo_redblue);
556 Cvar_RegisterVariable(&r_stereo_redcyan);
557 Cvar_RegisterVariable(&r_stereo_redgreen);
558 Cvar_RegisterVariable(&scr_zoomwindow);
559 Cvar_RegisterVariable(&scr_zoomwindow_viewsizex);
560 Cvar_RegisterVariable(&scr_zoomwindow_viewsizey);
561 Cvar_RegisterVariable(&scr_zoomwindow_fov);
563 Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)");
564 Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)");
565 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f, "takes a screenshot of the next rendered frame");
566 Cmd_AddCommand ("envmap", R_Envmap_f, "render a cubemap (skybox) of the current scene");
568 scr_initialized = true;
576 void SCR_ScreenShot_f (void)
578 static int shotnumber;
579 static char oldname[MAX_QPATH];
580 char base[MAX_QPATH];
581 char filename[MAX_QPATH];
582 unsigned char *buffer1;
583 unsigned char *buffer2;
584 unsigned char *buffer3;
585 qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
587 sprintf (base, "screenshots/%s", scr_screenshot_name.string);
589 if (strcmp (oldname, scr_screenshot_name.string))
591 sprintf(oldname, "%s", scr_screenshot_name.string);
595 // find a file name to save it to
596 for (;shotnumber < 1000000;shotnumber++)
597 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
599 if (shotnumber >= 1000000)
601 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
605 sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
607 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
608 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
609 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3 + 18);
611 if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, 0, 0, vid.width, vid.height, false, false, false, jpeg, true))
612 Con_Printf("Wrote %s\n", filename);
614 Con_Printf("unable to write %s\n", filename);
623 void SCR_CaptureVideo_BeginVideo(void)
627 unsigned char out[44];
628 if (cls.capturevideo_active)
630 // soundrate is figured out on the first SoundFrame
631 cls.capturevideo_active = true;
632 cls.capturevideo_starttime = Sys_DoubleTime();
633 cls.capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
634 cls.capturevideo_soundrate = 0;
635 cls.capturevideo_frame = 0;
636 cls.capturevideo_buffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (3+3+3) + 18);
637 gamma = 1.0/scr_screenshot_gamma.value;
640 for (i = 0;i < 256;i++)
642 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
643 cls.capturevideo_rgbgammatable[0][i] = j;
644 cls.capturevideo_rgbgammatable[1][i] = j;
645 cls.capturevideo_rgbgammatable[2][i] = j;
649 R = Y + 1.4075 * (Cr - 128);
650 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
651 B = Y + 1.7790 * (Cb - 128);
652 Y = R * .299 + G * .587 + B * .114;
653 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
654 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
656 for (i = 0;i < 256;i++)
658 g = 255*pow(i/255.0, gamma);
659 // Y weights from RGB
660 cls.capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
661 cls.capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
662 cls.capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
663 // Cb weights from RGB
664 cls.capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
665 cls.capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
666 cls.capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
667 // Cr weights from RGB
668 cls.capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
669 cls.capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
670 cls.capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
671 // range reduction of YCbCr to valid signal range
672 cls.capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
673 cls.capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
674 cls.capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
677 if (cl_capturevideo_rawrgb.integer)
679 cls.capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
680 cls.capturevideo_videofile = FS_Open ("video/dpvideo.rgb", "wb", false, true);
682 else if (cl_capturevideo_rawyv12.integer)
684 cls.capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
685 cls.capturevideo_videofile = FS_Open ("video/dpvideo.yv12", "wb", false, true);
687 else if (scr_screenshot_jpeg.integer)
689 cls.capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
690 cls.capturevideo_videofile = NULL;
694 cls.capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
695 cls.capturevideo_videofile = NULL;
698 if (cl_capturevideo_sound.integer)
700 cls.capturevideo_soundfile = FS_Open ("video/dpvideo.wav", "wb", false, true);
701 // wave header will be filled out when video ends
703 FS_Write (cls.capturevideo_soundfile, out, 44);
706 cls.capturevideo_soundfile = NULL;
709 void SCR_CaptureVideo_EndVideo(void)
712 unsigned char out[44];
713 if (!cls.capturevideo_active)
715 cls.capturevideo_active = false;
717 if (cls.capturevideo_videofile)
719 FS_Close(cls.capturevideo_videofile);
720 cls.capturevideo_videofile = NULL;
723 // finish the wave file
724 if (cls.capturevideo_soundfile)
726 i = (int)FS_Tell (cls.capturevideo_soundfile);
727 //"RIFF", (int) unknown (chunk size), "WAVE",
728 //"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
729 //"data", (int) unknown (chunk size)
730 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
731 // the length of the whole RIFF chunk
734 out[5] = (n >> 8) & 0xFF;
735 out[6] = (n >> 16) & 0xFF;
736 out[7] = (n >> 24) & 0xFF;
738 n = cls.capturevideo_soundrate;
739 out[24] = (n) & 0xFF;
740 out[25] = (n >> 8) & 0xFF;
741 out[26] = (n >> 16) & 0xFF;
742 out[27] = (n >> 24) & 0xFF;
743 // bytes per second (rate * channels * bytes per channel)
744 n = cls.capturevideo_soundrate * 2 * 2;
745 out[28] = (n) & 0xFF;
746 out[29] = (n >> 8) & 0xFF;
747 out[30] = (n >> 16) & 0xFF;
748 out[31] = (n >> 24) & 0xFF;
749 // the length of the data chunk
751 out[40] = (n) & 0xFF;
752 out[41] = (n >> 8) & 0xFF;
753 out[42] = (n >> 16) & 0xFF;
754 out[43] = (n >> 24) & 0xFF;
755 FS_Seek (cls.capturevideo_soundfile, 0, SEEK_SET);
756 FS_Write (cls.capturevideo_soundfile, out, 44);
757 FS_Close (cls.capturevideo_soundfile);
758 cls.capturevideo_soundfile = NULL;
761 if (cls.capturevideo_buffer)
763 Mem_Free (cls.capturevideo_buffer);
764 cls.capturevideo_buffer = NULL;
767 cls.capturevideo_starttime = 0;
768 cls.capturevideo_framerate = 0;
769 cls.capturevideo_frame = 0;
772 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
774 int x = 0, y = 0, width = vid.width, height = vid.height;
775 unsigned char *b, *out;
777 int outoffset = (width/2)*(height/2);
778 //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);
779 // speed is critical here, so do saving as directly as possible
780 switch (cls.capturevideo_format)
782 case CAPTUREVIDEOFORMAT_RAWYV12:
783 // FIXME: width/height must be multiple of 2, enforce this?
784 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);
786 // process one line at a time, and CbCr every other line at 2 pixel intervals
787 for (y = 0;y < height;y++)
790 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++)
791 *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]]];
794 // 2x2 Cb and Cr planes
796 // low quality, no averaging
797 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++)
800 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];
802 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];
805 // high quality, averaging
806 int inpitch = width*3;
807 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++)
809 int blockr, blockg, blockb;
810 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
811 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
812 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
814 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];
816 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];
821 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
822 if (!FS_Write (cls.capturevideo_videofile, cls.capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
825 case CAPTUREVIDEOFORMAT_RAWRGB:
826 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);
828 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
829 if (!FS_Write (cls.capturevideo_videofile, cls.capturevideo_buffer, width*height*3))
832 case CAPTUREVIDEOFORMAT_JPEG:
833 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);
835 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
837 sprintf(filename, "video/dp%06d.jpg", cls.capturevideo_frame);
838 if (!JPEG_SaveImage_preflipped (filename, width, height, cls.capturevideo_buffer))
842 case CAPTUREVIDEOFORMAT_TARGA:
843 //return Image_WriteTGARGB_preflipped (filename, width, height, cls.capturevideo_buffer, cls.capturevideo_buffer + vid.width * vid.height * 3, );
844 memset (cls.capturevideo_buffer, 0, 18);
845 cls.capturevideo_buffer[2] = 2; // uncompressed type
846 cls.capturevideo_buffer[12] = (width >> 0) & 0xFF;
847 cls.capturevideo_buffer[13] = (width >> 8) & 0xFF;
848 cls.capturevideo_buffer[14] = (height >> 0) & 0xFF;
849 cls.capturevideo_buffer[15] = (height >> 8) & 0xFF;
850 cls.capturevideo_buffer[16] = 24; // pixel size
851 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cls.capturevideo_buffer + 18);
853 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
855 sprintf(filename, "video/dp%06d.tga", cls.capturevideo_frame);
856 if (!FS_WriteFile (filename, cls.capturevideo_buffer, width*height*3 + 18))
865 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
867 if (!cls.capturevideo_soundfile)
869 cls.capturevideo_soundrate = rate;
870 if (FS_Write (cls.capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
872 Cvar_SetValueQuick(&cl_capturevideo, 0);
873 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo_frame);
874 SCR_CaptureVideo_EndVideo();
878 void SCR_CaptureVideo(void)
881 if (cl_capturevideo.integer && r_render.integer)
883 if (!cls.capturevideo_active)
884 SCR_CaptureVideo_BeginVideo();
885 if (cls.capturevideo_framerate != cl_capturevideo_fps.value)
887 Con_Printf("You can not change the video framerate while recording a video.\n");
888 Cvar_SetValueQuick(&cl_capturevideo_fps, cls.capturevideo_framerate);
890 if (cls.capturevideo_soundfile)
892 // preserve sound sync by duplicating frames when running slow
893 newframenum = (int)((Sys_DoubleTime() - cls.capturevideo_starttime) * cls.capturevideo_framerate);
896 newframenum = cls.capturevideo_frame + 1;
897 // if falling behind more than one second, stop
898 if (newframenum - cls.capturevideo_frame > (int)ceil(cls.capturevideo_framerate))
900 Cvar_SetValueQuick(&cl_capturevideo, 0);
901 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cls.capturevideo_frame);
902 SCR_CaptureVideo_EndVideo();
906 if (!SCR_CaptureVideo_VideoFrame(newframenum))
908 Cvar_SetValueQuick(&cl_capturevideo, 0);
909 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo_frame);
910 SCR_CaptureVideo_EndVideo();
913 else if (cls.capturevideo_active)
914 SCR_CaptureVideo_EndVideo();
921 Grab six views for environment mapping tests
928 qboolean flipx, flipy, flipdiagonaly;
932 {{ 0, 0, 0}, "rt", false, false, false},
933 {{ 0, 270, 0}, "ft", false, false, false},
934 {{ 0, 180, 0}, "lf", false, false, false},
935 {{ 0, 90, 0}, "bk", false, false, false},
936 {{-90, 180, 0}, "up", true, true, false},
937 {{ 90, 180, 0}, "dn", true, true, false},
939 {{ 0, 0, 0}, "px", true, true, true},
940 {{ 0, 90, 0}, "py", false, true, false},
941 {{ 0, 180, 0}, "nx", false, false, true},
942 {{ 0, 270, 0}, "ny", true, false, false},
943 {{-90, 180, 0}, "pz", false, false, true},
944 {{ 90, 180, 0}, "nz", false, false, true}
947 static void R_Envmap_f (void)
950 char filename[MAX_QPATH], basename[MAX_QPATH];
951 unsigned char *buffer1;
952 unsigned char *buffer2;
953 unsigned char *buffer3;
957 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");
961 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
962 size = atoi(Cmd_Argv(2));
963 if (size != 128 && size != 256 && size != 512 && size != 1024)
965 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
968 if (size > vid.width || size > vid.height)
970 Con_Print("envmap: your resolution is not big enough to render that size\n");
978 r_refdef.width = size;
979 r_refdef.height = size;
981 r_refdef.frustum_x = tan(90 * M_PI / 360.0);
982 r_refdef.frustum_y = tan(90 * M_PI / 360.0);
984 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
985 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
986 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
988 for (j = 0;j < 12;j++)
990 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
991 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);
996 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);
1006 //=============================================================================
1008 // LordHavoc: SHOWLMP stuff
1009 #define SHOWLMP_MAXLABELS 256
1010 typedef struct showlmp_s
1020 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1022 void SHOWLMP_decodehide(void)
1026 lmplabel = MSG_ReadString();
1027 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1028 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1030 showlmp[i].isactive = false;
1035 void SHOWLMP_decodeshow(void)
1038 char lmplabel[256], picname[256];
1040 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1041 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1042 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1049 x = MSG_ReadShort();
1050 y = MSG_ReadShort();
1053 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1054 if (showlmp[i].isactive)
1056 if (strcmp(showlmp[i].label, lmplabel) == 0)
1059 break; // drop out to replace it
1062 else if (k < 0) // find first empty one to replace
1065 return; // none found to replace
1066 // change existing one
1067 showlmp[k].isactive = true;
1068 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1069 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1074 void SHOWLMP_drawall(void)
1077 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1078 if (showlmp[i].isactive)
1079 DrawQ_Pic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic, true), 0, 0, 1, 1, 1, 1, 0);
1082 void SHOWLMP_clear(void)
1085 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1086 showlmp[i].isactive = false;
1090 ==============================================================================
1094 ==============================================================================
1097 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)
1099 int indices[3] = {0,1,2};
1102 if (!r_render.integer)
1105 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer1);
1108 if (scr_screenshot_gamma.value != 1 && gammacorrect)
1111 double igamma = 1.0 / scr_screenshot_gamma.value;
1112 unsigned char ramp[256];
1113 for (i = 0;i < 256;i++)
1114 ramp[i] = (unsigned char) (pow(i * (1.0 / 255.0), igamma) * 255.0);
1115 for (i = 0;i < width*height*3;i++)
1116 buffer1[i] = ramp[buffer1[i]];
1119 Image_CopyMux (buffer2, buffer1, width, height, flipx, flipy, flipdiagonal, 3, 3, indices);
1122 ret = JPEG_SaveImage_preflipped (filename, width, height, buffer2);
1124 ret = Image_WriteTGARGB_preflipped (filename, width, height, buffer2, buffer3);
1129 //=============================================================================
1131 void R_ClearScreen(void)
1133 if (r_render.integer)
1137 qglClearColor(fogcolor[0],fogcolor[1],fogcolor[2],0);
1139 qglClearColor(0,0,0,0);
1141 qglClearDepth(1);CHECKGLERROR
1144 // LordHavoc: we use a stencil centered around 128 instead of 0,
1145 // to avoid clamping interfering with strange shadow volume
1147 qglClearStencil(128);CHECKGLERROR
1150 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (gl_stencil ? GL_STENCIL_BUFFER_BIT : 0));
1151 // set dithering mode
1152 if (gl_dither.integer)
1154 qglEnable(GL_DITHER);CHECKGLERROR
1158 qglDisable(GL_DITHER);CHECKGLERROR
1163 qboolean CL_VM_UpdateView (void);
1164 void SCR_DrawConsole (void);
1165 void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1169 void SCR_DrawScreen (void)
1173 if (r_timereport_active)
1174 R_TimeReport("setup");
1176 if (cls.signon == SIGNONS)
1180 size = scr_viewsize.value * (1.0 / 100.0);
1181 size = min(size, 1);
1183 if (r_stereo_sidebyside.integer)
1185 r_refdef.width = (int)(vid.width * size / 2.5);
1186 r_refdef.height = (int)(vid.height * size / 2.5 * (1 - bound(0, r_letterbox.value, 100) / 100));
1187 r_refdef.x = (int)((vid.width - r_refdef.width * 2.5) * 0.5);
1188 r_refdef.y = (int)((vid.height - r_refdef.height)/2);
1190 r_refdef.x += (int)(r_refdef.width * 1.5);
1194 r_refdef.width = (int)(vid.width * size);
1195 r_refdef.height = (int)(vid.height * size * (1 - bound(0, r_letterbox.value, 100) / 100));
1196 r_refdef.x = (int)((vid.width - r_refdef.width)/2);
1197 r_refdef.y = (int)((vid.height - r_refdef.height)/2);
1200 // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
1201 // LordHavoc: this is designed to produce widescreen fov values
1202 // when the screen is wider than 4/3 width/height aspect, to do
1203 // this it simply assumes the requested fov is the vertical fov
1204 // for a 4x3 display, if the ratio is not 4x3 this makes the fov
1205 // higher/lower according to the ratio
1206 r_refdef.frustum_y = tan(scr_fov.value * cl.viewzoom * M_PI / 360.0) * (3.0/4.0);
1207 r_refdef.frustum_x = r_refdef.frustum_y * (float)r_refdef.width / (float)r_refdef.height / vid_pixelheight.value;
1209 r_refdef.frustum_x *= r_refdef.frustumscale_x;
1210 r_refdef.frustum_y *= r_refdef.frustumscale_y;
1212 if(!CL_VM_UpdateView())
1217 if (scr_zoomwindow.integer)
1219 float sizex = bound(10, scr_zoomwindow_viewsizex.value, 100) / 100.0;
1220 float sizey = bound(10, scr_zoomwindow_viewsizey.value, 100) / 100.0;
1221 r_refdef.width = (int)(vid.width * sizex);
1222 r_refdef.height = (int)(vid.height * sizey);
1223 r_refdef.x = (int)((vid.width - r_refdef.width)/2);
1226 r_refdef.frustum_y = tan(scr_zoomwindow_fov.value * cl.viewzoom * M_PI / 360.0) * (3.0/4.0);
1227 r_refdef.frustum_x = r_refdef.frustum_y * vid_pixelheight.value * (float)r_refdef.width / (float)r_refdef.height;
1229 r_refdef.frustum_x *= r_refdef.frustumscale_x;
1230 r_refdef.frustum_y *= r_refdef.frustumscale_y;
1232 if(!CL_VM_UpdateView())
1237 if (!r_stereo_sidebyside.integer)
1239 r_refdef.width = vid.width;
1240 r_refdef.height = vid.height;
1248 //FIXME: force menu if nothing else to look at?
1249 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1251 if (cls.signon == SIGNONS)
1256 if (!r_letterbox.value)
1259 SCR_CheckDrawCenterString();
1263 R_Shadow_EditLights_DrawSelectedLightProperties();
1272 if (r_timereport_active)
1275 if (cls.signon == SIGNONS)
1276 R_TimeReport_Frame();
1284 if (r_timereport_active)
1285 R_TimeReport("meshfinish");
1288 void SCR_UpdateLoadingScreen (void)
1293 float texcoord2f[8];
1294 // don't do anything if not initialized yet
1297 qglViewport(0, 0, vid.width, vid.height);
1298 //qglDisable(GL_SCISSOR_TEST);
1300 qglColorMask(1,1,1,1);
1301 //qglClearColor(0,0,0,0);
1302 //qglClear(GL_COLOR_BUFFER_BIT);
1303 //qglCullFace(GL_FRONT);
1304 //qglDisable(GL_CULL_FACE);
1307 GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
1309 R_Mesh_Matrix(&identitymatrix);
1310 // draw the loading plaque
1311 pic = Draw_CachePic("gfx/loading", true);
1312 x = (vid_conwidth.integer - pic->width)/2;
1313 y = (vid_conheight.integer - pic->height)/2;
1315 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1316 GL_DepthTest(false);
1317 R_Mesh_VertexPointer(vertex3f);
1318 R_Mesh_ColorPointer(NULL);
1319 R_Mesh_ResetTextureState();
1320 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
1321 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
1322 vertex3f[2] = vertex3f[5] = vertex3f[8] = vertex3f[11] = 0;
1323 vertex3f[0] = vertex3f[9] = x;
1324 vertex3f[1] = vertex3f[4] = y;
1325 vertex3f[3] = vertex3f[6] = x + pic->width;
1326 vertex3f[7] = vertex3f[10] = y + pic->height;
1327 texcoord2f[0] = 0;texcoord2f[1] = 0;
1328 texcoord2f[2] = 1;texcoord2f[3] = 0;
1329 texcoord2f[4] = 1;texcoord2f[5] = 1;
1330 texcoord2f[6] = 0;texcoord2f[7] = 1;
1331 R_Mesh_Draw(0, 4, 2, polygonelements);
1337 void CL_UpdateScreen(void)
1339 float conwidth, conheight;
1344 if (!scr_initialized || !con_initialized || vid_hidden)
1345 return; // not initialized yet
1347 // don't allow cheats in multiplayer
1348 if (!cl.islocalgame && cl.worldmodel)
1350 if (r_fullbright.integer != 0)
1351 Cvar_Set ("r_fullbright", "0");
1352 if (r_ambient.value != 0)
1353 Cvar_Set ("r_ambient", "0");
1356 conwidth = bound(320, vid_conwidth.value, 2048);
1357 conheight = bound(200, vid_conheight.value, 1536);
1358 if (vid_conwidth.value != conwidth)
1359 Cvar_SetValue("vid_conwidth", conwidth);
1360 if (vid_conheight.value != conheight)
1361 Cvar_SetValue("vid_conheight", conheight);
1364 if (scr_viewsize.value < 30)
1365 Cvar_Set ("viewsize","30");
1366 if (scr_viewsize.value > 120)
1367 Cvar_Set ("viewsize","120");
1369 // bound field of view
1370 if (scr_fov.value < 1)
1371 Cvar_Set ("fov","1");
1372 if (scr_fov.value > 170)
1373 Cvar_Set ("fov","170");
1375 // validate r_textureunits cvar
1376 if (r_textureunits.integer > gl_textureunits)
1377 Cvar_SetValueQuick(&r_textureunits, gl_textureunits);
1378 if (r_textureunits.integer < 1)
1379 Cvar_SetValueQuick(&r_textureunits, 1);
1381 // validate gl_combine cvar
1382 if (gl_combine.integer && !gl_combine_extension)
1383 Cvar_SetValueQuick(&gl_combine, 0);
1385 // intermission is always full screen
1386 if (cl.intermission)
1390 if (scr_viewsize.value >= 120)
1391 sb_lines = 0; // no status bar at all
1392 else if (scr_viewsize.value >= 110)
1393 sb_lines = 24; // no inventory
1398 r_refdef.colormask[0] = 1;
1399 r_refdef.colormask[1] = 1;
1400 r_refdef.colormask[2] = 1;
1402 if (r_timereport_active)
1403 R_TimeReport("other");
1405 SCR_SetUpToDrawConsole();
1407 if (r_timereport_active)
1408 R_TimeReport("start");
1411 qglViewport(0, 0, vid.width, vid.height);
1412 qglDisable(GL_SCISSOR_TEST);
1414 qglColorMask(1,1,1,1);
1415 qglClearColor(0,0,0,0);
1416 qglClear(GL_COLOR_BUFFER_BIT);
1419 if (r_timereport_active)
1420 R_TimeReport("clear");
1422 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer || r_stereo_sidebyside.integer)
1424 matrix4x4_t originalmatrix = r_refdef.viewentitymatrix;
1425 r_refdef.viewentitymatrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[0][1];
1426 r_refdef.viewentitymatrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[1][1];
1427 r_refdef.viewentitymatrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * -0.5f * r_refdef.viewentitymatrix.m[2][1];
1429 if (r_stereo_sidebyside.integer)
1432 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1434 r_refdef.colormask[0] = 1;
1435 r_refdef.colormask[1] = 0;
1436 r_refdef.colormask[2] = 0;
1441 r_refdef.viewentitymatrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[0][1];
1442 r_refdef.viewentitymatrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[1][1];
1443 r_refdef.viewentitymatrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * 0.5f * r_refdef.viewentitymatrix.m[2][1];
1445 if (r_stereo_sidebyside.integer)
1448 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1450 r_refdef.colormask[0] = 0;
1451 r_refdef.colormask[1] = r_stereo_redcyan.integer || r_stereo_redgreen.integer;
1452 r_refdef.colormask[2] = r_stereo_redcyan.integer || r_stereo_redblue.integer;
1457 r_refdef.viewentitymatrix = originalmatrix;
1465 if (r_timereport_active)
1466 R_TimeReport("finish");
1469 void CL_Screen_NewMap(void)