diff --git a/src/command.c b/src/command.c index dbdaceab5..cb6803b57 100644 --- a/src/command.c +++ b/src/command.c @@ -823,8 +823,13 @@ static void COM_Help_f(void) if (!stricmp(cvar->PossibleValue[MINVAL].strvalue, "MIN")) { if (floatmode) - CONS_Printf(" range from %f to %f\n", FIXED_TO_FLOAT(cvar->PossibleValue[MINVAL].value), - FIXED_TO_FLOAT(cvar->PossibleValue[MAXVAL].value)); + { + float fu = FIXED_TO_FLOAT(cvar->PossibleValue[MINVAL].value); + float ck = FIXED_TO_FLOAT(cvar->PossibleValue[MAXVAL].value); + CONS_Printf(" range from %ld%s to %ld%s\n", + (long)fu, M_Ftrim(fu), + (long)ck, M_Ftrim(ck)); + } else CONS_Printf(" range from %d to %d\n", cvar->PossibleValue[MINVAL].value, cvar->PossibleValue[MAXVAL].value); @@ -973,7 +978,10 @@ static void COM_Add_f(void) } if (( cvar->flags & CV_FLOAT )) - CV_Set(cvar, va("%f", FIXED_TO_FLOAT (cvar->value) + atof(COM_Argv(2)))); + { + float n =FIXED_TO_FLOAT (cvar->value) + atof(COM_Argv(2)); + CV_Set(cvar, va("%ld%s", (long)n, M_Ftrim(n))); + } else CV_AddValue(cvar, atoi(COM_Argv(2))); } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 3204d3227..bac297f8e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -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); diff --git a/src/dehacked.c b/src/dehacked.c index 6093d6fd6..4d1147276 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -585,21 +585,30 @@ static void readfreeslots(MYFILE *f) continue; // Copy in the spr2 name and increment free_spr2. if (free_spr2 < NUMPLAYERSPRITES) { - CONS_Printf("Sprite SPR2_%s allocated.\n",word); strncpy(spr2names[free_spr2],word,4); spr2defaults[free_spr2] = 0; spr2names[free_spr2++][4] = 0; } else - CONS_Alert(CONS_WARNING, "Ran out of free SPR2 slots!\n"); + deh_warning("Ran out of free SPR2 slots!\n"); } else if (fastcmp(type, "TOL")) { - if (lastcustomtol > 31) - CONS_Alert(CONS_WARNING, "Ran out of free typeoflevel slots!\n"); + // Search if we already have a typeoflevel by that name... + for (i = 0; TYPEOFLEVEL[i].name; i++) + if (fastcmp(word, TYPEOFLEVEL[i].name)) + break; + + // We found it? Then don't allocate another one. + if (TYPEOFLEVEL[i].name) + continue; + + // We don't, so freeslot it. + if (lastcustomtol == (UINT32)MAXTOL) // Unless you have way too many, since they're flags. + deh_warning("Ran out of free typeoflevel slots!\n"); else { - G_AddTOL((1< 31) - CONS_Alert(CONS_WARNING, "Ran out of free typeoflevel slots!\n"); - else - { - UINT32 newtol = (1< prefixlen)) { - CONS_Printf("Model for sprite PLAY detected in models.dat, use a player skin instead!\n"); - continue; + skinname += prefixlen; + goto addskinmodel; } - for (i = 0; i < NUMSPRITES; i++) + // add sprite model + if (len == 4) // must be 4 characters long exactly. otherwise it's not a sprite name. { - if (stricmp(name, sprnames[i]) == 0) + for (i = 0; i < NUMSPRITES; i++) { - //if (stricmp(name, "PLAY") == 0) - //continue; - - //CONS_Debug(DBG_RENDER, " Found: %s %s %f %f\n", name, filename, scale, offset); - md2_models[i].scale = scale; - md2_models[i].offset = offset; - md2_models[i].notfound = false; - strcpy(md2_models[i].filename, filename); - goto md2found; + if (stricmp(name, sprnames[i]) == 0) + { + md2_models[i].scale = scale; + md2_models[i].offset = offset; + md2_models[i].notfound = false; + strcpy(md2_models[i].filename, filename); + goto modelfound; + } } } +addskinmodel: + // add player model for (s = 0; s < MAXSKINS; s++) { - if (stricmp(name, skins[s].name) == 0) + if (stricmp(skinname, skins[s].name) == 0) { - //CONS_Printf(" Found: %s %s %f %f\n", name, filename, scale, offset); md2_playermodels[s].skin = s; md2_playermodels[s].scale = scale; md2_playermodels[s].offset = offset; md2_playermodels[s].notfound = false; strcpy(md2_playermodels[s].filename, filename); - goto md2found; + goto modelfound; } } - // no sprite/player skin name found?!? - //CONS_Printf("Unknown sprite/player skin %s detected in models.dat\n", name); -md2found: + +modelfound: // move on to next line... continue; } @@ -558,8 +567,9 @@ md2found: void HWR_AddPlayerModel(int skin) // For skins that were added after startup { FILE *f; - char name[18], filename[32]; + char name[24], filename[32]; float scale, offset; + size_t prefixlen; if (nomd2s) return; @@ -577,32 +587,42 @@ void HWR_AddPlayerModel(int skin) // For skins that were added after startup return; } - // Check for any model that match the names of player skins! - while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4) + // length of the player model prefix + prefixlen = strlen(PLAYERMODELPREFIX); + + // Check for any models that match the names of player skins! + while (fscanf(f, "%25s %31s %f %f", name, filename, &scale, &offset) == 4) { - if (stricmp(name, skins[skin].name) == 0) + char *skinname = name; + size_t len = strlen(name); + + // ignore the player model prefix. + if (!strnicmp(name, PLAYERMODELPREFIX, prefixlen) && (len > prefixlen)) + skinname += prefixlen; + + if (stricmp(skinname, skins[skin].name) == 0) { md2_playermodels[skin].skin = skin; md2_playermodels[skin].scale = scale; md2_playermodels[skin].offset = offset; md2_playermodels[skin].notfound = false; strcpy(md2_playermodels[skin].filename, filename); - goto playermd2found; + goto playermodelfound; } } - //CONS_Printf("Model for player skin %s not found\n", skins[skin].name); md2_playermodels[skin].notfound = true; -playermd2found: +playermodelfound: fclose(f); } void HWR_AddSpriteModel(size_t spritenum) // For sprites that were added after startup { FILE *f; - // name[18] is used to check for names in the models.dat file that match with sprites or player skins + // name[24] is used to check for names in the models.dat file that match with sprites or player skins // sprite names are always 4 characters long, and names is for player skins can be up to 19 characters long - char name[18], filename[32]; + // PLAYERMODELPREFIX is 6 characters long + char name[24], filename[32]; float scale, offset; if (nomd2s) @@ -622,22 +642,30 @@ void HWR_AddSpriteModel(size_t spritenum) // For sprites that were added after s return; } - // Check for any MD2s that match the names of sprite names! - while (fscanf(f, "%19s %31s %f %f", name, filename, &scale, &offset) == 4) + // Check for any models that match the names of sprite names! + while (fscanf(f, "%25s %31s %f %f", name, filename, &scale, &offset) == 4) { + // length of the sprite name + size_t len = strlen(name); + if (len != 4) // must be 4 characters long exactly. otherwise it's not a sprite name. + continue; + + // check for the player model prefix. + if (!strnicmp(name, PLAYERMODELPREFIX, strlen(PLAYERMODELPREFIX))) + continue; // that's not a sprite... + if (stricmp(name, sprnames[spritenum]) == 0) { md2_models[spritenum].scale = scale; md2_models[spritenum].offset = offset; md2_models[spritenum].notfound = false; strcpy(md2_models[spritenum].filename, filename); - goto spritemd2found; + goto spritemodelfound; } } - //CONS_Printf("MD2 for sprite %s not found\n", sprnames[spritenum]); md2_models[spritenum].notfound = true; -spritemd2found: +spritemodelfound: fclose(f); } diff --git a/src/hardware/hw_md2.h b/src/hardware/hw_md2.h index 6f5985a44..3bbe30053 100644 --- a/src/hardware/hw_md2.h +++ b/src/hardware/hw_md2.h @@ -49,4 +49,6 @@ void HWR_AddPlayerModel(INT32 skin); void HWR_AddSpriteModel(size_t spritenum); boolean HWR_DrawModel(gr_vissprite_t *spr); +#define PLAYERMODELPREFIX "PLAYER" + #endif // _HW_MD2_H_ diff --git a/src/m_anigif.c b/src/m_anigif.c index f062bc826..faa8f29e1 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -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; diff --git a/src/m_anigif.h b/src/m_anigif.h index 9bdf2cc7f..9eb6faa75 100644 --- a/src/m_anigif.h +++ b/src/m_anigif.h @@ -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 diff --git a/src/m_argv.c b/src/m_argv.c index 935f4b9e3..129706127 100644 --- a/src/m_argv.c +++ b/src/m_argv.c @@ -92,36 +92,21 @@ const char *M_GetNextParm(void) void M_PushSpecialParameters(void) { INT32 i; - char s[256]; - boolean onetime = false; - for (i = 1; i < myargc; i++) { if (myargv[i][0] == '+') { - strcpy(s, &myargv[i][1]); + COM_BufAddText(&myargv[i][1]); i++; // get the parameters of the command too for (; i < myargc && myargv[i][0] != '+' && myargv[i][0] != '-'; i++) { - strcat(s, " "); - if (!onetime) - { - strcat(s, "\""); - onetime = true; - } - strcat(s, myargv[i]); + COM_BufAddText(va(" \"%s\"", myargv[i])); } - if (onetime) - { - strcat(s, "\""); - onetime = false; - } - strcat(s, "\n"); // push it - COM_BufAddText(s); + COM_BufAddText("\n"); i--; } } diff --git a/src/m_menu.c b/src/m_menu.c index cd8a9e3b2..0d81baa46 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -325,6 +325,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); @@ -366,7 +367,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); @@ -1517,6 +1517,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}, @@ -1527,13 +1528,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[] = @@ -3031,7 +3033,8 @@ static void M_ChangeCvar(INT32 choice) || !(currentMenu->menuitems[itemOn].status & IT_CV_INTEGERSTEP)) { char s[20]; - sprintf(s,"%f",FIXED_TO_FLOAT(cv->value)+(choice)*(1.0f/16.0f)); + float n = FIXED_TO_FLOAT(cv->value)+(choice)*(1.0f/16.0f); + sprintf(s,"%ld%s",(long)n,M_Ftrim(n)); CV_Set(cv,s); } else @@ -3788,6 +3791,9 @@ void M_Ticker(void) if (--vidm_testingmode == 0) setmodeneeded = vidm_previousmode + 1; } + + if (currentMenu == &OP_ScreenshotOptionsDef) + M_SetupScreenshotMenu(); } // @@ -11422,9 +11428,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 // ============= @@ -12367,6 +12391,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 } // =============== diff --git a/src/m_misc.c b/src/m_misc.c index 3026f6654..3dfeef81e 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -2612,3 +2612,20 @@ int M_JumpWordReverse(const char *line, int offset) offset--; return offset; } + +const char * M_Ftrim (double f) +{ + static char dig[9];/* "0." + 6 digits (6 is printf's default) */ + int i; + /* I know I said it's the default, but just in case... */ + sprintf(dig, "%.6g", modf(f, &f)); + if (dig[0]) + { + for (i = strlen(dig); dig[i] == '0'; --i) + ; + dig[i + 1] = '\0'; + return &dig[1];/* skip the 0 */ + } + else + return ""; +} diff --git a/src/m_misc.h b/src/m_misc.h index 3fb9f031a..ad12517c1 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -109,6 +109,12 @@ int M_JumpWord (const char *s); /* E.g. cursor = M_JumpWordReverse(line, cursor); */ int M_JumpWordReverse (const char *line, int offset); +/* +Return dot and then the fractional part of a float, without +trailing zeros, or "" if the fractional part is zero. +*/ +const char * M_Ftrim (double); + // counting bits, for weapon ammo code, usually FUNCMATH UINT8 M_CountBits(UINT32 num, UINT8 size);