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 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 int SCR_DrawQWDownload(int offset)
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 - offset;
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);
331 static int SCR_DrawCurlDownload(int offset)
338 Curl_downloadinfo_t *downinfo;
342 downinfo = Curl_GetDownloadInfo(&nDownloads, &addinfo);
346 y = vid_conheight.integer - size * nDownloads - offset;
350 len = (int)strlen(addinfo);
351 x = (vid_conwidth.integer - len*size) / 2;
352 DrawQ_Pic(0, y - size, NULL, vid_conwidth.integer, size, 1, 1, 1, 0.8, 0);
353 DrawQ_String(x, y - size, addinfo, len, size, size, 0, 0, 0, 1, 0);
356 for(i = 0; i != nDownloads; ++i)
358 if(downinfo[i].queued)
359 dpsnprintf(temp, sizeof(temp), "Still in queue: %s\n", downinfo[i].filename);
360 else if(downinfo[i].progress <= 0)
361 dpsnprintf(temp, sizeof(temp), "Downloading %s ... ???.?%% @ %.1f KiB/s\n", downinfo[i].filename, downinfo[i].speed / 1024.0);
363 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);
364 len = (int)strlen(temp);
365 x = (vid_conwidth.integer - len*size) / 2;
366 DrawQ_Pic(0, y + i * size, NULL, vid_conwidth.integer, size, 0, 0, 0, 0.8, 0);
367 DrawQ_String(x, y + i * size, temp, len, size, size, 1, 1, 1, 1, 0);
372 return 8 * (nDownloads + (addinfo ? 1 : 0));
380 static void SCR_DrawDownload()
383 offset += SCR_DrawQWDownload(offset);
384 offset += SCR_DrawCurlDownload(offset);
387 //=============================================================================
391 SCR_SetUpToDrawConsole
394 void SCR_SetUpToDrawConsole (void)
396 // lines of console to display
398 static int framecounter = 0;
402 if (scr_menuforcewhiledisconnected.integer && key_dest == key_game && cls.state == ca_disconnected)
404 if (framecounter >= 2)
412 if (scr_conforcewhiledisconnected.integer && key_dest == key_game && cls.signon != SIGNONS)
413 key_consoleactive |= KEY_CONSOLEACTIVE_FORCED;
415 key_consoleactive &= ~KEY_CONSOLEACTIVE_FORCED;
417 // decide on the height of the console
418 if (key_consoleactive & KEY_CONSOLEACTIVE_USER)
419 conlines = vid_conheight.integer/2; // half screen
421 conlines = 0; // none visible
423 scr_con_current = conlines;
431 void SCR_DrawConsole (void)
433 if (key_consoleactive & KEY_CONSOLEACTIVE_FORCED)
436 Con_DrawConsole (vid_conheight.integer);
438 else if (scr_con_current)
439 Con_DrawConsole ((int)scr_con_current);
443 if ((key_dest == key_game || key_dest == key_message) && !r_letterbox.value)
444 Con_DrawNotify (); // only draw notify in game
450 SCR_BeginLoadingPlaque
454 void SCR_BeginLoadingPlaque (void)
456 // save console log up to this point to log_file if it was set by configs
461 SCR_UpdateLoadingScreen();
464 //=============================================================================
466 char r_speeds_string[1024];
467 int speedstringcount, r_timereport_active;
468 double r_timereport_temp = 0, r_timereport_current = 0, r_timereport_start = 0;
470 void R_TimeReport(char *desc)
476 if (r_speeds.integer < 2 || !r_timereport_active)
480 qglFinish();CHECKGLERROR
481 r_timereport_temp = r_timereport_current;
482 r_timereport_current = Sys_DoubleTime();
483 t = (int) ((r_timereport_current - r_timereport_temp) * 1000000.0 + 0.5);
485 dpsnprintf(tempbuf, sizeof(tempbuf), "%8i %-11s", t, desc);
486 length = (int)strlen(tempbuf);
487 if (speedstringcount + length > (vid_conwidth.integer / 8))
489 strlcat(r_speeds_string, "\n", sizeof(r_speeds_string));
490 speedstringcount = 0;
492 strlcat(r_speeds_string, tempbuf, sizeof(r_speeds_string));
493 speedstringcount += length;
496 void R_TimeReport_Frame(void)
500 if (r_speeds_string[0])
502 if (r_timereport_active)
504 r_timereport_current = r_timereport_start;
505 R_TimeReport("total");
508 if (r_speeds_string[strlen(r_speeds_string)-1] == '\n')
509 r_speeds_string[strlen(r_speeds_string)-1] = 0;
511 for (i = 0;r_speeds_string[i];i++)
512 if (r_speeds_string[i] == '\n')
514 y = vid_conheight.integer - sb_lines - lines * 8;
516 DrawQ_Pic(0, y, NULL, vid_conwidth.integer, lines * 8, 0, 0, 0, 0.5, 0);
517 while (r_speeds_string[i])
520 while (r_speeds_string[i] && r_speeds_string[i] != '\n')
523 DrawQ_String(0, y, r_speeds_string + j, i - j, 8, 8, 1, 1, 1, 1, 0);
524 if (r_speeds_string[i] == '\n')
528 r_speeds_string[0] = 0;
529 r_timereport_active = false;
531 if (r_speeds.integer && cls.signon == SIGNONS && cls.state == ca_connected)
533 speedstringcount = 0;
534 r_speeds_string[0] = 0;
535 r_timereport_active = false;
536 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]);
537 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);
538 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);
539 if (r_refdef.stats.bloom)
540 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);
542 sprintf(r_speeds_string + strlen(r_speeds_string), "rendered%6i meshes%8i triangles\n", r_refdef.stats.meshes, r_refdef.stats.meshes_elements / 3);
544 memset(&r_refdef.stats, 0, sizeof(r_refdef.stats));
546 if (r_speeds.integer >= 2)
548 r_timereport_active = true;
549 r_timereport_start = r_timereport_current = Sys_DoubleTime();
561 void SCR_SizeUp_f (void)
563 Cvar_SetValue ("viewsize",scr_viewsize.value+10);
574 void SCR_SizeDown_f (void)
576 Cvar_SetValue ("viewsize",scr_viewsize.value-10);
579 void CL_Screen_Init(void)
581 Cvar_RegisterVariable (&scr_fov);
582 Cvar_RegisterVariable (&scr_viewsize);
583 Cvar_RegisterVariable (&scr_conalpha);
584 Cvar_RegisterVariable (&scr_conbrightness);
585 Cvar_RegisterVariable (&scr_conforcewhiledisconnected);
586 Cvar_RegisterVariable (&scr_menuforcewhiledisconnected);
587 Cvar_RegisterVariable (&scr_showram);
588 Cvar_RegisterVariable (&scr_showturtle);
589 Cvar_RegisterVariable (&scr_showpause);
590 Cvar_RegisterVariable (&scr_showbrand);
591 Cvar_RegisterVariable (&scr_centertime);
592 Cvar_RegisterVariable (&scr_printspeed);
593 Cvar_RegisterVariable (&vid_conwidth);
594 Cvar_RegisterVariable (&vid_conheight);
595 Cvar_RegisterVariable (&vid_pixelheight);
596 Cvar_RegisterVariable (&scr_screenshot_jpeg);
597 Cvar_RegisterVariable (&scr_screenshot_jpeg_quality);
598 Cvar_RegisterVariable (&scr_screenshot_gammaboost);
599 Cvar_RegisterVariable (&cl_capturevideo);
600 Cvar_RegisterVariable (&cl_capturevideo_fps);
601 Cvar_RegisterVariable (&cl_capturevideo_rawrgb);
602 Cvar_RegisterVariable (&cl_capturevideo_rawyv12);
603 Cvar_RegisterVariable (&cl_capturevideo_number);
604 Cvar_RegisterVariable (&r_letterbox);
605 Cvar_RegisterVariable(&r_stereo_separation);
606 Cvar_RegisterVariable(&r_stereo_sidebyside);
607 Cvar_RegisterVariable(&r_stereo_redblue);
608 Cvar_RegisterVariable(&r_stereo_redcyan);
609 Cvar_RegisterVariable(&r_stereo_redgreen);
610 Cvar_RegisterVariable(&scr_zoomwindow);
611 Cvar_RegisterVariable(&scr_zoomwindow_viewsizex);
612 Cvar_RegisterVariable(&scr_zoomwindow_viewsizey);
613 Cvar_RegisterVariable(&scr_zoomwindow_fov);
615 Cmd_AddCommand ("sizeup",SCR_SizeUp_f, "increase view size (increases viewsize cvar)");
616 Cmd_AddCommand ("sizedown",SCR_SizeDown_f, "decrease view size (decreases viewsize cvar)");
617 Cmd_AddCommand ("screenshot",SCR_ScreenShot_f, "takes a screenshot of the next rendered frame");
618 Cmd_AddCommand ("envmap", R_Envmap_f, "render a cubemap (skybox) of the current scene");
620 scr_initialized = true;
628 void SCR_ScreenShot_f (void)
630 static int shotnumber;
631 static char oldname[MAX_QPATH];
632 char base[MAX_QPATH];
633 char filename[MAX_QPATH];
634 unsigned char *buffer1;
635 unsigned char *buffer2;
636 unsigned char *buffer3;
637 qboolean jpeg = (scr_screenshot_jpeg.integer != 0);
639 sprintf (base, "screenshots/%s", scr_screenshot_name.string);
641 if (strcmp (oldname, scr_screenshot_name.string))
643 sprintf(oldname, "%s", scr_screenshot_name.string);
647 // find a file name to save it to
648 for (;shotnumber < 1000000;shotnumber++)
649 if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber)))
651 if (shotnumber >= 1000000)
653 Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n");
657 sprintf(filename, "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga");
659 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
660 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3);
661 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3 + 18);
663 if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, 0, 0, vid.width, vid.height, false, false, false, jpeg, true))
664 Con_Printf("Wrote %s\n", filename);
666 Con_Printf("unable to write %s\n", filename);
675 void SCR_CaptureVideo_BeginVideo(void)
679 unsigned char out[44];
680 if (cls.capturevideo_active)
682 // soundrate is figured out on the first SoundFrame
683 cls.capturevideo_active = true;
684 cls.capturevideo_starttime = Sys_DoubleTime();
685 cls.capturevideo_framerate = bound(1, cl_capturevideo_fps.value, 1000);
686 cls.capturevideo_soundrate = 0;
687 cls.capturevideo_frame = 0;
688 cls.capturevideo_buffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * (3+3+3) + 18);
689 gamma = 1.0/scr_screenshot_gammaboost.value;
690 dpsnprintf(cls.capturevideo_basename, sizeof(cls.capturevideo_basename), "video/dpvideo%03i", cl_capturevideo_number.integer);
691 Cvar_SetValueQuick(&cl_capturevideo_number, cl_capturevideo_number.integer + 1);
694 for (i = 0;i < 256;i++)
696 unsigned char j = (unsigned char)bound(0, 255*pow(i/255.0, gamma), 255);
697 cls.capturevideo_rgbgammatable[0][i] = j;
698 cls.capturevideo_rgbgammatable[1][i] = j;
699 cls.capturevideo_rgbgammatable[2][i] = j;
703 R = Y + 1.4075 * (Cr - 128);
704 G = Y + -0.3455 * (Cb - 128) + -0.7169 * (Cr - 128);
705 B = Y + 1.7790 * (Cb - 128);
706 Y = R * .299 + G * .587 + B * .114;
707 Cb = R * -.169 + G * -.332 + B * .500 + 128.;
708 Cr = R * .500 + G * -.419 + B * -.0813 + 128.;
710 for (i = 0;i < 256;i++)
712 g = 255*pow(i/255.0, gamma);
713 // Y weights from RGB
714 cls.capturevideo_rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299);
715 cls.capturevideo_rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587);
716 cls.capturevideo_rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114);
717 // Cb weights from RGB
718 cls.capturevideo_rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169);
719 cls.capturevideo_rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332);
720 cls.capturevideo_rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500);
721 // Cr weights from RGB
722 cls.capturevideo_rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500);
723 cls.capturevideo_rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419);
724 cls.capturevideo_rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813);
725 // range reduction of YCbCr to valid signal range
726 cls.capturevideo_yuvnormalizetable[0][i] = 16 + i * (236-16) / 256;
727 cls.capturevideo_yuvnormalizetable[1][i] = 16 + i * (240-16) / 256;
728 cls.capturevideo_yuvnormalizetable[2][i] = 16 + i * (240-16) / 256;
731 if (cl_capturevideo_rawrgb.integer)
733 cls.capturevideo_format = CAPTUREVIDEOFORMAT_RAWRGB;
734 cls.capturevideo_videofile = FS_Open (va("%s.rgb", cls.capturevideo_basename), "wb", false, true);
736 else if (cl_capturevideo_rawyv12.integer)
738 cls.capturevideo_format = CAPTUREVIDEOFORMAT_RAWYV12;
739 cls.capturevideo_videofile = FS_Open (va("%s.yv12", cls.capturevideo_basename), "wb", false, true);
741 else if (scr_screenshot_jpeg.integer)
743 cls.capturevideo_format = CAPTUREVIDEOFORMAT_JPEG;
744 cls.capturevideo_videofile = NULL;
748 cls.capturevideo_format = CAPTUREVIDEOFORMAT_TARGA;
749 cls.capturevideo_videofile = NULL;
752 cls.capturevideo_soundfile = FS_Open (va("%s.wav", cls.capturevideo_basename), "wb", false, true);
753 if (cls.capturevideo_soundfile)
755 // wave header will be filled out when video ends
757 FS_Write (cls.capturevideo_soundfile, out, 44);
760 Con_Printf("Could not open video/dpvideo.wav for writing, sound capture disabled\n");
763 void SCR_CaptureVideo_EndVideo(void)
766 unsigned char out[44];
767 if (!cls.capturevideo_active)
769 cls.capturevideo_active = false;
771 if (cls.capturevideo_videofile)
773 FS_Close(cls.capturevideo_videofile);
774 cls.capturevideo_videofile = NULL;
777 // finish the wave file
778 if (cls.capturevideo_soundfile)
780 i = (int)FS_Tell (cls.capturevideo_soundfile);
781 //"RIFF", (int) unknown (chunk size), "WAVE",
782 //"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
783 //"data", (int) unknown (chunk size)
784 memcpy (out, "RIFF****WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00********\x04\x00\x10\0data****", 44);
785 // the length of the whole RIFF chunk
788 out[5] = (n >> 8) & 0xFF;
789 out[6] = (n >> 16) & 0xFF;
790 out[7] = (n >> 24) & 0xFF;
792 n = cls.capturevideo_soundrate;
793 out[24] = (n) & 0xFF;
794 out[25] = (n >> 8) & 0xFF;
795 out[26] = (n >> 16) & 0xFF;
796 out[27] = (n >> 24) & 0xFF;
797 // bytes per second (rate * channels * bytes per channel)
798 n = cls.capturevideo_soundrate * 2 * 2;
799 out[28] = (n) & 0xFF;
800 out[29] = (n >> 8) & 0xFF;
801 out[30] = (n >> 16) & 0xFF;
802 out[31] = (n >> 24) & 0xFF;
803 // the length of the data chunk
805 out[40] = (n) & 0xFF;
806 out[41] = (n >> 8) & 0xFF;
807 out[42] = (n >> 16) & 0xFF;
808 out[43] = (n >> 24) & 0xFF;
809 FS_Seek (cls.capturevideo_soundfile, 0, SEEK_SET);
810 FS_Write (cls.capturevideo_soundfile, out, 44);
811 FS_Close (cls.capturevideo_soundfile);
812 cls.capturevideo_soundfile = NULL;
815 if (cls.capturevideo_buffer)
817 Mem_Free (cls.capturevideo_buffer);
818 cls.capturevideo_buffer = NULL;
821 cls.capturevideo_starttime = 0;
822 cls.capturevideo_framerate = 0;
823 cls.capturevideo_frame = 0;
826 qboolean SCR_CaptureVideo_VideoFrame(int newframenum)
828 int x = 0, y = 0, width = vid.width, height = vid.height;
829 unsigned char *b, *out;
831 int outoffset = (width/2)*(height/2);
833 //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);
834 // speed is critical here, so do saving as directly as possible
835 switch (cls.capturevideo_format)
837 case CAPTUREVIDEOFORMAT_RAWYV12:
838 // if there's no videofile we have to just give up, and abort saving if there's no video or sound file
839 if (!cls.capturevideo_videofile)
840 return cls.capturevideo_soundfile != NULL;
841 // FIXME: width/height must be multiple of 2, enforce this?
842 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
843 // process one line at a time, and CbCr every other line at 2 pixel intervals
844 for (y = 0;y < height;y++)
847 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++)
848 *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]]];
851 // 2x2 Cb and Cr planes
853 // low quality, no averaging
854 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++)
857 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];
859 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];
862 // high quality, averaging
863 int inpitch = width*3;
864 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++)
866 int blockr, blockg, blockb;
867 blockr = (b[0] + b[3] + b[inpitch+0] + b[inpitch+3]) >> 2;
868 blockg = (b[1] + b[4] + b[inpitch+1] + b[inpitch+4]) >> 2;
869 blockb = (b[2] + b[5] + b[inpitch+2] + b[inpitch+5]) >> 2;
871 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];
873 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];
878 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
879 if (!FS_Write (cls.capturevideo_videofile, cls.capturevideo_buffer + width*height*3, width*height+(width/2)*(height/2)*2))
882 case CAPTUREVIDEOFORMAT_RAWRGB:
883 // if there's no videofile we have to just give up, and abort saving if there's no video or sound file
884 if (!cls.capturevideo_videofile)
885 return cls.capturevideo_soundfile != NULL;
886 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
887 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
888 if (!FS_Write (cls.capturevideo_videofile, cls.capturevideo_buffer, width*height*3))
891 case CAPTUREVIDEOFORMAT_JPEG:
892 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, cls.capturevideo_buffer);CHECKGLERROR
893 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
895 sprintf(filename, "%s_%06d.jpg", cls.capturevideo_basename, cls.capturevideo_frame);
896 if (!JPEG_SaveImage_preflipped (filename, width, height, cls.capturevideo_buffer))
900 case CAPTUREVIDEOFORMAT_TARGA:
901 //return Image_WriteTGARGB_preflipped (filename, width, height, cls.capturevideo_buffer, cls.capturevideo_buffer + vid.width * vid.height * 3, );
902 memset (cls.capturevideo_buffer, 0, 18);
903 cls.capturevideo_buffer[2] = 2; // uncompressed type
904 cls.capturevideo_buffer[12] = (width >> 0) & 0xFF;
905 cls.capturevideo_buffer[13] = (width >> 8) & 0xFF;
906 cls.capturevideo_buffer[14] = (height >> 0) & 0xFF;
907 cls.capturevideo_buffer[15] = (height >> 8) & 0xFF;
908 cls.capturevideo_buffer[16] = 24; // pixel size
909 qglReadPixels (x, y, width, height, GL_BGR, GL_UNSIGNED_BYTE, cls.capturevideo_buffer + 18);CHECKGLERROR
910 for (;cls.capturevideo_frame < newframenum;cls.capturevideo_frame++)
912 sprintf(filename, "%s_%06d.tga", cls.capturevideo_basename, cls.capturevideo_frame);
913 if (!FS_WriteFile (filename, cls.capturevideo_buffer, width*height*3 + 18))
922 void SCR_CaptureVideo_SoundFrame(unsigned char *bufstereo16le, size_t length, int rate)
924 if (!cls.capturevideo_soundfile)
926 cls.capturevideo_soundrate = rate;
927 if (FS_Write (cls.capturevideo_soundfile, bufstereo16le, 4 * length) < (fs_offset_t)(4 * length))
929 Cvar_SetValueQuick(&cl_capturevideo, 0);
930 Con_Printf("video sound saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo_frame);
931 SCR_CaptureVideo_EndVideo();
935 void SCR_CaptureVideo(void)
938 if (cl_capturevideo.integer && r_render.integer)
940 if (!cls.capturevideo_active)
941 SCR_CaptureVideo_BeginVideo();
942 if (cls.capturevideo_framerate != cl_capturevideo_fps.value)
944 Con_Printf("You can not change the video framerate while recording a video.\n");
945 Cvar_SetValueQuick(&cl_capturevideo_fps, cls.capturevideo_framerate);
948 if (cls.capturevideo_soundfile)
950 // preserve sound sync by duplicating frames when running slow
951 newframenum = (int)((Sys_DoubleTime() - cls.capturevideo_starttime) * cls.capturevideo_framerate);
955 newframenum = cls.capturevideo_frame + 1;
956 // if falling behind more than one second, stop
957 if (newframenum - cls.capturevideo_frame > (int)ceil(cls.capturevideo_framerate))
959 Cvar_SetValueQuick(&cl_capturevideo, 0);
960 Con_Printf("video saving failed on frame %i, your machine is too slow for this capture speed.\n", cls.capturevideo_frame);
961 SCR_CaptureVideo_EndVideo();
965 if (!SCR_CaptureVideo_VideoFrame(newframenum))
967 Cvar_SetValueQuick(&cl_capturevideo, 0);
968 Con_Printf("video saving failed on frame %i, out of disk space? stopping video capture.\n", cls.capturevideo_frame);
969 SCR_CaptureVideo_EndVideo();
972 else if (cls.capturevideo_active)
973 SCR_CaptureVideo_EndVideo();
980 Grab six views for environment mapping tests
987 qboolean flipx, flipy, flipdiagonaly;
991 {{ 0, 0, 0}, "rt", false, false, false},
992 {{ 0, 270, 0}, "ft", false, false, false},
993 {{ 0, 180, 0}, "lf", false, false, false},
994 {{ 0, 90, 0}, "bk", false, false, false},
995 {{-90, 180, 0}, "up", true, true, false},
996 {{ 90, 180, 0}, "dn", true, true, false},
998 {{ 0, 0, 0}, "px", true, true, true},
999 {{ 0, 90, 0}, "py", false, true, false},
1000 {{ 0, 180, 0}, "nx", false, false, true},
1001 {{ 0, 270, 0}, "ny", true, false, false},
1002 {{-90, 180, 0}, "pz", false, false, true},
1003 {{ 90, 180, 0}, "nz", false, false, true}
1006 static void R_Envmap_f (void)
1009 char filename[MAX_QPATH], basename[MAX_QPATH];
1010 unsigned char *buffer1;
1011 unsigned char *buffer2;
1012 unsigned char *buffer3;
1014 if (Cmd_Argc() != 3)
1016 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");
1020 strlcpy (basename, Cmd_Argv(1), sizeof (basename));
1021 size = atoi(Cmd_Argv(2));
1022 if (size != 128 && size != 256 && size != 512 && size != 1024)
1024 Con_Print("envmap: size must be one of 128, 256, 512, or 1024\n");
1027 if (size > vid.width || size > vid.height)
1029 Con_Print("envmap: your resolution is not big enough to render that size\n");
1033 r_refdef.envmap = true;
1035 R_UpdateVariables();
1040 r_view.width = size;
1041 r_view.height = size;
1044 r_view.frustum_x = tan(90 * M_PI / 360.0);
1045 r_view.frustum_y = tan(90 * M_PI / 360.0);
1047 buffer1 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1048 buffer2 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3);
1049 buffer3 = (unsigned char *)Mem_Alloc(tempmempool, size * size * 3 + 18);
1051 for (j = 0;j < 12;j++)
1053 sprintf(filename, "env/%s%s.tga", basename, envmapinfo[j].name);
1054 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);
1059 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);
1066 r_refdef.envmap = false;
1069 //=============================================================================
1071 // LordHavoc: SHOWLMP stuff
1072 #define SHOWLMP_MAXLABELS 256
1073 typedef struct showlmp_s
1083 showlmp_t showlmp[SHOWLMP_MAXLABELS];
1085 void SHOWLMP_decodehide(void)
1089 lmplabel = MSG_ReadString();
1090 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1091 if (showlmp[i].isactive && strcmp(showlmp[i].label, lmplabel) == 0)
1093 showlmp[i].isactive = false;
1098 void SHOWLMP_decodeshow(void)
1101 char lmplabel[256], picname[256];
1103 strlcpy (lmplabel,MSG_ReadString(), sizeof (lmplabel));
1104 strlcpy (picname, MSG_ReadString(), sizeof (picname));
1105 if (gamemode == GAME_NEHAHRA) // LordHavoc: nasty old legacy junk
1112 x = MSG_ReadShort();
1113 y = MSG_ReadShort();
1116 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1117 if (showlmp[i].isactive)
1119 if (strcmp(showlmp[i].label, lmplabel) == 0)
1122 break; // drop out to replace it
1125 else if (k < 0) // find first empty one to replace
1128 return; // none found to replace
1129 // change existing one
1130 showlmp[k].isactive = true;
1131 strlcpy (showlmp[k].label, lmplabel, sizeof (showlmp[k].label));
1132 strlcpy (showlmp[k].pic, picname, sizeof (showlmp[k].pic));
1137 void SHOWLMP_drawall(void)
1140 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1141 if (showlmp[i].isactive)
1142 DrawQ_Pic(showlmp[i].x, showlmp[i].y, Draw_CachePic(showlmp[i].pic, true), 0, 0, 1, 1, 1, 1, 0);
1145 void SHOWLMP_clear(void)
1148 for (i = 0;i < SHOWLMP_MAXLABELS;i++)
1149 showlmp[i].isactive = false;
1153 ==============================================================================
1157 ==============================================================================
1160 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)
1162 int indices[3] = {0,1,2};
1165 if (!r_render.integer)
1169 qglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer1);CHECKGLERROR
1171 if (scr_screenshot_gammaboost.value != 1 && gammacorrect)
1174 double igamma = 1.0 / scr_screenshot_gammaboost.value;
1175 unsigned char ramp[256];
1176 for (i = 0;i < 256;i++)
1177 ramp[i] = (unsigned char) (pow(i * (1.0 / 255.0), igamma) * 255.0);
1178 for (i = 0;i < width*height*3;i++)
1179 buffer1[i] = ramp[buffer1[i]];
1182 Image_CopyMux (buffer2, buffer1, width, height, flipx, flipy, flipdiagonal, 3, 3, indices);
1185 ret = JPEG_SaveImage_preflipped (filename, width, height, buffer2);
1187 ret = Image_WriteTGARGB_preflipped (filename, width, height, buffer2, buffer3);
1192 //=============================================================================
1194 void R_ClearScreen(void)
1198 if (r_refdef.fogenabled)
1200 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
1204 qglClearColor(0,0,0,0);CHECKGLERROR
1206 qglClearDepth(1);CHECKGLERROR
1209 // LordHavoc: we use a stencil centered around 128 instead of 0,
1210 // to avoid clamping interfering with strange shadow volume
1212 qglClearStencil(128);CHECKGLERROR
1215 if (r_render.integer)
1216 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | (gl_stencil ? GL_STENCIL_BUFFER_BIT : 0));
1217 // set dithering mode
1218 if (gl_dither.integer)
1220 qglEnable(GL_DITHER);CHECKGLERROR
1224 qglDisable(GL_DITHER);CHECKGLERROR
1228 qboolean CL_VM_UpdateView (void);
1229 void SCR_DrawConsole (void);
1230 void R_Shadow_EditLights_DrawSelectedLightProperties(void);
1234 void SCR_DrawScreen (void)
1238 if (r_timereport_active)
1239 R_TimeReport("setup");
1241 R_UpdateVariables();
1243 if (cls.signon == SIGNONS)
1247 size = scr_viewsize.value * (1.0 / 100.0);
1248 size = min(size, 1);
1250 if (r_stereo_sidebyside.integer)
1252 r_view.width = (int)(vid.width * size / 2.5);
1253 r_view.height = (int)(vid.height * size / 2.5 * (1 - bound(0, r_letterbox.value, 100) / 100));
1255 r_view.x = (int)((vid.width - r_view.width * 2.5) * 0.5);
1256 r_view.y = (int)((vid.height - r_view.height)/2);
1259 r_view.x += (int)(r_view.width * 1.5);
1263 r_view.width = (int)(vid.width * size);
1264 r_view.height = (int)(vid.height * size * (1 - bound(0, r_letterbox.value, 100) / 100));
1266 r_view.x = (int)((vid.width - r_view.width)/2);
1267 r_view.y = (int)((vid.height - r_view.height)/2);
1271 // LordHavoc: viewzoom (zoom in for sniper rifles, etc)
1272 // LordHavoc: this is designed to produce widescreen fov values
1273 // when the screen is wider than 4/3 width/height aspect, to do
1274 // this it simply assumes the requested fov is the vertical fov
1275 // for a 4x3 display, if the ratio is not 4x3 this makes the fov
1276 // higher/lower according to the ratio
1277 r_view.frustum_y = tan(scr_fov.value * cl.viewzoom * M_PI / 360.0) * (3.0/4.0);
1278 r_view.frustum_x = r_view.frustum_y * (float)r_view.width / (float)r_view.height / vid_pixelheight.value;
1280 r_view.frustum_x *= r_refdef.frustumscale_x;
1281 r_view.frustum_y *= r_refdef.frustumscale_y;
1283 if(!CL_VM_UpdateView())
1288 if (scr_zoomwindow.integer)
1290 float sizex = bound(10, scr_zoomwindow_viewsizex.value, 100) / 100.0;
1291 float sizey = bound(10, scr_zoomwindow_viewsizey.value, 100) / 100.0;
1292 r_view.width = (int)(vid.width * sizex);
1293 r_view.height = (int)(vid.height * sizey);
1295 r_view.x = (int)((vid.width - r_view.width)/2);
1299 r_view.frustum_y = tan(scr_zoomwindow_fov.value * cl.viewzoom * M_PI / 360.0) * (3.0/4.0);
1300 r_view.frustum_x = r_view.frustum_y * vid_pixelheight.value * (float)r_view.width / (float)r_view.height;
1302 r_view.frustum_x *= r_refdef.frustumscale_x;
1303 r_view.frustum_y *= r_refdef.frustumscale_y;
1305 if(!CL_VM_UpdateView())
1310 if (!r_stereo_sidebyside.integer)
1312 r_view.width = vid.width;
1313 r_view.height = vid.height;
1323 //FIXME: force menu if nothing else to look at?
1324 //if (key_dest == key_game && cls.signon != SIGNONS && cls.state == ca_disconnected)
1326 if (cls.signon == SIGNONS)
1331 if (!r_letterbox.value)
1334 SCR_CheckDrawCenterString();
1338 R_Shadow_EditLights_DrawSelectedLightProperties();
1347 if (r_timereport_active)
1350 if (cls.signon == SIGNONS)
1351 R_TimeReport_Frame();
1359 if (r_timereport_active)
1360 R_TimeReport("meshfinish");
1363 void SCR_UpdateLoadingScreen (void)
1368 float texcoord2f[8];
1369 // don't do anything if not initialized yet
1373 qglViewport(0, 0, vid.width, vid.height);CHECKGLERROR
1374 //qglDisable(GL_SCISSOR_TEST);CHECKGLERROR
1375 //qglDepthMask(1);CHECKGLERROR
1376 qglColorMask(1,1,1,1);CHECKGLERROR
1377 //qglClearColor(0,0,0,0);CHECKGLERROR
1378 //qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1379 //qglCullFace(GL_FRONT);CHECKGLERROR
1380 //qglDisable(GL_CULL_FACE);CHECKGLERROR
1383 GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
1385 R_Mesh_Matrix(&identitymatrix);
1386 // draw the loading plaque
1387 pic = Draw_CachePic("gfx/loading", true);
1388 x = (vid_conwidth.integer - pic->width)/2;
1389 y = (vid_conheight.integer - pic->height)/2;
1391 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1392 GL_DepthTest(false);
1393 R_Mesh_VertexPointer(vertex3f);
1394 R_Mesh_ColorPointer(NULL);
1395 R_Mesh_ResetTextureState();
1396 R_Mesh_TexBind(0, R_GetTexture(pic->tex));
1397 R_Mesh_TexCoordPointer(0, 2, texcoord2f);
1398 vertex3f[2] = vertex3f[5] = vertex3f[8] = vertex3f[11] = 0;
1399 vertex3f[0] = vertex3f[9] = x;
1400 vertex3f[1] = vertex3f[4] = y;
1401 vertex3f[3] = vertex3f[6] = x + pic->width;
1402 vertex3f[7] = vertex3f[10] = y + pic->height;
1403 texcoord2f[0] = 0;texcoord2f[1] = 0;
1404 texcoord2f[2] = 1;texcoord2f[3] = 0;
1405 texcoord2f[4] = 1;texcoord2f[5] = 1;
1406 texcoord2f[6] = 0;texcoord2f[7] = 1;
1407 R_Mesh_Draw(0, 4, 2, polygonelements);
1413 void CL_UpdateScreen(void)
1415 float conwidth, conheight;
1420 if (!scr_initialized || !con_initialized || vid_hidden)
1421 return; // not initialized yet
1423 // don't allow cheats in multiplayer
1424 if (!cl.islocalgame && cl.worldmodel)
1426 if (r_fullbright.integer != 0)
1427 Cvar_Set ("r_fullbright", "0");
1428 if (r_ambient.value != 0)
1429 Cvar_Set ("r_ambient", "0");
1432 conwidth = bound(320, vid_conwidth.value, 2048);
1433 conheight = bound(200, vid_conheight.value, 1536);
1434 if (vid_conwidth.value != conwidth)
1435 Cvar_SetValue("vid_conwidth", conwidth);
1436 if (vid_conheight.value != conheight)
1437 Cvar_SetValue("vid_conheight", conheight);
1440 if (scr_viewsize.value < 30)
1441 Cvar_Set ("viewsize","30");
1442 if (scr_viewsize.value > 120)
1443 Cvar_Set ("viewsize","120");
1445 // bound field of view
1446 if (scr_fov.value < 1)
1447 Cvar_Set ("fov","1");
1448 if (scr_fov.value > 170)
1449 Cvar_Set ("fov","170");
1451 // validate r_textureunits cvar
1452 if (r_textureunits.integer > gl_textureunits)
1453 Cvar_SetValueQuick(&r_textureunits, gl_textureunits);
1454 if (r_textureunits.integer < 1)
1455 Cvar_SetValueQuick(&r_textureunits, 1);
1457 // validate gl_combine cvar
1458 if (gl_combine.integer && !gl_combine_extension)
1459 Cvar_SetValueQuick(&gl_combine, 0);
1461 // intermission is always full screen
1462 if (cl.intermission)
1466 if (scr_viewsize.value >= 120)
1467 sb_lines = 0; // no status bar at all
1468 else if (scr_viewsize.value >= 110)
1469 sb_lines = 24; // no inventory
1474 r_view.colormask[0] = 1;
1475 r_view.colormask[1] = 1;
1476 r_view.colormask[2] = 1;
1478 if (r_timereport_active)
1479 R_TimeReport("other");
1481 SCR_SetUpToDrawConsole();
1483 if (r_timereport_active)
1484 R_TimeReport("start");
1487 qglViewport(0, 0, vid.width, vid.height);CHECKGLERROR
1488 qglDisable(GL_SCISSOR_TEST);CHECKGLERROR
1489 qglDepthMask(1);CHECKGLERROR
1490 qglColorMask(1,1,1,1);CHECKGLERROR
1491 qglClearColor(0,0,0,0);CHECKGLERROR
1492 qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1494 if (r_timereport_active)
1495 R_TimeReport("clear");
1497 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer || r_stereo_sidebyside.integer)
1499 matrix4x4_t originalmatrix = r_view.matrix;
1500 r_view.matrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * -0.5f * r_view.matrix.m[0][1];
1501 r_view.matrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * -0.5f * r_view.matrix.m[1][1];
1502 r_view.matrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * -0.5f * r_view.matrix.m[2][1];
1504 if (r_stereo_sidebyside.integer)
1507 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1509 r_view.colormask[0] = 1;
1510 r_view.colormask[1] = 0;
1511 r_view.colormask[2] = 0;
1516 r_view.matrix.m[0][3] = originalmatrix.m[0][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[0][1];
1517 r_view.matrix.m[1][3] = originalmatrix.m[1][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[1][1];
1518 r_view.matrix.m[2][3] = originalmatrix.m[2][3] + r_stereo_separation.value * 0.5f * r_view.matrix.m[2][1];
1520 if (r_stereo_sidebyside.integer)
1523 if (r_stereo_redblue.integer || r_stereo_redgreen.integer || r_stereo_redcyan.integer)
1525 r_view.colormask[0] = 0;
1526 r_view.colormask[1] = r_stereo_redcyan.integer || r_stereo_redgreen.integer;
1527 r_view.colormask[2] = r_stereo_redcyan.integer || r_stereo_redblue.integer;
1532 r_view.matrix = originalmatrix;
1540 if (r_timereport_active)
1541 R_TimeReport("finish");
1544 void CL_Screen_NewMap(void)