Merge branch 'local-color-table' into 'master'

Local Color Table for GIF movie mode

See merge request STJr/SRB2!742
This commit is contained in:
James R 2020-02-16 23:58:11 -05:00
commit 132e8f82d5
4 changed files with 112 additions and 30 deletions

View file

@ -677,6 +677,7 @@ void D_RegisterClientCommands(void)
// GIF variables
CV_RegisterVar(&cv_gif_optimize);
CV_RegisterVar(&cv_gif_downscale);
CV_RegisterVar(&cv_gif_localcolortable);
#ifdef WALLSPLATS
CV_RegisterVar(&cv_splats);

View file

@ -19,6 +19,7 @@
#include "v_video.h"
#include "i_video.h"
#include "m_misc.h"
#include "st_stuff.h" // st_palette
#ifdef HWRENDER
#include "hardware/hw_main.h"
@ -29,11 +30,17 @@
consvar_t cv_gif_optimize = {"gif_optimize", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_gif_downscale = {"gif_downscale", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_gif_localcolortable = {"gif_localcolortable", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
#ifdef HAVE_ANIGIF
static boolean gif_optimize = false; // So nobody can do something dumb
static boolean gif_downscale = false; // like changing cvars mid output
static RGBA_t *gif_palette = NULL;
// Palette handling
static boolean gif_localcolortable = false;
static boolean gif_colorprofile = false;
static RGBA_t *gif_headerpalette = NULL;
static RGBA_t *gif_framepalette = NULL;
static FILE *gif_out = NULL;
static INT32 gif_frames = 0;
@ -393,16 +400,47 @@ const UINT8 gifhead_nsid[19] = {0x21,0xFF,0x0B, // extension block + size
0x4E,0x45,0x54,0x53,0x43,0x41,0x50,0x45,0x32,0x2E,0x30, // NETSCAPE2.0
0x03,0x01,0xFF,0xFF,0x00}; // sub-block, repetitions
//
// GIF_getpalette
// determine the palette for the current frame.
//
static RGBA_t *GIF_getpalette(size_t palnum)
{
// In hardware mode, always returns the local palette
#ifdef HWRENDER
if (rendermode == render_opengl)
return pLocalPalette;
else
#endif
return (gif_colorprofile ? &pLocalPalette[palnum*256] : &pMasterPalette[palnum*256]);
}
//
// GIF_palwrite
// writes the gif palette.
// used both for the header and local color tables.
//
static UINT8 *GIF_palwrite(UINT8 *p, RGBA_t *pal)
{
INT32 i;
for (i = 0; i < 256; i++)
{
WRITEUINT8(p, pal[i].s.red);
WRITEUINT8(p, pal[i].s.green);
WRITEUINT8(p, pal[i].s.blue);
}
return p;
}
//
// GIF_headwrite
// writes the gif header to the currently open output file.
// NOTE that this code does not accomodate for palette changes.
//
static void GIF_headwrite(void)
{
UINT8 *gifhead = Z_Malloc(800, PU_STATIC, NULL);
UINT8 *p = gifhead;
INT32 i;
UINT16 rwidth, rheight;
if (!gif_out)
@ -423,24 +461,17 @@ static void GIF_headwrite(void)
rwidth = vid.width;
rheight = vid.height;
}
WRITEUINT16(p, rwidth);
WRITEUINT16(p, rheight);
// colors, aspect, etc
WRITEUINT8(p, 0xF7);
WRITEUINT8(p, 0xF7); // (0xF7 = 1111 0111)
WRITEUINT8(p, 0x00);
WRITEUINT8(p, 0x00);
// write color table
{
RGBA_t *pal = gif_palette;
for (i = 0; i < 256; i++)
{
WRITEUINT8(p, pal[i].s.red);
WRITEUINT8(p, pal[i].s.green);
WRITEUINT8(p, pal[i].s.blue);
}
}
p = GIF_palwrite(p, gif_headerpalette);
// write extension block
WRITEMEM(p, gifhead_nsid, sizeof(gifhead_nsid));
@ -468,7 +499,7 @@ static void hwrconvert(void)
INT32 x, y;
size_t i = 0;
InitColorLUT(gif_palette);
InitColorLUT(gif_framepalette);
for (y = 0; y < vid.height; y++)
{
@ -494,6 +525,7 @@ static void GIF_framewrite(void)
UINT8 *p;
UINT8 *movie_screen = screens[2];
INT32 blitx, blity, blitw, blith;
boolean palchanged;
if (!gifframe_data)
gifframe_data = Z_Malloc(gifframe_size, PU_STATIC, NULL);
@ -502,8 +534,18 @@ static void GIF_framewrite(void)
if (!gif_out)
return;
// Lactozilla: Compare the header's palette with the current frame's palette and see if it changed.
if (gif_localcolortable)
{
gif_framepalette = GIF_getpalette(max(st_palette, 0));
palchanged = memcmp(gif_headerpalette, gif_framepalette, sizeof(RGBA_t) * 256);
}
else
palchanged = false;
// Compare image data (for optimizing GIF)
if (gif_optimize && gif_frames > 0)
// If the palette has changed, the entire frame is considered to be different.
if (gif_optimize && gif_frames > 0 && (!palchanged))
{
// before blit movie_screen points to last frame, cur_screen points to this frame
UINT8 *cur_screen = screens[0];
@ -566,7 +608,20 @@ static void GIF_framewrite(void)
WRITEUINT16(p, (UINT16)(blity / scrbuf_downscaleamt));
WRITEUINT16(p, (UINT16)(blitw / scrbuf_downscaleamt));
WRITEUINT16(p, (UINT16)(blith / scrbuf_downscaleamt));
WRITEUINT8(p, 0); // no local table of colors
if (!gif_localcolortable)
WRITEUINT8(p, 0); // no local table of colors
else
{
if (palchanged)
{
// The palettes are different, so write the Local Color Table!
WRITEUINT8(p, 0x87); // (0x87 = 1000 0111)
p = GIF_palwrite(p, gif_framepalette);
}
else
WRITEUINT8(p, 0); // They are equal, no Local Color Table needed.
}
scrbuf_pos = movie_screen + blitx + (blity * vid.width);
scrbuf_writeend = scrbuf_pos + (blitw - 1) + ((blith - 1) * vid.width);
@ -630,15 +685,9 @@ INT32 GIF_open(const char *filename)
gif_optimize = (!!cv_gif_optimize.value);
gif_downscale = (!!cv_gif_downscale.value);
// GIF color table
// In hardware mode, forces the local palette
#ifdef HWRENDER
if (rendermode == render_opengl)
gif_palette = pLocalPalette;
else
#endif
gif_palette = ((cv_screenshot_colorprofile.value) ? pLocalPalette : pMasterPalette);
gif_localcolortable = (!!cv_gif_localcolortable.value);
gif_colorprofile = (!!cv_screenshot_colorprofile.value);
gif_headerpalette = GIF_getpalette(0);
GIF_headwrite();
gif_frames = 0;

View file

@ -27,6 +27,6 @@ void GIF_frame(void);
INT32 GIF_close(void);
#endif
extern consvar_t cv_gif_optimize, cv_gif_downscale;
extern consvar_t cv_gif_optimize, cv_gif_downscale, cv_gif_localcolortable;
#endif

View file

@ -323,6 +323,7 @@ menu_t OP_DataOptionsDef, OP_ScreenshotOptionsDef, OP_EraseDataDef;
menu_t OP_ServerOptionsDef;
menu_t OP_MonitorToggleDef;
static void M_ScreenshotOptions(INT32 choice);
static void M_SetupScreenshotMenu(void);
static void M_EraseData(INT32 choice);
static void M_Addons(INT32 choice);
@ -364,7 +365,6 @@ static void M_DrawMonitorToggles(void);
static void M_OGL_DrawFogMenu(void);
#endif
#ifndef NONET
static void M_DrawScreenshotMenu(void);
static void M_DrawConnectMenu(void);
static void M_DrawMPMainMenu(void);
static void M_DrawRoomMenu(void);
@ -1514,6 +1514,7 @@ static menuitem_t OP_ScreenshotOptionsMenu[] =
{IT_STRING|IT_CVAR, NULL, "Region Optimizing", &cv_gif_optimize, 95},
{IT_STRING|IT_CVAR, NULL, "Downscaling", &cv_gif_downscale, 100},
{IT_STRING|IT_CVAR, NULL, "Local Color Table", &cv_gif_localcolortable, 105},
{IT_STRING|IT_CVAR, NULL, "Memory Level", &cv_zlib_memorya, 95},
{IT_STRING|IT_CVAR, NULL, "Compression Level", &cv_zlib_levela, 100},
@ -1524,13 +1525,14 @@ static menuitem_t OP_ScreenshotOptionsMenu[] =
enum
{
op_screenshot_colorprofile = 1,
op_screenshot_storagelocation = 3,
op_screenshot_folder = 4,
op_movie_folder = 11,
op_screenshot_capture = 12,
op_screenshot_gif_start = 13,
op_screenshot_gif_end = 14,
op_screenshot_apng_start = 15,
op_screenshot_apng_end = 18,
op_screenshot_gif_end = 15,
op_screenshot_apng_start = 16,
op_screenshot_apng_end = 19,
};
static menuitem_t OP_EraseDataMenu[] =
@ -3785,6 +3787,9 @@ void M_Ticker(void)
if (--vidm_testingmode == 0)
setmodeneeded = vidm_previousmode + 1;
}
if (currentMenu == &OP_ScreenshotOptionsDef)
M_SetupScreenshotMenu();
}
//
@ -11349,9 +11354,27 @@ static void M_ScreenshotOptions(INT32 choice)
Screenshot_option_Onchange();
Moviemode_mode_Onchange();
M_SetupScreenshotMenu();
M_SetupNextMenu(&OP_ScreenshotOptionsDef);
}
static void M_SetupScreenshotMenu(void)
{
menuitem_t *item = &OP_ScreenshotOptionsMenu[op_screenshot_colorprofile];
#ifdef HWRENDER
// Hide some options based on render mode
if (rendermode == render_opengl)
{
item->status = IT_GRAYEDOUT;
if ((currentMenu == &OP_ScreenshotOptionsDef) && (itemOn == op_screenshot_colorprofile)) // Can't select that
itemOn = op_screenshot_storagelocation;
}
else
#endif
item->status = (IT_STRING | IT_CVAR);
}
// =============
// JOYSTICK MENU
// =============
@ -12294,6 +12317,15 @@ static void M_HandleVideoMode(INT32 ch)
static void M_DrawScreenshotMenu(void)
{
M_DrawGenericScrollMenu();
#ifdef HWRENDER
if ((rendermode == render_opengl) && (itemOn < 7)) // where it starts to go offscreen; change this number if you change the layout of the screenshot menu
{
INT32 y = currentMenu->y+currentMenu->menuitems[op_screenshot_colorprofile].alphaKey*2;
if (itemOn == 6)
y -= 10;
V_DrawRightAlignedString(BASEVIDWIDTH - currentMenu->x, y, V_REDMAP, "Yes");
}
#endif
}
// ===============