diff --git a/src/d_clisrv.c b/src/d_clisrv.c index f53d1f35a..f251d0c9b 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2022,7 +2022,7 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic } I_UpdateNoVsync(); // page flip or blit buffer if (moviemode) - M_SaveFrame(); + M_LegacySaveFrame(); S_UpdateSounds(); S_UpdateClosedCaptions(); } diff --git a/src/d_main.c b/src/d_main.c index b2e94818a..5b21248c0 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -873,7 +873,7 @@ void D_SRB2Loop(void) // Only take screenshots after drawing. if (moviemode) - M_SaveFrame(); + M_LegacySaveFrame(); #ifdef HWRENDER if (rendermode == render_opengl && takescreenshot) M_DoLegacyGLScreenShot(); diff --git a/src/f_finale.c b/src/f_finale.c index af0ab00dc..b78bc4139 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -438,7 +438,7 @@ void F_IntroTicker(void) I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001 if (moviemode) // make sure we save frames for the white hold too - M_SaveFrame(); + M_LegacySaveFrame(); } } diff --git a/src/f_wipe.c b/src/f_wipe.c index 5221080a3..1beb29506 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -526,7 +526,7 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu, const char *colormap, boolean r } if (moviemode) - M_SaveFrame(); + M_LegacySaveFrame(); NetKeepAlive(); // Update the network so we don't cause timeouts } diff --git a/src/g_game.c b/src/g_game.c index 706c9fdb5..ab9783b93 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1602,7 +1602,7 @@ void G_PreLevelTitleCard(void) NetKeepAlive(); // Prevent timeouts if (moviemode) - M_SaveFrame(); + M_LegacySaveFrame(); while (!((nowtime = I_GetTime()) - lasttime)) { diff --git a/src/hwr2/pass_screenshot.cpp b/src/hwr2/pass_screenshot.cpp index bd9a69bf6..b37409218 100644 --- a/src/hwr2/pass_screenshot.cpp +++ b/src/hwr2/pass_screenshot.cpp @@ -34,7 +34,7 @@ void ScreenshotPass::prepass(Rhi& rhi) ); } - doing_screenshot_ = takescreenshot; + doing_screenshot_ = takescreenshot || moviemode == MM_GIF; } void ScreenshotPass::transfer(Rhi& rhi, Handle ctx) @@ -63,6 +63,15 @@ void ScreenshotPass::postpass(Rhi& rhi) return; } - M_DoScreenShot(width_, height_, tcb::as_bytes(tcb::span(pixel_data_))); + if (takescreenshot) + { + M_DoScreenShot(width_, height_, tcb::as_bytes(tcb::span(pixel_data_))); + } + + if (moviemode == MM_GIF) + { + M_SaveFrame(width_, height_, tcb::as_bytes(tcb::span(pixel_data_))); + } + doing_screenshot_ = false; } diff --git a/src/m_anigif.c b/src/m_anigif.c index a6c830fa3..0bd14f422 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -508,7 +508,7 @@ static size_t gifframe_size = 8192; #ifdef HWRENDER static colorlookup_t gif_colorlookup; -static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr) +static void GIF_rgbconvert(const UINT8 *linear, UINT8 *scr) { UINT8 r, g, b; size_t src = 0, dest = 0; @@ -532,13 +532,18 @@ static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr) // GIF_framewrite // writes a frame into the file. // -static void GIF_framewrite(void) +static void GIF_framewrite(INT32 input_width, INT32 input_height, const UINT8 *input) { UINT8 *p; UINT8 *movie_screen = screens[2]; INT32 blitx, blity, blitw, blith; boolean palchanged; + (void)input_width; + (void)input_height; + + I_Assert(input_width == vid.width && input_height == vid.height); + if (!gifframe_data) gifframe_data = Z_Malloc(gifframe_size, PU_STATIC, NULL); p = gifframe_data; @@ -565,7 +570,10 @@ static void GIF_framewrite(void) // blit to temp screen if (rendermode == render_soft) - I_ReadScreen(movie_screen); + { + I_Assert(input != NULL); + GIF_rgbconvert(input, movie_screen); + } #ifdef HWRENDER else if (rendermode == render_opengl) { @@ -594,7 +602,10 @@ static void GIF_framewrite(void) // Copy the first frame into the movie screen // OpenGL already does the same above. if (gif_frames == 0 && rendermode == render_soft) - I_ReadScreen(movie_screen); + { + I_Assert(input != NULL); + GIF_rgbconvert(input, screens[0]); + } movie_screen = screens[0]; } @@ -751,7 +762,16 @@ INT32 GIF_open(const char *filename) void GIF_frame(void) { // there's not much actually needed here, is there. - GIF_framewrite(); + GIF_framewrite(vid.width, vid.height, NULL); +} + +// +// GIF_frame_rgb24 +// writes a frame into the output gif, with existing image data +// +void GIF_frame_rgb24(INT32 width, INT32 height, const UINT8 *buffer) +{ + GIF_framewrite(width, height, buffer); } // diff --git a/src/m_anigif.h b/src/m_anigif.h index 9ee209aea..34f149a88 100644 --- a/src/m_anigif.h +++ b/src/m_anigif.h @@ -28,6 +28,7 @@ extern "C" { #ifdef HAVE_ANIGIF INT32 GIF_open(const char *filename); void GIF_frame(void); +void GIF_frame_rgb24(INT32 width, INT32 height, const UINT8 *buffer); INT32 GIF_close(void); #endif diff --git a/src/m_misc.cpp b/src/m_misc.cpp index 491be3b30..9862fcf3f 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -1384,9 +1384,18 @@ void M_StartMovie(void) #endif } -void M_SaveFrame(void) +void M_LegacySaveFrame(void) { #if NUMSCREENS > 2 + // TODO: until HWR2 replaces legacy OpenGL renderer, this + // function still needs to called for OpenGL. +#ifdef HWRENDER + if (rendermode != render_opengl) +#endif + { + return; + } + // paranoia: should be unnecessary without singletics static tic_t oldtic = 0; @@ -1463,6 +1472,26 @@ void M_SaveFrame(void) #endif } +void M_SaveFrame(uint32_t width, uint32_t height, tcb::span data) +{ + if (moviemode != MM_GIF) + { + return; + } + + static tic_t oldtic = 0; + + // limit the recording to TICRATE + if (oldtic == I_GetTime()) + { + return; + } + + oldtic = I_GetTime(); + + GIF_frame_rgb24(width, height, reinterpret_cast(data.data())); +} + void M_StopMovie(void) { #if NUMSCREENS > 2 diff --git a/src/m_misc.h b/src/m_misc.h index 2610d2f01..8012c442d 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -28,6 +28,7 @@ #include void M_DoScreenShot(uint32_t width, uint32_t height, tcb::span data); +void M_SaveFrame(uint32_t width, uint32_t height, tcb::span data); extern "C" { #endif @@ -48,7 +49,7 @@ extern consvar_t cv_zlib_memorya, cv_zlib_levela, cv_zlib_strategya, cv_zlib_win extern consvar_t cv_apng_delay, cv_apng_downscale; void M_StartMovie(void); -void M_SaveFrame(void); +void M_LegacySaveFrame(void); void M_StopMovie(void); // the file where game vars and settings are saved diff --git a/src/p_setup.c b/src/p_setup.c index 20451daba..a5140cbb2 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7571,7 +7571,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) } \ lastwipetic = nowtime; \ if (moviemode) \ - M_SaveFrame(); \ + M_LegacySaveFrame(); \ NetKeepAlive(); \ } \