From a26a373d15429b774448196f9cb6997e2eee5a25 Mon Sep 17 00:00:00 2001 From: Spoike Date: Fri, 14 Aug 2015 02:46:38 +0000 Subject: [PATCH] fixed picmip simpleitems issue. fixed double picmip bug. use pbos for videocapture, for extra speed. mwahaha. fix issues with 2d batching. including drawflags. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4962 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/client/cl_ents.c | 2 +- engine/client/cl_screen.c | 185 ++++++++++++++++++++++++++--------- engine/client/client.h | 2 +- engine/client/image.c | 119 +++++++++++----------- engine/client/m_mp3.c | 151 ++++++++++++++++++++++++---- engine/client/merged.h | 4 +- engine/client/pr_menu.c | 6 ++ engine/client/r_2d.c | 9 +- engine/client/renderer.c | 2 +- engine/client/screen.h | 3 +- engine/client/vid.h | 2 +- engine/client/vid_headless.c | 3 +- engine/d3d/vid_d3d.c | 11 ++- engine/d3d/vid_d3d11.c | 6 +- engine/gl/gl_font.c | 13 +-- engine/gl/gl_screen.c | 44 ++++++--- engine/gl/glsupp.h | 4 + engine/server/savegame.c | 5 +- plugins/avplug/avencode.c | 28 +++++- 19 files changed, 424 insertions(+), 175 deletions(-) diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index 6665e6717..a81825b82 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -3686,7 +3686,7 @@ void CL_LinkPacketEntities (void) Q_snprintfz(name, sizeof(name), "textures/bmodels/simple_%s_%i.tga", basename, ent->skinnum); else Q_snprintfz(name, sizeof(name), "textures/models/simple_%s_%i.tga", basename, ent->skinnum); - model->simpleskin[ent->skinnum] = R_RegisterShader(name, 0, va("{\nprogram defaultsprite\nsurfaceparm noshadows\nsurfaceparm nodlight\nsort seethrough\n{\nmap \"%s\"\nalphafunc ge128\n}\n}\n", name)); + model->simpleskin[ent->skinnum] = R_RegisterShader(name, 0, va("{\nnomipmaps\nprogram defaultsprite\nsurfaceparm noshadows\nsurfaceparm nodlight\nsort seethrough\n{\nmap \"%s\"\nalphafunc ge128\n}\n}\n", name)); } VectorCopy(le->angles, angles); diff --git a/engine/client/cl_screen.c b/engine/client/cl_screen.c index 8c8f99226..ab1305ffc 100644 --- a/engine/client/cl_screen.c +++ b/engine/client/cl_screen.c @@ -2031,13 +2031,96 @@ typedef struct _TargaHeader { #if defined(AVAIL_JPEGLIB) && !defined(NO_JPEG) -qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression, qbyte *screendata, int screenwidth, int screenheight); +qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression, qbyte *screendata, int screenwidth, int screenheight, enum uploadfmt fmt); #endif #ifdef AVAIL_PNGLIB -int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, qbyte *pixels, int width, int height); +int Image_WritePNG (char *filename, enum fs_relative fsroot, int compression, qbyte *pixels, int width, int height, enum uploadfmt fmt); #endif void WriteBMPFile(char *filename, enum fs_relative fsroot, qbyte *in, int width, int height); +qboolean WriteTGA(char *filename, enum fs_relative fsroot, qbyte *rgb_buffer, int width, int height, enum uploadfmt fmt) +{ + size_t c, i; + vfsfile_t *vfs; + if (fmt != TF_BGRA32 && fmt != TF_RGB24 && fmt != TF_RGBA32 && fmt != TF_BGR24) + return false; + FS_CreatePath(filename, fsroot); + vfs = FS_OpenVFS(filename, "wb", fsroot); + if (vfs) + { + unsigned char header[18]; + memset (header, 0, 18); + header[2] = 2; // uncompressed type + header[12] = width&255; + header[13] = width>>8; + header[14] = height&255; + header[15] = height>>8; + header[16] = 24; // pixel size + + if (fmt == TF_BGRA32) + { +#if 0 + header[16] = 32; +#else + qbyte tmp[3]; + // compact+swap + c = width*height; + for (i=0 ; i>8; - header[14] = height&255; - header[15] = height>>8; - header[16] = 24; // pixel size - VFS_WRITE(vfs, header, sizeof(header)); - - // swap rgb to bgr - c = width*height*3; - for (i=0 ; ierr)->setjmp_buffer, 1); } -qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression, qbyte *screendata, int screenwidth, int screenheight) //input is rgb NOT rgba +qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression, qbyte *screendata, int screenwidth, int screenheight, enum uploadfmt fmt) { qbyte *buffer; vfsfile_t *outfile; @@ -1543,6 +1570,9 @@ qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression struct jpeg_compress_struct cinfo; JSAMPROW row_pointer[1]; + if (fmt != TF_RGB24) + return false; + if (!LIBJPEG_LOADED()) return false; @@ -1556,29 +1586,17 @@ qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression } } - #ifdef DYNAMIC_LIBJPEG - cinfo.err = qjpeg_std_error(&jerr.pub); - #else - cinfo.err = jpeg_std_error(&jerr.pub); - #endif + cinfo.err = qjpeg_std_error(&jerr.pub); jerr.pub.error_exit = jpeg_error_exit; if (setjmp(jerr.setjmp_buffer)) { - #ifdef DYNAMIC_LIBJPEG - qjpeg_destroy_compress(&cinfo); - #else - jpeg_destroy_compress(&cinfo); - #endif + qjpeg_destroy_compress(&cinfo); VFS_CLOSE(outfile); FS_Remove(filename, FS_GAME); Con_Printf("Failed to create jpeg\n"); return false; } - #ifdef DYNAMIC_LIBJPEG - qjpeg_create_compress(&cinfo); - #else - jpeg_create_compress(&cinfo); - #endif + qjpeg_create_compress(&cinfo); buffer = screendata; @@ -1587,42 +1605,18 @@ qboolean screenshotJPEG(char *filename, enum fs_relative fsroot, int compression cinfo.image_height = screenheight; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; - #ifdef DYNAMIC_LIBJPEG - qjpeg_set_defaults(&cinfo); - #else - jpeg_set_defaults(&cinfo); - #endif - #ifdef DYNAMIC_LIBJPEG - qjpeg_set_quality (&cinfo, bound(0, compression, 100), true); - #else - jpeg_set_quality (&cinfo, bound(0, compression, 100), true); - #endif - #ifdef DYNAMIC_LIBJPEG - qjpeg_start_compress(&cinfo, true); - #else - jpeg_start_compress(&cinfo, true); - #endif + qjpeg_set_defaults(&cinfo); + qjpeg_set_quality (&cinfo, bound(0, compression, 100), true); + qjpeg_start_compress(&cinfo, true); while (cinfo.next_scanline < cinfo.image_height) { *row_pointer = &buffer[(cinfo.image_height - cinfo.next_scanline - 1) * cinfo.image_width * 3]; - #ifdef DYNAMIC_LIBJPEG - qjpeg_write_scanlines(&cinfo, row_pointer, 1); - #else - jpeg_write_scanlines(&cinfo, row_pointer, 1); - #endif + qjpeg_write_scanlines(&cinfo, row_pointer, 1); } - #ifdef DYNAMIC_LIBJPEG - qjpeg_finish_compress(&cinfo); - #else - jpeg_finish_compress(&cinfo); - #endif + qjpeg_finish_compress(&cinfo); VFS_CLOSE(outfile); - #ifdef DYNAMIC_LIBJPEG - qjpeg_destroy_compress(&cinfo); - #else - jpeg_destroy_compress(&cinfo); - #endif + qjpeg_destroy_compress(&cinfo); return true; } #endif @@ -3155,21 +3149,24 @@ static void Image_RoundDimensions(int *scaled_width, int *scaled_height, unsigne } } - if (flags & IF_NOMIPMAP) + if (!(flags & IF_NOPICMIP)) { - if (gl_picmip2d.ival > 0) + if (flags & IF_NOMIPMAP) { - *scaled_width >>= gl_picmip2d.ival; - *scaled_height >>= gl_picmip2d.ival; + if (gl_picmip2d.ival > 0) + { + *scaled_width >>= gl_picmip2d.ival; + *scaled_height >>= gl_picmip2d.ival; + } } - } - else - { - if (gl_picmip.ival > 0) + else { - TRACE(("dbg: GL_RoundDimensions: %f\n", gl_picmip.value)); - *scaled_width >>= gl_picmip.ival; - *scaled_height >>= gl_picmip.ival; + if (gl_picmip.ival > 0) + { + TRACE(("dbg: GL_RoundDimensions: %f\n", gl_picmip.value)); + *scaled_width >>= gl_picmip.ival; + *scaled_height >>= gl_picmip.ival; + } } } @@ -3500,6 +3497,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag case TF_MIP4_LUM8: //8bit opaque data Image_RoundDimensions(&mips->mip[0].width, &mips->mip[0].height, flags); + flags |= IF_NOPICMIP; if (mips->mip[0].width == imgwidth && mips->mip[0].height == imgheight) { unsigned int pixels = @@ -3537,6 +3535,7 @@ static qboolean Image_GenMip0(struct pendingtextureinfo *mips, unsigned int flag case TF_MIP4_SOLID8: //8bit opaque data Image_RoundDimensions(&mips->mip[0].width, &mips->mip[0].height, flags); + flags |= IF_NOPICMIP; if (mips->mip[0].width == imgwidth && mips->mip[0].height == imgheight && sh_config.texfmt[PTI_RGBX8]) { unsigned int pixels = diff --git a/engine/client/m_mp3.c b/engine/client/m_mp3.c index 4c368eccb..c0661b01b 100644 --- a/engine/client/m_mp3.c +++ b/engine/client/m_mp3.c @@ -697,7 +697,6 @@ void Media_LoadTrackNames (char *listname); void M_Media_Draw (menu_t *menu) { - mpic_t *p; mediatrack_t *track; int y; int op, i; @@ -2672,6 +2671,12 @@ int captureoldfbo; qboolean capturingfbo; texid_t capturetexture; qboolean captureframeforce; +#ifdef GLQUAKE +//ring buffer +int pbo_handles[4]; +enum uploadfmt pbo_format; +#endif +int pbo_oldest; qboolean capturepaused; extern cvar_t vid_conautoscale; @@ -2751,13 +2756,13 @@ static void *QDECL capture_raw_begin (char *streamname, int videorate, int width } return ctx; } -static void QDECL capture_raw_video (void *vctx, void *data, int frame, int width, int height) +static void QDECL capture_raw_video (void *vctx, void *data, int frame, int width, int height, enum uploadfmt fmt) { struct capture_raw_ctx *ctx = vctx; char filename[MAX_OSPATH]; ctx->frames = frame+1; Q_snprintfz(filename, sizeof(filename), "%s%8.8i.%s", ctx->videonameprefix, frame, ctx->videonameextension); - SCR_ScreenShot(filename, ctx->fsroot, data, width, height); + SCR_ScreenShot(filename, ctx->fsroot, data, width, height, fmt); } static void QDECL capture_raw_audio (void *vctx, void *data, int bytes) { @@ -2949,19 +2954,39 @@ static void *QDECL capture_avi_begin (char *streamname, int videorate, int width return ctx; } -static void QDECL capture_avi_video(void *vctx, void *vdata, int frame, int width, int height) +static void QDECL capture_avi_video(void *vctx, void *vdata, int frame, int width, int height, enum uploadfmt fmt) { struct capture_avi_ctx *ctx = vctx; qbyte *data = vdata; int c, i; qbyte temp; - // swap rgb to bgr - c = width*height*3; - for (i=0 ; icapture_video(currentcapture_ctx, buffer, captureframe, truewidth, trueheight); - capturelastvideotime += captureframeinterval; - captureframe++; - BZ_Free (buffer); + int imagesize = vid.fbpwidth * vid.fbpheight * 4; + while (pbo_oldest + countof(pbo_handles) <= captureframe) + { + qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbo_handles[pbo_oldest%countof(pbo_handles)]); + buffer = qglMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB); + if (buffer) + { + currentcapture_funcs->capture_video(currentcapture_ctx, buffer, pbo_oldest, vid.fbpwidth, vid.fbpheight, pbo_format); + qglUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); + } + pbo_oldest++; + } + + if (!pbo_handles[captureframe%countof(pbo_handles)]) + { + qglGenBuffersARB(1, &pbo_handles[captureframe%countof(pbo_handles)]); + qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbo_handles[captureframe%countof(pbo_handles)]); + qglBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, imagesize, NULL, GL_STATIC_READ_ARB); + } + qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbo_handles[captureframe%countof(pbo_handles)]); + switch(pbo_format) + { + case TF_BGR24: + qglReadPixels(0, 0, vid.fbpwidth, vid.fbpheight, GL_BGR_EXT, GL_UNSIGNED_BYTE, 0); + break; + case TF_BGRA32: + qglReadPixels(0, 0, vid.fbpwidth, vid.fbpheight, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, 0); + break; + case TF_RGB24: + qglReadPixels(0, 0, vid.fbpwidth, vid.fbpheight, GL_RGB, GL_UNSIGNED_BYTE, 0); + break; + case TF_RGBA32: + qglReadPixels(0, 0, vid.fbpwidth, vid.fbpheight, GL_RGBA, GL_UNSIGNED_BYTE, 0); + break; + } + qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); } else - Con_DPrintf("Unable to grab video image\n"); +#endif + { + pbo_oldest = captureframe+1; + //submit the current video frame. audio will be mixed to match. + buffer = VID_GetRGBInfo(&truewidth, &trueheight, &fmt); + if (buffer) + { + currentcapture_funcs->capture_video(currentcapture_ctx, buffer, captureframe, truewidth, trueheight, fmt); + BZ_Free (buffer); + } + else + { + Con_DPrintf("Unable to grab video image\n"); + currentcapture_funcs->capture_video(currentcapture_ctx, NULL, captureframe, 0, 0, TF_INVALID); + } + } + captureframe++; + capturelastvideotime += captureframeinterval; captureframeforce = false; @@ -3358,6 +3432,35 @@ void Media_InitFakeSoundDevice (int speed, int channels, int samplebits) void Media_StopRecordFilm_f (void) { +#ifdef GLQUAKE + if (pbo_format) + { + int i; + int imagesize = vid.fbpwidth * vid.fbpheight * 4; + while (pbo_oldest < captureframe) + { + qbyte *buffer; + qglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbo_handles[pbo_oldest%countof(pbo_handles)]); + buffer = qglMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB); + if (buffer) + { + currentcapture_funcs->capture_video(currentcapture_ctx, buffer, pbo_oldest, vid.fbpwidth, vid.fbpheight, TF_BGR24); +// currentcapture_funcs->capture_video(currentcapture_ctx, buffer, pbo_oldest, vid.fbpwidth, vid.fbpheight, TF_BGRA32); + qglUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); + } + pbo_oldest++; + } + + for (i = 0; i < countof(pbo_handles); i++) + { + if (pbo_handles[i]) + qglDeleteBuffersARB(1, &pbo_handles[i]); + pbo_handles[i] = 0; + } + } +#endif + + if (capture_fakesounddevice) S_ShutdownCard(capture_fakesounddevice); capture_fakesounddevice = NULL; @@ -3401,7 +3504,7 @@ static void Media_RecordFilm (char *recordingname, qboolean demo) Con_ClearNotify(); - captureframe = 0; + captureframe = pbo_oldest = 0; for (i = 0; i < sizeof(pluginencodersfunc)/sizeof(pluginencodersfunc[0]); i++) { if (pluginencodersfunc[i]) @@ -3438,11 +3541,17 @@ static void Media_RecordFilm (char *recordingname, qboolean demo) { capturingfbo = true; capturetexture = R2D_RT_Configure("$democapture", capturewidth.ival, captureheight.ival, TF_BGRA32); - captureoldfbo = GLBE_FBO_Update(&capturefbo, FBO_RB_DEPTH, &capturetexture, 1, r_nulltex, capturewidth.ival, captureheight.ival, 0); + captureoldfbo = GLBE_FBO_Update(&capturefbo, FBO_RB_DEPTH|(Sh_StencilShadowsActive()?FBO_RB_STENCIL:0), &capturetexture, 1, r_nulltex, capturewidth.ival, captureheight.ival, 0); vid.fbpwidth = capturewidth.ival; vid.fbpheight = captureheight.ival; vid.framebuffer = capturetexture; } + + pbo_format = TF_INVALID; + if (qrenderer == QR_OPENGL && !gl_config.gles && gl_config.glversion >= 2.1) + { //both tgas and vfw favour bgr24, so lets get the gl drivers to suffer instead of us. + pbo_format = TF_BGR24; + } #endif recordingdemo = demo; diff --git a/engine/client/merged.h b/engine/client/merged.h index 23bb35428..8a780724e 100644 --- a/engine/client/merged.h +++ b/engine/client/merged.h @@ -101,7 +101,7 @@ extern void (*R_RenderView) (void); // must set r_refdef first extern qboolean (*VID_Init) (rendererstate_t *info, unsigned char *palette); extern void (*VID_DeInit) (void); -extern char *(*VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevidheight); +extern char *(*VID_GetRGBInfo) (int *truevidwidth, int *truevidheight, enum uploadfmt *fmt); extern void (*VID_SetWindowCaption) (char *msg); extern void SCR_Init (void); @@ -413,7 +413,7 @@ typedef struct rendererinfo_s { void (*VID_DestroyCursor) (void *cursor); //may be null void (*VID_SetWindowCaption) (char *msg); - char *(*VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevidheight); + char *(*VID_GetRGBInfo) (int *truevidwidth, int *truevidheight, enum uploadfmt *fmt); void (*SCR_UpdateScreen) (void); diff --git a/engine/client/pr_menu.c b/engine/client/pr_menu.c index 17c6a444a..813a2b231 100644 --- a/engine/client/pr_menu.c +++ b/engine/client/pr_menu.c @@ -55,6 +55,9 @@ void QCBUILTIN PF_CL_drawfill (pubprogfuncs_t *prinst, struct globalvars_s *pr_g void QCBUILTIN PF_CL_drawsetcliparea (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { srect_t srect; + if (R2D_Flush) + R2D_Flush(); + csqc_dp_lastwas3d = false; srect.x = G_FLOAT(OFS_PARM0) / (float)vid.fbvwidth; @@ -71,6 +74,9 @@ void QCBUILTIN PF_CL_drawsetcliparea (pubprogfuncs_t *prinst, struct globalvars_ //void drawresetcliparea(void) = #459; void QCBUILTIN PF_CL_drawresetcliparea (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { + if (R2D_Flush) + R2D_Flush(); + csqc_dp_lastwas3d = false; BE_Scissor(NULL); diff --git a/engine/client/r_2d.c b/engine/client/r_2d.c index 6d2f03949..9c87ea815 100644 --- a/engine/client/r_2d.c +++ b/engine/client/r_2d.c @@ -31,6 +31,7 @@ shader_t *shader_polyblend; shader_t *shader_menutint; #define DRAW_QUADS 128 +static int draw_active_flags; static shader_t *draw_active_shader; static avec4_t draw_active_colour; static mesh_t draw_mesh; @@ -576,7 +577,7 @@ void R2D_ImageAtlas(float x, float y, float w, float h, float s1, float t1, floa void R2D_ImageFlush(void) { - BE_DrawMesh_Single(draw_active_shader, &draw_mesh, NULL, r2d_be_flags); + BE_DrawMesh_Single(draw_active_shader, &draw_mesh, NULL, draw_active_flags); R2D_Flush = NULL; draw_active_shader = NULL; @@ -597,12 +598,13 @@ void R2D_Image(float x, float y, float w, float h, float s1, float t1, float s2, return; } - if (draw_active_shader != pic || draw_mesh.numvertexes+4 > DRAW_QUADS) + if (draw_active_shader != pic || draw_active_flags != r2d_be_flags || draw_mesh.numvertexes+4 > DRAW_QUADS) { if (R2D_Flush) R2D_Flush(); draw_active_shader = pic; + draw_active_flags = r2d_be_flags; R2D_Flush = R2D_ImageFlush; draw_mesh.numindexes = 0; @@ -663,12 +665,13 @@ void R2D_FillBlock(float x, float y, float w, float h) pic = shader_draw_fill_trans; else pic = shader_draw_fill; - if (draw_active_shader != pic || draw_mesh.numvertexes+4 > DRAW_QUADS) + if (draw_active_shader != pic || draw_active_flags != r2d_be_flags || draw_mesh.numvertexes+4 > DRAW_QUADS) { if (R2D_Flush) R2D_Flush(); draw_active_shader = pic; + draw_active_flags = r2d_be_flags; R2D_Flush = R2D_ImageFlush; draw_mesh.numindexes = 0; diff --git a/engine/client/renderer.c b/engine/client/renderer.c index febcbb36c..f07bd3bb4 100644 --- a/engine/client/renderer.c +++ b/engine/client/renderer.c @@ -856,7 +856,7 @@ void (*R_RenderView) (void); // must set r_refdef first qboolean (*VID_Init) (rendererstate_t *info, unsigned char *palette); void (*VID_DeInit) (void); -char *(*VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevidheight); +char *(*VID_GetRGBInfo) (int *truevidwidth, int *truevidheight, enum uploadfmt *fmt); void (*VID_SetWindowCaption) (char *msg); void (*SCR_UpdateScreen) (void); diff --git a/engine/client/screen.h b/engine/client/screen.h index 3d67d5ec3..5c86808e3 100644 --- a/engine/client/screen.h +++ b/engine/client/screen.h @@ -80,7 +80,8 @@ void SCR_ShowPic_Remove_f(void); //a header is better than none... void Draw_TextBox (int x, int y, int width, int lines); enum fs_relative; -qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void *rgb_buffer, int width, int height); +enum uploadfmt; +qboolean SCR_ScreenShot (char *filename, enum fs_relative fsroot, void *rgb_buffer, int width, int height, enum uploadfmt fmt); void SCR_DrawTwoDimensional(int uimenu, qboolean nohud); diff --git a/engine/client/vid.h b/engine/client/vid.h index 039d58805..abea41160 100644 --- a/engine/client/vid.h +++ b/engine/client/vid.h @@ -110,6 +110,6 @@ int GLVID_SetMode (rendererstate_t *info, unsigned char *palette); qboolean GLVID_Is8bit(void); void GLVID_SwapBuffers(void); -char *GLVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight); +char *GLVID_GetRGBInfo(int *truewidth, int *trueheight, enum uploadfmt *fmt); void GLVID_SetCaption(char *caption); #endif diff --git a/engine/client/vid_headless.c b/engine/client/vid_headless.c index 5d1d3e3e1..f4c355724 100644 --- a/engine/client/vid_headless.c +++ b/engine/client/vid_headless.c @@ -163,8 +163,9 @@ static qboolean Headless_VID_ApplyGammaRamps (unsigned short *ramps) static void Headless_VID_SetWindowCaption (char *msg) { } -static char *Headless_VID_GetRGBInfo (int prepad, int *truevidwidth, int *truevidheight) +static char *Headless_VID_GetRGBInfo (int *truevidwidth, int *truevidheight, enum uploadfmt *fmt) { + *fmt = TF_INVALID; *truevidwidth = *truevidheight = 0; return NULL; } diff --git a/engine/d3d/vid_d3d.c b/engine/d3d/vid_d3d.c index 891536113..8b58ba3f2 100644 --- a/engine/d3d/vid_d3d.c +++ b/engine/d3d/vid_d3d.c @@ -802,7 +802,7 @@ qboolean D3D9_VID_ApplyGammaRamps (unsigned short *ramps) IDirect3DDevice9_SetGammaRamp(pD3DDev9, 0, D3DSGR_NO_CALIBRATION, (D3DGAMMARAMP *)ramps); return true; } -static char *(D3D9_VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevidheight) +static char *(D3D9_VID_GetRGBInfo) (int *truevidwidth, int *truevidheight, enum uploadfmt *fmt) { IDirect3DSurface9 *backbuf, *surf; D3DLOCKED_RECT rect; @@ -828,14 +828,16 @@ static char *(D3D9_VID_GetRGBInfo) (int prepad, int *truevidwidth, int *truevi if (!FAILED(IDirect3DDevice9_GetRenderTargetData(pD3DDev9, backbuf, surf))) if (!FAILED(IDirect3DSurface9_LockRect(surf, &rect, NULL, D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_READONLY|D3DLOCK_NOSYSLOCK))) { - ret = BZ_Malloc(prepad + desc.Width*desc.Height*3); + ret = BZ_Malloc(desc.Width*desc.Height*3); if (ret) { + *fmt = TF_RGB24; + // read surface rect and convert 32 bgra to 24 rgb and flip - c = prepad+desc.Width*desc.Height*3; + c = desc.Width*desc.Height*3; p = (qbyte *)rect.pBits; - for (i=c-(3*desc.Width); i>=prepad; i-=(3*desc.Width)) + for (i=c-(3*desc.Width); i>=0; i-=(3*desc.Width)) { for (j=0; j 0; ) { in = lock.pData; @@ -1150,6 +1149,7 @@ static char *D3D11_VID_GetRGBInfo(int prepad, int *truevidwidth, int *truevidhei ID3D11Texture2D_Release(texture); *truevidwidth = vid.pixelwidth; *truevidheight = vid.pixelheight; + *fmt = TF_RGB24; return r; } static void (D3D11_VID_SetWindowCaption) (char *msg) diff --git a/engine/gl/gl_font.c b/engine/gl/gl_font.c index 9a21fbdeb..ef0f346f8 100644 --- a/engine/gl/gl_font.c +++ b/engine/gl/gl_font.c @@ -28,6 +28,7 @@ int Font_LineBreaks(conchar_t *start, conchar_t *end, int maxpixelwidth, int max struct font_s *font_default; struct font_s *font_console; struct font_s *font_tiny; +static int font_be_flags; extern unsigned int r2d_be_flags; //by adding 'extern' to one definition of a function in a translation unit, then the definition in that TU is NOT considered an inline definition. meaning non-inlined references in other TUs can link to it instead of their own if needed. @@ -409,10 +410,10 @@ static void Font_Flush(void) font_backmesh.numvertexes = font_foremesh.numvertexes; font_backmesh.istrifan = font_foremesh.istrifan; - BE_DrawMesh_Single(fontplanes.backshader, &font_backmesh, NULL, r2d_be_flags); + BE_DrawMesh_Single(fontplanes.backshader, &font_backmesh, NULL, font_be_flags); } TEXASSIGN(fontplanes.shader->defaulttextures->base, font_texture); - BE_DrawMesh_Single(fontplanes.shader, &font_foremesh, NULL, r2d_be_flags); + BE_DrawMesh_Single(fontplanes.shader, &font_foremesh, NULL, font_be_flags); font_foremesh.numindexes = 0; font_foremesh.numvertexes = 0; } @@ -1523,10 +1524,10 @@ void Font_Free(struct font_s *f) //maps a given virtual screen coord to a pixel coord, which matches the font's height/width values void Font_BeginString(struct font_s *font, float vx, float vy, int *px, int *py) { - if (R2D_Flush && (R2D_Flush != Font_Flush || curfont != font)) + if (R2D_Flush && (R2D_Flush != Font_Flush || curfont != font || font_be_flags != r2d_be_flags)) R2D_Flush(); R2D_Flush = Font_Flush; - + font_be_flags = r2d_be_flags; curfont = font; *px = (vx*(int)vid.rotpixelwidth) / (float)vid.width; *py = (vy*(int)vid.rotpixelheight) / (float)vid.height; @@ -1544,10 +1545,10 @@ void Font_Transform(float vx, float vy, int *px, int *py) } void Font_BeginScaledString(struct font_s *font, float vx, float vy, float szx, float szy, float *px, float *py) { - if (R2D_Flush && (R2D_Flush != Font_Flush || curfont != font)) + if (R2D_Flush && (R2D_Flush != Font_Flush || curfont != font || font_be_flags != r2d_be_flags)) R2D_Flush(); R2D_Flush = Font_Flush; - + font_be_flags = r2d_be_flags; curfont = font; *px = (vx*(float)vid.rotpixelwidth) / (float)vid.width; *py = (vy*(float)vid.rotpixelheight) / (float)vid.height; diff --git a/engine/gl/gl_screen.c b/engine/gl/gl_screen.c index b67a554cf..dce08e0e5 100644 --- a/engine/gl/gl_screen.c +++ b/engine/gl/gl_screen.c @@ -243,7 +243,7 @@ void GLSCR_UpdateScreen (void) } -char *GLVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight) +char *GLVID_GetRGBInfo(int *truewidth, int *trueheight, enum uploadfmt *fmt) { //returns a BZ_Malloced array extern qboolean gammaworks; int i, c; @@ -259,14 +259,14 @@ char *GLVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight) p = BZ_Malloc(vid.pixelwidth*vid.pixelheight*sizeof(float)); qglReadPixels (0, 0, vid.pixelwidth, vid.pixelheight, GL_DEPTH_COMPONENT, GL_FLOAT, p); - ret = BZ_Malloc(prepadbytes + vid.pixelwidth*vid.pixelheight*3); + ret = BZ_Malloc(vid.pixelwidth*vid.pixelheight*3); c = vid.pixelwidth*vid.pixelheight; for (i = 1; i < c; i++) { - ret[prepadbytes+i*3+0]=p[i]*p[i]*p[i]*255; - ret[prepadbytes+i*3+1]=p[i]*p[i]*p[i]*255; - ret[prepadbytes+i*3+2]=p[i]*p[i]*p[i]*255; + ret[i*3+0]=p[i]*p[i]*p[i]*255; + ret[i*3+1]=p[i]*p[i]*p[i]*255; + ret[i*3+2]=p[i]*p[i]*p[i]*255; } BZ_Free(p); } @@ -274,30 +274,46 @@ char *GLVID_GetRGBInfo(int prepadbytes, int *truewidth, int *trueheight) { qbyte *p; - // gles only guarantees GL_RGBA/GL_UNSIGNED_BYTE so downconvert and resize - ret = BZ_Malloc(prepadbytes + (*truewidth)*(*trueheight)*4); - qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGBA, GL_UNSIGNED_BYTE, ret + prepadbytes); + //gles: + //Only two format/type parameter pairs are accepted. + //GL_RGBA/GL_UNSIGNED_BYTE is always accepted, and the other acceptable pair can be discovered by querying GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE. + //thus its simpler to only use GL_RGBA/GL_UNSIGNED_BYTE + //desktopgl: + //total line byte length must be aligned to GL_PACK_ALIGNMENT. by reading rgba instead of rgb, we can ensure the line is a multiple of 4 bytes. + ret = BZ_Malloc((*truewidth)*(*trueheight)*4); + qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGBA, GL_UNSIGNED_BYTE, ret); + + *fmt = TF_RGB24; c = (*truewidth)*(*trueheight); - p = ret + prepadbytes; + p = ret; for (i = 1; i < c; i++) { p[i*3+0]=p[i*4+0]; p[i*3+1]=p[i*4+1]; p[i*3+2]=p[i*4+2]; } - ret = BZ_Realloc(ret, prepadbytes + (*truewidth)*(*trueheight)*3); + ret = BZ_Realloc(ret, (*truewidth)*(*trueheight)*3); } +#ifdef _DEBUG + else if (!gl_config.gles && gl_config.glversion >= 1.2) + { + *fmt = TF_BGRA32; + ret = BZ_Malloc((*truewidth)*(*trueheight)*4); + qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, ret); + } +#endif else { - ret = BZ_Malloc(prepadbytes + (*truewidth)*(*trueheight)*3); - qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGB, GL_UNSIGNED_BYTE, ret + prepadbytes); + *fmt = TF_RGB24; + ret = BZ_Malloc((*truewidth)*(*trueheight)*3); + qglReadPixels (0, 0, (*truewidth), (*trueheight), GL_RGB, GL_UNSIGNED_BYTE, ret); } if (gammaworks) { - c = prepadbytes+(*truewidth)*(*trueheight)*3; - for (i=prepadbytes ; ivideo_outbuf); } -static void AVEnc_Video (void *vctx, void *data, int frame, int width, int height) +static void AVEnc_Video (void *vctx, void *data, int frame, int width, int height, enum uploadfmt qpfmt) { struct encctx *ctx = vctx; - //weird maths to flip it. - const uint8_t *srcslices[2] = {(uint8_t*)data + (height-1)*width*3, NULL}; - int srcstride[2] = {-width*3, 0}; + const uint8_t *srcslices[2]; + int srcstride[2]; int success; AVPacket pkt; + int avpfmt; + int inbpp; if (!ctx->video_st) return; + switch(qpfmt) + { + case TF_BGRA32: avpfmt = AV_PIX_FMT_BGRA; inbpp = 4; break; + case TF_RGBA32: avpfmt = AV_PIX_FMT_RGBA; inbpp = 4; break; + case TF_BGR24: avpfmt = AV_PIX_FMT_BGR24; inbpp = 3; break; + case TF_RGB24: avpfmt = AV_PIX_FMT_RGB24; inbpp = 3; break; + default: + return; + } + + //weird maths to flip it. + srcslices[0] = (uint8_t*)data + (height-1)*width*inbpp; + srcstride[0] = -width*inbpp; + srcslices[1] = NULL; + srcstride[1] = 0; + //convert RGB to whatever the codec needs (ie: yuv...). - ctx->scale_ctx = sws_getCachedContext(ctx->scale_ctx, width, height, AV_PIX_FMT_RGB24, ctx->picture->width, ctx->picture->height, ctx->video_st->codec->pix_fmt, SWS_POINT, 0, 0, 0); + //also rescales, but only if the user resizes the video while recording. which is a stupid thing to do. + ctx->scale_ctx = sws_getCachedContext(ctx->scale_ctx, width, height, qpfmt, ctx->picture->width, ctx->picture->height, ctx->video_st->codec->pix_fmt, SWS_POINT, 0, 0, 0); sws_scale(ctx->scale_ctx, srcslices, srcstride, 0, height, ctx->picture->data, ctx->picture->linesize); av_init_packet(&pkt);