6 #include "cl_collision.h"
10 cvar_t scr_viewsize = {CVAR_SAVE, "viewsize","100", "how large the view should be, 110 disables inventory bar, 120 disables status bar"};
11 cvar_t scr_fov = {CVAR_SAVE, "fov","90", "field of vision, 1-170 degrees, default 90, some players use 110-130"}; // 1 - 170
12 cvar_t scr_conalpha = {CVAR_SAVE, "scr_conalpha", "1", "opacity of console background"};
13 cvar_t scr_conbrightness = {CVAR_SAVE, "scr_conbrightness", "1", "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_gammaboost = {CVAR_SAVE, "scr_screenshot_gammaboost","1", "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_gammaboost affects the brightness of the output)"};
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 cl_capturevideo_number = {CVAR_SAVE, "cl_capturevideo_number", "1", "number to append to video filename, incremented each time a capture begins"};
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 number of characters on the line, not counting color codes
131 for (l=0 ; l<vid_conwidth.integer/8 ; l++)
133 if (start[l] == '\n' || !start[l])
135 // color codes add no visible characters, so don't count them
136 if (start[l] == '^' && (start[l+1] >= '0' && start[l+1] <= '9'))
141 x = (vid_conwidth.integer - chars*8)/2;
146 DrawQ_ColoredString(x, y, start, l, 8, 8, 1, 1, 1, 1, 0, &color);
154 while (*start && *start != '\n')
159 start++; // skip the \n
163 void SCR_CheckDrawCenterString (void)
165 if (scr_center_lines > scr_erase_lines)
166 scr_erase_lines = scr_center_lines;
168 scr_centertime_off -= cl.realframetime;
170 // don't draw if this is a normal stats-screen intermission,
171 // only if it is not an intermission, or a finale intermission
172 if (cl.intermission == 1)
174 if (scr_centertime_off <= 0 && !cl.intermission)
176 if (key_dest != key_game)
179 SCR_DrawCenterString ();
187 void SCR_DrawTurtle (void)
191 if (cls.state != ca_connected)
194 if (!scr_showturtle.integer)
197 if (cl.realframetime < 0.1)
207 DrawQ_Pic (0, 0, Draw_CachePic("gfx/turtle", true), 0, 0, 1, 1, 1, 1, 0);
215 void SCR_DrawNet (void)
217 if (cls.state != ca_connected)
219 if (realtime - cl.last_received_message < 0.3)
221 if (cls.demoplayback)
224 DrawQ_Pic (64, 0, Draw_CachePic("gfx/net", true), 0, 0, 1, 1, 1, 1, 0);
232 void SCR_DrawPause (void)
236 if (cls.state != ca_connected)
239 if (!scr_showpause.integer) // turn off for screenshots
245 pic = Draw_CachePic ("gfx/pause", true);
246 DrawQ_Pic ((vid_conwidth.integer - pic->width)/2, (vid_conheight.integer - pic->height)/2, pic, 0, 0, 1, 1, 1, 1, 0);
254 void SCR_DrawBrand (void)
259 if (!scr_showbrand.value)
262 pic = Draw_CachePic ("gfx/brand", true);
264 switch ((int)scr_showbrand.value)
266 case 1: // bottom left
268 y = vid_conheight.integer - pic->height;
270 case 2: // bottom centre
271 x = (vid_conwidth.integer - pic->width) / 2;
272 y = vid_conheight.integer - pic->height;
274 case 3: // bottom right
275 x = vid_conwidth.integer - pic->width;
276 y = vid_conheight.integer - pic->height;
278 case 4: // centre right
279 x = vid_conwidth.integer - pic->width;
280 y = (vid_conheight.integer - pic->height) / 2;
283 x = vid_conwidth.integer - pic->width;
286 case 6: // top centre
287 x = (vid_conwidth.integer - pic->width) / 2;
294 case 8: // centre left
296 y = (vid_conheight.integer - pic->height) / 2;
302 DrawQ_Pic (x, y, pic, 0, 0, 1, 1, 1, 1, 0);
310 static int SCR_DrawQWDownload(int offset)
316 if (!cls.qw_downloadname[0])
318 dpsnprintf(temp, sizeof(temp), "Downloading %s ... %3i%%\n", cls.qw_downloadname, cls.qw_downloadpercent);
319 len = (int)strlen(temp);
320 x = (vid_conwidth.integer - len*size) / 2;
321 y = vid_conheight.integer - size - offset;
322 DrawQ_Pic(0, y, NULL, vid_conwidth.integer, size, 0, 0, 0, 0.5, 0);
323 DrawQ_String(x, y, temp, len, size, size, 1, 1, 1, 1, 0);
332 static int SCR_DrawCurlDownload(int offset)
339 Curl_downloadinfo_t *downinfo;
343 downinfo = Curl_GetDownloadInfo(&nDownloads, &addinfo);
347 y = vid_conheight.integer - size * nDownloads - offset;
351 len = (int)strlen(addinfo);
352 x = (vid_conwidth.integer - len*size) / 2;
353 DrawQ_Pic(0, y - size, NULL, vid_conwidth.integer, size, 1, 1, 1, 0.8, 0);
354 DrawQ_String(x, y - size, addinfo, len, size, size, 0, 0, 0, 1, 0);
357 for(i = 0; i != nDownloads; ++i)
359 if(downinfo[i].queued)
360 dpsnprintf(temp, sizeof(temp), "Still in queue: %s\n", downinfo[i].filename);
361 else if(downinfo[i].progress <= 0)
362 dpsnprintf(temp, sizeof(temp), "Downloading %s ... ???.?%% @ %.1f KiB/s\n", downinfo[i].filename, downinfo[i].speed / 1024.0);
364 dpsnprintf(temp, sizeof(temp), "Downloading %s ... %5.1f%% @ %.1f KiB/s\n", downinfo[i].filename, 100.0 * downinfo[i].progress, downinfo[i].speed / 1024.0);
365 len = (int)strlen(temp);
366 x = (vid_conwidth.integer - len*size) / 2;
367 DrawQ_Pic(0, y + i * size, NULL, vid_conwidth.integer, size, 0, 0, 0, 0.8, 0);
368 DrawQ_String(x, y + i * size, temp, len, size, size, 1, 1, 1, 1, 0);
373 return 8 * (nDownloads + (addinfo ? 1 : 0));
381 static void SCR_DrawDownload()
384 offset += SCR_DrawQWDownload(offset);
385 offset += SCR_DrawCurlDownload(offset);
388 //=============================================================================
392 SCR_SetUpToDrawConsole
395 void SCR_SetUpToDrawConsole (void)
397 // lines of console to display
399 static int framecounter = 0;
403 if (scr_menuforcewhiledisconnected.integer && key_dest == key_game && cls.state == ca_disconnected)
405 if (framecounter >= 2)
413 if (scr_conforcewhiledisconnected.integer && key_dest == key_game && cls.signon != SIGNONS)
414 key_consoleactive |= KEY_CONSOLEACTIVE_FORCED;
416 key_consoleactive &= ~KEY_CONSOLEACTIVE_FORCED;
418 // decide on the height of the console
419 if (key_consoleactive & KEY_CONSOLEACTIVE_USER)
420 conlines = vid_conheight.integer/2; // half screen
422 conlines = 0; // none visible
424 scr_con_current = conlines;
432 void SCR_DrawConsole (void)
434 if (key_consoleactive & KEY_CONSOLEACTIVE_FORCED)
437 Con_DrawConsole (vid_conheight.integer);
439 else if (scr_con_current)
440 Con_DrawConsole ((int)scr_con_current);
444 if (key_dest == key_game || key_dest == key_message)
445 Con_DrawNotify (); // only draw notify in game
451 SCR_BeginLoadingPlaque
455 void SCR_BeginLoadingPlaque (void)
457 // save console log up to this point to log_file if it was set by configs
462 SCR_UpdateLoadingScreen();
465 //=============================================================================
467 char r_speeds_string[1024];
468 int speedstringcount, r_timereport_active;
469 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
471 void R_TimeReport(char *desc)
477 if (r_speeds.integer < 2 || !r_timereport_active)
481 qglFinish();CHECKGLERROR
482 r_timereport_temp = r_timereport_current;
483 r_timereport_current = Sys_DoubleTime();
484 t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0 + 0.5);
486 dpsnprintf(tempbuf, sizeof(tempbuf), "%8i %-11s", t, desc);
487 length = (int)strlen(tempbuf);
488 if (speedstringcount + length > (vid_conwidth.integer / 8))
490 strlcat(r_speeds_string, "\n", sizeof(r_speeds_string));
491 speedstringcount = 0;
493 strlcat(r_speeds_string, tempbuf, sizeof(r_speeds_string));
494 speedstringcount += length;
497 void R_TimeReport_Frame(void)
501 if (r_speeds_string[0])
503 if (r_timereport_active)
505 r_timereport_current = r_timereport_start;
506 R_TimeReport("total");
509 if (r_speeds_string[strlen(r_speeds_string)-1] == '\n')
510 r_speeds_string[strlen(r_speeds_string)-1] = 0;
512 for (i = 0;r_speeds_string[i];i++)
513 if (r_speeds_string[i] == '\n')
515 y = vid_conheight.integer - sb_lines - lines * 8;
517 DrawQ_Pic(0, y, NULL, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0);
518 while (r_speeds_string[i])
521 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
524 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
525 if (r_speeds_string[i] == '\n')
529 r_speeds_string[0] = 0;
530 r_timereport_active = false;
532 if (r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected)
534 speedstringcount = 0;
535 r_speeds_string[0] = 0;
536 r_timereport_active = false;
537 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]);
538 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);
539 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);
540 if (r_refdef.stats.bloom)
541 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);
543 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles\n", r_refdef.stats.meshes, r_refdef.stats.meshes_elements / 3);
545 memset(&r_refdef.stats, 0, sizeof(r_refdef.stats));
547 if (r_speeds.integer >= 2)
549 r_timereport_active = true;
550 r_timereport_start = r_timereport_current = Sys_DoubleTime();
562 void SCR_SizeUp_f (void)
564 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
575 void SCR_SizeDown_f (void)
577 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
580 void CL_Screen_Init(void)
582 Cvar_RegisterVariable (&scr_fov);
583 Cvar_RegisterVariable (&scr_viewsize);
584 Cvar_RegisterVariable (&scr_conalpha);
585 Cvar_RegisterVariable (&scr_conbrightness);
586 Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
587 Cvar_RegisterVariable (&scr_menuforcewhiledisconnected);
588 Cvar_RegisterVariable (&scr_showram);
589 Cvar_RegisterVariable (&scr_showturtle);
590 Cvar_RegisterVariable (&scr_showpause);
591 Cvar_RegisterVariable (&scr_showbrand);
592 Cvar_RegisterVariable (&scr_centertime);
593 Cvar_RegisterVariable (&scr_printspeed);
594 Cvar_RegisterVariable (&vid_conwidth);
595 Cvar_RegisterVariable (&vid_conheight);
596 Cvar_RegisterVariable (&vid_pixelheight);
597 Cvar_RegisterVariable (&scr_screenshot_jpeg);
598 Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
599 Cvar_RegisterVariable (&scr_screenshot_gammaboost);
600 Cvar_RegisterVariable (&cl_capturevideo);
601 Cvar_RegisterVariable (&cl_capturevideo_fps);
602 Cvar_RegisterVariable (&cl_capturevideo_rawrgb);
603 Cvar_RegisterVariable (&cl_capturevideo_rawyv12);
604 Cvar_RegisterVariable (&cl_capturevideo_number);
605 Cvar_RegisterVariable (&r_letterbox);
606 Cvar_RegisterVariable(&r_stereo_separation);
607 Cvar_RegisterVariable(&r_stereo_sidebyside);
608 Cvar_RegisterVariable(&r_stereo_redblue);
609 Cvar_RegisterVariable(&r_stereo_redcyan);
610 Cvar_RegisterVariable(&r_stereo_redgreen);
611 Cvar_RegisterVariable(&scr_zoomwindow);
612 Cvar_RegisterVariable(&scr_zoomwindow_viewsizex);
613 Cvar_RegisterVariable(&scr_zoomwindow_viewsizey);
614 Cvar_RegisterVariable(&scr_zoomwindow_fov);
616 Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)");
617 Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)");
618 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f, "takes a screenshot of the next rendered frame");
619 Cmd_AddCommand ("envmap", R_Envmap_f, "render a cubemap (skybox) of the current scene");
621 scr_initialized = true;
629 void SCR_ScreenShot_f (void)
631 static int shotnumber;
632 static char oldname[MAX_QPATH];
633 char base[MAX_QPATH];
634 char filename[MAX_QPATH];
635 unsigned char *buffer1;
636 unsigned char *buffer2;
637 unsigned char *buffer3;
638 qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
640 sprintf (base, "screenshots/%s", scr_screenshot_name.string);
642 if (strcmp (oldname, scr_screenshot_name.string))
644 sprintf(oldname, "%s", scr_screenshot_name.string);
648 // find a file name to save it to
649 for (;shotnumber < 1000000;shotnumber++)
650 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
652 if (shotnumber >= 1000000)
654 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
658 sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
660 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
661 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
662 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3 + 18);
664 if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, 0, 0, vid.width, vid.height, false, false, false, jpeg, true))
665 Con_Printf("Wrote %s\n", filename);
667 Con_Printf("unable to write %s\n", filename);
676 void SCR_CaptureVideo_BeginVideo(void)
680 unsigned char out[44];
681 if (cls.capturevideo_active)
683 // soundrate is figured out on the first SoundFrame
684 cls.capturevideo_active = true;
685 cls.capturevideo_starttime = Sys_DoubleTime();
686 cls.capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
687 cls.capturevideo_soundrate = 0;
688 cls.capturevideo_frame = 0;
689 cls.capturevideo_buffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (3+3+3) + 18);
690 gamma = 1.0/scr_screenshot_gammaboost.value;
691 dpsnprintf(cls.capturevideo_basename, sizeof(cls.capturevideo_basename), "video/dpvideo%03i", cl_capturevideo_number.integer);
692 Cvar_SetValueQuick(&cl_capturevideo_number, cl_capturevideo_number.integer + 1);
695 for (i = 0;i < 256;i++)
697 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
698 cls.capturevideo_rgbgammatable[0][i] = j;
699 cls.capturevideo_rgbgammatable[1][i] = j;
700 cls.capturevideo_rgbgammatable[2][i] = j;
704 R = Y + 1.4075 * (Cr - 128);
705 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
706 B = Y + 1.7790 * (Cb - 128);
707 Y = R * .299 + G * .587 + B * .114;
708 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
709 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
711 for (i = 0;i < 256;i++)
713 g = 255*pow(i/255.0, gamma);
714 // Y weights from RGB
715 cls.capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
716 cls.capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
717 cls.capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
718 // Cb weights from RGB
719 cls.capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
720 cls.capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
721 cls.capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
722 // Cr weights from RGB
723 cls.capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
724 cls.capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
725 cls.capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
726 // range reduction of YCbCr to valid signal range
727 cls.capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
728 cls.capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
729 cls.capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
732 if (cl_capturevideo_rawrgb.integer)
734 cls.capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
735 cls.capturevideo_videofile = FS_Open (va("%s.rgb", cls.capturevideo_basename), "wb", false, true);
737 else if (cl_capturevideo_rawyv12.integer)
739 cls.capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
740 cls.capturevideo_videofile = FS_Open (va("%s.yv12", cls.capturevideo_basename), "wb", false, true);
742 else if (scr_screenshot_jpeg.integer)
744 cls.capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
745 cls.capturevideo_videofile = NULL;
749 cls.capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
750 cls.capturevideo_videofile = NULL;
753 cls.capturevideo_soundfile = FS_Open (va("%s.wav", cls.capturevideo_basename), "wb", false, true);
754 if (cls.capturevideo_soundfile)
756 // wave header will be filled out when video ends
758 FS_Write (cls.capturevideo_soundfile, out, 44);
761 Con_Printf("Could not open video/dpvideo.wav for writing, sound capture disabled\n");
764 void SCR_CaptureVideo_EndVideo(void)
767 unsigned char out[44];
768 if (!cls.capturevideo_active)
770 cls.capturevideo_active = false;
772 if (cls.capturevideo_videofile)
774 FS_Close(cls.capturevideo_videofile);
775 cls.capturevideo_videofile = NULL;
778 // finish the wave file
779 if (cls.capturevideo_soundfile)
781 i = (int)FS_Tell (cls.capturevideo_soundfile);
782 //"RIFF", (int) unknown (chunk size), "WAVE",
783 //"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
784 //"data", (int) unknown (chunk size)
785 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
786 // the length of the whole RIFF chunk
789 out[5] = (n >> 8) & 0xFF;
790 out[6] = (n >> 16) & 0xFF;
791 out[7] = (n >> 24) & 0xFF;
793 n = cls.capturevideo_soundrate;
794 out[24] = (n) & 0xFF;
795 out[25] = (n >> 8) & 0xFF;
796 out[26] = (n >> 16) & 0xFF;
797 out[27] = (n >> 24) & 0xFF;
798 // bytes per second (rate * channels * bytes per channel)
799 n = cls.capturevideo_soundrate * 2 * 2;
800 out[28] = (n) & 0xFF;
801 out[29] = (n >> 8) & 0xFF;
802 out[30] = (n >> 16) & 0xFF;
803 out[31] = (n >> 24) & 0xFF;
804 // the length of the data chunk
806 out[40] = (n) & 0xFF;
807 out[41] = (n >> 8) & 0xFF;
808 out[42] = (n >> 16) & 0xFF;
809 out[43] = (n >> 24) & 0xFF;
810 FS_Seek (cls.capturevideo_soundfile, 0, SEEK_SET);
811 FS_Write (cls.capturevideo_soundfile, out, 44);
812 FS_Close (cls.capturevideo_soundfile);
813 cls.capturevideo_soundfile = NULL;
816 if (cls.capturevideo_buffer)
818 Mem_Free (cls.capturevideo_buffer);
819 cls.capturevideo_buffer = NULL;
822 cls.capturevideo_starttime = 0;
823 cls.capturevideo_framerate = 0;
824 cls.capturevideo_frame = 0;
827 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
829 int x = 0, y = 0, width = vid.width, height = vid.height;
830 unsigned char *b, *out;
832 int outoffset = (width/2)*(height/2);
834 //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);
835 // speed is critical here, so do saving as directly as possible
836 switch (cls.capturevideo_format)
838 case CAPTUREVIDEOFORMAT_RAWYV12:
839 // if there's no videofile we have to just give up, and abort saving if there's no video or sound file
840 if (!cls.capturevideo_videofile)
841 return cls.capturevideo_soundfile != NULL;
842 // FIXME: width/height must be multiple of 2, enforce this?
843 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
844 // process one line at a time, and CbCr every other line at 2 pixel intervals
845 for (y = 0;y < height;y++)
848 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++)
849 *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]]];
852 // 2x2 Cb and Cr planes
854 // low quality, no averaging
855 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++)
858 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];
860 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];
863 // high quality, averaging
864 int inpitch = width*3;
865 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++)
867 int blockr, blockg, blockb;
868 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
869 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
870 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
872 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];
874 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];
879 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
880 if (!FS_Write (cls.capturevideo_videofile, cls.capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
883 case CAPTUREVIDEOFORMAT_RAWRGB:
884 // if there's no videofile we have to just give up, and abort saving if there's no video or sound file
885 if (!cls.capturevideo_videofile)
886 return cls.capturevideo_soundfile != NULL;
887 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
888 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
889 if (!FS_Write (cls.capturevideo_videofile, cls.capturevideo_buffer, width*height*3))
892 case CAPTUREVIDEOFORMAT_JPEG:
893 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
894 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
896 sprintf(filename, "%s_%06d.jpg", cls.capturevideo_basename, cls.capturevideo_frame);
897 if (!JPEG_SaveImage_preflipped (filename, width, height, cls.capturevideo_buffer))
901 case CAPTUREVIDEOFORMAT_TARGA:
902 //return Image_WriteTGARGB_preflipped (filename, width, height, cls.capturevideo_buffer, cls.capturevideo_buffer + vid.width * vid.height * 3, );
903 memset (cls.capturevideo_buffer, 0, 18);
904 cls.capturevideo_buffer[2] = 2; // uncompressed type
905 cls.capturevideo_buffer[12] = (width >> 0) & 0xFF;
906 cls.capturevideo_buffer[13] = (width >> 8) & 0xFF;
907 cls.capturevideo_buffer[14] = (height >> 0) & 0xFF;
908 cls.capturevideo_buffer[15] = (height >> 8) & 0xFF;
909 cls.capturevideo_buffer[16] = 24; // pixel size
910 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cls.capturevideo_buffer + 18);CHECKGLERROR
911 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
913 sprintf(filename, "%s_%06d.tga", cls.capturevideo_basename, cls.capturevideo_frame);
914 if (!FS_WriteFile (filename, cls.capturevideo_buffer, width*height*3 + 18))
923 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
925 if (!cls.capturevideo_soundfile)
927 cls.capturevideo_soundrate = rate;
928 if (FS_Write (cls.capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
930 Cvar_SetValueQuick(&cl_capturevideo, 0);
931 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo_frame);
932 SCR_CaptureVideo_EndVideo();
936 void SCR_CaptureVideo(void)
939 if (cl_capturevideo.integer && r_render.integer)
941 if (!cls.capturevideo_active)
942 SCR_CaptureVideo_BeginVideo();
943 if (cls.capturevideo_framerate != cl_capturevideo_fps.value)
945 Con_Printf("You can not change the video framerate while recording a video.\n");
946 Cvar_SetValueQuick(&cl_capturevideo_fps, cls.capturevideo_framerate);
949 if (cls.capturevideo_soundfile)
951 // preserve sound sync by duplicating frames when running slow
952 newframenum = (int)((Sys_DoubleTime() - cls.capturevideo_starttime) * cls.capturevideo_framerate);
956 newframenum = cls.capturevideo_frame + 1;
957 // if falling behind more than one second, stop
958 if (newframenum - cls.capturevideo_frame > (int)ceil(cls.capturevideo_framerate))
960 Cvar_SetValueQuick(&cl_capturevideo, 0);
961 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cls.capturevideo_frame);
962 SCR_CaptureVideo_EndVideo();
966 if (!SCR_CaptureVideo_VideoFrame(newframenum))
968 Cvar_SetValueQuick(&cl_capturevideo, 0);
969 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo_frame);
970 SCR_CaptureVideo_EndVideo();
973 else if (cls.capturevideo_active)
974 SCR_CaptureVideo_EndVideo();
981 Grab six views for environment mapping tests
988 qboolean flipx, flipy, flipdiagonaly;
992 {{ 0, 0, 0}, "rt", false, false, false},
993 {{ 0, 270, 0}, "ft", false, false, false},
994 {{ 0, 180, 0}, "lf", false, false, false},
995 {{ 0, 90, 0}, "bk", false, false, false},
996 {{-90, 180, 0}, "up", true, true, false},
997 {{ 90, 180, 0}, "dn", true, true, false},
999 {{ 0, 0, 0}, "px", true, true, true},
1000 {{ 0, 90, 0}, "py", false, true, false},
1001 {{ 0, 180, 0}, "nx", false, false, true},
1002 {{ 0, 270, 0}, "ny", true, false, false},
1003 {{-90, 180, 0}, "pz", false, false, true},
1004 {{ 90, 180, 0}, "nz", false, false, true}
1007 static void R_Envmap_f (void)
1010 char filename[MAX_QPATH], basename[MAX_QPATH];
1011 unsigned char *buffer1;
1012 unsigned char *buffer2;
1013 unsigned char *buffer3;
1015 if (Cmd_Argc() != 3)
1017 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");
1021 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
1022 size = atoi(Cmd_Argv(2));
1023 if (size != 128 && size != 256 && size != 512 && size != 1024)
1025 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
1028 if (size > vid.width || size > vid.height)
1030 Con_Print("envmap: your resolution is not big enough to render that size\n");
1034 r_refdef.envmap = true;
1036 R_UpdateVariables();
1041 r_view.width = size;
1042 r_view.height = size;
1045 r_view.frustum_x = tan(90 * M_PI / 360.0);
1046 r_view.frustum_y = tan(90 * M_PI / 360.0);
1048 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1049 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1050 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
1052 for (j = 0;j < 12;j++)
1054 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
1055 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);
1060 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);
1067 r_refdef.envmap = false;
1070 //=============================================================================
1072 // LordHavoc: SHOWLMP stuff
1073 #define SHOWLMP_MAXLABELS 256
1074 typedef struct showlmp_s
1084 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1086 void SHOWLMP_decodehide(void)
1090 lmplabel = MSG_ReadString();
1091 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1092 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1094 showlmp[i].isactive = false;
1099 void SHOWLMP_decodeshow(void)
1102 char lmplabel[256], picname[256];
1104 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1105 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1106 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1113 x = MSG_ReadShort();
1114 y = MSG_ReadShort();
1117 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1118 if (showlmp[i].isactive)
1120 if (strcmp(showlmp[i].label, lmplabel) == 0)
1123 break; // drop out to replace it
1126 else if (k < 0) // find first empty one to replace
1129 return; // none found to replace
1130 // change existing one
1131 showlmp[k].isactive = true;
1132 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1133 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1138 void SHOWLMP_drawall(void)
1141 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1142 if (showlmp[i].isactive)
1143 DrawQ_Pic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic, true), 0, 0, 1, 1, 1, 1, 0);
1146 void SHOWLMP_clear(void)
1149 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1150 showlmp[i].isactive = false;
1154 ==============================================================================
1158 ==============================================================================
1161 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)
1163 int indices[3] = {0,1,2};
1166 if (!r_render.integer)
1170 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer1);CHECKGLERROR
1172 if (scr_screenshot_gammaboost.value != 1 && gammacorrect)
1175 double igamma = 1.0 / scr_screenshot_gammaboost.value;
1176 unsigned char ramp[256];
1177 for (i = 0;i < 256;i++)
1178 ramp[i] = (unsigned char) (pow(i * (1.0 / 255.0), igamma) * 255.0);
1179 for (i = 0;i < width*height*3;i++)
1180 buffer1[i] = ramp[buffer1[i]];
1183 Image_CopyMux (buffer2, buffer1, width, height, flipx, flipy, flipdiagonal, 3, 3, indices);
1186 ret = JPEG_SaveImage_preflipped (filename, width, height, buffer2);
1188 ret = Image_WriteTGARGB_preflipped (filename, width, height, buffer2, buffer3);
1193 //=============================================================================
1195 void R_ClearScreen(void)
1199 if (r_refdef.fogenabled)
1201 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
1205 qglClearColor(0,0,0,0);CHECKGLERROR
1207 qglClearDepth(1);CHECKGLERROR
1210 // LordHavoc: we use a stencil centered around 128 instead of 0,
1211 // to avoid clamping interfering with strange shadow volume
1213 qglClearStencil(128);CHECKGLERROR
1216 if (r_render.integer)
1217 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (gl_stencil ? GL_STENCIL_BUFFER_BIT : 0));
1218 // set dithering mode
1219 if (gl_dither.integer)
1221 qglEnable(GL_DITHER);CHECKGLERROR
1225 qglDisable(GL_DITHER);CHECKGLERROR
1229 qboolean CL_VM_UpdateView (void);
1230 void SCR_DrawConsole (void);
1231 void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1235 void SCR_DrawScreen (void)
1239 if (r_timereport_active)
1240 R_TimeReport("setup");
1242 R_UpdateVariables();
1244 if (cls.signon == SIGNONS)
1248 size = scr_viewsize.value * (1.0 / 100.0);
1249 size = min(size, 1);
1251 if (r_stereo_sidebyside.integer)
1253 r_view.width = (int)(vid.width * size / 2.5);
1254 r_view.height = (int)(vid.height * size / 2.5 * (1 - bound(0, r_letterbox.value, 100) / 100));
1256 r_view.x = (int)((vid.width - r_view.width * 2.5) * 0.5);
1257 r_view.y = (int)((vid.height - r_view.height)/2);
1260 r_view.x += (int)(r_view.width * 1.5);
1264 r_view.width = (int)(vid.width * size);
1265 r_view.height = (int)(vid.height * size * (1 - bound(0, r_letterbox.value, 100) / 100));
1267 r_view.x = (int)((vid.width - r_view.width)/2);
1268 r_view.y = (int)((vid.height - r_view.height)/2);
1272 // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
1273 // LordHavoc: this is designed to produce widescreen fov values
1274 // when the screen is wider than 4/3 width/height aspect, to do
1275 // this it simply assumes the requested fov is the vertical fov
1276 // for a 4x3 display, if the ratio is not 4x3 this makes the fov
1277 // higher/lower according to the ratio
1278 r_view.frustum_y = tan(scr_fov.value * cl.viewzoom * M_PI / 360.0) * (3.0/4.0);
1279 r_view.frustum_x = r_view.frustum_y * (float)r_view.width / (float)r_view.height / vid_pixelheight.value;
1281 r_view.frustum_x *= r_refdef.frustumscale_x;
1282 r_view.frustum_y *= r_refdef.frustumscale_y;
1284 if(!CL_VM_UpdateView())
1289 if (scr_zoomwindow.integer)
1291 float sizex = bound(10, scr_zoomwindow_viewsizex.value, 100) / 100.0;
1292 float sizey = bound(10, scr_zoomwindow_viewsizey.value, 100) / 100.0;
1293 r_view.width = (int)(vid.width * sizex);
1294 r_view.height = (int)(vid.height * sizey);
1296 r_view.x = (int)((vid.width - r_view.width)/2);
1300 r_view.frustum_y = tan(scr_zoomwindow_fov.value * cl.viewzoom * M_PI / 360.0) * (3.0/4.0);
1301 r_view.frustum_x = r_view.frustum_y * vid_pixelheight.value * (float)r_view.width / (float)r_view.height;
1303 r_view.frustum_x *= r_refdef.frustumscale_x;
1304 r_view.frustum_y *= r_refdef.frustumscale_y;
1306 if(!CL_VM_UpdateView())
1311 if (!r_stereo_sidebyside.integer)
1313 r_view.width = vid.width;
1314 r_view.height = vid.height;
1324 //FIXME: force menu if nothing else to look at?
1325 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1327 if (cls.signon == SIGNONS)
1332 if (!r_letterbox.value)
1335 SCR_CheckDrawCenterString();
1339 R_Shadow_EditLights_DrawSelectedLightProperties();
1348 if (r_timereport_active)
1351 if (cls.signon == SIGNONS)
1352 R_TimeReport_Frame();
1360 if (r_timereport_active)
1361 R_TimeReport("meshfinish");
1364 void SCR_UpdateLoadingScreen (void)
1369 float texcoord2f[8];
1370 // don't do anything if not initialized yet
1374 qglViewport(0, 0, vid.width, vid.height);CHECKGLERROR
1375 //qglDisable(GL_SCISSOR_TEST);CHECKGLERROR
1376 //qglDepthMask(1);CHECKGLERROR
1377 qglColorMask(1,1,1,1);CHECKGLERROR
1378 //qglClearColor(0,0,0,0);CHECKGLERROR
1379 //qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1380 //qglCullFace(GL_FRONT);CHECKGLERROR
1381 //qglDisable(GL_CULL_FACE);CHECKGLERROR
1384 GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
1386 R_Mesh_Matrix(&identitymatrix);
1387 // draw the loading plaque
1388 pic = Draw_CachePic("gfx/loading", true);
1389 x = (vid_conwidth.integer - pic->width)/2;
1390 y = (vid_conheight.integer - pic->height)/2;
1392 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1393 GL_DepthTest(false);
1394 R_Mesh_VertexPointer(vertex3f);
1395 R_Mesh_ColorPointer(NULL);
1396 R_Mesh_ResetTextureState();
1397 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
1398 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
1399 vertex3f[2] = vertex3f[5] = vertex3f[8] = vertex3f[11] = 0;
1400 vertex3f[0] = vertex3f[9] = x;
1401 vertex3f[1] = vertex3f[4] = y;
1402 vertex3f[3] = vertex3f[6] = x + pic->width;
1403 vertex3f[7] = vertex3f[10] = y + pic->height;
1404 texcoord2f[0] = 0;texcoord2f[1] = 0;
1405 texcoord2f[2] = 1;texcoord2f[3] = 0;
1406 texcoord2f[4] = 1;texcoord2f[5] = 1;
1407 texcoord2f[6] = 0;texcoord2f[7] = 1;
1408 R_Mesh_Draw(0, 4, 2, polygonelements);
1414 void CL_UpdateScreen(void)
1416 float conwidth, conheight;
1421 if (!scr_initialized || !con_initialized || vid_hidden)
1422 return; // not initialized yet
1424 // don't allow cheats in multiplayer
1425 if (!cl.islocalgame && cl.worldmodel)
1427 if (r_fullbright.integer != 0)
1428 Cvar_Set ("r_fullbright", "0");
1429 if (r_ambient.value != 0)
1430 Cvar_Set ("r_ambient", "0");
1433 conwidth = bound(320, vid_conwidth.value, 2048);
1434 conheight = bound(200, vid_conheight.value, 1536);
1435 if (vid_conwidth.value != conwidth)
1436 Cvar_SetValue("vid_conwidth", conwidth);
1437 if (vid_conheight.value != conheight)
1438 Cvar_SetValue("vid_conheight", conheight);
1441 if (scr_viewsize.value < 30)
1442 Cvar_Set ("viewsize","30");
1443 if (scr_viewsize.value > 120)
1444 Cvar_Set ("viewsize","120");
1446 // bound field of view
1447 if (scr_fov.value < 1)
1448 Cvar_Set ("fov","1");
1449 if (scr_fov.value > 170)
1450 Cvar_Set ("fov","170");
1452 // validate r_textureunits cvar
1453 if (r_textureunits.integer > gl_textureunits)
1454 Cvar_SetValueQuick(&r_textureunits, gl_textureunits);
1455 if (r_textureunits.integer < 1)
1456 Cvar_SetValueQuick(&r_textureunits, 1);
1458 // validate gl_combine cvar
1459 if (gl_combine.integer && !gl_combine_extension)
1460 Cvar_SetValueQuick(&gl_combine, 0);
1462 // intermission is always full screen
1463 if (cl.intermission)
1467 if (scr_viewsize.value >= 120)
1468 sb_lines = 0; // no status bar at all
1469 else if (scr_viewsize.value >= 110)
1470 sb_lines = 24; // no inventory
1475 r_view.colormask[0] = 1;
1476 r_view.colormask[1] = 1;
1477 r_view.colormask[2] = 1;
1479 if (r_timereport_active)
1480 R_TimeReport("other");
1482 SCR_SetUpToDrawConsole();
1484 if (r_timereport_active)
1485 R_TimeReport("start");
1488 qglViewport(0, 0, vid.width, vid.height);CHECKGLERROR
1489 qglDisable(GL_SCISSOR_TEST);CHECKGLERROR
1490 qglDepthMask(1);CHECKGLERROR
1491 qglColorMask(1,1,1,1);CHECKGLERROR
1492 qglClearColor(0,0,0,0);CHECKGLERROR
1493 qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1495 if (r_timereport_active)
1496 R_TimeReport("clear");
1498 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer || r_stereo_sidebyside.integer)
1500 matrix4x4_t originalmatrix = r_view.matrix;
1501 r_view.matrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * -0.5f * r_view.matrix.m[0][1];
1502 r_view.matrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * -0.5f * r_view.matrix.m[1][1];
1503 r_view.matrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * -0.5f * r_view.matrix.m[2][1];
1505 if (r_stereo_sidebyside.integer)
1508 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1510 r_view.colormask[0] = 1;
1511 r_view.colormask[1] = 0;
1512 r_view.colormask[2] = 0;
1517 r_view.matrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[0][1];
1518 r_view.matrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[1][1];
1519 r_view.matrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[2][1];
1521 if (r_stereo_sidebyside.integer)
1524 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1526 r_view.colormask[0] = 0;
1527 r_view.colormask[1] = r_stereo_redcyan.integer || r_stereo_redgreen.integer;
1528 r_view.colormask[2] = r_stereo_redcyan.integer || r_stereo_redblue.integer;
1533 r_view.matrix = originalmatrix;
1541 if (r_timereport_active)
1542 R_TimeReport("finish");
1545 void CL_Screen_NewMap(void)