X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=cl_screen.c;h=12426fd8f1bd40f72e362b89054f2c0562b856f5;hp=b3eb2a67297f16ea6a221cfe197052ff6c04a148;hb=cf22ff4047c6cac2ee44bb3ecf554ca0f9eed819;hpb=c4e92b9982882076e7b35e55fb43bd1a0dbd340d diff --git a/cl_screen.c b/cl_screen.c index b3eb2a67..12426fd8 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -30,15 +30,17 @@ cvar_t vid_pixelheight = {CVAR_SAVE, "vid_pixelheight", "1", "adjusts vertical f cvar_t scr_screenshot_jpeg = {CVAR_SAVE, "scr_screenshot_jpeg","1", "save jpeg instead of targa"}; cvar_t scr_screenshot_jpeg_quality = {CVAR_SAVE, "scr_screenshot_jpeg_quality","0.9", "image quality of saved jpeg"}; cvar_t scr_screenshot_gammaboost = {CVAR_SAVE, "scr_screenshot_gammaboost","1", "gamma correction on saved screenshots and videos, 1.0 saves unmodified images"}; +cvar_t scr_screenshot_hwgamma = {CVAR_SAVE, "scr_screenshot_hwgamma","1", "apply the video gamma ramp to saved screenshots and videos"}; // scr_screenshot_name is defined in fs.c cvar_t cl_capturevideo = {0, "cl_capturevideo", "0", "enables saving of video to a .avi file using uncompressed I420 colorspace and PCM audio, note that scr_screenshot_gammaboost affects the brightness of the output)"}; -cvar_t cl_capturevideo_printfps = {0, "cl_capturevideo_printfps", "1", "prints the frames per second captured in capturevideo (is only written to the log file, not to the console, as that would be visible on the video)"}; -cvar_t cl_capturevideo_width = {0, "cl_capturevideo_width", "0", "scales all frames to this resolution before saving the video"}; -cvar_t cl_capturevideo_height = {0, "cl_capturevideo_height", "0", "scales all frames to this resolution before saving the video"}; +cvar_t cl_capturevideo_printfps = {CVAR_SAVE, "cl_capturevideo_printfps", "1", "prints the frames per second captured in capturevideo (is only written to the log file, not to the console, as that would be visible on the video)"}; +cvar_t cl_capturevideo_width = {CVAR_SAVE, "cl_capturevideo_width", "0", "scales all frames to this resolution before saving the video"}; +cvar_t cl_capturevideo_height = {CVAR_SAVE, "cl_capturevideo_height", "0", "scales all frames to this resolution before saving the video"}; cvar_t cl_capturevideo_realtime = {0, "cl_capturevideo_realtime", "0", "causes video saving to operate in realtime (mostly useful while playing, not while capturing demos), this can produce a much lower quality video due to poor sound/video sync and will abort saving if your machine stalls for over a minute"}; -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)"}; +cvar_t cl_capturevideo_fps = {CVAR_SAVE, "cl_capturevideo_fps", "30", "how many frames per second to save (29.97 for NTSC, 30 for typical PC video, 15 can be useful)"}; +cvar_t cl_capturevideo_nameformat = {CVAR_SAVE, "cl_capturevideo_nameformat", "dpvideo", "prefix for saved videos (the date is encoded using strftime escapes)"}; cvar_t cl_capturevideo_number = {CVAR_SAVE, "cl_capturevideo_number", "1", "number to append to video filename, incremented each time a capture begins"}; -cvar_t cl_capturevideo_ogg = {0, "cl_capturevideo_ogg", "0", "save captured video data as Ogg/Vorbis/Theora streams"}; +cvar_t cl_capturevideo_ogg = {CVAR_SAVE, "cl_capturevideo_ogg", "1", "save captured video data as Ogg/Vorbis/Theora streams"}; 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)"}; cvar_t r_stereo_separation = {0, "r_stereo_separation", "4", "separation distance of eyes in the world (negative values are only useful for cross-eyed viewing)"}; 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 (note: use a negative r_stereo_separation if you want cross-eyed viewing)"}; @@ -55,6 +57,10 @@ cvar_t scr_refresh = {0, "scr_refresh", "1", "allows you to completely shut off cvar_t shownetgraph = {CVAR_SAVE, "shownetgraph", "0", "shows a graph of packet sizes and other information, 0 = off, 1 = show client netgraph, 2 = show client and server netgraphs (when hosting a server)"}; cvar_t cl_demo_mousegrab = {0, "cl_demo_mousegrab", "0", "Allows reading the mouse input while playing demos. Useful for camera mods developed in csqc. (0: never, 1: always)"}; +extern cvar_t r_glsl; +extern cvar_t v_glslgamma; +#define WANT_SCREENSHOT_HWGAMMA (scr_screenshot_hwgamma.integer && !(r_glsl.integer && v_glslgamma.integer)) + int jpeg_supported = false; qboolean scr_initialized; // ready to draw @@ -851,12 +857,14 @@ void CL_Screen_Init(void) Cvar_RegisterVariable (&scr_screenshot_jpeg); Cvar_RegisterVariable (&scr_screenshot_jpeg_quality); Cvar_RegisterVariable (&scr_screenshot_gammaboost); + Cvar_RegisterVariable (&scr_screenshot_hwgamma); Cvar_RegisterVariable (&cl_capturevideo); Cvar_RegisterVariable (&cl_capturevideo_printfps); Cvar_RegisterVariable (&cl_capturevideo_width); Cvar_RegisterVariable (&cl_capturevideo_height); Cvar_RegisterVariable (&cl_capturevideo_realtime); Cvar_RegisterVariable (&cl_capturevideo_fps); + Cvar_RegisterVariable (&cl_capturevideo_nameformat); Cvar_RegisterVariable (&cl_capturevideo_number); Cvar_RegisterVariable (&cl_capturevideo_ogg); Cvar_RegisterVariable (&r_letterbox); @@ -894,33 +902,33 @@ SCR_ScreenShot_f void SCR_ScreenShot_f (void) { static int shotnumber; - static char oldname[MAX_QPATH]; - char base[MAX_QPATH]; + static char old_prefix_name[MAX_QPATH]; + char prefix_name[MAX_QPATH]; char filename[MAX_QPATH]; unsigned char *buffer1; unsigned char *buffer2; unsigned char *buffer3; qboolean jpeg = (scr_screenshot_jpeg.integer != 0); - dpsnprintf (base, sizeof(base), "screenshots/%s", scr_screenshot_name.string); + dpsnprintf (prefix_name, sizeof(prefix_name), "%s", Sys_TimeString(scr_screenshot_name.string)); - if (strcmp (oldname, scr_screenshot_name.string)) + if (strcmp(old_prefix_name, prefix_name)) { - dpsnprintf(oldname, sizeof(oldname), "%s", scr_screenshot_name.string); + dpsnprintf(old_prefix_name, sizeof(old_prefix_name), "%s", prefix_name ); shotnumber = 0; } // find a file name to save it to for (;shotnumber < 1000000;shotnumber++) - if (!FS_SysFileExists(va("%s/%s%06d.tga", fs_gamedir, base, shotnumber)) && !FS_SysFileExists(va("%s/%s%06d.jpg", fs_gamedir, base, shotnumber))) + if (!FS_SysFileExists(va("%s/screenshots/%s%06d.tga", fs_gamedir, prefix_name, shotnumber)) && !FS_SysFileExists(va("%s/screenshots/%s%06d.jpg", fs_gamedir, prefix_name, shotnumber))) break; if (shotnumber >= 1000000) { - Con_Print("SCR_ScreenShot_f: Couldn't create the image file\n"); + Con_Print("Couldn't create the image file\n"); return; } - dpsnprintf(filename, sizeof(filename), "%s%06d.%s", base, shotnumber, jpeg ? "jpg" : "tga"); + dpsnprintf(filename, sizeof(filename), "screenshots/%s%06d.%s", prefix_name, shotnumber, jpeg ? "jpg" : "tga"); buffer1 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3); buffer2 = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 3); @@ -929,7 +937,7 @@ void SCR_ScreenShot_f (void) if (SCR_ScreenShot (filename, buffer1, buffer2, buffer3, 0, 0, vid.width, vid.height, false, false, false, jpeg, true)) Con_Printf("Wrote %s\n", filename); else - Con_Printf("unable to write %s\n", filename); + Con_Printf("Unable to write %s\n", filename); Mem_Free (buffer1); Mem_Free (buffer2); @@ -940,7 +948,7 @@ void SCR_ScreenShot_f (void) void SCR_CaptureVideo_BeginVideo(void) { - double gamma, g; + double r, g, b; unsigned int i; int width = cl_capturevideo_width.integer, height = cl_capturevideo_height.integer; if (cls.capturevideo.active) @@ -977,8 +985,7 @@ void SCR_CaptureVideo_BeginVideo(void) cls.capturevideo.realtime = cl_capturevideo_realtime.integer != 0; cls.capturevideo.screenbuffer = (unsigned char *)Mem_Alloc(tempmempool, vid.width * vid.height * 4); cls.capturevideo.outbuffer = (unsigned char *)Mem_Alloc(tempmempool, width * height * (4+4) + 18); - gamma = 1.0/scr_screenshot_gammaboost.value; - dpsnprintf(cls.capturevideo.basename, sizeof(cls.capturevideo.basename), "video/dpvideo%03i", cl_capturevideo_number.integer); + dpsnprintf(cls.capturevideo.basename, sizeof(cls.capturevideo.basename), "video/%s%03i", Sys_TimeString(cl_capturevideo_nameformat.string), cl_capturevideo_number.integer); Cvar_SetValueQuick(&cl_capturevideo_number, cl_capturevideo_number.integer + 1); /* @@ -998,35 +1005,61 @@ Y = R * .299 + G * .587 + B * .114; Cb = R * -.169 + G * -.332 + B * .500 + 128.; Cr = R * .500 + G * -.419 + B * -.0813 + 128.; */ + + if(WANT_SCREENSHOT_HWGAMMA) + { + VID_BuildGammaTables(&cls.capturevideo.vidramp[0], 256); + } + else + { + // identity gamma table + BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, cls.capturevideo.vidramp, 256); + BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, cls.capturevideo.vidramp + 256, 256); + BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, cls.capturevideo.vidramp + 256*2, 256); + } + if(scr_screenshot_gammaboost.value != 1) + { + double igamma = 1 / scr_screenshot_gammaboost.value; + for (i = 0;i < 256 * 3;i++) + cls.capturevideo.vidramp[i] = (unsigned short) (0.5 + pow(cls.capturevideo.vidramp[i] * (1.0 / 65535.0), igamma) * 65535.0); + } + for (i = 0;i < 256;i++) { - g = 255*pow(i/255.0, gamma); + r = 255*cls.capturevideo.vidramp[i]/65535.0; + g = 255*cls.capturevideo.vidramp[i+256]/65535.0; + b = 255*cls.capturevideo.vidramp[i+512]/65535.0; + // NOTE: we have to round DOWN here, or integer overflows happen. Sorry for slightly wrong looking colors sometimes... // Y weights from RGB - cls.capturevideo.rgbtoyuvscaletable[0][0][i] = (short)(g * 0.299); + cls.capturevideo.rgbtoyuvscaletable[0][0][i] = (short)(r * 0.299); cls.capturevideo.rgbtoyuvscaletable[0][1][i] = (short)(g * 0.587); - cls.capturevideo.rgbtoyuvscaletable[0][2][i] = (short)(g * 0.114); + cls.capturevideo.rgbtoyuvscaletable[0][2][i] = (short)(b * 0.114); // Cb weights from RGB - cls.capturevideo.rgbtoyuvscaletable[1][0][i] = (short)(g * -0.169); + cls.capturevideo.rgbtoyuvscaletable[1][0][i] = (short)(r * -0.169); cls.capturevideo.rgbtoyuvscaletable[1][1][i] = (short)(g * -0.332); - cls.capturevideo.rgbtoyuvscaletable[1][2][i] = (short)(g * 0.500); + cls.capturevideo.rgbtoyuvscaletable[1][2][i] = (short)(b * 0.500); // Cr weights from RGB - cls.capturevideo.rgbtoyuvscaletable[2][0][i] = (short)(g * 0.500); + cls.capturevideo.rgbtoyuvscaletable[2][0][i] = (short)(r * 0.500); cls.capturevideo.rgbtoyuvscaletable[2][1][i] = (short)(g * -0.419); - cls.capturevideo.rgbtoyuvscaletable[2][2][i] = (short)(g * -0.0813); + cls.capturevideo.rgbtoyuvscaletable[2][2][i] = (short)(b * -0.0813); // range reduction of YCbCr to valid signal range cls.capturevideo.yuvnormalizetable[0][i] = 16 + i * (236-16) / 256; cls.capturevideo.yuvnormalizetable[1][i] = 16 + i * (240-16) / 256; cls.capturevideo.yuvnormalizetable[2][i] = 16 + i * (240-16) / 256; } - if (cl_capturevideo_ogg.integer && SCR_CaptureVideo_Ogg_Available()) - { - SCR_CaptureVideo_Ogg_BeginVideo(); - } - else + if (cl_capturevideo_ogg.integer) { - SCR_CaptureVideo_Avi_BeginVideo(); + if(SCR_CaptureVideo_Ogg_Available()) + { + SCR_CaptureVideo_Ogg_BeginVideo(); + return; + } + else + Con_Print("cl_capturevideo_ogg: libraries not available. Capturing in AVI instead.\n"); } + + SCR_CaptureVideo_Avi_BeginVideo(); } void SCR_CaptureVideo_EndVideo(void) @@ -1035,7 +1068,7 @@ void SCR_CaptureVideo_EndVideo(void) return; cls.capturevideo.active = false; - Con_DPrintf("Finishing capture (%d frames, %d audio frames)\n", cls.capturevideo.frame, cls.capturevideo.soundsampleframe); + Con_Printf("Finishing capture of %s.%s (%d frames, %d audio frames)\n", cls.capturevideo.basename, cls.capturevideo.formatextension, cls.capturevideo.frame, cls.capturevideo.soundsampleframe); if (cls.capturevideo.videofile) { @@ -1365,15 +1398,33 @@ qboolean SCR_ScreenShot(char *filename, unsigned char *buffer1, unsigned char *b CHECKGLERROR qglReadPixels (x, y, width, height, jpeg ? GL_RGB : GL_BGR, GL_UNSIGNED_BYTE, buffer1);CHECKGLERROR - if (scr_screenshot_gammaboost.value != 1 && gammacorrect) + if(gammacorrect && (scr_screenshot_gammaboost.value != 1 || WANT_SCREENSHOT_HWGAMMA)) { int i; double igamma = 1.0 / scr_screenshot_gammaboost.value; - unsigned char ramp[256]; - for (i = 0;i < 256;i++) - ramp[i] = (unsigned char) (pow(i * (1.0 / 255.0), igamma) * 255.0); - for (i = 0;i < width*height*3;i++) - buffer1[i] = ramp[buffer1[i]]; + unsigned short vidramp[256 * 3]; + if(WANT_SCREENSHOT_HWGAMMA) + { + VID_BuildGammaTables(&vidramp[0], 256); + } + else + { + // identity gamma table + BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, vidramp, 256); + BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, vidramp + 256, 256); + BuildGammaTable16(1.0f, 1.0f, 1.0f, 0.0f, 1.0f, vidramp + 256*2, 256); + } + if(scr_screenshot_gammaboost.value != 1) + { + for (i = 0;i < 256 * 3;i++) + vidramp[i] = (unsigned short) (0.5 + pow(vidramp[i] * (1.0 / 65535.0), igamma) * 65535.0); + } + for (i = 0;i < width*height*3;i += 3) + { + buffer1[i] = (unsigned char) (vidramp[buffer1[i]] * 255.0 / 65535.0 + 0.5); + buffer1[i+1] = (unsigned char) (vidramp[buffer1[i+1] + 256] * 255.0 / 65535.0 + 0.5); + buffer1[i+2] = (unsigned char) (vidramp[buffer1[i+2] + 512] * 255.0 / 65535.0 + 0.5); + } } Image_CopyMux (buffer2, buffer1, width, height, flipx, flipy, flipdiagonal, 3, 3, indices); @@ -1559,15 +1610,206 @@ void SCR_DrawScreen (void) R_Mesh_Finish(); } -void SCR_UpdateLoadingScreen (qboolean clear) +typedef struct loadingscreenstack_s { - float x, y; - cachepic_t *pic; - float vertex3f[12]; - float texcoord2f[8]; - // don't do anything if not initialized yet - if (vid_hidden || !scr_refresh.integer) + struct loadingscreenstack_s *prev; + char msg[MAX_QPATH]; + float absolute_loading_amount_min; // this corresponds to relative completion 0 of this item + float absolute_loading_amount_len; // this corresponds to relative completion 1 of this item + float relative_completion; // 0 .. 1 +} +loadingscreenstack_t; +static loadingscreenstack_t *loadingscreenstack = NULL; +static double loadingscreentime = -1; +static qboolean loadingscreencleared = false; +static float loadingscreenheight = 0; +rtexture_t *loadingscreentexture = NULL; +static float loadingscreentexture_vertex3f[12]; +static float loadingscreentexture_texcoord2f[8]; + +static void SCR_ClearLoadingScreenTexture() +{ + if(loadingscreentexture) + R_FreeTexture(loadingscreentexture); + loadingscreentexture = NULL; +} + +extern rtexturepool_t *r_main_texturepool; +static void SCR_SetLoadingScreenTexture() +{ + int w, h; + float loadingscreentexture_w; + float loadingscreentexture_h; + + SCR_ClearLoadingScreenTexture(); + + if (gl_support_arb_texture_non_power_of_two) + { + w = vid.width; h = vid.height; + loadingscreentexture_w = loadingscreentexture_h = 1; + } + else + { + w = CeilPowerOf2(vid.width); h = CeilPowerOf2(vid.height); + loadingscreentexture_w = vid.width / (float) w; + loadingscreentexture_h = vid.height / (float) h; + } + + loadingscreentexture = R_LoadTexture2D(r_main_texturepool, "loadingscreentexture", w, h, NULL, TEXTYPE_BGRA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL); + R_Mesh_TexBind(0, R_GetTexture(loadingscreentexture)); + GL_ActiveTexture(0); + CHECKGLERROR + qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, vid.width, vid.height);CHECKGLERROR + + loadingscreentexture_vertex3f[2] = loadingscreentexture_vertex3f[5] = loadingscreentexture_vertex3f[8] = loadingscreentexture_vertex3f[11] = 0; + loadingscreentexture_vertex3f[0] = loadingscreentexture_vertex3f[9] = 0; + loadingscreentexture_vertex3f[1] = loadingscreentexture_vertex3f[4] = 0; + loadingscreentexture_vertex3f[3] = loadingscreentexture_vertex3f[6] = vid_conwidth.integer; + loadingscreentexture_vertex3f[7] = loadingscreentexture_vertex3f[10] = vid_conheight.integer; + loadingscreentexture_texcoord2f[0] = 0;loadingscreentexture_texcoord2f[1] = loadingscreentexture_h; + loadingscreentexture_texcoord2f[2] = loadingscreentexture_w;loadingscreentexture_texcoord2f[3] = loadingscreentexture_h; + loadingscreentexture_texcoord2f[4] = loadingscreentexture_w;loadingscreentexture_texcoord2f[5] = 0; + loadingscreentexture_texcoord2f[6] = 0;loadingscreentexture_texcoord2f[7] = 0; +} + +void SCR_UpdateLoadingScreenIfShown() +{ + if(realtime == loadingscreentime) + SCR_UpdateLoadingScreen(loadingscreencleared); +} + +void SCR_PushLoadingScreen (qboolean redraw, const char *msg, float len_in_parent) +{ + loadingscreenstack_t *s = (loadingscreenstack_t *) Z_Malloc(sizeof(loadingscreenstack_t)); + s->prev = loadingscreenstack; + loadingscreenstack = s; + + strlcpy(s->msg, msg, sizeof(s->msg)); + s->relative_completion = 0; + + if(s->prev) + { + s->absolute_loading_amount_min = s->prev->absolute_loading_amount_min + s->prev->absolute_loading_amount_len * s->prev->relative_completion; + s->absolute_loading_amount_len = s->prev->absolute_loading_amount_len * len_in_parent; + if(s->absolute_loading_amount_len > s->prev->absolute_loading_amount_min + s->prev->absolute_loading_amount_len - s->absolute_loading_amount_min) + s->absolute_loading_amount_len = s->prev->absolute_loading_amount_min + s->prev->absolute_loading_amount_len - s->absolute_loading_amount_min; + } + else + { + s->absolute_loading_amount_min = 0; + s->absolute_loading_amount_len = 1; + } + + if(redraw) + SCR_UpdateLoadingScreenIfShown(); +} + +void SCR_PopLoadingScreen (qboolean redraw) +{ + loadingscreenstack_t *s = loadingscreenstack; + + if(!s) + { + Con_DPrintf("Popping a loading screen item from an empty stack!\n"); return; + } + + loadingscreenstack = s->prev; + if(s->prev) + s->prev->relative_completion = (s->absolute_loading_amount_min + s->absolute_loading_amount_len - s->prev->absolute_loading_amount_min) / s->prev->absolute_loading_amount_len; + Z_Free(s); + + if(redraw) + SCR_UpdateLoadingScreenIfShown(); +} + +void SCR_ClearLoadingScreen (qboolean redraw) +{ + while(loadingscreenstack) + SCR_PopLoadingScreen(redraw && !loadingscreenstack->prev); +} + +static float SCR_DrawLoadingStack_r(loadingscreenstack_t *s, float y) +{ + float size = 8; + float x; + size_t len; + float total; + + total = 0; +#if 0 + if(s) + { + total += SCR_DrawLoadingStack_r(s->prev, y); + y -= total; + if(!s->prev || strcmp(s->msg, s->prev->msg)) + { + len = strlen(s->msg); + x = (vid_conwidth.integer - DrawQ_TextWidth_Font(s->msg, len, true, FONT_INFOBAR) * size) / 2; + y -= size; + DrawQ_Fill(0, y, vid_conwidth.integer, size, 0, 0, 0, 1, 0); + DrawQ_String_Font(x, y, s->msg, len, size, size, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + total += size; + } + } +#else + if(s) + { + len = strlen(s->msg); + x = (vid_conwidth.integer - DrawQ_TextWidth_Font(s->msg, len, true, FONT_INFOBAR) * size) / 2; + y -= size; + DrawQ_Fill(0, y, vid_conwidth.integer, size, 0, 0, 0, 1, 0); + DrawQ_String_Font(x, y, s->msg, len, size, size, 1, 1, 1, 1, 0, NULL, true, FONT_INFOBAR); + total += size; + } +#endif + return total; +} + +static void SCR_DrawLoadingStack() +{ + float verts[12]; + float colors[16]; + int i; + + loadingscreenheight = SCR_DrawLoadingStack_r(loadingscreenstack, vid_conheight.integer); + if(loadingscreenstack) + { + // height = 32; // sorry, using the actual one is ugly + GL_BlendFunc(GL_SRC_ALPHA, GL_ONE); + GL_DepthRange(0, 1); + GL_PolygonOffset(0, 0); + GL_DepthTest(false); + R_Mesh_VertexPointer(verts, 0, 0); + R_Mesh_ColorPointer(colors, 0, 0); + R_Mesh_ResetTextureState(); + R_SetupGenericShader(false); + verts[2] = verts[5] = verts[8] = verts[11] = 0; + verts[0] = verts[9] = 0; + verts[1] = verts[4] = vid_conheight.integer - 8; + verts[3] = verts[6] = vid_conwidth.integer * loadingscreenstack->absolute_loading_amount_min; + verts[7] = verts[10] = vid_conheight.integer; + + for(i = 0; i < 16; ++i) + colors[i] = (i % 4 == 3) ? 1 : (i >= 8 && i % 4 == 2) ? 1 : 0; + // ^^^^^^^^^^ blue component + // ^^^^^^ bottom row + // ^^^^^^^^^^^^ alpha is always on + R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0); + + // make sure everything is cleared, including the progress indicator + if(loadingscreenheight < 8) + loadingscreenheight = 8; + } +} + +static cachepic_t *loadingscreenpic; +static float loadingscreenpic_vertex3f[12]; +static float loadingscreenpic_texcoord2f[8]; + +static void SCR_DrawLoadingScreen_SharedSetup (qboolean clear) +{ + float x, y; // release mouse grab while loading if (!vid.fullscreen) VID_SetMouse(false, false, false); @@ -1579,59 +1821,110 @@ void SCR_UpdateLoadingScreen (qboolean clear) qglClearColor(0,0,0,0);CHECKGLERROR // when starting up a new video mode, make sure the screen is cleared to black if (clear) - { qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR - } - //qglDisable(GL_CULL_FACE);CHECKGLERROR - //R_ClearScreen(); R_Textures_Frame(); GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100); R_Mesh_Start(); R_Mesh_Matrix(&identitymatrix); // draw the loading plaque - pic = Draw_CachePic ("gfx/loading"); - x = (vid_conwidth.integer - pic->width)/2; - y = (vid_conheight.integer - pic->height)/2; + loadingscreenpic = Draw_CachePic ("gfx/loading"); + x = (vid_conwidth.integer - loadingscreenpic->width)/2; + y = (vid_conheight.integer - loadingscreenpic->height)/2; + loadingscreenpic_vertex3f[2] = loadingscreenpic_vertex3f[5] = loadingscreenpic_vertex3f[8] = loadingscreenpic_vertex3f[11] = 0; + loadingscreenpic_vertex3f[0] = loadingscreenpic_vertex3f[9] = x; + loadingscreenpic_vertex3f[1] = loadingscreenpic_vertex3f[4] = y; + loadingscreenpic_vertex3f[3] = loadingscreenpic_vertex3f[6] = x + loadingscreenpic->width; + loadingscreenpic_vertex3f[7] = loadingscreenpic_vertex3f[10] = y + loadingscreenpic->height; + loadingscreenpic_texcoord2f[0] = 0;loadingscreenpic_texcoord2f[1] = 0; + loadingscreenpic_texcoord2f[2] = 1;loadingscreenpic_texcoord2f[3] = 0; + loadingscreenpic_texcoord2f[4] = 1;loadingscreenpic_texcoord2f[5] = 1; + loadingscreenpic_texcoord2f[6] = 0;loadingscreenpic_texcoord2f[7] = 1; +} + +static void SCR_DrawLoadingScreen (qboolean clear) +{ + // we only need to draw the image if it isn't already there GL_Color(1,1,1,1); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_DepthRange(0, 1); GL_PolygonOffset(0, 0); GL_DepthTest(false); - R_Mesh_VertexPointer(vertex3f, 0, 0); - R_Mesh_ColorPointer(NULL, 0, 0); - R_Mesh_ResetTextureState(); - R_Mesh_TexBind(0, R_GetTexture(pic->tex)); - R_Mesh_TexCoordPointer(0, 2, texcoord2f, 0, 0); R_SetupGenericShader(true); - vertex3f[2] = vertex3f[5] = vertex3f[8] = vertex3f[11] = 0; - vertex3f[0] = vertex3f[9] = x; - vertex3f[1] = vertex3f[4] = y; - vertex3f[3] = vertex3f[6] = x + pic->width; - vertex3f[7] = vertex3f[10] = y + pic->height; - texcoord2f[0] = 0;texcoord2f[1] = 0; - texcoord2f[2] = 1;texcoord2f[3] = 0; - texcoord2f[4] = 1;texcoord2f[5] = 1; - texcoord2f[6] = 0;texcoord2f[7] = 1; - if (vid.stereobuffer) - { - qglDrawBuffer(GL_FRONT_LEFT); - R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0); - qglDrawBuffer(GL_FRONT_RIGHT); - R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0); - } - else + R_Mesh_ColorPointer(NULL, 0, 0); + if(loadingscreentexture) { - qglDrawBuffer(GL_FRONT); + R_Mesh_VertexPointer(loadingscreentexture_vertex3f, 0, 0); + R_Mesh_ResetTextureState(); + R_Mesh_TexBind(0, R_GetTexture(loadingscreentexture)); + R_Mesh_TexCoordPointer(0, 2, loadingscreentexture_texcoord2f, 0, 0); R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0); } + R_Mesh_VertexPointer(loadingscreenpic_vertex3f, 0, 0); + R_Mesh_ResetTextureState(); + R_Mesh_TexBind(0, R_GetTexture(loadingscreenpic->tex)); + R_Mesh_TexCoordPointer(0, 2, loadingscreenpic_texcoord2f, 0, 0); + R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0); + SCR_DrawLoadingStack(); +} + +static void SCR_DrawLoadingScreen_SharedFinish (qboolean clear) +{ R_Mesh_Finish(); // refresh - // not necessary when rendering to GL_FRONT buffers - //VID_Finish(); + VID_Finish(); // however this IS necessary on Windows Vista qglFinish(); } +void SCR_UpdateLoadingScreen (qboolean clear) +{ + keydest_t old_key_dest; + int old_key_consoleactive; + + // don't do anything if not initialized yet + if (vid_hidden || !scr_refresh.integer || cls.state == ca_dedicated) + return; + + if(loadingscreentime == realtime) + clear |= loadingscreencleared; + + if(clear) + SCR_ClearLoadingScreenTexture(); + else if(loadingscreentime != realtime) + SCR_SetLoadingScreenTexture(); + + if(loadingscreentime != realtime) + { + loadingscreentime = realtime; + loadingscreenheight = 0; + } + loadingscreencleared = clear; + + SCR_DrawLoadingScreen_SharedSetup(clear); + if (vid.stereobuffer) + { + qglDrawBuffer(GL_BACK_LEFT); + SCR_DrawLoadingScreen(clear); + qglDrawBuffer(GL_BACK_RIGHT); + SCR_DrawLoadingScreen(clear); + } + else + { + qglDrawBuffer(GL_BACK); + SCR_DrawLoadingScreen(clear); + } + SCR_DrawLoadingScreen_SharedFinish(clear); + + // this goes into the event loop, and should prevent unresponsive cursor on vista + old_key_dest = key_dest; + old_key_consoleactive = key_consoleactive; + key_dest = key_void; + key_consoleactive = false; + Sys_SendKeyEvents(); + key_dest = old_key_dest; + key_consoleactive = old_key_consoleactive; +} + extern cvar_t cl_minfps; extern cvar_t cl_minfps_fade; extern cvar_t cl_minfps_qualitymax;