diff --git a/src/doom/am_map.c b/src/doom/am_map.c index 67b8d8f218..35c9601848 100644 --- a/src/doom/am_map.c +++ b/src/doom/am_map.c @@ -1309,7 +1309,7 @@ AM_drawFline_Vanilla #ifndef CRISPY_TRUECOLOR #define PUTDOT(xx,yy,cc) PUTDOT_RAW(xx,yy,cc) #else -#define PUTDOT(xx,yy,cc) PUTDOT_RAW(xx,yy,(colormaps[(cc)])) +#define PUTDOT(xx,yy,cc) PUTDOT_RAW(xx,yy,(pal_color[(cc)])) #endif dx = fl->b.x - fl->a.x; @@ -2104,7 +2104,7 @@ static void AM_drawCrosshair(int color, boolean force) #ifndef CRISPY_TRUECOLOR fb[(f_w*(f_h+1))/2] = color; // single point for now #else - fb[(f_w*(f_h+1))/2] = colormaps[color]; // single point for now + fb[(f_w*(f_h+1))/2] = pal_color[color]; // single point for now #endif */ diff --git a/src/doom/d_pwad.c b/src/doom/d_pwad.c index c886f939bf..537d1c50aa 100644 --- a/src/doom/d_pwad.c +++ b/src/doom/d_pwad.c @@ -46,10 +46,7 @@ static boolean LoadSigilWad (const char *iwaddir, boolean pwadtexture) "SIGIL.wad" }; - static const struct { - const char *name; - const char new_name[8]; - } sigil_lumps [] = { + static const lump_rename_t sigil_lumps [] = { {"CREDIT", "SIGCREDI"}, {"HELP1", "SIGHELP1"}, {"TITLEPIC", "SIGTITLE"}, @@ -164,7 +161,7 @@ static boolean LoadSigilWad (const char *iwaddir, boolean pwadtexture) { if ((autoload_dir = M_GetAutoloadDir(sigil_basename, false))) { - W_AutoLoadWADs(autoload_dir); + W_AutoLoadWADsRename(autoload_dir, sigil_lumps, arrlen(sigil_lumps)); DEH_AutoLoadPatches(autoload_dir); free(autoload_dir); } @@ -185,10 +182,7 @@ static boolean LoadSigil2Wad (const char *iwaddir, boolean pwadtexture) "SIGIL_II_V1_0.WAD", }; - static const struct { - const char *name; - const char new_name[8]; - } sigil2_lumps [] = { + static const lump_rename_t sigil2_lumps [] = { {"CREDIT", "SG2CREDI"}, {"HELP1", "SG2HELP1"}, {"TITLEPIC", "SG2TITLE"}, @@ -268,7 +262,7 @@ static boolean LoadSigil2Wad (const char *iwaddir, boolean pwadtexture) { if ((autoload_dir = M_GetAutoloadDir(sigil2_basename, false))) { - W_AutoLoadWADs(autoload_dir); + W_AutoLoadWADsRename(autoload_dir, sigil2_lumps, arrlen(sigil2_lumps)); DEH_AutoLoadPatches(autoload_dir); free(autoload_dir); } @@ -351,10 +345,7 @@ static void CheckLoadNerve (void) char *autoload_dir; int i, j; - static const struct { - const char *name; - const char new_name[8]; - } nerve_lumps [] = { + static const lump_rename_t nerve_lumps [] = { {"TITLEPIC", "NERVEPIC"}, {"INTERPIC", "NERVEINT"}, }; @@ -423,7 +414,7 @@ static void CheckLoadNerve (void) { if ((autoload_dir = M_GetAutoloadDir(nerve_basename, false))) { - W_AutoLoadWADs(autoload_dir); + W_AutoLoadWADsRename(autoload_dir, nerve_lumps, arrlen(nerve_lumps)); DEH_AutoLoadPatches(autoload_dir); free(autoload_dir); } @@ -463,6 +454,11 @@ static boolean CheckMasterlevelsLoaded (void) return false; } +static const lump_rename_t master_lumps [] = { + {"TITLEPIC", "MASTRPIC"}, + {"INTERPIC", "MASTRINT"}, +}; + // [crispy] auto-load the single MASTERLEVELS.WAD if available static boolean CheckLoadMasterlevels (void) { @@ -532,7 +528,7 @@ static boolean CheckLoadMasterlevels (void) { if ((autoload_dir = M_GetAutoloadDir(master_basename, false))) { - W_AutoLoadWADs(autoload_dir); + W_AutoLoadWADsRename(autoload_dir, master_lumps, arrlen(master_lumps)); DEH_AutoLoadPatches(autoload_dir); free(autoload_dir); } @@ -634,6 +630,7 @@ static void LoadMasterlevelsWads (void) { int i, j; char lumpname[9]; + char *autoload_dir; const char *const sky_lumps[] = { "RSKY1", @@ -677,6 +674,17 @@ static void LoadMasterlevelsWads (void) // [crispy] indicate this is not the single MASTERLEVELS.WAD crispy->havemaster = (char *)-1; + // [crispy] autoload from MASTERLEVELS.WAD autoload directory + if (!M_ParmExists("-noautoload")) + { + if ((autoload_dir = M_GetAutoloadDir("MASTERLEVELS.WAD", false))) + { + W_AutoLoadWADsRename(autoload_dir, master_lumps, arrlen(master_lumps)); + DEH_AutoLoadPatches(autoload_dir); + free(autoload_dir); + } + } + // [crispy] regenerate the hashtable W_GenerateHashTable(); return; diff --git a/src/doom/f_finale.c b/src/doom/f_finale.c index a0b7cb180b..89f99998bc 100644 --- a/src/doom/f_finale.c +++ b/src/doom/f_finale.c @@ -879,7 +879,7 @@ F_DrawPatchCol #ifndef CRISPY_TRUECOLOR *dest = source[srccol >> FRACBITS]; #else - *dest = colormaps[source[srccol >> FRACBITS]]; + *dest = pal_color[source[srccol >> FRACBITS]]; #endif srccol += dyi; dest += SCREENWIDTH; diff --git a/src/doom/hu_stuff.c b/src/doom/hu_stuff.c index fa7aadd0d7..763a15b4a9 100644 --- a/src/doom/hu_stuff.c +++ b/src/doom/hu_stuff.c @@ -47,7 +47,7 @@ #include "dstrings.h" #include "sounds.h" -#include "r_state.h" // [crispy] colormaps +#include "r_state.h" // [crispy] pal_color #include "v_video.h" // [crispy] V_DrawPatch() et al. #include "v_trans.h" // [crispy] colored kills/items/secret/etc. messages @@ -782,12 +782,12 @@ void HU_DemoProgressBar (void) // V_DrawHorizLine(0, SCREENHEIGHT - 2, 1, 4); // [crispy] white start // V_DrawHorizLine(i - 1, SCREENHEIGHT - 2, 1, 4); // [crispy] white end #else -// V_DrawHorizLine(0, SCREENHEIGHT - 3, i, colormaps[4]); // [crispy] white - V_DrawHorizLine(0, SCREENHEIGHT - 2, i, colormaps[0]); // [crispy] black - V_DrawHorizLine(0, SCREENHEIGHT - 1, i, colormaps[4]); // [crispy] white +// V_DrawHorizLine(0, SCREENHEIGHT - 3, i, pal_color[4]); // [crispy] white + V_DrawHorizLine(0, SCREENHEIGHT - 2, i, pal_color[0]); // [crispy] black + V_DrawHorizLine(0, SCREENHEIGHT - 1, i, pal_color[4]); // [crispy] white -// V_DrawHorizLine(0, SCREENHEIGHT - 2, 1, colormaps[4]); // [crispy] white start -// V_DrawHorizLine(i - 1, SCREENHEIGHT - 2, 1, colormaps[4]); // [crispy] white end +// V_DrawHorizLine(0, SCREENHEIGHT - 2, 1, pal_color[4]); // [crispy] white start +// V_DrawHorizLine(i - 1, SCREENHEIGHT - 2, 1, pal_color[4]); // [crispy] white end #endif } diff --git a/src/doom/r_data.c b/src/doom/r_data.c index c09b12232d..aebbd3354d 100644 --- a/src/doom/r_data.c +++ b/src/doom/r_data.c @@ -168,6 +168,7 @@ fixed_t* spriteoffset; fixed_t* spritetopoffset; lighttable_t *colormaps; +lighttable_t *pal_color; // [crispy] array holding palette colors for true color mode // [FG] check if the lump can be a Doom patch // taken from PrBoom+ prboom2/src/r_patch.c:L350-L390 @@ -1189,11 +1190,11 @@ void R_InitColormaps (void) lump = W_GetNumForName(DEH_String("COLORMAP")); colormaps = W_CacheLumpNum(lump, PU_STATIC); #else - byte *playpal; int c, i, j = 0; byte r, g, b; - playpal = W_CacheLumpName("PLAYPAL", PU_STATIC); + byte *const playpal = W_CacheLumpName("PLAYPAL", PU_STATIC); + byte *const colormap = W_CacheLumpName("COLORMAP", PU_STATIC); if (!colormaps) { @@ -1208,9 +1209,11 @@ void R_InitColormaps (void) for (i = 0; i < 256; i++) { - r = gamma2table[crispy->gamma][playpal[3 * i + 0]] * (1. - scale) + gamma2table[crispy->gamma][0] * scale; - g = gamma2table[crispy->gamma][playpal[3 * i + 1]] * (1. - scale) + gamma2table[crispy->gamma][0] * scale; - b = gamma2table[crispy->gamma][playpal[3 * i + 2]] * (1. - scale) + gamma2table[crispy->gamma][0] * scale; + const byte k = colormap[i]; + + r = gamma2table[crispy->gamma][playpal[3 * k + 0]] * (1. - scale) + gamma2table[crispy->gamma][0] * scale; + g = gamma2table[crispy->gamma][playpal[3 * k + 1]] * (1. - scale) + gamma2table[crispy->gamma][0] * scale; + b = gamma2table[crispy->gamma][playpal[3 * k + 2]] * (1. - scale) + gamma2table[crispy->gamma][0] * scale; colormaps[j++] = 0xff000000 | (r << 16) | (g << 8) | b; } @@ -1230,8 +1233,6 @@ void R_InitColormaps (void) } else { - byte *const colormap = W_CacheLumpName("COLORMAP", PU_STATIC); - for (c = 0; c <= NUMCOLORMAPS; c++) { for (i = 0; i < 256; i++) @@ -1243,13 +1244,31 @@ void R_InitColormaps (void) colormaps[j++] = 0xff000000 | (r << 16) | (g << 8) | b; } } + } + + W_ReleaseLumpName("COLORMAP"); - W_ReleaseLumpName("COLORMAP"); + if (!pal_color) + { + pal_color = (pixel_t*) Z_Malloc(256 * sizeof(pixel_t), PU_STATIC, 0); } + + for (i = 0, j = 0; i < 256; i++) + { + r = gamma2table[crispy->gamma][playpal[3 * i + 0]]; + g = gamma2table[crispy->gamma][playpal[3 * i + 1]]; + b = gamma2table[crispy->gamma][playpal[3 * i + 2]]; + + pal_color[j++] = 0xff000000 | (r << 16) | (g << 8) | b; + } + + W_ReleaseLumpName("PLAYPAL"); #endif +} - // [crispy] initialize color translation and color strings tables - { +// [crispy] initialize color translation and color string tables +static void R_InitHSVColors(void) +{ byte *playpal = W_CacheLumpName("PLAYPAL", PU_STATIC); char c[3]; int i, j; @@ -1289,7 +1308,6 @@ void R_InitColormaps (void) { cr[CR_RED2BLUE] = W_CacheLumpNum(i, PU_STATIC); } - } } @@ -1318,6 +1336,8 @@ void R_InitData (void) // [crispy] Initialize and generate gamma-correction levels. I_SetGammaTable (); R_InitColormaps (); + // [crispy] Initialize color translation and color string tables. + R_InitHSVColors (); #ifndef CRISPY_TRUECOLOR R_InitTranMap(); // [crispy] prints a mark itself #endif diff --git a/src/doom/r_main.c b/src/doom/r_main.c index b133d5cd94..809ac03ba0 100644 --- a/src/doom/r_main.c +++ b/src/doom/r_main.c @@ -1128,7 +1128,7 @@ void R_RenderPlayerView (player_t* player) #ifndef CRISPY_TRUECOLOR 176 + (gametic % 16)); #else - colormaps[176 + (gametic % 16)]); + pal_color[176 + (gametic % 16)]); #endif } diff --git a/src/doom/r_state.h b/src/doom/r_state.h index 63553fb4f0..37f314b9ff 100644 --- a/src/doom/r_state.h +++ b/src/doom/r_state.h @@ -44,6 +44,7 @@ extern fixed_t* spriteoffset; extern fixed_t* spritetopoffset; extern lighttable_t* colormaps; +extern lighttable_t* pal_color; extern int viewwidth; extern int scaledviewwidth; diff --git a/src/doom/wi_stuff.c b/src/doom/wi_stuff.c index f2c34a0049..9fc113230d 100644 --- a/src/doom/wi_stuff.c +++ b/src/doom/wi_stuff.c @@ -1865,6 +1865,10 @@ static void WI_loadUnloadData(load_callback_t callback) { M_StringCopy(name, DEH_String("NERVEINT"), sizeof(name)); } + else if (crispy->havemaster && wbs->epsd == 2 && W_CheckNumForName(DEH_String("MASTRINT")) != -1) // [crispy] gamemission == pack_master + { + M_StringCopy(name, DEH_String("MASTRINT"), sizeof(name)); + } else { M_StringCopy(name, DEH_String("INTERPIC"), sizeof(name)); diff --git a/src/heretic/am_map.c b/src/heretic/am_map.c index e8445dcb79..82694e7136 100644 --- a/src/heretic/am_map.c +++ b/src/heretic/am_map.c @@ -33,9 +33,6 @@ vertex_t KeyPoints[NUM_KEY_TYPES]; #define NUMALIAS 3 // Number of antialiased lines. -// [crispy] precalculated color LUT for antialiased line drawing using COLORMAP -#define NUMSHADES 8 -static pixel_t color_shades[NUMSHADES * 256]; const char *LevelNames[] = { // EPISODE 1 - THE CITY OF THE DAMNED @@ -155,17 +152,21 @@ static char cheat_amap[] = { 'r', 'a', 'v', 'm', 'a', 'p' }; static byte cheatcount = 0; -// [crispy] line colors for map normal mode -static byte antialias_normal[NUMALIAS] = { - 96, 110, 75 +// [crispy] gradient table for map normal mode +static byte antialias_normal[NUMALIAS][8] = { + {96, 97, 98, 99, 100, 101, 102, 103}, + {110, 109, 108, 107, 106, 105, 104, 103}, + {75, 76, 77, 78, 79, 80, 81, 103} }; -// [crispy] line colors for map overlay mode -static byte antialias_overlay[NUMALIAS] = { - 100, 110, 75 +// [crispy] gradient table for map overlay mode +static byte antialias_overlay[NUMALIAS][8] = { + {100, 99, 98, 97, 96, 95, 95, 95}, + {110, 109, 108, 105, 102, 99, 97, 95}, + {75, 74, 73, 72, 71, 70, 69, 95} }; -static byte (*antialias)[NUMALIAS]; // [crispy] +static byte (*antialias)[NUMALIAS][8]; // [crispy] /* static byte *aliasmax[NUMALIAS] = { &antialias[0][7], &antialias[1][7], &antialias[2][7] @@ -192,7 +193,7 @@ static angle_t mapangle; // Functions -void DrawWuLine(int X0, int Y0, int X1, int Y1, int Color, +void DrawWuLine(int X0, int Y0, int X1, int Y1, byte * BaseColor, int NumLevels, unsigned short IntensityBits); // Calculates the slope and slope according to the x-axis of a line @@ -538,8 +539,6 @@ void AM_LevelInit(boolean reinit) { // [crispy] Used for reinit static int f_h_old; - // [crispy] Only need to precalculate color lookup tables once - static boolean precalc_once; finit_width = SCREENWIDTH; finit_height = SCREENHEIGHT - (42 << crispy->hires); @@ -571,26 +570,6 @@ void AM_LevelInit(boolean reinit) scale_ftom = FixedDiv(FRACUNIT, scale_mtof); f_h_old = f_h; - - // [crispy] Precalculate color lookup tables for antialiased line drawing using COLORMAP - if (!precalc_once) - { - precalc_once = true; - for (int color = 0; color < 256; ++color) - { -#define REINDEX(I) (color + I * 256) - // Pick a range of shades for a steep gradient to keep lines thin - int shade_index[NUMSHADES] = - { - REINDEX(0), REINDEX(1), REINDEX(2), REINDEX(3), REINDEX(4), REINDEX(5), REINDEX(6), REINDEX(7), - }; -#undef REINDEX - for (int shade = 0; shade < NUMSHADES; ++shade) - { - color_shades[color * NUMSHADES + shade] = colormaps[shade_index[shade]]; - } - } - } } static boolean stopped = true; @@ -1122,21 +1101,21 @@ void AM_clearFB(int color) for (z = 0; z < x3; z++) { - dest[z] = colormaps[src[z]]; + dest[z] = pal_color[src[z]]; } dest += x3; src += x3 - x2; for (z = 0; z < x2; z++) { - dest[z] = colormaps[src[z]]; + dest[z] = pal_color[src[z]]; } dest += x2; src = maplump + j; for (z = 0; z < x1; z++) { - dest[z] = colormaps[src[z]]; + dest[z] = pal_color[src[z]]; } #endif j += MAPBGROUNDWIDTH << crispy->hires; @@ -1268,15 +1247,15 @@ void AM_drawFline(fline_t * fl, int color) switch (color) { case WALLCOLORS: - DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, (*antialias)[0], + DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &(*antialias)[0][0], 8, 3); break; case FDWALLCOLORS: - DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, (*antialias)[1], + DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &(*antialias)[1][0], 8, 3); break; case CDWALLCOLORS: - DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, (*antialias)[2], + DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &(*antialias)[2][0], 8, 3); break; default: @@ -1294,7 +1273,7 @@ void AM_drawFline(fline_t * fl, int color) #ifndef CRISPY_TRUECOLOR #define DOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc) //the MACRO! #else -#define DOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(colormaps[cc]) +#define DOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(pal_color[cc]) #endif dx = fl->b.x - fl->a.x; @@ -1355,11 +1334,11 @@ void AM_drawFline(fline_t * fl, int color) * IntensityBits = log base 2 of NumLevels; the # of bits used to describe * the intensity of the drawing color. 2**IntensityBits==NumLevels */ -void PUTDOT(short xx, short yy, pixel_t * cc, pixel_t * cm) +void PUTDOT(short xx, short yy, byte * cc, byte * cm) { static int oldyy; static int oldyyshifted; - pixel_t *oldcc = cc; + byte *oldcc = cc; if (xx < 32) cc += 7 - (xx >> 2); @@ -1395,17 +1374,20 @@ void PUTDOT(short xx, short yy, pixel_t * cc, pixel_t * cm) oldyy = yy; oldyyshifted = yy * f_w; } +#ifndef CRISPY_TRUECOLOR fb[oldyyshifted + xx] = *(cc); +#else + fb[oldyyshifted + xx] = pal_color[*(cc)]; +#endif // fb[(yy)*f_w+(xx)]=*(cc); } -void DrawWuLine(int X0, int Y0, int X1, int Y1, int Color, +void DrawWuLine(int X0, int Y0, int X1, int Y1, byte * BaseColor, int NumLevels, unsigned short IntensityBits) { unsigned short IntensityShift, ErrorAdj, ErrorAcc; unsigned short ErrorAccTemp, Weighting, WeightingComplementMask; short DeltaX, DeltaY, Temp, XDir; - pixel_t *BaseColor = &color_shades[Color * NUMSHADES]; /* Make sure the line runs top to bottom */ if (Y0 > Y1) diff --git a/src/heretic/g_game.c b/src/heretic/g_game.c index c17b240806..f7031895da 100644 --- a/src/heretic/g_game.c +++ b/src/heretic/g_game.c @@ -1142,6 +1142,14 @@ boolean G_Responder(event_t * ev) usearti = true; } + // [crispy] demo fast-forward + if (ev->type == ev_keydown && ev->data1 == key_demospeed && + (demoplayback || gamestate == GS_DEMOSCREEN)) + { + singletics = !singletics; + return true; + } + // Check for spy mode player cycle if (gamestate == GS_LEVEL && ev->type == ev_keydown && ev->data1 == KEY_F12 && !deathmatch) diff --git a/src/heretic/mn_menu.c b/src/heretic/mn_menu.c index eb0a77ca0b..998340b1fe 100644 --- a/src/heretic/mn_menu.c +++ b/src/heretic/mn_menu.c @@ -2221,7 +2221,8 @@ boolean MN_Responder(event_t * event) if (!MenuActive) { - if (key == key_menu_activate || gamestate == GS_DEMOSCREEN || demoplayback) + // [crispy] don't pop up the menu on other keys during a demo + if (key == key_menu_activate) //|| gamestate == GS_DEMOSCREEN || demoplayback) { MN_ActivateMenu(); return (true); diff --git a/src/heretic/r_bmaps.c b/src/heretic/r_bmaps.c index 8eb216ccbc..0dd6f5818c 100644 --- a/src/heretic/r_bmaps.c +++ b/src/heretic/r_bmaps.c @@ -149,6 +149,26 @@ static const byte flame[256] = 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, }; +static const byte serptorch[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, +}; + static const byte ethereal[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -326,10 +346,6 @@ const byte *R_BrightmapForSprite (const int state) case S_FIREBRAZIER6: case S_FIREBRAZIER7: case S_FIREBRAZIER8: - // Serpent Torch - case S_SERPTORCH1: - case S_SERPTORCH2: - case S_SERPTORCH3: // Torch (artifact) case S_ARTI_TRCH1: case S_ARTI_TRCH2: @@ -355,6 +371,14 @@ const byte *R_BrightmapForSprite (const int state) return flame; break; } + // Serpent Torch, has stray pixels with 'flame' map + case S_SERPTORCH1: + case S_SERPTORCH2: + case S_SERPTORCH3: + { + return serptorch; + break; + } // Iron Lich (idle and attack states) case S_HEAD_LOOK: case S_HEAD_FLOAT: diff --git a/src/heretic/r_data.c b/src/heretic/r_data.c index 07640f05c5..d628122d05 100644 --- a/src/heretic/r_data.c +++ b/src/heretic/r_data.c @@ -16,6 +16,8 @@ // R_data.c +#include // [crispy] calloc() + #include "doomdef.h" #include "deh_str.h" @@ -59,7 +61,7 @@ int *texturewidthmask; fixed_t *textureheight; // needed for texture pegging int *texturecompositesize; short **texturecolumnlump; -unsigned short **texturecolumnofs; +unsigned **texturecolumnofs; // [crispy] was short byte **texturecomposite; const byte **texturebrightmap; // [crispy] brightmaps @@ -71,6 +73,7 @@ fixed_t *spriteoffset; fixed_t *spritetopoffset; lighttable_t *colormaps; +lighttable_t *pal_color; // [crispy] array holding palette colors for true color mode /* @@ -87,53 +90,73 @@ will have new column_ts generated. ============================================================================== */ -/* -=================== -= -= R_DrawColumnInCache -= -= Clip and draw a column from a patch into a cached post -= -=================== -*/ +// [crispy] replace R_DrawColumnInCache(), R_GenerateComposite() and +// R_GenerateLookup() with Lee Killough's implementations found in MBF to fix +// Medusa bug taken from mbfsrc/R_DATA.C:136-425 +// +// R_DrawColumnInCache +// Clip and draw a column from a patch into a cached post. +// +// Rewritten by Lee Killough for performance and to fix Medusa bug +// void R_DrawColumnInCache(column_t * patch, byte * cache, int originy, - int cacheheight) + int cacheheight, byte * marks) { int count, position; byte *source; + int top = -1; while (patch->topdelta != 0xff) { - source = (byte *) patch + 3; + // [crispy] support for DeePsea tall patches + if (patch->topdelta <= top) + { + top += patch->topdelta; + } + else + { + top = patch->topdelta; + } + source = (byte *)patch + 3; count = patch->length; - position = originy + patch->topdelta; + position = originy + top; + if (position < 0) { count += position; position = 0; } + if (position + count > cacheheight) count = cacheheight - position; + if (count > 0) + { memcpy(cache + position, source, count); - patch = (column_t *) ((byte *) patch + patch->length + 4); + // killough 4/9/98: remember which cells in column have been drawn, + // so that column can later be converted into a series of posts, to + // fix the Medusa bug. + + memset(marks + position, 0xff, count); + } + + patch = (column_t *)((byte *)patch + patch->length + 4); } } -/* -=================== -= -= R_GenerateComposite -= -=================== -*/ +// +// R_GenerateComposite +// Using the texture definition, the composite texture is created from the +// patches, and each column is cached. +// +// Rewritten by Lee Killough for performance and to fix Medusa bug void R_GenerateComposite(int texnum) { - byte *block; + byte* block; texture_t *texture; texpatch_t *patch; patch_t *realpatch; @@ -141,14 +164,24 @@ void R_GenerateComposite(int texnum) int i; column_t *patchcol; short *collump; - unsigned short *colofs; + unsigned* colofs; // killough 4/9/98: make 32-bit + byte *marks; // killough 4/9/98: transparency marks + byte *source; // killough 4/9/98: temporary column texture = textures[texnum]; + block = Z_Malloc(texturecompositesize[texnum], PU_STATIC, &texturecomposite[texnum]); + collump = texturecolumnlump[texnum]; colofs = texturecolumnofs[texnum]; + // killough 4/9/98: marks to identify transparent regions in merged textures + marks = calloc(texture->width, texture->height); + + // [crispy] initialize composite background to palette index 0 (usually black) + memset(block, 0, texturecompositesize[texnum]); + // // composite the columns together // @@ -170,41 +203,111 @@ void R_GenerateComposite(int texnum) { if (collump[x] >= 0) continue; // column does not have multiple patches + patchcol = (column_t *) ((byte *) realpatch + LONG(realpatch->columnofs[x - x1])); - R_DrawColumnInCache(patchcol, block + colofs[x], patch->originy, - texture->height); + R_DrawColumnInCache(patchcol, block + colofs[x], + patch->originy, + texture->height, + marks + x * texture->height); } } -// now that the texture has been built, it is purgable + // killough 4/9/98: Next, convert multipatched columns into true columns, + // to fix Medusa bug while still allowing for transparent regions. + + source = I_Realloc(NULL, texture->height); // temporary column + for (i = 0; i < texture->width; i++) + { + if (collump[i] == -1) // process only multipatched columns + { + column_t *col = + (column_t *) (block + colofs[i] - 3); // cached column + const byte *mark = marks + i * texture->height; + int j = 0; + // [crispy] absolute topdelta for first 254 pixels, then relative + int abstop, reltop = 0; + boolean relative = false; + + // save column in temporary so we can shuffle it around + memcpy(source, (byte *) col + 3, texture->height); + + for (;;) // reconstruct the column by scanning transparency marks + { + unsigned len; // killough 12/98 + + while (j < texture->height && reltop < 254 && + !mark[j]) // skip transparent cells + j++, reltop++; + + if (j >= texture->height) // if at end of column + { + col->topdelta = -1; // end-of-column marker + break; + } + + // [crispy] absolute topdelta for first 254 pixels, then relative + col->topdelta = + relative ? reltop : j; // starting offset of post + + // [crispy] once we pass the 254 boundary, topdelta becomes relative + if ((abstop = j) >= 254) + { + relative = true; + reltop = 0; + } + + // killough 12/98: Use 32-bit len counter, to support tall 1s + // multipatched textures + + for (len = 0; j < texture->height && reltop < 254 && mark[j]; + j++, reltop++) + len++; // count opaque cells + + col->length = len; // killough 12/98: intentionally truncate length + + // copy opaque cells from the temporary back into the column + memcpy((byte *) col + 3, source + abstop, len); + col = (column_t *) ((byte *) col + len + 4); // next post + } + } + } + + free(source); // free temporary column + free(marks); // free transparency marks + + // Now that the texture has been built in column cache, it is purgable + // from zone memory. Z_ChangeTag(block, PU_CACHE); } -/* -=================== -= -= R_GenerateLookup -= -=================== -*/ +// +// R_GenerateLookup +// +// Rewritten by Lee Killough for performance and to fix Medusa bug +// void R_GenerateLookup(int texnum) { texture_t *texture; byte *patchcount; // [texture->width] + byte *postcount; // killough 4/9/98: keep count of posts in addition to patches. texpatch_t *patch; patch_t *realpatch; int x, x1, x2; int i; short *collump; - unsigned short *colofs; + unsigned *colofs; // killough 4/9/98: make 32-bit + int csize = 0; // killough 10/98 + int err = 0; // killough 10/98 texture = textures[texnum]; - texturecomposite[texnum] = 0; // composited not created yet + // Composited texture not created yet. + texturecomposite[texnum] = 0; + texturecompositesize[texnum] = 0; collump = texturecolumnlump[texnum]; colofs = texturecolumnofs[texnum]; @@ -215,7 +318,9 @@ void R_GenerateLookup(int texnum) // all done // patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount); + postcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &postcount); memset(patchcount, 0, texture->width); + memset(postcount, 0, texture->width); for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) @@ -237,26 +342,101 @@ void R_GenerateLookup(int texnum) } } + // killough 4/9/98: keep a count of the number of posts in column, + // to fix Medusa bug while allowing for transparent multipatches. + // + // killough 12/98: + // Post counts are only necessary if column is multipatched, + // so skip counting posts if column comes from a single patch. + // This allows arbitrarily tall textures for 1s walls. + // + // If texture is >= 256 tall, assume it's 1s, and hence it has + // only one post per column. This avoids crashes while allowing + // for arbitrarily tall multipatched 1s textures. + + if (texture->patchcount > 1 && texture->height < 256) + { + // killough 12/98: Warn about a common column construction bug + unsigned limit = texture->height * 3 + 3; // absolute column size limit + + for (i = texture->patchcount, patch = texture->patches; --i >= 0;) + { + int pat = patch->patch; + const patch_t *realpatch = W_CacheLumpNum(pat, PU_CACHE); + int x, x1 = patch++->originx, x2 = x1 + SHORT(realpatch->width); + const int *cofs = realpatch->columnofs - x1; + + if (x2 > texture->width) + x2 = texture->width; + if (x1 < 0) + x1 = 0; + + for (x = x1; x < x2; x++) + { + if (patchcount[x] > 1) // Only multipatched columns + { + const column_t *col = + (const column_t *) ((const byte *) realpatch + + LONG(cofs[x])); + const byte *base = (const byte *) col; + + // count posts + for (; col->topdelta != 0xff; postcount[x]++) + { + if ((unsigned) ((const byte *) col - base) <= limit) + col = (const column_t *) ((const byte *) col + + col->length + 4); + else + break; + } + } + } + } + } + for (x = 0; x < texture->width; x++) { - if (!patchcount[x]) + if (!patchcount[x] && !err++) // killough 10/98: non-verbose output { - printf("R_GenerateLookup: column without a patch (%s)\n", - texture->name); + // [crispy] fix absurd texture name in error message + printf("R_GenerateLookup: column without a patch (%.8s)\n", + texture->name); + // [crispy] do not return yet + /* return; + */ } -// I_Error ("R_GenerateLookup: column without a patch"); - if (patchcount[x] > 1) + // I_Error ("R_GenerateLookup: column without a patch"); + + // [crispy] treat patch-less columns the same as multi-patched + if (patchcount[x] > 1 || !patchcount[x]) { - collump[x] = -1; // use the cached block - colofs[x] = texturecompositesize[texnum]; + // killough 1/25/98, 4/9/98: + // + // Fix Medusa bug, by adding room for column header + // and trailer bytes for each post in merged column. + // For now, just allocate conservatively 4 bytes + // per post per patch per column, since we don't + // yet know how many posts the merged column will + // require, and it's bounded above by this limit. + collump[x] = -1; // use the cached block + colofs[x] = csize + 3; // three header bytes in a column + // killough 12/98: add room for one extra post + csize += 4 * postcount[x] + 5; // 1 stop byte plus 4 bytes per post + } + + // [crispy] remove limit + /* if (texturecompositesize[texnum] > 0x10000 - texture->height) I_Error("R_GenerateLookup: texture %i is >64k", texnum); - texturecompositesize[texnum] += texture->height; - } + */ + csize += texture->height; // height bytes of texture data } + texturecompositesize[texnum] += csize; + Z_Free(patchcount); + Z_Free(postcount); } @@ -282,7 +462,6 @@ byte *R_GetColumn(int tex, int col) return texturecomposite[tex] + ofs; } - /* ================== = @@ -363,7 +542,7 @@ void R_InitTextures(void) textures = Z_Malloc(numtextures * sizeof(texture_t *), PU_STATIC, 0); texturecolumnlump = Z_Malloc(numtextures * sizeof(short *), PU_STATIC, 0); - texturecolumnofs = Z_Malloc(numtextures * sizeof(unsigned short *), PU_STATIC, 0); + texturecolumnofs = Z_Malloc(numtextures * sizeof(*texturecolumnofs), PU_STATIC, 0); texturecomposite = Z_Malloc(numtextures * sizeof(byte *), PU_STATIC, 0); texturecompositesize = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0); texturewidthmask = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0); @@ -411,9 +590,9 @@ void R_InitTextures(void) I_Error("R_InitTextures: Missing patch in texture %s", texture->name); } - texturecolumnlump[i] = Z_Malloc(texture->width * sizeof(short), + texturecolumnlump[i] = Z_Malloc(texture->width * sizeof(**texturecolumnlump), PU_STATIC, 0); - texturecolumnofs[i] = Z_Malloc(texture->width * sizeof(short), + texturecolumnofs[i] = Z_Malloc(texture->width * sizeof(**texturecolumnofs), PU_STATIC, 0); j = 1; while (j * 2 <= texture->width) @@ -530,12 +709,11 @@ void R_InitColormaps(void) colormaps = Z_Malloc(length, PU_STATIC, 0); W_ReadLump(lump, colormaps); #else - byte *playpal; - byte *const colormap = W_CacheLumpName("COLORMAP", PU_STATIC); int c, i, j = 0; byte r, g, b; - playpal = W_CacheLumpName("PLAYPAL", PU_STATIC); + byte *const playpal = W_CacheLumpName("PLAYPAL", PU_STATIC); + byte *const colormap = W_CacheLumpName("COLORMAP", PU_STATIC); if (!colormaps) { @@ -550,9 +728,11 @@ void R_InitColormaps(void) for (i = 0; i < 256; i++) { - r = gamma2table[crispy->gamma][playpal[3 * i + 0]] * (1. - scale) + gamma2table[crispy->gamma][0] * scale; - g = gamma2table[crispy->gamma][playpal[3 * i + 1]] * (1. - scale) + gamma2table[crispy->gamma][0] * scale; - b = gamma2table[crispy->gamma][playpal[3 * i + 2]] * (1. - scale) + gamma2table[crispy->gamma][0] * scale; + const byte k = colormap[i]; + + r = gamma2table[crispy->gamma][playpal[3 * k + 0]] * (1. - scale) + gamma2table[crispy->gamma][0] * scale; + g = gamma2table[crispy->gamma][playpal[3 * k + 1]] * (1. - scale) + gamma2table[crispy->gamma][0] * scale; + b = gamma2table[crispy->gamma][playpal[3 * k + 2]] * (1. - scale) + gamma2table[crispy->gamma][0] * scale; colormaps[j++] = 0xff000000 | (r << 16) | (g << 8) | b; } @@ -584,10 +764,28 @@ void R_InitColormaps(void) } W_ReleaseLumpName("COLORMAP"); + + if (!pal_color) + { + pal_color = (pixel_t*) Z_Malloc(256 * sizeof(pixel_t), PU_STATIC, 0); + } + + for (i = 0, j = 0; i < 256; i++) + { + r = gamma2table[crispy->gamma][playpal[3 * i + 0]]; + g = gamma2table[crispy->gamma][playpal[3 * i + 1]]; + b = gamma2table[crispy->gamma][playpal[3 * i + 2]]; + + pal_color[j++] = 0xff000000 | (r << 16) | (g << 8) | b; + } + + W_ReleaseLumpName("PLAYPAL"); #endif +} - // [crispy] initialize color translation and color string tables - { +// [crispy] initialize color translation and color string tables +static void R_InitHSVColors(void) +{ byte *playpal = W_CacheLumpName("PLAYPAL", PU_STATIC); char c[3]; int i, j; @@ -608,7 +806,6 @@ void R_InitColormaps(void) } W_ReleaseLumpName("PLAYPAL"); - } } #ifdef CRISPY_TRUECOLOR @@ -626,7 +823,7 @@ void R_SetUnderwaterPalette(byte *palette) g = gamma2table[crispy->gamma][palette[3 * i + 1]] + gamma2table[crispy->gamma][0]; b = gamma2table[crispy->gamma][palette[3 * i + 2]] + gamma2table[crispy->gamma][0]; - colormaps[j++] = 0xff000000 | (r << 16) | (g << 8) | b; + pal_color[j++] = 0xff000000 | (r << 16) | (g << 8) | b; } } #endif @@ -665,6 +862,8 @@ void R_InitData(void) // [crispy] Initialize and generate gamma-correction levels. I_SetGammaTable(); R_InitColormaps(); + // [crispy] Initialize color translation and color string tables. + R_InitHSVColors(); } diff --git a/src/heretic/r_local.h b/src/heretic/r_local.h index acdba58937..6f138385fa 100644 --- a/src/heretic/r_local.h +++ b/src/heretic/r_local.h @@ -446,7 +446,7 @@ extern fixed_t *textureheight; // needed for texture pegging extern fixed_t *spritewidth; // needed for pre rendering (fracs) extern fixed_t *spriteoffset; extern fixed_t *spritetopoffset; -extern lighttable_t *colormaps; +extern lighttable_t *colormaps, *pal_color; extern int firstflat; extern int numflats; diff --git a/src/heretic/r_plane.c b/src/heretic/r_plane.c index 597eb13bf9..daf00e62aa 100644 --- a/src/heretic/r_plane.c +++ b/src/heretic/r_plane.c @@ -416,6 +416,8 @@ void R_MakeSpans(int x, unsigned int t1, unsigned int b1, unsigned int t2, unsig */ #define SKYTEXTUREMIDSHIFTED 200 // [crispy] +#define FLATSCROLL(X) \ + ((interpfactor << (X)) - (((63 - ((leveltime >> 1) & 63)) << (X) & 63) * FRACUNIT)) void R_DrawPlanes(void) { @@ -518,7 +520,7 @@ void R_DrawPlanes(void) #ifndef CRISPY_TRUECOLOR *dest = dc_source[frac >> FRACBITS]; #else - *dest = colormaps[dc_source[frac >> FRACBITS]]; + *dest = pal_color[dc_source[frac >> FRACBITS]]; #endif dest += SCREENWIDTH; @@ -538,7 +540,7 @@ void R_DrawPlanes(void) #ifndef CRISPY_TRUECOLOR *dest = dc_source[(frac >> FRACBITS) & heightmask]; #else - *dest = colormaps[dc_source[(frac >> FRACBITS) & heightmask]]; + *dest = pal_color[dc_source[(frac >> FRACBITS) & heightmask]]; #endif dest += SCREENWIDTH; frac += fracstep; @@ -579,6 +581,7 @@ void R_DrawPlanes(void) interpfactor = 0; } + //[crispy] use smoothscrolloffsets to unconditonally animate all scrolling floors switch (pl->special) { case 25: @@ -587,7 +590,7 @@ void R_DrawPlanes(void) case 28: case 29: // Scroll_North xsmoothscrolloffset = 0; - ysmoothscrolloffset = 0; + ysmoothscrolloffset = FLATSCROLL(pl->special - 25); ds_source = tempSource; break; case 20: @@ -595,10 +598,13 @@ void R_DrawPlanes(void) case 22: case 23: case 24: // Scroll_East - xsmoothscrolloffset = -(interpfactor << (pl->special - 20)); + // [crispy] vanilla Heretic animates Eastward scrollers by adding to tempSource. + // this directly offsets the position the flat is read from, and results in + // visual artifacts (tutti-frutti on flats that aren't at least 65px tall, jittery + // animation, unwanted visplane merging of adjacent flats with different scrollers) + xsmoothscrolloffset = -FLATSCROLL(pl->special - 20); ysmoothscrolloffset = 0; - ds_source = tempSource + ((63 - ((leveltime >> 1) & 63)) << - (pl->special - 20) & 63); + ds_source = tempSource; //ds_source = tempSource+((leveltime>>1)&63); break; case 30: @@ -607,7 +613,7 @@ void R_DrawPlanes(void) case 33: case 34: // Scroll_South xsmoothscrolloffset = 0; - ysmoothscrolloffset = 0; + ysmoothscrolloffset = -FLATSCROLL(pl->special - 30); ds_source = tempSource; break; case 35: @@ -615,15 +621,15 @@ void R_DrawPlanes(void) case 37: case 38: case 39: // Scroll_West - xsmoothscrolloffset = 0; + xsmoothscrolloffset = FLATSCROLL(pl->special - 35); ysmoothscrolloffset = 0; ds_source = tempSource; break; case 4: // Scroll_EastLavaDamage - xsmoothscrolloffset = -(interpfactor << 3); + // [crispy] calculation moved from tempSource, see Scroll_East above + xsmoothscrolloffset = -FLATSCROLL(3); ysmoothscrolloffset = 0; - ds_source = - tempSource + (((63 - ((leveltime >> 1) & 63)) << 3) & 63); + ds_source = tempSource; break; default: xsmoothscrolloffset = 0; diff --git a/src/hexen/am_map.c b/src/hexen/am_map.c index 51fedca9b6..fd6e20254d 100644 --- a/src/hexen/am_map.c +++ b/src/hexen/am_map.c @@ -39,7 +39,7 @@ static int finit_height;// = SCREENHEIGHT - SBARHEIGHT - (3 << crispy->hires); static int f_x, f_y; // location of window on screen static int f_w, f_h; // size of window on screen static int lightlev; // used for funky strobing effect -static byte *fb; // pseudo-frame buffer +static pixel_t *fb; // pseudo-frame buffer static int amclock; static mpoint_t m_paninc; // how far the window pans each tic (map coords) @@ -989,6 +989,7 @@ void AM_clearFB(int color) for (i = 0; i < SCREENHEIGHT - SBARHEIGHT; i++) { +#ifndef CRISPY_TRUECOLOR memcpy(I_VideoBuffer + i * finit_width, maplump + j + (MAPBGROUNDWIDTH << crispy->hires) - x3, x3); @@ -997,6 +998,30 @@ void AM_clearFB(int color) memcpy(I_VideoBuffer + i * finit_width + x2 + x3, maplump + j, x1); +#else + int z; + pixel_t *dest = I_VideoBuffer + i * finit_width; + byte *src = maplump + j + (MAPBGROUNDWIDTH << crispy->hires) - x3; + + for (z = 0; z < x3; z++) + { + dest[z] = pal_color[src[z]]; + } + + dest += x3; + src += x3 - x2; + for (z = 0; z < x2; z++) + { + dest[z] = pal_color[src[z]]; + } + + dest += x2; + src = maplump + j; + for (z = 0; z < x1; z++) + { + dest[z] = pal_color[src[z]]; + } +#endif j += MAPBGROUNDWIDTH << crispy->hires; if (j >= MAPBGROUNDHEIGHT * MAPBGROUNDWIDTH) @@ -1149,7 +1174,11 @@ void AM_drawFline(fline_t * fl, int color) return; } +#ifndef CRISPY_TRUECOLOR #define DOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc) //the MACRO! +#else +#define DOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(pal_color[cc]) +#endif dx = fl->b.x - fl->a.x; ax = 2 * (dx < 0 ? -dx : dx); @@ -1249,7 +1278,11 @@ void PUTDOT(short xx, short yy, byte * cc, byte * cm) oldyy = yy; oldyyshifted = yy * f_w; } +#ifndef CRISPY_TRUECOLOR fb[oldyyshifted + xx] = *(cc); +#else + fb[oldyyshifted + xx] = pal_color[*(cc)]; +#endif // fb[(yy)*f_w+(xx)]=*(cc); } diff --git a/src/hexen/f_finale.c b/src/hexen/f_finale.c index 44ad00295c..bc418d42bc 100644 --- a/src/hexen/f_finale.c +++ b/src/hexen/f_finale.c @@ -26,6 +26,7 @@ #include "v_video.h" #include "i_swap.h" #include "am_map.h" +#include "v_trans.h" // [crispy] blending functions // MACROS ------------------------------------------------------------------ @@ -61,9 +62,14 @@ static int FinaleLumpNum; static int FontABaseLump; static char *FinaleText; +#ifndef CRISPY_TRUECOLOR static fixed_t *Palette; static fixed_t *PaletteDelta; static byte *RealPalette; +#else +static int BlendTic; // [crispy] tics representing opacity value for blending function +#define BLENDSTEP 4 // [crispy] step of increasing/decreasing opacity value +#endif // CODE -------------------------------------------------------------------- @@ -153,6 +159,26 @@ void F_Ticker(void) { FadePic(); } +#ifdef CRISPY_TRUECOLOR + // [crispy] Fade in (from-black-to-normal) on 0 and 4 stages, + // and fade out (from normal-to-black) on 3 stage. + if (FinaleStage == 0 || FinaleStage == 4) + { + BlendTic += BLENDSTEP; + if (BlendTic > 255) + { + BlendTic = 255; + } + } + if (FinaleStage == 3) + { + BlendTic -= BLENDSTEP; + if (BlendTic < 0) + { + BlendTic = 0; + } + } +#endif } //=========================================================================== @@ -240,6 +266,7 @@ static void TextWrite(void) static void InitializeFade(boolean fadeIn) { +#ifndef CRISPY_TRUECOLOR unsigned i; Palette = Z_Malloc(768 * sizeof(fixed_t), PU_STATIC, 0); @@ -268,6 +295,10 @@ static void InitializeFade(boolean fadeIn) } } I_SetPalette(RealPalette); +#else + // [crispy] reset blending tic to initial value + BlendTic = fadeIn ? 0 : 255; +#endif } //=========================================================================== @@ -278,9 +309,11 @@ static void InitializeFade(boolean fadeIn) static void DeInitializeFade(void) { +#ifndef CRISPY_TRUECOLOR Z_Free(Palette); Z_Free(PaletteDelta); Z_Free(RealPalette); +#endif } //=========================================================================== @@ -291,6 +324,7 @@ static void DeInitializeFade(void) static void FadePic(void) { +#ifndef CRISPY_TRUECOLOR unsigned i; for (i = 0; i < 768; i++) @@ -299,6 +333,7 @@ static void FadePic(void) RealPalette[i] = Palette[i] >> FRACBITS; } I_SetPalette(RealPalette); +#endif } //=========================================================================== @@ -323,6 +358,13 @@ static void DrawPic(void) 1, PU_CACHE)); } } +#ifdef CRISPY_TRUECOLOR + // [crispy] apply true color blending on top of patch drawing functions + for (int y = 0; y < SCREENWIDTH * SCREENHEIGHT; y++) + { + I_VideoBuffer[y] = I_BlendDark(I_VideoBuffer[y], BlendTic); + } +#endif } //=========================================================================== diff --git a/src/hexen/g_game.c b/src/hexen/g_game.c index 00f027e8d9..58304be0e5 100644 --- a/src/hexen/g_game.c +++ b/src/hexen/g_game.c @@ -1072,6 +1072,14 @@ boolean G_Responder(event_t * ev) usearti = true; } + // [crispy] demo fast-forward + if (ev->type == ev_keydown && ev->data1 == key_demospeed && + (demoplayback || gamestate == GS_DEMOSCREEN)) + { + singletics = !singletics; + return true; + } + // Check for spy mode player cycle if (gamestate == GS_LEVEL && ev->type == ev_keydown && ev->data1 == key_spy && !deathmatch) @@ -2049,7 +2057,9 @@ void G_InitNew(skill_t skill, int episode, int map) } // Set up a bunch of globals - if (!demoextend) + // [crispy] since demoextend is the default, we also want to check to + // make sure we're not playing a demo + if (!demoextend || (!demorecording && !demoplayback)) { // This prevents map-loading from interrupting a demo. // demoextend is set back to false only if starting a new game or diff --git a/src/hexen/h2_main.c b/src/hexen/h2_main.c index 2c27ad5525..8c47c73599 100644 --- a/src/hexen/h2_main.c +++ b/src/hexen/h2_main.c @@ -208,6 +208,9 @@ void D_BindVariables(void) M_BindIntVariable("crispy_mouselook", &crispy->mouselook); M_BindIntVariable("crispy_playercoords", &crispy->playercoords); M_BindIntVariable("crispy_soundmono", &crispy->soundmono); +#ifdef CRISPY_TRUECOLOR + M_BindIntVariable("crispy_truecolor", &crispy->truecolor); +#endif M_BindIntVariable("crispy_smoothscaling", &crispy->smoothscaling); M_BindIntVariable("crispy_vsync", &crispy->vsync); M_BindIntVariable("crispy_widescreen", &crispy->widescreen); diff --git a/src/hexen/in_lude.c b/src/hexen/in_lude.c index bac465d125..2d5459071a 100644 --- a/src/hexen/in_lude.c +++ b/src/hexen/in_lude.c @@ -99,7 +99,11 @@ static char *HubText; void IN_Start(void) { int i; +#ifndef CRISPY_TRUECOLOR I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE)); +#else + I_SetPalette(0); +#endif InitStats(); LoadPics(); intermission = true; diff --git a/src/hexen/mn_menu.c b/src/hexen/mn_menu.c index 4ae950df30..738c594e13 100644 --- a/src/hexen/mn_menu.c +++ b/src/hexen/mn_menu.c @@ -1273,7 +1273,7 @@ static void SCSaveGame(int option) // [crispy] generate a default save slot name when saving to an empty slot if (!strcmp(ptr, "") /* && joypadsave */ || (strlen(oldSlotText) >= 3 && !strncmp(oldSlotText, "HUB", 3))) { - (void) SetDefaultSaveName(0); // [crispy] unused + SetDefaultSaveName(option); M_snprintf(ptr, sizeof(oldSlotText), "HUB %d.%d, %s", P_GetMapCluster(gamemap), gamemap, class_str[PlayerClass[consoleplayer]]); @@ -1948,7 +1948,11 @@ boolean MN_Responder(event_t * event) askforquit = false; typeofask = 0; paused = false; +#ifndef CRISPY_TRUECOLOR I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE)); +#else + I_SetPalette(0); +#endif H2_StartTitle(); // go to intro/demo mode. return false; case 3: @@ -2187,6 +2191,11 @@ boolean MN_Responder(event_t * event) crispy->gamma = 0; } SB_PaletteFlash(true); // force change +#ifdef CRISPY_TRUECOLOR + R_InitTrueColormaps(LevelUseFullBright ? "COLORMAP" : "FOGMAP"); + BorderNeedRefresh = true; + SB_state = -1; +#endif P_SetMessage(&players[consoleplayer], GammaText[crispy->gamma], false); return true; @@ -2215,7 +2224,8 @@ boolean MN_Responder(event_t * event) if (!MenuActive) { - if (key == key_menu_activate || gamestate == GS_DEMOSCREEN || demoplayback) + // [crispy] don't pop up the menu on other keys during a demo + if (key == key_menu_activate) //|| gamestate == GS_DEMOSCREEN || demoplayback) { MN_ActivateMenu(); return (true); @@ -2593,7 +2603,11 @@ void MN_DrawInfo(void) { lumpindex_t lumpindex; // [crispy] +#ifndef CRISPY_TRUECOLOR I_SetPalette(W_CacheLumpName("PLAYPAL", PU_CACHE)); +#else + I_SetPalette(0); +#endif // [crispy] Refactor to allow for use of V_DrawFullscreenRawOrPatch @@ -2699,7 +2713,8 @@ static void DrawMouseMenu(void) static void M_DrawCrispnessBackground(void) { - byte *src, *dest; + byte *src; + pixel_t *dest; src = W_CacheLumpName("F_022", PU_CACHE); dest = I_VideoBuffer; diff --git a/src/hexen/p_map.c b/src/hexen/p_map.c index be6a292843..00c4fdbbe5 100644 --- a/src/hexen/p_map.c +++ b/src/hexen/p_map.c @@ -189,6 +189,10 @@ boolean P_TeleportMove(mobj_t * thing, fixed_t x, fixed_t y) thing->x = x; thing->y = y; + // [AM] Don't interpolate mobjs that pass + // through teleporters + thing->interp = false; + P_SetThingPosition(thing); return true; diff --git a/src/hexen/p_pspr.c b/src/hexen/p_pspr.c index b9a169a1d1..a036676b07 100644 --- a/src/hexen/p_pspr.c +++ b/src/hexen/p_pspr.c @@ -1187,9 +1187,13 @@ void A_MStaffAttack(mobj_t *actor, player_t *player, pspdef_t *psp) { player->damagecount = 0; player->bonuscount = 0; +#ifndef CRISPY_TRUECOLOR I_SetPalette((byte *) W_CacheLumpNum(W_GetNumForName("playpal"), PU_CACHE) + STARTSCOURGEPAL * 768); +#else + I_SetPalette(STARTSCOURGEPAL); +#endif } } @@ -1210,8 +1214,12 @@ void A_MStaffPalette(mobj_t *actor, player_t *player, pspdef_t *psp) { // reset back to original playpal pal = 0; } +#ifndef CRISPY_TRUECOLOR I_SetPalette((byte *) W_CacheLumpNum(W_GetNumForName("playpal"), PU_CACHE) + pal * 768); +#else + I_SetPalette(pal); +#endif } } @@ -1929,8 +1937,12 @@ void A_CHolyAttack(mobj_t *actor, player_t *player, pspdef_t *psp) { player->damagecount = 0; player->bonuscount = 0; +#ifndef CRISPY_TRUECOLOR I_SetPalette((byte *) W_CacheLumpNum(W_GetNumForName("playpal"), PU_CACHE) + STARTHOLYPAL * 768); +#else + I_SetPalette(STARTHOLYPAL); +#endif } S_StartSound(player->mo, SFX_CHOLY_FIRE); } @@ -1952,8 +1964,12 @@ void A_CHolyPalette(mobj_t *actor, player_t *player, pspdef_t *psp) { // reset back to original playpal pal = 0; } +#ifndef CRISPY_TRUECOLOR I_SetPalette((byte *) W_CacheLumpNum(W_GetNumForName("playpal"), PU_CACHE) + pal * 768); +#else + I_SetPalette(pal); +#endif } } diff --git a/src/hexen/p_setup.c b/src/hexen/p_setup.c index 39191308cd..5c9e439a7c 100644 --- a/src/hexen/p_setup.c +++ b/src/hexen/p_setup.c @@ -178,6 +178,10 @@ void P_LoadVertexes(int lump) { li->x = SHORT(ml->x) << FRACBITS; li->y = SHORT(ml->y) << FRACBITS; + + // [crispy] initialize vertex coordinates *only* used in rendering + li->r_x = li->x; + li->r_y = li->y; } W_ReleaseLumpNum(lump); @@ -232,6 +236,17 @@ void P_LoadSegs(int lump) // [crispy] fix long wall wobble +static angle_t anglediff(angle_t a, angle_t b) +{ + if (b > a) + return anglediff(b, a); + + if (a - b < ANG180) + return a - b; + else // [crispy] wrap around + return b - a; +} + static void P_SegLengths (void) { int i; @@ -245,6 +260,17 @@ static void P_SegLengths (void) dy = li->v2->y - li->v1->y; li->length = (uint32_t)(sqrt((double)dx*dx + (double)dy*dy)/2); + + // [crispy] re-calculate angle used for rendering + viewx = li->v1->r_x; + viewy = li->v1->r_y; + li->r_angle = R_PointToAngleCrispy(li->v2->r_x, li->v2->r_y); + // [crispy] more than just a little adjustment? + // back to the original angle then + if (anglediff(li->r_angle, li->angle) > ANG60/2) + { + li->r_angle = li->angle; + } } } @@ -807,6 +833,12 @@ void P_SetupLevel(int episode, int map, int playermask, skill_t skill) LevelUseFullBright = false; } +#ifdef CRISPY_TRUECOLOR + // [crispy] If true color is compiled in but disabled as an option, + // we still need to re-generate colormaps for proper colormaps[] array colors. + R_InitTrueColormaps(LevelUseFullBright ? "COLORMAP" : "FOGMAP"); +#endif + // preload graphics if (precache) R_PrecacheLevel(); diff --git a/src/hexen/p_user.c b/src/hexen/p_user.c index b6971b70de..b2ef415bd9 100644 --- a/src/hexen/p_user.c +++ b/src/hexen/p_user.c @@ -431,7 +431,11 @@ void P_DeathThink(player_t * player) { if (player == &players[consoleplayer]) { +#ifndef CRISPY_TRUECOLOR I_SetPalette((byte *) W_CacheLumpName("PLAYPAL", PU_CACHE)); +#else + I_SetPalette(0); +#endif inv_ptr = 0; curpos = 0; newtorch = 0; diff --git a/src/hexen/po_man.c b/src/hexen/po_man.c index 541e410271..459b6a69a3 100644 --- a/src/hexen/po_man.c +++ b/src/hexen/po_man.c @@ -717,7 +717,7 @@ static void RotatePolyVertices(polyobj_t *po, angle_t angle) vertex_t *prevPts; int an; - an = (po->angle - po->rtheta + angle) >> ANGLETOFINESHIFT; + an = (po->angle + angle) >> ANGLETOFINESHIFT; segList = po->segs; originalPts = po->originalPts; prevPts = po->prevPts; @@ -731,7 +731,29 @@ static void RotatePolyVertices(polyobj_t *po, angle_t angle) (*segList)->v1->y = originalPts->y; RotatePt(an, &(*segList)->v1->x, &(*segList)->v1->y, po->startSpot.x, po->startSpot.y); - (*segList)->angle += angle; + (*segList)->v1->r_x = (*segList)->v1->x; + (*segList)->v1->r_y = (*segList)->v1->y; + } +} + +static void RotatePolyVerticesRendering(polyobj_t *po, angle_t angle) +{ + int count; + seg_t **segList; + vertex_t *originalPts; + int an; + + an = (po->angle - po->rtheta + angle) >> ANGLETOFINESHIFT; + segList = po->segs; + originalPts = po->originalPts; + + for (count = po->numsegs; count; count--, segList++, originalPts++) + { + (*segList)->v1->r_x = originalPts->x; + (*segList)->v1->r_y = originalPts->y; + RotatePt(an, &(*segList)->v1->r_x, &(*segList)->v1->r_y, po->startSpot.x, + po->startSpot.y); + (*segList)->r_angle += angle; } } @@ -757,6 +779,34 @@ static void TranslatePolyVertices(polyobj_t *po, fixed_t dx, fixed_t dy) { (*segList)->v1->x += dx; (*segList)->v1->y += dy; + (*segList)->v1->r_x = (*segList)->v1->x; + (*segList)->v1->r_y = (*segList)->v1->y; + } + } +} + +// [crispy] +static void TranslatePolyVerticesRendering(polyobj_t *po, fixed_t dx, fixed_t dy) +{ + seg_t **segList; + seg_t **veryTempSeg; + int count; + + segList = po->segs; + + for (count = po->numsegs; count; count--, segList++) + { + for (veryTempSeg = po->segs; veryTempSeg != segList; veryTempSeg++) + { + if ((*veryTempSeg)->v1 == (*segList)->v1) + { + break; + } + } + if (veryTempSeg == segList) + { + (*segList)->v1->r_x += dx; + (*segList)->v1->r_y += dy; } } } @@ -786,8 +836,7 @@ boolean PO_MovePolyobj(int num, int x, int y, boolean interp) prevPts = po->prevPts; blocked = false; - // [crispy] sync poly vertices every gametic - TranslatePolyVertices(po, x + po->rx, y + po->ry); + TranslatePolyVertices(po, x, y); po->rx = 0; po->ry = 0; @@ -842,11 +891,11 @@ boolean PO_MovePolyobj(int num, int x, int y, boolean interp) po->startSpot.y += y; LinkPolyobj(po); - // [crispy] Move points back after calculating bounding boxes. We'll handle - // the actual movement in PO_InterpolatePolyObjects(). + // [crispy] Handle the rendering vertex movement in + // PO_InterpolatePolyObjects(). if (crispy->uncapped && interp) { - TranslatePolyVertices(po, -x, -y); + TranslatePolyVerticesRendering(po, -x, -y); po->dx = x; po->dy = y; po->rx = x; @@ -924,7 +973,7 @@ void PO_InterpolatePolyObjects(void) } } - TranslatePolyVertices(po, dx, dy); + TranslatePolyVerticesRendering(po, dx, dy); po->rx -= dx; po->ry -= dy; } @@ -939,7 +988,7 @@ void PO_InterpolatePolyObjects(void) interpangle = po->rtheta; } - RotatePolyVertices(po, interpangle); + RotatePolyVerticesRendering(po, interpangle); po->rtheta -= interpangle; } } @@ -991,7 +1040,6 @@ boolean PO_RotatePolyobj(int num, angle_t angle, boolean interp) UnLinkPolyobj(po); - RotatePolyVertices(po, po->rtheta); // [crispy] po->rtheta = po->dtheta = 0; // [crispy] RotatePolyVertices(po, angle); // [crispy] prevPts get set here. @@ -1009,6 +1057,8 @@ boolean PO_RotatePolyobj(int num, angle_t angle, boolean interp) UpdateSegBBox(*segList); (*segList)->linedef->validcount = validcount; } + (*segList)->angle += angle; + (*segList)->r_angle = (*segList)->angle; } if (blocked) { @@ -1036,19 +1086,18 @@ boolean PO_RotatePolyobj(int num, angle_t angle, boolean interp) po->angle += angle; LinkPolyobj(po); - // [crispy] Move points back after calculating bounding boxes. We'll handle - // the actual movement in PO_InterpolatePolyObjects(). - // Note: 180 degree rotations can be called for during loading of the - // level. Don't try to interpolate those. + // [crispy] Handle the movement of rendering angle and vertices in + // PO_InterpolatePolyObjects(). Note: 180 degree rotations can be called + // for during loading of the level. Don't try to interpolate those. if (crispy->uncapped && interp && angle != ANG180) { segList = po->segs; prevPts = po->prevPts; for (count = po->numsegs; count; count--, segList++, prevPts++) { - (*segList)->v1->x = prevPts->x; - (*segList)->v1->y = prevPts->y; - (*segList)->angle -= angle; + (*segList)->v1->r_x = prevPts->x; + (*segList)->v1->r_y = prevPts->y; + (*segList)->r_angle -= angle; } po->rtheta = po->dtheta = angle; } @@ -1540,6 +1589,8 @@ static void TranslateToStartSpot(int tag, int originX, int originY) { // the point hasn't been translated, yet (*tempSeg)->v1->x -= deltaX; (*tempSeg)->v1->y -= deltaY; + (*tempSeg)->v1->r_x -= deltaX; + (*tempSeg)->v1->r_y -= deltaY; } avg.x += (*tempSeg)->v1->x >> FRACBITS; avg.y += (*tempSeg)->v1->y >> FRACBITS; diff --git a/src/hexen/r_bsp.c b/src/hexen/r_bsp.c index c475744781..1165e1a080 100644 --- a/src/hexen/r_bsp.c +++ b/src/hexen/r_bsp.c @@ -246,8 +246,9 @@ void R_AddLine(seg_t * line) // OPTIMIZE: quickly reject orthogonal back sides - angle1 = R_PointToAngle(line->v1->x, line->v1->y); - angle2 = R_PointToAngle(line->v2->x, line->v2->y); + // [crispy] remove slime trails + angle1 = R_PointToAngleCrispy(line->v1->r_x, line->v1->r_y); + angle2 = R_PointToAngleCrispy(line->v2->r_x, line->v2->r_y); // // clip to view edges @@ -385,8 +386,8 @@ boolean R_CheckBBox(fixed_t * bspcoord) // // check clip list for an open space // - angle1 = R_PointToAngle(x1, y1) - viewangle; - angle2 = R_PointToAngle(x2, y2) - viewangle; + angle1 = R_PointToAngleCrispy(x1, y1) - viewangle; + angle2 = R_PointToAngleCrispy(x2, y2) - viewangle; span = angle1 - angle2; if (span >= ANG180) diff --git a/src/hexen/r_data.c b/src/hexen/r_data.c index b0a3560966..e9eeed0980 100644 --- a/src/hexen/r_data.c +++ b/src/hexen/r_data.c @@ -14,6 +14,7 @@ // GNU General Public License for more details. // +#include // [crispy] calloc() #include "h2def.h" #include "i_system.h" @@ -55,7 +56,7 @@ int *texturewidthmask; fixed_t *textureheight; // needed for texture pegging int *texturecompositesize; short **texturecolumnlump; -unsigned short **texturecolumnofs; +unsigned **texturecolumnofs; // [crispy] was short byte **texturecomposite; const byte **texturebrightmap; // [crispy] brightmaps @@ -67,6 +68,7 @@ fixed_t *spriteoffset; fixed_t *spritetopoffset; lighttable_t *colormaps; +lighttable_t *pal_color; // [crispy] array holding palette colors for true color mode /* @@ -83,53 +85,73 @@ will have new column_ts generated. ============================================================================== */ -/* -=================== -= -= R_DrawColumnInCache -= -= Clip and draw a column from a patch into a cached post -= -=================== -*/ +// [crispy] replace R_DrawColumnInCache(), R_GenerateComposite() and +// R_GenerateLookup() with Lee Killough's implementations found in MBF to fix +// Medusa bug taken from mbfsrc/R_DATA.C:136-425 +// +// R_DrawColumnInCache +// Clip and draw a column from a patch into a cached post. +// +// Rewritten by Lee Killough for performance and to fix Medusa bug +// void R_DrawColumnInCache(column_t * patch, byte * cache, int originy, - int cacheheight) + int cacheheight, byte * marks) { int count, position; byte *source; + int top = -1; while (patch->topdelta != 0xff) { - source = (byte *) patch + 3; + // [crispy] support for DeePsea tall patches + if (patch->topdelta <= top) + { + top += patch->topdelta; + } + else + { + top = patch->topdelta; + } + source = (byte *)patch + 3; count = patch->length; - position = originy + patch->topdelta; + position = originy + top; + if (position < 0) { count += position; position = 0; } + if (position + count > cacheheight) count = cacheheight - position; + if (count > 0) + { memcpy(cache + position, source, count); - patch = (column_t *) ((byte *) patch + patch->length + 4); + // killough 4/9/98: remember which cells in column have been drawn, + // so that column can later be converted into a series of posts, to + // fix the Medusa bug. + + memset(marks + position, 0xff, count); + } + + patch = (column_t *)((byte *)patch + patch->length + 4); } } -/* -=================== -= -= R_GenerateComposite -= -=================== -*/ +// +// R_GenerateComposite +// Using the texture definition, the composite texture is created from the +// patches, and each column is cached. +// +// Rewritten by Lee Killough for performance and to fix Medusa bug void R_GenerateComposite(int texnum) { - byte *block; + byte* block; texture_t *texture; texpatch_t *patch; patch_t *realpatch; @@ -137,14 +159,24 @@ void R_GenerateComposite(int texnum) int i; column_t *patchcol; short *collump; - unsigned short *colofs; + unsigned* colofs; // killough 4/9/98: make 32-bit + byte *marks; // killough 4/9/98: transparency marks + byte *source; // killough 4/9/98: temporary column texture = textures[texnum]; + block = Z_Malloc(texturecompositesize[texnum], PU_STATIC, &texturecomposite[texnum]); + collump = texturecolumnlump[texnum]; colofs = texturecolumnofs[texnum]; + // killough 4/9/98: marks to identify transparent regions in merged textures + marks = calloc(texture->width, texture->height); + + // [crispy] initialize composite background to palette index 0 (usually black) + memset(block, 0, texturecompositesize[texnum]); + // // composite the columns together // @@ -166,41 +198,111 @@ void R_GenerateComposite(int texnum) { if (collump[x] >= 0) continue; // column does not have multiple patches + patchcol = (column_t *) ((byte *) realpatch + LONG(realpatch->columnofs[x - x1])); - R_DrawColumnInCache(patchcol, block + colofs[x], patch->originy, - texture->height); + R_DrawColumnInCache(patchcol, block + colofs[x], + patch->originy, + texture->height, + marks + x * texture->height); } } -// now that the texture has been built, it is purgable + // killough 4/9/98: Next, convert multipatched columns into true columns, + // to fix Medusa bug while still allowing for transparent regions. + + source = I_Realloc(NULL, texture->height); // temporary column + for (i = 0; i < texture->width; i++) + { + if (collump[i] == -1) // process only multipatched columns + { + column_t *col = + (column_t *) (block + colofs[i] - 3); // cached column + const byte *mark = marks + i * texture->height; + int j = 0; + // [crispy] absolute topdelta for first 254 pixels, then relative + int abstop, reltop = 0; + boolean relative = false; + + // save column in temporary so we can shuffle it around + memcpy(source, (byte *) col + 3, texture->height); + + for (;;) // reconstruct the column by scanning transparency marks + { + unsigned len; // killough 12/98 + + while (j < texture->height && reltop < 254 && + !mark[j]) // skip transparent cells + j++, reltop++; + + if (j >= texture->height) // if at end of column + { + col->topdelta = -1; // end-of-column marker + break; + } + + // [crispy] absolute topdelta for first 254 pixels, then relative + col->topdelta = + relative ? reltop : j; // starting offset of post + + // [crispy] once we pass the 254 boundary, topdelta becomes relative + if ((abstop = j) >= 254) + { + relative = true; + reltop = 0; + } + + // killough 12/98: Use 32-bit len counter, to support tall 1s + // multipatched textures + + for (len = 0; j < texture->height && reltop < 254 && mark[j]; + j++, reltop++) + len++; // count opaque cells + + col->length = len; // killough 12/98: intentionally truncate length + + // copy opaque cells from the temporary back into the column + memcpy((byte *) col + 3, source + abstop, len); + col = (column_t *) ((byte *) col + len + 4); // next post + } + } + } + + free(source); // free temporary column + free(marks); // free transparency marks + + // Now that the texture has been built in column cache, it is purgable + // from zone memory. Z_ChangeTag(block, PU_CACHE); } -/* -=================== -= -= R_GenerateLookup -= -=================== -*/ +// +// R_GenerateLookup +// +// Rewritten by Lee Killough for performance and to fix Medusa bug +// void R_GenerateLookup(int texnum) { texture_t *texture; byte *patchcount; // [texture->width] + byte *postcount; // killough 4/9/98: keep count of posts in addition to patches. texpatch_t *patch; patch_t *realpatch; int x, x1, x2; int i; short *collump; - unsigned short *colofs; + unsigned *colofs; // killough 4/9/98: make 32-bit + int csize = 0; // killough 10/98 + int err = 0; // killough 10/98 texture = textures[texnum]; - texturecomposite[texnum] = 0; // composited not created yet + // Composited texture not created yet. + texturecomposite[texnum] = 0; + texturecompositesize[texnum] = 0; collump = texturecolumnlump[texnum]; colofs = texturecolumnofs[texnum]; @@ -211,7 +313,10 @@ void R_GenerateLookup(int texnum) // all done // patchcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &patchcount); + postcount = (byte *) Z_Malloc(texture->width, PU_STATIC, &postcount); memset(patchcount, 0, texture->width); + memset(postcount, 0, texture->width); + for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) { @@ -232,26 +337,101 @@ void R_GenerateLookup(int texnum) } } + // killough 4/9/98: keep a count of the number of posts in column, + // to fix Medusa bug while allowing for transparent multipatches. + // + // killough 12/98: + // Post counts are only necessary if column is multipatched, + // so skip counting posts if column comes from a single patch. + // This allows arbitrarily tall textures for 1s walls. + // + // If texture is >= 256 tall, assume it's 1s, and hence it has + // only one post per column. This avoids crashes while allowing + // for arbitrarily tall multipatched 1s textures. + + if (texture->patchcount > 1 && texture->height < 256) + { + // killough 12/98: Warn about a common column construction bug + unsigned limit = texture->height * 3 + 3; // absolute column size limit + + for (i = texture->patchcount, patch = texture->patches; --i >= 0;) + { + int pat = patch->patch; + const patch_t *realpatch = W_CacheLumpNum(pat, PU_CACHE); + int x, x1 = patch++->originx, x2 = x1 + SHORT(realpatch->width); + const int *cofs = realpatch->columnofs - x1; + + if (x2 > texture->width) + x2 = texture->width; + if (x1 < 0) + x1 = 0; + + for (x = x1; x < x2; x++) + { + if (patchcount[x] > 1) // Only multipatched columns + { + const column_t *col = + (const column_t *) ((const byte *) realpatch + + LONG(cofs[x])); + const byte *base = (const byte *) col; + + // count posts + for (; col->topdelta != 0xff; postcount[x]++) + { + if ((unsigned) ((const byte *) col - base) <= limit) + col = (const column_t *) ((const byte *) col + + col->length + 4); + else + break; + } + } + } + } + } + for (x = 0; x < texture->width; x++) { - if (!patchcount[x]) + if (!patchcount[x] && !err++) // killough 10/98: non-verbose output { - ST_Message("R_GenerateLookup: column without a patch (%s)\n", - texture->name); + // [crispy] fix absurd texture name in error message + printf("R_GenerateLookup: column without a patch (%.8s)\n", + texture->name); + // [crispy] do not return yet + /* return; + */ } -// I_Error ("R_GenerateLookup: column without a patch"); - if (patchcount[x] > 1) + // I_Error ("R_GenerateLookup: column without a patch"); + + // [crispy] treat patch-less columns the same as multi-patched + if (patchcount[x] > 1 || !patchcount[x]) { - collump[x] = -1; // use the cached block - colofs[x] = texturecompositesize[texnum]; + // killough 1/25/98, 4/9/98: + // + // Fix Medusa bug, by adding room for column header + // and trailer bytes for each post in merged column. + // For now, just allocate conservatively 4 bytes + // per post per patch per column, since we don't + // yet know how many posts the merged column will + // require, and it's bounded above by this limit. + collump[x] = -1; // use the cached block + colofs[x] = csize + 3; // three header bytes in a column + // killough 12/98: add room for one extra post + csize += 4 * postcount[x] + 5; // 1 stop byte plus 4 bytes per post + } + + // [crispy] remove limit + /* if (texturecompositesize[texnum] > 0x10000 - texture->height) I_Error("R_GenerateLookup: texture %i is >64k", texnum); - texturecompositesize[texnum] += texture->height; - } + */ + csize += texture->height; // height bytes of texture data } + texturecompositesize[texnum] += csize; + Z_Free(patchcount); + Z_Free(postcount); } @@ -341,7 +521,7 @@ void R_InitTextures(void) textures = Z_Malloc(numtextures * sizeof(texture_t *), PU_STATIC, 0); texturecolumnlump = Z_Malloc(numtextures * sizeof(short *), PU_STATIC, 0); - texturecolumnofs = Z_Malloc(numtextures * sizeof(short *), PU_STATIC, 0); + texturecolumnofs = Z_Malloc(numtextures * sizeof(*texturecolumnofs), PU_STATIC, 0); texturecomposite = Z_Malloc(numtextures * sizeof(byte *), PU_STATIC, 0); texturecompositesize = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0); texturewidthmask = Z_Malloc(numtextures * sizeof(int), PU_STATIC, 0); @@ -384,7 +564,8 @@ void R_InitTextures(void) texture->name); } texturecolumnlump[i] = Z_Malloc(texture->width * sizeof(short), PU_STATIC, 0); - texturecolumnofs[i] = Z_Malloc(texture->width * sizeof(short), PU_STATIC, 0); + texturecolumnofs[i] = Z_Malloc(texture->width * sizeof(**texturecolumnofs), + PU_STATIC, 0); j = 1; while (j * 2 <= texture->width) j <<= 1; @@ -482,6 +663,7 @@ void R_InitSpriteLumps(void) ================= */ +#ifndef CRISPY_TRUECOLOR void R_InitColormaps(void) { int lump, length; @@ -493,9 +675,84 @@ void R_InitColormaps(void) length = W_LumpLength(lump); colormaps = Z_Malloc(length, PU_STATIC, 0); W_ReadLump(lump, colormaps); +} - // [crispy] initialize color translation and color string tables - { +#else + +// [crispy] Our own function to generate colormaps for normal and foggy levels. +void R_InitTrueColormaps(char *current_colormap) +{ + int c, i, j = 0; + byte r, g, b; + + byte *const playpal = W_CacheLumpName("PLAYPAL", PU_STATIC); + byte *const colormap = W_CacheLumpName(current_colormap, PU_STATIC); + + if (!colormaps) + { + colormaps = (lighttable_t*) Z_Malloc((NUMCOLORMAPS + 1) * 256 * sizeof(lighttable_t), PU_STATIC, 0); + } + + if (crispy->truecolor) + { + // [crispy] If level is allowed to use full bright mode, fade colormaps to + // black (0) color. Otherwise, fade to gray (147) to emulate FOGMAP table. + const int fade_color = LevelUseFullBright ? 0 : 147; + + for (c = 0; c < NUMCOLORMAPS; c++) + { + const float scale = 1. * c / NUMCOLORMAPS; + + for (i = 0; i < 256; i++) + { + const byte k = colormap[i]; + + r = gamma2table[crispy->gamma][playpal[3 * k + 0]] * (1. - scale) + gamma2table[crispy->gamma][fade_color] * scale; + g = gamma2table[crispy->gamma][playpal[3 * k + 1]] * (1. - scale) + gamma2table[crispy->gamma][fade_color] * scale; + b = gamma2table[crispy->gamma][playpal[3 * k + 2]] * (1. - scale) + gamma2table[crispy->gamma][fade_color] * scale; + + colormaps[j++] = 0xff000000 | (r << 16) | (g << 8) | b; + } + } + } + else + { + for (c = 0; c < NUMCOLORMAPS; c++) + { + for (i = 0; i < 256; i++) + { + r = gamma2table[crispy->gamma][playpal[3 * colormap[c * 256 + i] + 0]] & ~3; + g = gamma2table[crispy->gamma][playpal[3 * colormap[c * 256 + i] + 1]] & ~3; + b = gamma2table[crispy->gamma][playpal[3 * colormap[c * 256 + i] + 2]] & ~3; + + colormaps[j++] = 0xff000000 | (r << 16) | (g << 8) | b; + } + } + } + + W_ReleaseLumpName(current_colormap); + + if (!pal_color) + { + pal_color = (pixel_t*) Z_Malloc(256 * sizeof(pixel_t), PU_STATIC, 0); + } + + for (i = 0, j = 0; i < 256; i++) + { + r = gamma2table[crispy->gamma][playpal[3 * i + 0]]; + g = gamma2table[crispy->gamma][playpal[3 * i + 1]]; + b = gamma2table[crispy->gamma][playpal[3 * i + 2]]; + + pal_color[j++] = 0xff000000 | (r << 16) | (g << 8) | b; + } + + W_ReleaseLumpName("PLAYPAL"); +} +#endif + +// [crispy] initialize color translation and color string tables +static void R_InitHSVColors(void) +{ byte *playpal = W_CacheLumpName("PLAYPAL", PU_STATIC); char c[3]; int i, j; @@ -516,7 +773,6 @@ void R_InitColormaps(void) } W_ReleaseLumpName("PLAYPAL"); - } } @@ -537,7 +793,14 @@ void R_InitData(void) R_InitSpriteLumps(); // [crispy] Initialize and generate gamma-correction levels. I_SetGammaTable(); +#ifndef CRISPY_TRUECOLOR R_InitColormaps(); +#else + // [crispy] Generate initial colormaps[] array from standard COLORMAP. + R_InitTrueColormaps("COLORMAP"); +#endif + // [crispy] initialize color translation and color string tables + R_InitHSVColors(); } //============================================================================= diff --git a/src/hexen/r_draw.c b/src/hexen/r_draw.c index d9dc69bdc4..93fb095aef 100644 --- a/src/hexen/r_draw.c +++ b/src/hexen/r_draw.c @@ -20,6 +20,7 @@ #include "i_video.h" #include "r_local.h" #include "v_video.h" +#include "v_trans.h" // [crispy] blending functions /* @@ -30,7 +31,7 @@ files only know about ccordinates, not the architecture of the frame buffer. byte *viewimage; int viewwidth, scaledviewwidth, viewheight, viewwindowx, viewwindowy; -byte *ylookup[MAXHEIGHT]; +pixel_t *ylookup[MAXHEIGHT]; int columnofs[MAXWIDTH]; //byte translations[3][256]; // color tables for different players @@ -61,7 +62,7 @@ int dccount; // just for profiling void R_DrawColumn(void) { int count; - byte *dest; + pixel_t *dest; fixed_t frac, fracstep; int heightmask = dc_texheight - 1; // [crispy] @@ -116,7 +117,7 @@ void R_DrawColumn(void) void R_DrawColumnLow(void) { int count; - byte *dest; + pixel_t *dest; fixed_t frac, fracstep; int heightmask = dc_texheight - 1; // [crispy] @@ -172,7 +173,7 @@ void R_DrawColumnLow(void) void R_DrawTLColumn(void) { int count; - byte *dest; + pixel_t *dest; fixed_t frac, fracstep; int heightmask = dc_texheight - 1; // [crispy] @@ -210,9 +211,14 @@ void R_DrawTLColumn(void) { // [crispy] brightmaps const byte source = dc_source[frac >> FRACBITS]; +#ifndef CRISPY_TRUECOLOR *dest = tinttable[*dest + (dc_colormap[dc_brightmap[source]][source] << 8)]; +#else + const pixel_t destrgb = dc_colormap[dc_brightmap[source]][source]; + *dest = blendfunc(*dest, destrgb); +#endif dest += SCREENWIDTH; if ((frac += fracstep) >= heightmask) frac -= heightmask; @@ -224,9 +230,14 @@ void R_DrawTLColumn(void) { // [crispy] brightmaps const byte source = dc_source[(frac >> FRACBITS) & heightmask]; +#ifndef CRISPY_TRUECOLOR *dest = tinttable[*dest + (dc_colormap[dc_brightmap[source]][source] << 8)]; +#else + const pixel_t destrgb = dc_colormap[dc_brightmap[source]][source]; + *dest = blendfunc(*dest, destrgb); +#endif dest += SCREENWIDTH; frac += fracstep; } while (count--); @@ -242,7 +253,7 @@ void R_DrawTLColumn(void) void R_DrawAltTLColumn(void) { int count; - byte *dest; + pixel_t *dest; fixed_t frac, fracstep; int heightmask = dc_texheight - 1; // [crispy] @@ -280,8 +291,13 @@ void R_DrawAltTLColumn(void) { // [crispy] brightmaps const byte source = dc_source[frac >> FRACBITS]; +#ifndef CRISPY_TRUECOLOR *dest = tinttable[((*dest) << 8) + dc_colormap[dc_brightmap[source]][source]]; +#else + const pixel_t destrgb = dc_colormap[dc_brightmap[source]][source]; + *dest = blendfunc(*dest, destrgb); +#endif dest += SCREENWIDTH; if ((frac += fracstep) >= heightmask) frac -= heightmask; @@ -293,8 +309,13 @@ void R_DrawAltTLColumn(void) { // [crispy] brightmaps const byte source = dc_source[(frac >> FRACBITS) & heightmask]; +#ifndef CRISPY_TRUECOLOR *dest = tinttable[((*dest) << 8) + dc_colormap[dc_brightmap[source]][source]]; +#else + const pixel_t destrgb = dc_colormap[dc_brightmap[source]][source]; + *dest = blendfunc(*dest, destrgb); +#endif dest += SCREENWIDTH; frac += fracstep; } while (count--); @@ -315,7 +336,7 @@ byte *translationtables; void R_DrawTranslatedColumn(void) { int count; - byte *dest; + pixel_t *dest; fixed_t frac, fracstep; count = dc_yh - dc_yl; @@ -352,7 +373,7 @@ void R_DrawTranslatedColumn(void) void R_DrawTranslatedTLColumn(void) { int count; - byte *dest; + pixel_t *dest; fixed_t frac, fracstep; count = dc_yh - dc_yl; @@ -373,9 +394,14 @@ void R_DrawTranslatedTLColumn(void) { // [crispy] brightmaps byte src = dc_translation[dc_source[frac >> FRACBITS]]; +#ifndef CRISPY_TRUECOLOR *dest = tinttable[((*dest) << 8) + dc_colormap[dc_brightmap[src]][src]]; +#else + const pixel_t destrgb = dc_colormap[dc_brightmap[src]][src]; + *dest = blendfunc(*dest, destrgb); +#endif dest += SCREENWIDTH; frac += fracstep; } @@ -431,7 +457,9 @@ void R_InitTranslationTables(void) byte *transLump; int lumpnum; +#ifndef CRISPY_TRUECOLOR V_LoadTintTable(); +#endif // Allocate translation tables translationtables = Z_Malloc(256 * 3 * (maxplayers - 1), PU_STATIC, 0); @@ -468,7 +496,7 @@ int dscount; // just for profiling void R_DrawSpan(void) { fixed_t xfrac, yfrac; - byte *dest; + pixel_t *dest; int count, spot; #ifdef RANGECHECK @@ -496,7 +524,7 @@ void R_DrawSpan(void) void R_DrawSpanLow(void) { fixed_t xfrac, yfrac; - byte *dest; + pixel_t *dest; int count, spot; #ifdef RANGECHECK @@ -562,7 +590,8 @@ boolean BorderNeedRefresh; void R_DrawViewBorder(void) { - byte *src, *dest; + byte *src; + pixel_t *dest; int x, y; if (scaledviewwidth == SCREENWIDTH) @@ -615,7 +644,8 @@ boolean BorderTopRefresh; void R_DrawTopBorder(void) { - byte *src, *dest; + byte *src; + pixel_t *dest; if (scaledviewwidth == SCREENWIDTH) return; diff --git a/src/hexen/r_local.h b/src/hexen/r_local.h index 741a2219df..5c55258945 100644 --- a/src/hexen/r_local.h +++ b/src/hexen/r_local.h @@ -63,6 +63,7 @@ typedef struct { fixed_t x, y; + fixed_t r_x, r_y; // [crispy] for rendering only } vertex_t; struct line_s; @@ -170,6 +171,7 @@ typedef struct vertex_t *v1, *v2; fixed_t offset; angle_t angle; + angle_t r_angle; // [crispy] for rendering only side_t *sidedef; line_t *linedef; sector_t *frontsector; @@ -231,7 +233,7 @@ typedef struct ============================================================================== */ -typedef byte lighttable_t; // this could be wider for >8 bit display +typedef pixel_t lighttable_t; // this could be wider for >8 bit display #define MAXVISPLANES 160*8 #define MAXOPENINGS MAXWIDTH*64*4 @@ -293,6 +295,9 @@ typedef struct vissprite_s boolean psprite; // true if psprite int class; // player class (used in translation) fixed_t floorclip; +#ifdef CRISPY_TRUECOLOR + const pixel_t (*blendfunc)(const pixel_t fg, const pixel_t bg); +#endif } vissprite_t; @@ -397,6 +402,7 @@ extern void R_InterpolateTextureOffsets (void); int R_PointOnSide(fixed_t x, fixed_t y, node_t * node); int R_PointOnSegSide(fixed_t x, fixed_t y, seg_t * line); angle_t R_PointToAngle(fixed_t x, fixed_t y); +angle_t R_PointToAngleCrispy(fixed_t x, fixed_t y); angle_t R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2); fixed_t R_PointToDist(fixed_t x, fixed_t y); fixed_t R_ScaleFromGlobalAngle(angle_t visangle); @@ -499,7 +505,7 @@ extern fixed_t *textureheight; // needed for texture pegging extern fixed_t *spritewidth; // needed for pre rendering (fracs) extern fixed_t *spriteoffset; extern fixed_t *spritetopoffset; -extern lighttable_t *colormaps; +extern lighttable_t *colormaps, *pal_color; extern int firstflat; extern int numflats; @@ -513,6 +519,9 @@ byte *R_GetColumn(int tex, int col); void R_InitData(void); void R_PrecacheLevel(void); +#ifdef CRISPY_TRUECOLOR +extern void R_InitTrueColormaps(char *current_colormap); +#endif // // R_things.c @@ -563,7 +572,7 @@ extern int dc_yh; extern fixed_t dc_iscale; extern fixed_t dc_texturemid; extern byte *dc_source; // first pixel in a column -extern byte *ylookup[MAXHEIGHT]; +extern pixel_t *ylookup[MAXHEIGHT]; extern int columnofs[MAXWIDTH]; extern int dc_texheight; // [crispy] extern const byte *dc_brightmap; diff --git a/src/hexen/r_main.c b/src/hexen/r_main.c index 5aac24fdd4..05e0e5ce80 100644 --- a/src/hexen/r_main.c +++ b/src/hexen/r_main.c @@ -188,17 +188,21 @@ int R_PointOnSegSide(fixed_t x, fixed_t y, seg_t * line) } +// [crispy] turned into a general R_PointToAngle() flavor +// called with either slope_div = SlopeDivCrispy() from R_PointToAngleCrispy() +// or slope_div = SlopeDiv() else /* =============================================================================== = -= R_PointToAngle += R_PointToAngleSlope = =============================================================================== */ #define DBITS (FRACBITS-SLOPEBITS) -angle_t R_PointToAngle(fixed_t x, fixed_t y) +angle_t R_PointToAngleSlope(fixed_t x, fixed_t y, + int (*slope_div) (unsigned int num, unsigned int den)) { x -= viewx; y -= viewy; @@ -246,11 +250,38 @@ angle_t R_PointToAngle(fixed_t x, fixed_t y) } +angle_t R_PointToAngle(fixed_t x, fixed_t y) +{ + return R_PointToAngleSlope(x, y, SlopeDiv); +} + +// [crispy] overflow-safe R_PointToAngle() flavor +// called only from R_CheckBBox(), R_AddLine() and P_SegLengths() +angle_t R_PointToAngleCrispy(fixed_t x, fixed_t y) +{ + // [crispy] fix overflows for very long distances + int64_t y_viewy = (int64_t)y - viewy; + int64_t x_viewx = (int64_t)x - viewx; + + // [crispy] the worst that could happen is e.g. INT_MIN-INT_MAX = 2*INT_MIN + if (x_viewx < INT_MIN || x_viewx > INT_MAX || + y_viewy < INT_MIN || y_viewy > INT_MAX) + { + // [crispy] preserving the angle by halfing the distance in both directions + x = x_viewx / 2 + viewx; + y = y_viewy / 2 + viewy; + } + + return R_PointToAngleSlope(x, y, SlopeDivCrispy); +} + + angle_t R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2) { viewx = x1; viewy = y1; - return R_PointToAngle(x2, y2); + // [crispy] R_PointToAngle2() is never called during rendering + return R_PointToAngleSlope(x2, y2, SlopeDiv); } @@ -847,7 +878,9 @@ void R_SetupFrame(player_t * player) if (player->fixedcolormap) { fixedcolormap = colormaps + player->fixedcolormap - * 256 * sizeof(lighttable_t); + // [crispy] sizeof(lighttable_t) not needed in paletted render + // and breaks Torch's fixed colormap indexes in true color render + * 256 /* * sizeof(lighttable_t)*/; walllights = scalelightfixed; for (i = 0; i < MAXLIGHTSCALE; i++) { diff --git a/src/hexen/r_plane.c b/src/hexen/r_plane.c index a27e4ac3dd..edd55fa462 100644 --- a/src/hexen/r_plane.c +++ b/src/hexen/r_plane.c @@ -396,7 +396,7 @@ void R_DrawPlanes(void) byte *tempSource; byte *source; byte *source2; - byte *dest; + pixel_t *dest; int count; int offset; int skyTexture; @@ -475,11 +475,19 @@ void R_DrawPlanes(void) { if (source[frac >> FRACBITS]) { +#ifndef CRISPY_TRUECOLOR *dest = source[frac >> FRACBITS]; +#else + *dest = pal_color[source[frac >> FRACBITS]]; +#endif } else { +#ifndef CRISPY_TRUECOLOR *dest = source2[frac >> FRACBITS]; +#else + *dest = pal_color[source2[frac >> FRACBITS]]; +#endif } dest += SCREENWIDTH; if ((frac += fracstep) >= heightmask) @@ -495,11 +503,19 @@ void R_DrawPlanes(void) { if (source[(frac >> FRACBITS) & heightmask]) { +#ifndef CRISPY_TRUECOLOR *dest = source[(frac >> FRACBITS) & heightmask]; +#else + *dest = pal_color[source[(frac >> FRACBITS) & heightmask]]; +#endif } else { +#ifndef CRISPY_TRUECOLOR *dest = source2[(frac >> FRACBITS) & heightmask]; +#else + *dest = pal_color[source2[(frac >> FRACBITS) & heightmask]]; +#endif } dest += SCREENWIDTH; @@ -553,7 +569,11 @@ void R_DrawPlanes(void) do { +#ifndef CRISPY_TRUECOLOR *dest = source[frac >> FRACBITS]; +#else + *dest = pal_color[source[frac >> FRACBITS]]; +#endif dest += SCREENWIDTH; if ((frac += fracstep) >= heightmask) @@ -567,7 +587,11 @@ void R_DrawPlanes(void) { do { +#ifndef CRISPY_TRUECOLOR *dest = source[(frac >> FRACBITS) & heightmask]; +#else + *dest = pal_color[source[(frac >> FRACBITS) & heightmask]]; +#endif dest += SCREENWIDTH; frac += fracstep; } while (count--); diff --git a/src/hexen/r_segs.c b/src/hexen/r_segs.c index 17791d45ca..97696461be 100644 --- a/src/hexen/r_segs.c +++ b/src/hexen/r_segs.c @@ -513,16 +513,16 @@ void R_StoreWallRange(int start, int stop) // // calculate rw_distance for scale calculation // - rw_normalangle = curline->angle + ANG90; + rw_normalangle = curline->r_angle + ANG90; // [crispy] fix long wall wobble // thank you very much Linguica, e6y and kb1 // http://www.doomworld.com/vb/post/1340718 // shift right to avoid possibility of int64 overflow in rw_distance calculation - dx = ((int64_t)curline->v2->x - curline->v1->x) >> 1; - dy = ((int64_t)curline->v2->y - curline->v1->y) >> 1; - dx1 = ((int64_t)viewx - curline->v1->x) >> 1; - dy1 = ((int64_t)viewy - curline->v1->y) >> 1; + dx = ((int64_t)curline->v2->r_x - curline->v1->r_x) >> 1; + dy = ((int64_t)curline->v2->r_y - curline->v1->r_y) >> 1; + dx1 = ((int64_t)viewx - curline->v1->r_x) >> 1; + dy1 = ((int64_t)viewy - curline->v1->r_y) >> 1; dist = ((dy * dx1 - dx * dy1) / len) << 1; rw_distance = (fixed_t)BETWEEN(INT_MIN, INT_MAX, dist); diff --git a/src/hexen/r_things.c b/src/hexen/r_things.c index 5bb3a323f0..62baad0d56 100644 --- a/src/hexen/r_things.c +++ b/src/hexen/r_things.c @@ -22,6 +22,7 @@ #include "i_swap.h" #include "r_bmaps.h" #include "r_local.h" +#include "v_trans.h" // [crispy] blending functions //void R_DrawTranslatedAltTLColumn(void); @@ -415,6 +416,9 @@ void R_DrawVisSprite(vissprite_t * vis, int x1, int x2) { colfunc = R_DrawAltTLColumn; } +#ifdef CRISPY_TRUECOLOR + blendfunc = vis->blendfunc; +#endif } else if (vis->mobjflags & MF_TRANSLATION) { @@ -465,6 +469,9 @@ void R_DrawVisSprite(vissprite_t * vis, int x1, int x2) } colfunc = basecolfunc; +#ifdef CRISPY_TRUECOLOR + blendfunc = I_BlendOverTinttab; +#endif } @@ -660,6 +667,19 @@ void R_ProjectSprite(mobj_t * thing) } vis->brightmap = R_BrightmapForSprite(thing->state - states); +#ifdef CRISPY_TRUECOLOR + // [crispy] not using additive blending (I_BlendAdd) here for full + // bright states to preserve look & feel of original Hexen's translucency + if (thing->flags & MF_SHADOW) + { + vis->blendfunc = I_BlendOverTinttab; + } + else + if (thing->flags & MF_ALTSHADOW) + { + vis->blendfunc = I_BlendOverAltTinttab; + } +#endif } @@ -811,15 +831,24 @@ void R_DrawPSprite(pspdef_t * psp) if (viewplayer->mo->flags2 & MF2_DONTDRAW) { // don't draw the psprite vis->mobjflags |= MF_SHADOW; +#ifdef CRISPY_TRUECOLOR + vis->blendfunc = I_BlendOverTinttab; +#endif } else if (viewplayer->mo->flags & MF_SHADOW) { vis->mobjflags |= MF_ALTSHADOW; +#ifdef CRISPY_TRUECOLOR + vis->blendfunc = I_BlendOverAltTinttab; +#endif } } else if (viewplayer->powers[pw_invulnerability] & 8) { vis->mobjflags |= MF_SHADOW; +#ifdef CRISPY_TRUECOLOR + vis->blendfunc = I_BlendOverTinttab; +#endif } } else if (fixedcolormap) diff --git a/src/hexen/sb_bar.c b/src/hexen/sb_bar.c index 6dca14a8a0..346238ff23 100644 --- a/src/hexen/sb_bar.c +++ b/src/hexen/sb_bar.c @@ -1001,7 +1001,9 @@ void SB_PaletteFlash(boolean forceChange) { static int sb_palette = 0; int palette; +#ifndef CRISPY_TRUECOLOR byte *pal; +#endif if (forceChange) { @@ -1054,8 +1056,12 @@ void SB_PaletteFlash(boolean forceChange) if (palette != sb_palette) { sb_palette = palette; +#ifndef CRISPY_TRUECOLOR pal = (byte *) W_CacheLumpNum(PlayPalette, PU_CACHE) + palette * 768; I_SetPalette(pal); +#else + I_SetPalette(palette); +#endif } } diff --git a/src/i_sdlsound.c b/src/i_sdlsound.c index df8bb27958..157f6e9f49 100644 --- a/src/i_sdlsound.c +++ b/src/i_sdlsound.c @@ -53,7 +53,10 @@ int use_libsamplerate = 1; // of the time: with all the Doom IWAD sound effects, at least. If a PWAD // is used, clipping might occur. -float libsamplerate_scale = 0.65f; +// [crispy] Get full output from libsamplerate. Our default is to use linear +// interpolation, which means the resampling process will not introduce any new +// clipping. This will also better match vanilla's volume. +float libsamplerate_scale = 1.0f; #ifndef DISABLE_SDL2MIXER diff --git a/src/i_video.c b/src/i_video.c index 4b99533f40..0136ab8b2b 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -124,11 +124,17 @@ static SDL_Texture *curpane = NULL; static SDL_Texture *redpane = NULL; static SDL_Texture *yelpane = NULL; static SDL_Texture *grnpane = NULL; +// Hexen exclusive color panes +static SDL_Texture *grnspane = NULL; +static SDL_Texture *bluepane = NULL; +static SDL_Texture *graypane = NULL; +static SDL_Texture *orngpane = NULL; static int pane_alpha; static unsigned int rmask, gmask, bmask, amask; // [crispy] moved up here static const uint8_t blend_alpha = 0xa8; -static const uint8_t blend_alpha_tinttab = 0x60; -extern pixel_t* colormaps; // [crispy] evil hack to get FPS dots working as in Vanilla +static const uint8_t blend_alpha_tinttab = 0x60; // 96 +static const uint8_t blend_alpha_alttinttab = 0x8E; // 142 +extern pixel_t* pal_color; // [crispy] evil hack to get FPS dots working as in Vanilla #else static SDL_Color palette[256]; #endif @@ -838,13 +844,13 @@ void I_FinishUpdate (void) #ifndef CRISPY_TRUECOLOR I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff; #else - I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = colormaps[0xff]; + I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = pal_color[0xff]; #endif for ( ; i<20*4 ; i+=4) #ifndef CRISPY_TRUECOLOR I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0; #else - I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = colormaps[0x0]; + I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = pal_color[0x0]; #endif } @@ -1236,6 +1242,64 @@ void I_SetPalette (int palette) curpane = grnpane; pane_alpha = 0xff * 125 / 1000; break; + // Hexen exclusive color panes and palette indexes + // https://doomwiki.org/wiki/PLAYPAL#Hexen + case 14: // STARTPOISONPALS + 1 (13 is shared with other games) + curpane = grnspane; + pane_alpha = 0x33; // 51 (20%) + break; + case 15: + curpane = grnspane; + pane_alpha = 0x4c; // 76 (30%) + break; + case 16: + curpane = grnspane; + pane_alpha = 0x66; // 102 (40%) + break; + case 17: + curpane = grnspane; + pane_alpha = 0x7f; // 127 (50%) + break; + case 18: + curpane = grnspane; + pane_alpha = 0x99; // 153 (60%) + break; + case 19: + curpane = grnspane; + pane_alpha = 0xb2; // 178 (70%) + break; + case 20: + curpane = grnspane; + pane_alpha = 0xcc; // 204 (80%) + break; + case 21: // STARTICEPAL + curpane = bluepane; + pane_alpha = 0x80; // 128 (50%) + break; + case 22: // STARTHOLYPAL + curpane = graypane; + pane_alpha = 0x7f; // 127 (50%) + break; + case 23: + curpane = graypane; + pane_alpha = 0x6a; // 106 + break; + case 24: + curpane = graypane; + pane_alpha = 0x34; // 52 + break; + case 25: // STARTSCOURGEPAL + curpane = orngpane; + pane_alpha = 0x7f; // 127 (50%) + break; + case 26: + curpane = orngpane; + pane_alpha = 0x60; // 96 + break; + case 27: + curpane = orngpane; + pane_alpha = 0x48; // 72 + break; default: I_Error("Unknown palette: %d!\n", palette); break; @@ -1841,6 +1905,22 @@ static void SetVideoMode(void) SDL_FillRect(argbbuffer, NULL, I_MapRGB(0x0, 0xff, 0x0)); grnpane = SDL_CreateTextureFromSurface(renderer, argbbuffer); SDL_SetTextureBlendMode(grnpane, SDL_BLENDMODE_BLEND); + + SDL_FillRect(argbbuffer, NULL, I_MapRGB(0x2c, 0x5c, 0x24)); // 44, 92, 36 + grnspane = SDL_CreateTextureFromSurface(renderer, argbbuffer); + SDL_SetTextureBlendMode(grnspane, SDL_BLENDMODE_BLEND); + + SDL_FillRect(argbbuffer, NULL, I_MapRGB(0x0, 0x0, 0xe0)); // 0, 0, 224 + bluepane = SDL_CreateTextureFromSurface(renderer, argbbuffer); + SDL_SetTextureBlendMode(bluepane, SDL_BLENDMODE_BLEND); + + SDL_FillRect(argbbuffer, NULL, I_MapRGB(0x82, 0x82, 0x82)); // 130, 130, 130 + graypane = SDL_CreateTextureFromSurface(renderer, argbbuffer); + SDL_SetTextureBlendMode(graypane, SDL_BLENDMODE_BLEND); + + SDL_FillRect(argbbuffer, NULL, I_MapRGB(0x96, 0x6e, 0x0)); // 150, 110, 0 + orngpane = SDL_CreateTextureFromSurface(renderer, argbbuffer); + SDL_SetTextureBlendMode(orngpane, SDL_BLENDMODE_BLEND); #endif SDL_FillRect(argbbuffer, NULL, 0); } @@ -2356,6 +2436,16 @@ const pixel_t I_BlendOverTinttab (const pixel_t bg, const pixel_t fg) return amask | r | g | b; } +// [crispy] More opaque ("Alt") TINTTAB blending emulation, used for Hexen's MF_ALTSHADOW drawing +const pixel_t I_BlendOverAltTinttab (const pixel_t bg, const pixel_t fg) +{ + const uint32_t r = ((blend_alpha_alttinttab * (fg & rmask) + (0xff - blend_alpha_alttinttab) * (bg & rmask)) >> 8) & rmask; + const uint32_t g = ((blend_alpha_alttinttab * (fg & gmask) + (0xff - blend_alpha_alttinttab) * (bg & gmask)) >> 8) & gmask; + const uint32_t b = ((blend_alpha_alttinttab * (fg & bmask) + (0xff - blend_alpha_alttinttab) * (bg & bmask)) >> 8) & bmask; + + return amask | r | g | b; +} + const pixel_t (*blendfunc) (const pixel_t fg, const pixel_t bg) = I_BlendOver; const pixel_t I_MapRGB (const uint8_t r, const uint8_t g, const uint8_t b) diff --git a/src/setup/sound.c b/src/setup/sound.c index 08be6d2dbe..fea2b32713 100644 --- a/src/setup/sound.c +++ b/src/setup/sound.c @@ -75,7 +75,7 @@ static int show_talk = 1; // [crispy] show subtitles by default // but 1 is closer to "use_libsamplerate = 0" which is the default in Choco // and causes only a short delay at startup int use_libsamplerate = 1; -float libsamplerate_scale = 0.65; +float libsamplerate_scale = 1.0f; // [crispy] char *music_pack_path = NULL; char *timidity_cfg_path = NULL; diff --git a/src/strife/r_data.c b/src/strife/r_data.c index 6e33aeac3a..b141c253a9 100644 --- a/src/strife/r_data.c +++ b/src/strife/r_data.c @@ -157,7 +157,7 @@ fixed_t* spritewidth; fixed_t* spriteoffset; fixed_t* spritetopoffset; -lighttable_t *colormaps; +lighttable_t *colormaps, *pal_color; // @@ -695,6 +695,7 @@ void R_InitColormaps (void) // Load in the light tables, 256 byte align tables. lump = W_GetNumForName(DEH_String("COLORMAP")); colormaps = W_CacheLumpNum(lump, PU_STATIC); + pal_color = colormaps; // [crispy] initialize color translation and color strings tables { diff --git a/src/v_trans.h b/src/v_trans.h index 02a235c3f0..068c706b54 100644 --- a/src/v_trans.h +++ b/src/v_trans.h @@ -64,6 +64,7 @@ extern const pixel_t I_BlendAdd (const pixel_t bg, const pixel_t fg); extern const pixel_t I_BlendDark (const pixel_t bg, const int d); extern const pixel_t I_BlendOver (const pixel_t bg, const pixel_t fg); extern const pixel_t I_BlendOverTinttab (const pixel_t bg, const pixel_t fg); +extern const pixel_t I_BlendOverAltTinttab (const pixel_t bg, const pixel_t fg); #endif int V_GetPaletteIndex(byte *palette, int r, int g, int b); diff --git a/src/v_video.c b/src/v_video.c index 005e0dd902..90d955ac14 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -61,7 +61,7 @@ byte *tranmap = NULL; byte *dp_translation = NULL; boolean dp_translucent = false; #ifdef CRISPY_TRUECOLOR -extern pixel_t *colormaps; +extern pixel_t *pal_color; #endif // villsa [STRIFE] Blending table used for Strife @@ -170,49 +170,56 @@ static const inline pixel_t drawpatchpx00 (const pixel_t dest, const pixel_t sou #ifndef CRISPY_TRUECOLOR {return source;} #else -{return colormaps[source];} +{return pal_color[source];} #endif // (2) color-translated, opaque patch static const inline pixel_t drawpatchpx01 (const pixel_t dest, const pixel_t source) #ifndef CRISPY_TRUECOLOR {return dp_translation[source];} #else -{return colormaps[dp_translation[source]];} +{return pal_color[dp_translation[source]];} #endif // (3) normal, translucent patch static const inline pixel_t drawpatchpx10 (const pixel_t dest, const pixel_t source) #ifndef CRISPY_TRUECOLOR {return tranmap[(dest<<8)+source];} #else -{return I_BlendOver(dest, colormaps[source]);} +{return I_BlendOver(dest, pal_color[source]);} #endif // (4) color-translated, translucent patch static const inline pixel_t drawpatchpx11 (const pixel_t dest, const pixel_t source) #ifndef CRISPY_TRUECOLOR {return tranmap[(dest<<8)+dp_translation[source]];} #else -{return I_BlendOver(dest, colormaps[dp_translation[source]]);} +{return I_BlendOver(dest, pal_color[dp_translation[source]]);} #endif + // [crispy] TINTTAB rendering functions: -// (1) normal, translucent patch -static const inline pixel_t drawtinttab0 (const pixel_t dest, const pixel_t source) +// V_DrawShadowedPatch (shadow only) +static const inline pixel_t drawshadow (const pixel_t dest, const pixel_t source) #ifndef CRISPY_TRUECOLOR -{return tinttable[(dest<<8)+source];} +{return tinttable[(dest<<8)];} #else -{return I_BlendOverTinttab(dest, colormaps[source]);} +{return I_BlendDark(dest, 0xa0);} // 160 (62.75%) of 256 full translucency #endif -// (2) translucent shadow only -static const inline pixel_t drawtinttab1 (const pixel_t dest, const pixel_t source) +// V_DrawTLPatch (translucent patch, no coloring or color-translation are used) +static const inline pixel_t drawtinttab (const pixel_t dest, const pixel_t source) #ifndef CRISPY_TRUECOLOR -{return tinttable[(dest<<8)];} +{return tinttable[dest+(source<<8)];} +#else +{return I_BlendOverTinttab(dest, pal_color[source]);} +#endif +// V_DrawAltTLPatch (translucent patch, no coloring or color-translation are used) +static const inline pixel_t drawalttinttab (const pixel_t dest, const pixel_t source) +#ifndef CRISPY_TRUECOLOR +{return tinttable[(dest<<8)+source];} #else -{return I_BlendDark(dest, 0xB4);} +{return I_BlendOverAltTinttab(dest, pal_color[source]);} #endif + // [crispy] array of function pointers holding the different rendering functions typedef const pixel_t drawpatchpx_t (const pixel_t dest, const pixel_t source); static drawpatchpx_t *const drawpatchpx_a[2][2] = {{drawpatchpx11, drawpatchpx10}, {drawpatchpx01, drawpatchpx00}}; -// [crispy] array of function pointers holding the different TINTTAB rendering functions -static drawpatchpx_t *const drawtinttab_a[2] = {drawtinttab0, drawtinttab1}; static fixed_t dx, dxi, dy, dyi; @@ -469,7 +476,7 @@ void V_DrawPatchFlipped(int x, int y, patch_t *patch) #ifndef CRISPY_TRUECOLOR *dest = source[srccol >> FRACBITS]; #else - *dest = colormaps[source[srccol >> FRACBITS]]; + *dest = pal_color[source[srccol >> FRACBITS]]; #endif } srccol += dyi; @@ -506,6 +513,9 @@ void V_DrawTLPatch(int x, int y, patch_t * patch) byte *source; int w; + // [crispy] translucent patch, no coloring or color-translation are used + drawpatchpx_t *const drawpatchpx = drawtinttab; + y -= SHORT(patch->topoffset); x -= SHORT(patch->leftoffset); x += WIDESCREENDELTA; // [crispy] horizontal widescreen offset @@ -537,7 +547,7 @@ void V_DrawTLPatch(int x, int y, patch_t * patch) while (count--) { - *dest = tinttable[*dest + ((source[srccol >> FRACBITS]) << 8)]; + *dest = drawpatchpx(*dest, source[srccol >> FRACBITS]); srccol += dyi; dest += SCREENWIDTH; } @@ -615,7 +625,7 @@ void V_DrawAltTLPatch(int x, int y, patch_t * patch) int w; // [crispy] translucent patch, no coloring or color-translation are used - drawpatchpx_t *const drawpatchpx = drawtinttab_a[dp_translucent]; + drawpatchpx_t *const drawpatchpx = drawalttinttab; y -= SHORT(patch->topoffset); x -= SHORT(patch->leftoffset); @@ -675,7 +685,7 @@ void V_DrawShadowedPatch(int x, int y, patch_t *patch) // [crispy] four different rendering functions drawpatchpx_t *const drawpatchpx = drawpatchpx_a[!dp_translucent][!dp_translation]; // [crispy] shadow, no coloring or color-translation are used - drawpatchpx_t *const drawpatchpx2 = drawtinttab_a[!dp_translation]; + drawpatchpx_t *const drawpatchpx2 = drawshadow; y -= SHORT(patch->topoffset); x -= SHORT(patch->leftoffset); @@ -909,7 +919,7 @@ void V_CopyScaledBuffer(pixel_t *dest, byte *src, size_t size) #ifndef CRISPY_TRUECOLOR *(dest + index - (j * SCREENWIDTH) - i) = *(src + size); #else - *(dest + index - (j * SCREENWIDTH) - i) = colormaps[src[size]]; + *(dest + index - (j * SCREENWIDTH) - i) = pal_color[src[size]]; #endif } } @@ -964,7 +974,7 @@ void V_FillFlat(int y_start, int y_stop, int x_start, int x_stop, #ifndef CRISPY_TRUECOLOR *dest++ = src[((y & 63) * 64) + (x & 63)]; #else - *dest++ = colormaps[src[((y & 63) * 64) + (x & 63)]]; + *dest++ = pal_color[src[((y & 63) * 64) + (x & 63)]]; #endif } } diff --git a/src/w_main.c b/src/w_main.c index 3520ebe76f..78f33bafc2 100644 --- a/src/w_main.c +++ b/src/w_main.c @@ -17,12 +17,14 @@ // #include +#include #include "config.h" #include "d_iwad.h" #include "i_glob.h" #include "i_system.h" #include "m_argv.h" +#include "m_misc.h" #include "w_main.h" #include "w_merge.h" #include "w_wad.h" @@ -204,9 +206,16 @@ boolean W_ParseCommandLine(void) // Load all WAD files from the given directory. void W_AutoLoadWADs(const char *path) +{ + W_AutoLoadWADsRename(path, NULL, 0); +} + +void W_AutoLoadWADsRename(const char *path, const lump_rename_t *renames, + int num_renames) { glob_t *glob; - const char *filename; + const char *filename, *basename; + int i, j; glob = I_StartMultiGlob(path, GLOB_FLAG_NOCASE|GLOB_FLAG_SORTED, "*.wad", "*.lmp", NULL); @@ -219,6 +228,21 @@ void W_AutoLoadWADs(const char *path) } printf(" [autoload] merging %s\n", filename); W_MergeFile(filename); + + if (renames && num_renames > 0) + { + basename = M_BaseName(filename); + for (i = 0; i < num_renames; i++) + { + j = W_CheckNumForName(renames[i].name); + + if (j != -1 && + !strcasecmp(W_WadNameForLump(lumpinfo[j]), basename)) + { + memcpy(lumpinfo[j]->name, renames[i].new_name, 8); + } + } + } } I_EndGlob(glob); diff --git a/src/w_main.h b/src/w_main.h index 4343f2dfbf..ba6284ce87 100644 --- a/src/w_main.h +++ b/src/w_main.h @@ -20,6 +20,13 @@ #include "d_mode.h" +// [crispy] +typedef struct +{ + const char *name; + const char new_name[8]; +} lump_rename_t; + boolean W_ParseCommandLine(void); void W_CheckCorrectIWAD(GameMission_t mission); @@ -29,5 +36,9 @@ int W_LumpDump (const char *lumpname); // Autoload all .wad files from the given directory: void W_AutoLoadWADs(const char *path); +// [crispy] Autoload from directory with lump renaming +void W_AutoLoadWADsRename(const char *path, const lump_rename_t *renames, + int num_renames); + #endif /* #ifndef W_MAIN_H */