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 number of characters on the line, not counting color codes
130 for (l=0 ; l<vid_conwidth.integer/8 ; l++)
132 if (start[l] == '\n' || !start[l])
134 // color codes add no visible characters, so don't count them
135 if (start[l] == '^' && (start[l+1] >= '0' && start[l+1] <= '9'))
140 x = (vid_conwidth.integer - chars*8)/2;
145 DrawQ_ColoredString(x, y, start, l, 8, 8, 1, 1, 1, 1, 0, &color);
153 while (*start && *start != '\n')
158 start++; // skip the \n
162 void SCR_CheckDrawCenterString (void)
164 if (scr_center_lines > scr_erase_lines)
165 scr_erase_lines = scr_center_lines;
167 scr_centertime_off -= cl.realframetime;
169 // don't draw if this is a normal stats-screen intermission,
170 // only if it is not an intermission, or a finale intermission
171 if (cl.intermission == 1)
173 if (scr_centertime_off <= 0 && !cl.intermission)
175 if (key_dest != key_game)
178 SCR_DrawCenterString ();
186 void SCR_DrawTurtle (void)
190 if (cls.state != ca_connected)
193 if (!scr_showturtle.integer)
196 if (cl.realframetime < 0.1)
206 DrawQ_Pic (0, 0, Draw_CachePic("gfx/turtle", true), 0, 0, 1, 1, 1, 1, 0);
214 void SCR_DrawNet (void)
216 if (cls.state != ca_connected)
218 if (realtime - cl.last_received_message < 0.3)
220 if (cls.demoplayback)
223 DrawQ_Pic (64, 0, Draw_CachePic("gfx/net", true), 0, 0, 1, 1, 1, 1, 0);
231 void SCR_DrawPause (void)
235 if (cls.state != ca_connected)
238 if (!scr_showpause.integer) // turn off for screenshots
244 pic = Draw_CachePic ("gfx/pause", true);
245 DrawQ_Pic ((vid_conwidth.integer - pic->width)/2, (vid_conheight.integer - pic->height)/2, pic, 0, 0, 1, 1, 1, 1, 0);
253 void SCR_DrawBrand (void)
258 if (!scr_showbrand.value)
261 pic = Draw_CachePic ("gfx/brand", true);
263 switch ((int)scr_showbrand.value)
265 case 1: // bottom left
267 y = vid_conheight.integer - pic->height;
269 case 2: // bottom centre
270 x = (vid_conwidth.integer - pic->width) / 2;
271 y = vid_conheight.integer - pic->height;
273 case 3: // bottom right
274 x = vid_conwidth.integer - pic->width;
275 y = vid_conheight.integer - pic->height;
277 case 4: // centre right
278 x = vid_conwidth.integer - pic->width;
279 y = (vid_conheight.integer - pic->height) / 2;
282 x = vid_conwidth.integer - pic->width;
285 case 6: // top centre
286 x = (vid_conwidth.integer - pic->width) / 2;
293 case 8: // centre left
295 y = (vid_conheight.integer - pic->height) / 2;
301 DrawQ_Pic (x, y, pic, 0, 0, 1, 1, 1, 1, 0);
309 static void SCR_DrawDownload(void)
315 if (!cls.qw_downloadname[0])
317 dpsnprintf(temp, sizeof(temp), "Downloading %s ... %3i%%\n", cls.qw_downloadname, cls.qw_downloadpercent);
318 len = (int)strlen(temp);
319 x = (vid_conwidth.integer - len*size) / 2;
320 y = vid_conheight.integer - size;
321 DrawQ_Pic(0, y, NULL, vid_conwidth.integer, size, 0, 0, 0, 0.5, 0);
322 DrawQ_String(x, y, temp, len, size, size, 1, 1, 1, 1, 0);
325 //=============================================================================
330 SCR_SetUpToDrawConsole
333 void SCR_SetUpToDrawConsole (void)
335 // lines of console to display
337 static int framecounter = 0;
341 if (scr_menuforcewhiledisconnected.integer && key_dest == key_game && cls.state == ca_disconnected)
343 if (framecounter >= 2)
351 if (scr_conforcewhiledisconnected.integer && key_dest == key_game && cls.signon != SIGNONS)
352 key_consoleactive |= KEY_CONSOLEACTIVE_FORCED;
354 key_consoleactive &= ~KEY_CONSOLEACTIVE_FORCED;
356 // decide on the height of the console
357 if (key_consoleactive & KEY_CONSOLEACTIVE_USER)
358 conlines = vid_conheight.integer/2; // half screen
360 conlines = 0; // none visible
362 scr_con_current = conlines;
370 void SCR_DrawConsole (void)
372 if (key_consoleactive & KEY_CONSOLEACTIVE_FORCED)
375 Con_DrawConsole (vid_conheight.integer);
377 else if (scr_con_current)
378 Con_DrawConsole ((int)scr_con_current);
382 if (key_dest == key_game || key_dest == key_message)
383 Con_DrawNotify (); // only draw notify in game
389 SCR_BeginLoadingPlaque
393 void SCR_BeginLoadingPlaque (void)
395 // save console log up to this point to log_file if it was set by configs
400 SCR_UpdateLoadingScreen();
403 //=============================================================================
405 char r_speeds_string[1024];
406 int speedstringcount, r_timereport_active;
407 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
409 void R_TimeReport(char *desc)
415 if (r_speeds.integer < 2 || !r_timereport_active)
419 qglFinish();CHECKGLERROR
420 r_timereport_temp = r_timereport_current;
421 r_timereport_current = Sys_DoubleTime();
422 t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0 + 0.5);
424 dpsnprintf(tempbuf, sizeof(tempbuf), "%8i %-11s", t, desc);
425 length = (int)strlen(tempbuf);
426 if (speedstringcount + length > (vid_conwidth.integer / 8))
428 strlcat(r_speeds_string, "\n", sizeof(r_speeds_string));
429 speedstringcount = 0;
431 strlcat(r_speeds_string, tempbuf, sizeof(r_speeds_string));
432 speedstringcount += length;
435 void R_TimeReport_Frame(void)
439 if (r_speeds_string[0])
441 if (r_timereport_active)
443 r_timereport_current = r_timereport_start;
444 R_TimeReport("total");
447 if (r_speeds_string[strlen(r_speeds_string)-1] == '\n')
448 r_speeds_string[strlen(r_speeds_string)-1] = 0;
450 for (i = 0;r_speeds_string[i];i++)
451 if (r_speeds_string[i] == '\n')
453 y = vid_conheight.integer - sb_lines - lines * 8;
455 DrawQ_Pic(0, y, NULL, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0);
456 while (r_speeds_string[i])
459 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
462 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
463 if (r_speeds_string[i] == '\n')
467 r_speeds_string[0] = 0;
468 r_timereport_active = false;
470 if (r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected)
472 speedstringcount = 0;
473 r_speeds_string[0] = 0;
474 r_timereport_active = false;
475 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]);
476 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);
477 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);
478 if (r_refdef.stats.bloom)
479 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);
481 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles\n", r_refdef.stats.meshes, r_refdef.stats.meshes_elements / 3);
483 memset(&r_refdef.stats, 0, sizeof(r_refdef.stats));
485 if (r_speeds.integer >= 2)
487 r_timereport_active = true;
488 r_timereport_start = r_timereport_current = Sys_DoubleTime();
500 void SCR_SizeUp_f (void)
502 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
513 void SCR_SizeDown_f (void)
515 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
518 void CL_Screen_Init(void)
520 Cvar_RegisterVariable (&scr_fov);
521 Cvar_RegisterVariable (&scr_viewsize);
522 Cvar_RegisterVariable (&scr_conalpha);
523 Cvar_RegisterVariable (&scr_conbrightness);
524 Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
525 Cvar_RegisterVariable (&scr_menuforcewhiledisconnected);
526 Cvar_RegisterVariable (&scr_showram);
527 Cvar_RegisterVariable (&scr_showturtle);
528 Cvar_RegisterVariable (&scr_showpause);
529 Cvar_RegisterVariable (&scr_showbrand);
530 Cvar_RegisterVariable (&scr_centertime);
531 Cvar_RegisterVariable (&scr_printspeed);
532 Cvar_RegisterVariable (&vid_conwidth);
533 Cvar_RegisterVariable (&vid_conheight);
534 Cvar_RegisterVariable (&vid_pixelheight);
535 Cvar_RegisterVariable (&scr_screenshot_jpeg);
536 Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
537 Cvar_RegisterVariable (&scr_screenshot_gammaboost);
538 Cvar_RegisterVariable (&cl_capturevideo);
539 Cvar_RegisterVariable (&cl_capturevideo_sound);
540 Cvar_RegisterVariable (&cl_capturevideo_fps);
541 Cvar_RegisterVariable (&cl_capturevideo_rawrgb);
542 Cvar_RegisterVariable (&cl_capturevideo_rawyv12);
543 Cvar_RegisterVariable (&r_letterbox);
544 Cvar_RegisterVariable(&r_stereo_separation);
545 Cvar_RegisterVariable(&r_stereo_sidebyside);
546 Cvar_RegisterVariable(&r_stereo_redblue);
547 Cvar_RegisterVariable(&r_stereo_redcyan);
548 Cvar_RegisterVariable(&r_stereo_redgreen);
549 Cvar_RegisterVariable(&scr_zoomwindow);
550 Cvar_RegisterVariable(&scr_zoomwindow_viewsizex);
551 Cvar_RegisterVariable(&scr_zoomwindow_viewsizey);
552 Cvar_RegisterVariable(&scr_zoomwindow_fov);
554 Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)");
555 Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)");
556 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f, "takes a screenshot of the next rendered frame");
557 Cmd_AddCommand ("envmap", R_Envmap_f, "render a cubemap (skybox) of the current scene");
559 scr_initialized = true;
567 void SCR_ScreenShot_f (void)
569 static int shotnumber;
570 static char oldname[MAX_QPATH];
571 char base[MAX_QPATH];
572 char filename[MAX_QPATH];
573 unsigned char *buffer1;
574 unsigned char *buffer2;
575 unsigned char *buffer3;
576 qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
578 sprintf (base, "screenshots/%s", scr_screenshot_name.string);
580 if (strcmp (oldname, scr_screenshot_name.string))
582 sprintf(oldname, "%s", scr_screenshot_name.string);
586 // find a file name to save it to
587 for (;shotnumber < 1000000;shotnumber++)
588 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
590 if (shotnumber >= 1000000)
592 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
596 sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
598 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
599 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
600 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3 + 18);
602 if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, 0, 0, vid.width, vid.height, false, false, false, jpeg, true))
603 Con_Printf("Wrote %s\n", filename);
605 Con_Printf("unable to write %s\n", filename);
614 void SCR_CaptureVideo_BeginVideo(void)
618 unsigned char out[44];
619 if (cls.capturevideo_active)
621 // soundrate is figured out on the first SoundFrame
622 cls.capturevideo_active = true;
623 cls.capturevideo_starttime = Sys_DoubleTime();
624 cls.capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
625 cls.capturevideo_soundrate = 0;
626 cls.capturevideo_frame = 0;
627 cls.capturevideo_buffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (3+3+3) + 18);
628 gamma = 1.0/scr_screenshot_gammaboost.value;
631 for (i = 0;i < 256;i++)
633 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
634 cls.capturevideo_rgbgammatable[0][i] = j;
635 cls.capturevideo_rgbgammatable[1][i] = j;
636 cls.capturevideo_rgbgammatable[2][i] = j;
640 R = Y + 1.4075 * (Cr - 128);
641 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
642 B = Y + 1.7790 * (Cb - 128);
643 Y = R * .299 + G * .587 + B * .114;
644 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
645 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
647 for (i = 0;i < 256;i++)
649 g = 255*pow(i/255.0, gamma);
650 // Y weights from RGB
651 cls.capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
652 cls.capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
653 cls.capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
654 // Cb weights from RGB
655 cls.capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
656 cls.capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
657 cls.capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
658 // Cr weights from RGB
659 cls.capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
660 cls.capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
661 cls.capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
662 // range reduction of YCbCr to valid signal range
663 cls.capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
664 cls.capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
665 cls.capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
668 if (cl_capturevideo_rawrgb.integer)
670 cls.capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
671 cls.capturevideo_videofile = FS_Open ("video/dpvideo.rgb", "wb", false, true);
673 else if (cl_capturevideo_rawyv12.integer)
675 cls.capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
676 cls.capturevideo_videofile = FS_Open ("video/dpvideo.yv12", "wb", false, true);
678 else if (scr_screenshot_jpeg.integer)
680 cls.capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
681 cls.capturevideo_videofile = NULL;
685 cls.capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
686 cls.capturevideo_videofile = NULL;
689 if (cl_capturevideo_sound.integer)
691 cls.capturevideo_soundfile = FS_Open ("video/dpvideo.wav", "wb", false, true);
692 // wave header will be filled out when video ends
694 FS_Write (cls.capturevideo_soundfile, out, 44);
697 cls.capturevideo_soundfile = NULL;
700 void SCR_CaptureVideo_EndVideo(void)
703 unsigned char out[44];
704 if (!cls.capturevideo_active)
706 cls.capturevideo_active = false;
708 if (cls.capturevideo_videofile)
710 FS_Close(cls.capturevideo_videofile);
711 cls.capturevideo_videofile = NULL;
714 // finish the wave file
715 if (cls.capturevideo_soundfile)
717 i = (int)FS_Tell (cls.capturevideo_soundfile);
718 //"RIFF", (int) unknown (chunk size), "WAVE",
719 //"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
720 //"data", (int) unknown (chunk size)
721 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
722 // the length of the whole RIFF chunk
725 out[5] = (n >> 8) & 0xFF;
726 out[6] = (n >> 16) & 0xFF;
727 out[7] = (n >> 24) & 0xFF;
729 n = cls.capturevideo_soundrate;
730 out[24] = (n) & 0xFF;
731 out[25] = (n >> 8) & 0xFF;
732 out[26] = (n >> 16) & 0xFF;
733 out[27] = (n >> 24) & 0xFF;
734 // bytes per second (rate * channels * bytes per channel)
735 n = cls.capturevideo_soundrate * 2 * 2;
736 out[28] = (n) & 0xFF;
737 out[29] = (n >> 8) & 0xFF;
738 out[30] = (n >> 16) & 0xFF;
739 out[31] = (n >> 24) & 0xFF;
740 // the length of the data chunk
742 out[40] = (n) & 0xFF;
743 out[41] = (n >> 8) & 0xFF;
744 out[42] = (n >> 16) & 0xFF;
745 out[43] = (n >> 24) & 0xFF;
746 FS_Seek (cls.capturevideo_soundfile, 0, SEEK_SET);
747 FS_Write (cls.capturevideo_soundfile, out, 44);
748 FS_Close (cls.capturevideo_soundfile);
749 cls.capturevideo_soundfile = NULL;
752 if (cls.capturevideo_buffer)
754 Mem_Free (cls.capturevideo_buffer);
755 cls.capturevideo_buffer = NULL;
758 cls.capturevideo_starttime = 0;
759 cls.capturevideo_framerate = 0;
760 cls.capturevideo_frame = 0;
763 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
765 int x = 0, y = 0, width = vid.width, height = vid.height;
766 unsigned char *b, *out;
768 int outoffset = (width/2)*(height/2);
770 //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);
771 // speed is critical here, so do saving as directly as possible
772 switch (cls.capturevideo_format)
774 case CAPTUREVIDEOFORMAT_RAWYV12:
775 // FIXME: width/height must be multiple of 2, enforce this?
776 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
777 // process one line at a time, and CbCr every other line at 2 pixel intervals
778 for (y = 0;y < height;y++)
781 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++)
782 *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]]];
785 // 2x2 Cb and Cr planes
787 // low quality, no averaging
788 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++)
791 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];
793 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];
796 // high quality, averaging
797 int inpitch = width*3;
798 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 int blockr, blockg, blockb;
801 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
802 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
803 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
805 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];
807 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];
812 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
813 if (!FS_Write (cls.capturevideo_videofile, cls.capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
816 case CAPTUREVIDEOFORMAT_RAWRGB:
817 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
818 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
819 if (!FS_Write (cls.capturevideo_videofile, cls.capturevideo_buffer, width*height*3))
822 case CAPTUREVIDEOFORMAT_JPEG:
823 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
824 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
826 sprintf(filename, "video/dp%06d.jpg", cls.capturevideo_frame);
827 if (!JPEG_SaveImage_preflipped (filename, width, height, cls.capturevideo_buffer))
831 case CAPTUREVIDEOFORMAT_TARGA:
832 //return Image_WriteTGARGB_preflipped (filename, width, height, cls.capturevideo_buffer, cls.capturevideo_buffer + vid.width * vid.height * 3, );
833 memset (cls.capturevideo_buffer, 0, 18);
834 cls.capturevideo_buffer[2] = 2; // uncompressed type
835 cls.capturevideo_buffer[12] = (width >> 0) & 0xFF;
836 cls.capturevideo_buffer[13] = (width >> 8) & 0xFF;
837 cls.capturevideo_buffer[14] = (height >> 0) & 0xFF;
838 cls.capturevideo_buffer[15] = (height >> 8) & 0xFF;
839 cls.capturevideo_buffer[16] = 24; // pixel size
840 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cls.capturevideo_buffer + 18);CHECKGLERROR
841 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
843 sprintf(filename, "video/dp%06d.tga", cls.capturevideo_frame);
844 if (!FS_WriteFile (filename, cls.capturevideo_buffer, width*height*3 + 18))
853 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
855 if (!cls.capturevideo_soundfile)
857 cls.capturevideo_soundrate = rate;
858 if (FS_Write (cls.capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
860 Cvar_SetValueQuick(&cl_capturevideo, 0);
861 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo_frame);
862 SCR_CaptureVideo_EndVideo();
866 void SCR_CaptureVideo(void)
869 if (cl_capturevideo.integer && r_render.integer)
871 if (!cls.capturevideo_active)
872 SCR_CaptureVideo_BeginVideo();
873 if (cls.capturevideo_framerate != cl_capturevideo_fps.value)
875 Con_Printf("You can not change the video framerate while recording a video.\n");
876 Cvar_SetValueQuick(&cl_capturevideo_fps, cls.capturevideo_framerate);
878 if (cls.capturevideo_soundfile)
880 // preserve sound sync by duplicating frames when running slow
881 newframenum = (int)((Sys_DoubleTime() - cls.capturevideo_starttime) * cls.capturevideo_framerate);
884 newframenum = cls.capturevideo_frame + 1;
885 // if falling behind more than one second, stop
886 if (newframenum - cls.capturevideo_frame > (int)ceil(cls.capturevideo_framerate))
888 Cvar_SetValueQuick(&cl_capturevideo, 0);
889 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cls.capturevideo_frame);
890 SCR_CaptureVideo_EndVideo();
894 if (!SCR_CaptureVideo_VideoFrame(newframenum))
896 Cvar_SetValueQuick(&cl_capturevideo, 0);
897 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo_frame);
898 SCR_CaptureVideo_EndVideo();
901 else if (cls.capturevideo_active)
902 SCR_CaptureVideo_EndVideo();
909 Grab six views for environment mapping tests
916 qboolean flipx, flipy, flipdiagonaly;
920 {{ 0, 0, 0}, "rt", false, false, false},
921 {{ 0, 270, 0}, "ft", false, false, false},
922 {{ 0, 180, 0}, "lf", false, false, false},
923 {{ 0, 90, 0}, "bk", false, false, false},
924 {{-90, 180, 0}, "up", true, true, false},
925 {{ 90, 180, 0}, "dn", true, true, false},
927 {{ 0, 0, 0}, "px", true, true, true},
928 {{ 0, 90, 0}, "py", false, true, false},
929 {{ 0, 180, 0}, "nx", false, false, true},
930 {{ 0, 270, 0}, "ny", true, false, false},
931 {{-90, 180, 0}, "pz", false, false, true},
932 {{ 90, 180, 0}, "nz", false, false, true}
935 static void R_Envmap_f (void)
938 char filename[MAX_QPATH], basename[MAX_QPATH];
939 unsigned char *buffer1;
940 unsigned char *buffer2;
941 unsigned char *buffer3;
945 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");
949 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
950 size = atoi(Cmd_Argv(2));
951 if (size != 128 && size != 256 && size != 512 && size != 1024)
953 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
956 if (size > vid.width || size > vid.height)
958 Con_Print("envmap: your resolution is not big enough to render that size\n");
962 r_refdef.envmap = true;
970 r_view.height = size;
973 r_view.frustum_x = tan(90 * M_PI / 360.0);
974 r_view.frustum_y = tan(90 * M_PI / 360.0);
976 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
977 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
978 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
980 for (j = 0;j < 12;j++)
982 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
983 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);
988 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);
995 r_refdef.envmap = false;
998 //=============================================================================
1000 // LordHavoc: SHOWLMP stuff
1001 #define SHOWLMP_MAXLABELS 256
1002 typedef struct showlmp_s
1012 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1014 void SHOWLMP_decodehide(void)
1018 lmplabel = MSG_ReadString();
1019 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1020 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1022 showlmp[i].isactive = false;
1027 void SHOWLMP_decodeshow(void)
1030 char lmplabel[256], picname[256];
1032 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1033 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1034 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1041 x = MSG_ReadShort();
1042 y = MSG_ReadShort();
1045 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1046 if (showlmp[i].isactive)
1048 if (strcmp(showlmp[i].label, lmplabel) == 0)
1051 break; // drop out to replace it
1054 else if (k < 0) // find first empty one to replace
1057 return; // none found to replace
1058 // change existing one
1059 showlmp[k].isactive = true;
1060 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1061 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1066 void SHOWLMP_drawall(void)
1069 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1070 if (showlmp[i].isactive)
1071 DrawQ_Pic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic, true), 0, 0, 1, 1, 1, 1, 0);
1074 void SHOWLMP_clear(void)
1077 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1078 showlmp[i].isactive = false;
1082 ==============================================================================
1086 ==============================================================================
1089 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)
1091 int indices[3] = {0,1,2};
1094 if (!r_render.integer)
1098 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer1);CHECKGLERROR
1100 if (scr_screenshot_gammaboost.value != 1 && gammacorrect)
1103 double igamma = 1.0 / scr_screenshot_gammaboost.value;
1104 unsigned char ramp[256];
1105 for (i = 0;i < 256;i++)
1106 ramp[i] = (unsigned char) (pow(i * (1.0 / 255.0), igamma) * 255.0);
1107 for (i = 0;i < width*height*3;i++)
1108 buffer1[i] = ramp[buffer1[i]];
1111 Image_CopyMux (buffer2, buffer1, width, height, flipx, flipy, flipdiagonal, 3, 3, indices);
1114 ret = JPEG_SaveImage_preflipped (filename, width, height, buffer2);
1116 ret = Image_WriteTGARGB_preflipped (filename, width, height, buffer2, buffer3);
1121 //=============================================================================
1123 void R_ClearScreen(void)
1127 if (r_refdef.fogenabled)
1129 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
1133 qglClearColor(0,0,0,0);CHECKGLERROR
1135 qglClearDepth(1);CHECKGLERROR
1138 // LordHavoc: we use a stencil centered around 128 instead of 0,
1139 // to avoid clamping interfering with strange shadow volume
1141 qglClearStencil(128);CHECKGLERROR
1144 if (r_render.integer)
1145 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (gl_stencil ? GL_STENCIL_BUFFER_BIT : 0));
1146 // set dithering mode
1147 if (gl_dither.integer)
1149 qglEnable(GL_DITHER);CHECKGLERROR
1153 qglDisable(GL_DITHER);CHECKGLERROR
1157 qboolean CL_VM_UpdateView (void);
1158 void SCR_DrawConsole (void);
1159 void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1163 void SCR_DrawScreen (void)
1167 if (r_timereport_active)
1168 R_TimeReport("setup");
1170 R_UpdateVariables();
1172 if (cls.signon == SIGNONS)
1176 size = scr_viewsize.value * (1.0 / 100.0);
1177 size = min(size, 1);
1179 if (r_stereo_sidebyside.integer)
1181 r_view.width = (int)(vid.width * size / 2.5);
1182 r_view.height = (int)(vid.height * size / 2.5 * (1 - bound(0, r_letterbox.value, 100) / 100));
1184 r_view.x = (int)((vid.width - r_view.width * 2.5) * 0.5);
1185 r_view.y = (int)((vid.height - r_view.height)/2);
1188 r_view.x += (int)(r_view.width * 1.5);
1192 r_view.width = (int)(vid.width * size);
1193 r_view.height = (int)(vid.height * size * (1 - bound(0, r_letterbox.value, 100) / 100));
1195 r_view.x = (int)((vid.width - r_view.width)/2);
1196 r_view.y = (int)((vid.height - r_view.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_view.frustum_y = tan(scr_fov.value * cl.viewzoom * M_PI / 360.0) * (3.0/4.0);
1207 r_view.frustum_x = r_view.frustum_y * (float)r_view.width / (float)r_view.height / vid_pixelheight.value;
1209 r_view.frustum_x *= r_refdef.frustumscale_x;
1210 r_view.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_view.width = (int)(vid.width * sizex);
1222 r_view.height = (int)(vid.height * sizey);
1224 r_view.x = (int)((vid.width - r_view.width)/2);
1228 r_view.frustum_y = tan(scr_zoomwindow_fov.value * cl.viewzoom * M_PI / 360.0) * (3.0/4.0);
1229 r_view.frustum_x = r_view.frustum_y * vid_pixelheight.value * (float)r_view.width / (float)r_view.height;
1231 r_view.frustum_x *= r_refdef.frustumscale_x;
1232 r_view.frustum_y *= r_refdef.frustumscale_y;
1234 if(!CL_VM_UpdateView())
1239 if (!r_stereo_sidebyside.integer)
1241 r_view.width = vid.width;
1242 r_view.height = vid.height;
1252 //FIXME: force menu if nothing else to look at?
1253 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1255 if (cls.signon == SIGNONS)
1260 if (!r_letterbox.value)
1263 SCR_CheckDrawCenterString();
1267 R_Shadow_EditLights_DrawSelectedLightProperties();
1276 if (r_timereport_active)
1279 if (cls.signon == SIGNONS)
1280 R_TimeReport_Frame();
1288 if (r_timereport_active)
1289 R_TimeReport("meshfinish");
1292 void SCR_UpdateLoadingScreen (void)
1297 float texcoord2f[8];
1298 // don't do anything if not initialized yet
1302 qglViewport(0, 0, vid.width, vid.height);CHECKGLERROR
1303 //qglDisable(GL_SCISSOR_TEST);CHECKGLERROR
1304 //qglDepthMask(1);CHECKGLERROR
1305 qglColorMask(1,1,1,1);CHECKGLERROR
1306 //qglClearColor(0,0,0,0);CHECKGLERROR
1307 //qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1308 //qglCullFace(GL_FRONT);CHECKGLERROR
1309 //qglDisable(GL_CULL_FACE);CHECKGLERROR
1312 GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
1314 R_Mesh_Matrix(&identitymatrix);
1315 // draw the loading plaque
1316 pic = Draw_CachePic("gfx/loading", true);
1317 x = (vid_conwidth.integer - pic->width)/2;
1318 y = (vid_conheight.integer - pic->height)/2;
1320 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1321 GL_DepthTest(false);
1322 R_Mesh_VertexPointer(vertex3f);
1323 R_Mesh_ColorPointer(NULL);
1324 R_Mesh_ResetTextureState();
1325 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
1326 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
1327 vertex3f[2] = vertex3f[5] = vertex3f[8] = vertex3f[11] = 0;
1328 vertex3f[0] = vertex3f[9] = x;
1329 vertex3f[1] = vertex3f[4] = y;
1330 vertex3f[3] = vertex3f[6] = x + pic->width;
1331 vertex3f[7] = vertex3f[10] = y + pic->height;
1332 texcoord2f[0] = 0;texcoord2f[1] = 0;
1333 texcoord2f[2] = 1;texcoord2f[3] = 0;
1334 texcoord2f[4] = 1;texcoord2f[5] = 1;
1335 texcoord2f[6] = 0;texcoord2f[7] = 1;
1336 R_Mesh_Draw(0, 4, 2, polygonelements);
1342 void CL_UpdateScreen(void)
1344 float conwidth, conheight;
1349 if (!scr_initialized || !con_initialized || vid_hidden)
1350 return; // not initialized yet
1352 // don't allow cheats in multiplayer
1353 if (!cl.islocalgame && cl.worldmodel)
1355 if (r_fullbright.integer != 0)
1356 Cvar_Set ("r_fullbright", "0");
1357 if (r_ambient.value != 0)
1358 Cvar_Set ("r_ambient", "0");
1361 conwidth = bound(320, vid_conwidth.value, 2048);
1362 conheight = bound(200, vid_conheight.value, 1536);
1363 if (vid_conwidth.value != conwidth)
1364 Cvar_SetValue("vid_conwidth", conwidth);
1365 if (vid_conheight.value != conheight)
1366 Cvar_SetValue("vid_conheight", conheight);
1369 if (scr_viewsize.value < 30)
1370 Cvar_Set ("viewsize","30");
1371 if (scr_viewsize.value > 120)
1372 Cvar_Set ("viewsize","120");
1374 // bound field of view
1375 if (scr_fov.value < 1)
1376 Cvar_Set ("fov","1");
1377 if (scr_fov.value > 170)
1378 Cvar_Set ("fov","170");
1380 // validate r_textureunits cvar
1381 if (r_textureunits.integer > gl_textureunits)
1382 Cvar_SetValueQuick(&r_textureunits, gl_textureunits);
1383 if (r_textureunits.integer < 1)
1384 Cvar_SetValueQuick(&r_textureunits, 1);
1386 // validate gl_combine cvar
1387 if (gl_combine.integer && !gl_combine_extension)
1388 Cvar_SetValueQuick(&gl_combine, 0);
1390 // intermission is always full screen
1391 if (cl.intermission)
1395 if (scr_viewsize.value >= 120)
1396 sb_lines = 0; // no status bar at all
1397 else if (scr_viewsize.value >= 110)
1398 sb_lines = 24; // no inventory
1403 r_view.colormask[0] = 1;
1404 r_view.colormask[1] = 1;
1405 r_view.colormask[2] = 1;
1407 if (r_timereport_active)
1408 R_TimeReport("other");
1410 SCR_SetUpToDrawConsole();
1412 if (r_timereport_active)
1413 R_TimeReport("start");
1416 qglViewport(0, 0, vid.width, vid.height);CHECKGLERROR
1417 qglDisable(GL_SCISSOR_TEST);CHECKGLERROR
1418 qglDepthMask(1);CHECKGLERROR
1419 qglColorMask(1,1,1,1);CHECKGLERROR
1420 qglClearColor(0,0,0,0);CHECKGLERROR
1421 qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1423 if (r_timereport_active)
1424 R_TimeReport("clear");
1426 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer || r_stereo_sidebyside.integer)
1428 matrix4x4_t originalmatrix = r_view.matrix;
1429 r_view.matrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * -0.5f * r_view.matrix.m[0][1];
1430 r_view.matrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * -0.5f * r_view.matrix.m[1][1];
1431 r_view.matrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * -0.5f * r_view.matrix.m[2][1];
1433 if (r_stereo_sidebyside.integer)
1436 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1438 r_view.colormask[0] = 1;
1439 r_view.colormask[1] = 0;
1440 r_view.colormask[2] = 0;
1445 r_view.matrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[0][1];
1446 r_view.matrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[1][1];
1447 r_view.matrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[2][1];
1449 if (r_stereo_sidebyside.integer)
1452 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1454 r_view.colormask[0] = 0;
1455 r_view.colormask[1] = r_stereo_redcyan.integer || r_stereo_redgreen.integer;
1456 r_view.colormask[2] = r_stereo_redcyan.integer || r_stereo_redblue.integer;
1461 r_view.matrix = originalmatrix;
1469 if (r_timereport_active)
1470 R_TimeReport("finish");
1473 void CL_Screen_NewMap(void)