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_fps = {0, "cl_capturevideo_fps", "30", "how many frames per second to save (29.97 for NTSC, 30 for typical PC video, 15 can be useful)"};
30 cvar_t cl_capturevideo_rawrgb = {0, "cl_capturevideo_rawrgb", "0", "saves a single .rgb video file containing raw RGB images (you'll need special processing tools to encode this to something more useful)"};
31 cvar_t cl_capturevideo_rawyv12 = {0, "cl_capturevideo_rawyv12", "0", "saves a single .yv12 video file containing raw YV12 (luma plane, then half resolution chroma planes, first chroma blue then chroma red, this is the format used internally by many encoders, some tools can read it directly)"};
32 cvar_t cl_capturevideo_number = {CVAR_SAVE, "cl_capturevideo_number", "1", "number to append to video filename, incremented each time a capture begins"};
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_fps);
540 Cvar_RegisterVariable (&cl_capturevideo_rawrgb);
541 Cvar_RegisterVariable (&cl_capturevideo_rawyv12);
542 Cvar_RegisterVariable (&cl_capturevideo_number);
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;
629 dpsnprintf(cls.capturevideo_basename, sizeof(cls.capturevideo_basename), "video/dpvideo%03i", cl_capturevideo_number.integer);
630 Cvar_SetValueQuick(&cl_capturevideo_number, cl_capturevideo_number.integer + 1);
633 for (i = 0;i < 256;i++)
635 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
636 cls.capturevideo_rgbgammatable[0][i] = j;
637 cls.capturevideo_rgbgammatable[1][i] = j;
638 cls.capturevideo_rgbgammatable[2][i] = j;
642 R = Y + 1.4075 * (Cr - 128);
643 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
644 B = Y + 1.7790 * (Cb - 128);
645 Y = R * .299 + G * .587 + B * .114;
646 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
647 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
649 for (i = 0;i < 256;i++)
651 g = 255*pow(i/255.0, gamma);
652 // Y weights from RGB
653 cls.capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
654 cls.capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
655 cls.capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
656 // Cb weights from RGB
657 cls.capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
658 cls.capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
659 cls.capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
660 // Cr weights from RGB
661 cls.capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
662 cls.capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
663 cls.capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
664 // range reduction of YCbCr to valid signal range
665 cls.capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
666 cls.capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
667 cls.capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
670 if (cl_capturevideo_rawrgb.integer)
672 cls.capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
673 cls.capturevideo_videofile = FS_Open (va("%s.rgb", cls.capturevideo_basename), "wb", false, true);
675 else if (cl_capturevideo_rawyv12.integer)
677 cls.capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
678 cls.capturevideo_videofile = FS_Open (va("%s.yv12", cls.capturevideo_basename), "wb", false, true);
680 else if (scr_screenshot_jpeg.integer)
682 cls.capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
683 cls.capturevideo_videofile = NULL;
687 cls.capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
688 cls.capturevideo_videofile = NULL;
691 cls.capturevideo_soundfile = FS_Open (va("%s.wav", cls.capturevideo_basename), "wb", false, true);
692 if (cls.capturevideo_soundfile)
694 // wave header will be filled out when video ends
696 FS_Write (cls.capturevideo_soundfile, out, 44);
699 Con_Printf("Could not open video/dpvideo.wav for writing, sound capture disabled\n");
702 void SCR_CaptureVideo_EndVideo(void)
705 unsigned char out[44];
706 if (!cls.capturevideo_active)
708 cls.capturevideo_active = false;
710 if (cls.capturevideo_videofile)
712 FS_Close(cls.capturevideo_videofile);
713 cls.capturevideo_videofile = NULL;
716 // finish the wave file
717 if (cls.capturevideo_soundfile)
719 i = (int)FS_Tell (cls.capturevideo_soundfile);
720 //"RIFF", (int) unknown (chunk size), "WAVE",
721 //"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
722 //"data", (int) unknown (chunk size)
723 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
724 // the length of the whole RIFF chunk
727 out[5] = (n >> 8) & 0xFF;
728 out[6] = (n >> 16) & 0xFF;
729 out[7] = (n >> 24) & 0xFF;
731 n = cls.capturevideo_soundrate;
732 out[24] = (n) & 0xFF;
733 out[25] = (n >> 8) & 0xFF;
734 out[26] = (n >> 16) & 0xFF;
735 out[27] = (n >> 24) & 0xFF;
736 // bytes per second (rate * channels * bytes per channel)
737 n = cls.capturevideo_soundrate * 2 * 2;
738 out[28] = (n) & 0xFF;
739 out[29] = (n >> 8) & 0xFF;
740 out[30] = (n >> 16) & 0xFF;
741 out[31] = (n >> 24) & 0xFF;
742 // the length of the data chunk
744 out[40] = (n) & 0xFF;
745 out[41] = (n >> 8) & 0xFF;
746 out[42] = (n >> 16) & 0xFF;
747 out[43] = (n >> 24) & 0xFF;
748 FS_Seek (cls.capturevideo_soundfile, 0, SEEK_SET);
749 FS_Write (cls.capturevideo_soundfile, out, 44);
750 FS_Close (cls.capturevideo_soundfile);
751 cls.capturevideo_soundfile = NULL;
754 if (cls.capturevideo_buffer)
756 Mem_Free (cls.capturevideo_buffer);
757 cls.capturevideo_buffer = NULL;
760 cls.capturevideo_starttime = 0;
761 cls.capturevideo_framerate = 0;
762 cls.capturevideo_frame = 0;
765 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
767 int x = 0, y = 0, width = vid.width, height = vid.height;
768 unsigned char *b, *out;
770 int outoffset = (width/2)*(height/2);
772 //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);
773 // speed is critical here, so do saving as directly as possible
774 switch (cls.capturevideo_format)
776 case CAPTUREVIDEOFORMAT_RAWYV12:
777 // if there's no videofile we have to just give up, and abort saving if there's no video or sound file
778 if (!cls.capturevideo_videofile)
779 return cls.capturevideo_soundfile != NULL;
780 // FIXME: width/height must be multiple of 2, enforce this?
781 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
782 // process one line at a time, and CbCr every other line at 2 pixel intervals
783 for (y = 0;y < height;y++)
786 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++)
787 *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]]];
790 // 2x2 Cb and Cr planes
792 // low quality, no averaging
793 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++)
796 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];
798 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];
801 // high quality, averaging
802 int inpitch = width*3;
803 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++)
805 int blockr, blockg, blockb;
806 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
807 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
808 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
810 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];
812 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];
817 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
818 if (!FS_Write (cls.capturevideo_videofile, cls.capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
821 case CAPTUREVIDEOFORMAT_RAWRGB:
822 // if there's no videofile we have to just give up, and abort saving if there's no video or sound file
823 if (!cls.capturevideo_videofile)
824 return cls.capturevideo_soundfile != NULL;
825 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
826 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
827 if (!FS_Write (cls.capturevideo_videofile, cls.capturevideo_buffer, width*height*3))
830 case CAPTUREVIDEOFORMAT_JPEG:
831 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
832 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
834 sprintf(filename, "%s_%06d.jpg", cls.capturevideo_basename, cls.capturevideo_frame);
835 if (!JPEG_SaveImage_preflipped (filename, width, height, cls.capturevideo_buffer))
839 case CAPTUREVIDEOFORMAT_TARGA:
840 //return Image_WriteTGARGB_preflipped (filename, width, height, cls.capturevideo_buffer, cls.capturevideo_buffer + vid.width * vid.height * 3, );
841 memset (cls.capturevideo_buffer, 0, 18);
842 cls.capturevideo_buffer[2] = 2; // uncompressed type
843 cls.capturevideo_buffer[12] = (width >> 0) & 0xFF;
844 cls.capturevideo_buffer[13] = (width >> 8) & 0xFF;
845 cls.capturevideo_buffer[14] = (height >> 0) & 0xFF;
846 cls.capturevideo_buffer[15] = (height >> 8) & 0xFF;
847 cls.capturevideo_buffer[16] = 24; // pixel size
848 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cls.capturevideo_buffer + 18);CHECKGLERROR
849 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
851 sprintf(filename, "%s_%06d.tga", cls.capturevideo_basename, cls.capturevideo_frame);
852 if (!FS_WriteFile (filename, cls.capturevideo_buffer, width*height*3 + 18))
861 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
863 if (!cls.capturevideo_soundfile)
865 cls.capturevideo_soundrate = rate;
866 if (FS_Write (cls.capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
868 Cvar_SetValueQuick(&cl_capturevideo, 0);
869 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo_frame);
870 SCR_CaptureVideo_EndVideo();
874 void SCR_CaptureVideo(void)
877 if (cl_capturevideo.integer && r_render.integer)
879 if (!cls.capturevideo_active)
880 SCR_CaptureVideo_BeginVideo();
881 if (cls.capturevideo_framerate != cl_capturevideo_fps.value)
883 Con_Printf("You can not change the video framerate while recording a video.\n");
884 Cvar_SetValueQuick(&cl_capturevideo_fps, cls.capturevideo_framerate);
887 if (cls.capturevideo_soundfile)
889 // preserve sound sync by duplicating frames when running slow
890 newframenum = (int)((Sys_DoubleTime() - cls.capturevideo_starttime) * cls.capturevideo_framerate);
894 newframenum = cls.capturevideo_frame + 1;
895 // if falling behind more than one second, stop
896 if (newframenum - cls.capturevideo_frame > (int)ceil(cls.capturevideo_framerate))
898 Cvar_SetValueQuick(&cl_capturevideo, 0);
899 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cls.capturevideo_frame);
900 SCR_CaptureVideo_EndVideo();
904 if (!SCR_CaptureVideo_VideoFrame(newframenum))
906 Cvar_SetValueQuick(&cl_capturevideo, 0);
907 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo_frame);
908 SCR_CaptureVideo_EndVideo();
911 else if (cls.capturevideo_active)
912 SCR_CaptureVideo_EndVideo();
919 Grab six views for environment mapping tests
926 qboolean flipx, flipy, flipdiagonaly;
930 {{ 0, 0, 0}, "rt", false, false, false},
931 {{ 0, 270, 0}, "ft", false, false, false},
932 {{ 0, 180, 0}, "lf", false, false, false},
933 {{ 0, 90, 0}, "bk", false, false, false},
934 {{-90, 180, 0}, "up", true, true, false},
935 {{ 90, 180, 0}, "dn", true, true, false},
937 {{ 0, 0, 0}, "px", true, true, true},
938 {{ 0, 90, 0}, "py", false, true, false},
939 {{ 0, 180, 0}, "nx", false, false, true},
940 {{ 0, 270, 0}, "ny", true, false, false},
941 {{-90, 180, 0}, "pz", false, false, true},
942 {{ 90, 180, 0}, "nz", false, false, true}
945 static void R_Envmap_f (void)
948 char filename[MAX_QPATH], basename[MAX_QPATH];
949 unsigned char *buffer1;
950 unsigned char *buffer2;
951 unsigned char *buffer3;
955 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");
959 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
960 size = atoi(Cmd_Argv(2));
961 if (size != 128 && size != 256 && size != 512 && size != 1024)
963 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
966 if (size > vid.width || size > vid.height)
968 Con_Print("envmap: your resolution is not big enough to render that size\n");
972 r_refdef.envmap = true;
980 r_view.height = size;
983 r_view.frustum_x = tan(90 * M_PI / 360.0);
984 r_view.frustum_y = tan(90 * M_PI / 360.0);
986 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
987 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
988 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
990 for (j = 0;j < 12;j++)
992 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
993 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);
998 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);
1005 r_refdef.envmap = false;
1008 //=============================================================================
1010 // LordHavoc: SHOWLMP stuff
1011 #define SHOWLMP_MAXLABELS 256
1012 typedef struct showlmp_s
1022 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1024 void SHOWLMP_decodehide(void)
1028 lmplabel = MSG_ReadString();
1029 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1030 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1032 showlmp[i].isactive = false;
1037 void SHOWLMP_decodeshow(void)
1040 char lmplabel[256], picname[256];
1042 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1043 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1044 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1051 x = MSG_ReadShort();
1052 y = MSG_ReadShort();
1055 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1056 if (showlmp[i].isactive)
1058 if (strcmp(showlmp[i].label, lmplabel) == 0)
1061 break; // drop out to replace it
1064 else if (k < 0) // find first empty one to replace
1067 return; // none found to replace
1068 // change existing one
1069 showlmp[k].isactive = true;
1070 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1071 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1076 void SHOWLMP_drawall(void)
1079 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1080 if (showlmp[i].isactive)
1081 DrawQ_Pic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic, true), 0, 0, 1, 1, 1, 1, 0);
1084 void SHOWLMP_clear(void)
1087 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1088 showlmp[i].isactive = false;
1092 ==============================================================================
1096 ==============================================================================
1099 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)
1101 int indices[3] = {0,1,2};
1104 if (!r_render.integer)
1108 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer1);CHECKGLERROR
1110 if (scr_screenshot_gammaboost.value != 1 && gammacorrect)
1113 double igamma = 1.0 / scr_screenshot_gammaboost.value;
1114 unsigned char ramp[256];
1115 for (i = 0;i < 256;i++)
1116 ramp[i] = (unsigned char) (pow(i * (1.0 / 255.0), igamma) * 255.0);
1117 for (i = 0;i < width*height*3;i++)
1118 buffer1[i] = ramp[buffer1[i]];
1121 Image_CopyMux (buffer2, buffer1, width, height, flipx, flipy, flipdiagonal, 3, 3, indices);
1124 ret = JPEG_SaveImage_preflipped (filename, width, height, buffer2);
1126 ret = Image_WriteTGARGB_preflipped (filename, width, height, buffer2, buffer3);
1131 //=============================================================================
1133 void R_ClearScreen(void)
1137 if (r_refdef.fogenabled)
1139 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
1143 qglClearColor(0,0,0,0);CHECKGLERROR
1145 qglClearDepth(1);CHECKGLERROR
1148 // LordHavoc: we use a stencil centered around 128 instead of 0,
1149 // to avoid clamping interfering with strange shadow volume
1151 qglClearStencil(128);CHECKGLERROR
1154 if (r_render.integer)
1155 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (gl_stencil ? GL_STENCIL_BUFFER_BIT : 0));
1156 // set dithering mode
1157 if (gl_dither.integer)
1159 qglEnable(GL_DITHER);CHECKGLERROR
1163 qglDisable(GL_DITHER);CHECKGLERROR
1167 qboolean CL_VM_UpdateView (void);
1168 void SCR_DrawConsole (void);
1169 void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1173 void SCR_DrawScreen (void)
1177 if (r_timereport_active)
1178 R_TimeReport("setup");
1180 R_UpdateVariables();
1182 if (cls.signon == SIGNONS)
1186 size = scr_viewsize.value * (1.0 / 100.0);
1187 size = min(size, 1);
1189 if (r_stereo_sidebyside.integer)
1191 r_view.width = (int)(vid.width * size / 2.5);
1192 r_view.height = (int)(vid.height * size / 2.5 * (1 - bound(0, r_letterbox.value, 100) / 100));
1194 r_view.x = (int)((vid.width - r_view.width * 2.5) * 0.5);
1195 r_view.y = (int)((vid.height - r_view.height)/2);
1198 r_view.x += (int)(r_view.width * 1.5);
1202 r_view.width = (int)(vid.width * size);
1203 r_view.height = (int)(vid.height * size * (1 - bound(0, r_letterbox.value, 100) / 100));
1205 r_view.x = (int)((vid.width - r_view.width)/2);
1206 r_view.y = (int)((vid.height - r_view.height)/2);
1210 // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
1211 // LordHavoc: this is designed to produce widescreen fov values
1212 // when the screen is wider than 4/3 width/height aspect, to do
1213 // this it simply assumes the requested fov is the vertical fov
1214 // for a 4x3 display, if the ratio is not 4x3 this makes the fov
1215 // higher/lower according to the ratio
1216 r_view.frustum_y = tan(scr_fov.value * cl.viewzoom * M_PI / 360.0) * (3.0/4.0);
1217 r_view.frustum_x = r_view.frustum_y * (float)r_view.width / (float)r_view.height / vid_pixelheight.value;
1219 r_view.frustum_x *= r_refdef.frustumscale_x;
1220 r_view.frustum_y *= r_refdef.frustumscale_y;
1222 if(!CL_VM_UpdateView())
1227 if (scr_zoomwindow.integer)
1229 float sizex = bound(10, scr_zoomwindow_viewsizex.value, 100) / 100.0;
1230 float sizey = bound(10, scr_zoomwindow_viewsizey.value, 100) / 100.0;
1231 r_view.width = (int)(vid.width * sizex);
1232 r_view.height = (int)(vid.height * sizey);
1234 r_view.x = (int)((vid.width - r_view.width)/2);
1238 r_view.frustum_y = tan(scr_zoomwindow_fov.value * cl.viewzoom * M_PI / 360.0) * (3.0/4.0);
1239 r_view.frustum_x = r_view.frustum_y * vid_pixelheight.value * (float)r_view.width / (float)r_view.height;
1241 r_view.frustum_x *= r_refdef.frustumscale_x;
1242 r_view.frustum_y *= r_refdef.frustumscale_y;
1244 if(!CL_VM_UpdateView())
1249 if (!r_stereo_sidebyside.integer)
1251 r_view.width = vid.width;
1252 r_view.height = vid.height;
1262 //FIXME: force menu if nothing else to look at?
1263 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1265 if (cls.signon == SIGNONS)
1270 if (!r_letterbox.value)
1273 SCR_CheckDrawCenterString();
1277 R_Shadow_EditLights_DrawSelectedLightProperties();
1286 if (r_timereport_active)
1289 if (cls.signon == SIGNONS)
1290 R_TimeReport_Frame();
1298 if (r_timereport_active)
1299 R_TimeReport("meshfinish");
1302 void SCR_UpdateLoadingScreen (void)
1307 float texcoord2f[8];
1308 // don't do anything if not initialized yet
1312 qglViewport(0, 0, vid.width, vid.height);CHECKGLERROR
1313 //qglDisable(GL_SCISSOR_TEST);CHECKGLERROR
1314 //qglDepthMask(1);CHECKGLERROR
1315 qglColorMask(1,1,1,1);CHECKGLERROR
1316 //qglClearColor(0,0,0,0);CHECKGLERROR
1317 //qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1318 //qglCullFace(GL_FRONT);CHECKGLERROR
1319 //qglDisable(GL_CULL_FACE);CHECKGLERROR
1322 GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
1324 R_Mesh_Matrix(&identitymatrix);
1325 // draw the loading plaque
1326 pic = Draw_CachePic("gfx/loading", true);
1327 x = (vid_conwidth.integer - pic->width)/2;
1328 y = (vid_conheight.integer - pic->height)/2;
1330 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1331 GL_DepthTest(false);
1332 R_Mesh_VertexPointer(vertex3f);
1333 R_Mesh_ColorPointer(NULL);
1334 R_Mesh_ResetTextureState();
1335 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
1336 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
1337 vertex3f[2] = vertex3f[5] = vertex3f[8] = vertex3f[11] = 0;
1338 vertex3f[0] = vertex3f[9] = x;
1339 vertex3f[1] = vertex3f[4] = y;
1340 vertex3f[3] = vertex3f[6] = x + pic->width;
1341 vertex3f[7] = vertex3f[10] = y + pic->height;
1342 texcoord2f[0] = 0;texcoord2f[1] = 0;
1343 texcoord2f[2] = 1;texcoord2f[3] = 0;
1344 texcoord2f[4] = 1;texcoord2f[5] = 1;
1345 texcoord2f[6] = 0;texcoord2f[7] = 1;
1346 R_Mesh_Draw(0, 4, 2, polygonelements);
1352 void CL_UpdateScreen(void)
1354 float conwidth, conheight;
1359 if (!scr_initialized || !con_initialized || vid_hidden)
1360 return; // not initialized yet
1362 // don't allow cheats in multiplayer
1363 if (!cl.islocalgame && cl.worldmodel)
1365 if (r_fullbright.integer != 0)
1366 Cvar_Set ("r_fullbright", "0");
1367 if (r_ambient.value != 0)
1368 Cvar_Set ("r_ambient", "0");
1371 conwidth = bound(320, vid_conwidth.value, 2048);
1372 conheight = bound(200, vid_conheight.value, 1536);
1373 if (vid_conwidth.value != conwidth)
1374 Cvar_SetValue("vid_conwidth", conwidth);
1375 if (vid_conheight.value != conheight)
1376 Cvar_SetValue("vid_conheight", conheight);
1379 if (scr_viewsize.value < 30)
1380 Cvar_Set ("viewsize","30");
1381 if (scr_viewsize.value > 120)
1382 Cvar_Set ("viewsize","120");
1384 // bound field of view
1385 if (scr_fov.value < 1)
1386 Cvar_Set ("fov","1");
1387 if (scr_fov.value > 170)
1388 Cvar_Set ("fov","170");
1390 // validate r_textureunits cvar
1391 if (r_textureunits.integer > gl_textureunits)
1392 Cvar_SetValueQuick(&r_textureunits, gl_textureunits);
1393 if (r_textureunits.integer < 1)
1394 Cvar_SetValueQuick(&r_textureunits, 1);
1396 // validate gl_combine cvar
1397 if (gl_combine.integer && !gl_combine_extension)
1398 Cvar_SetValueQuick(&gl_combine, 0);
1400 // intermission is always full screen
1401 if (cl.intermission)
1405 if (scr_viewsize.value >= 120)
1406 sb_lines = 0; // no status bar at all
1407 else if (scr_viewsize.value >= 110)
1408 sb_lines = 24; // no inventory
1413 r_view.colormask[0] = 1;
1414 r_view.colormask[1] = 1;
1415 r_view.colormask[2] = 1;
1417 if (r_timereport_active)
1418 R_TimeReport("other");
1420 SCR_SetUpToDrawConsole();
1422 if (r_timereport_active)
1423 R_TimeReport("start");
1426 qglViewport(0, 0, vid.width, vid.height);CHECKGLERROR
1427 qglDisable(GL_SCISSOR_TEST);CHECKGLERROR
1428 qglDepthMask(1);CHECKGLERROR
1429 qglColorMask(1,1,1,1);CHECKGLERROR
1430 qglClearColor(0,0,0,0);CHECKGLERROR
1431 qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1433 if (r_timereport_active)
1434 R_TimeReport("clear");
1436 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer || r_stereo_sidebyside.integer)
1438 matrix4x4_t originalmatrix = r_view.matrix;
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] = 1;
1449 r_view.colormask[1] = 0;
1450 r_view.colormask[2] = 0;
1455 r_view.matrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[0][1];
1456 r_view.matrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[1][1];
1457 r_view.matrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[2][1];
1459 if (r_stereo_sidebyside.integer)
1462 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1464 r_view.colormask[0] = 0;
1465 r_view.colormask[1] = r_stereo_redcyan.integer || r_stereo_redgreen.integer;
1466 r_view.colormask[2] = r_stereo_redcyan.integer || r_stereo_redblue.integer;
1471 r_view.matrix = originalmatrix;
1479 if (r_timereport_active)
1480 R_TimeReport("finish");
1483 void CL_Screen_NewMap(void)