diff --git a/src/swrenderer/drawers/r_draw.cpp b/src/swrenderer/drawers/r_draw.cpp index 65958db04..c894e46ce 100644 --- a/src/swrenderer/drawers/r_draw.cpp +++ b/src/swrenderer/drawers/r_draw.cpp @@ -53,6 +53,7 @@ #include "swrenderer/scene/r_light.h" CVAR(Bool, r_dynlights, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); +CVAR(Bool, r_fuzzscale, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); namespace swrenderer { @@ -64,6 +65,20 @@ namespace swrenderer int fuzzpos; int fuzzviewheight; + int fuzz_random_x_offset[FUZZ_RANDOM_X_SIZE] = + { + 75, 76, 21, 91, 56, 33, 62, 99, 61, 79, + 95, 54, 41, 18, 69, 43, 49, 59, 10, 84, + 94, 17, 57, 46, 9, 39, 55, 34,100, 81, + 73, 88, 92, 3, 63, 36, 7, 28, 13, 80, + 16, 96, 78, 29, 71, 58, 89, 24, 1, 35, + 52, 82, 4, 14, 22, 53, 38, 66, 12, 72, + 90, 44, 77, 83, 6, 27, 48, 30, 42, 32, + 65, 15, 97, 20, 67, 74, 98, 85, 60, 68, + 19, 26, 8, 87, 86, 64, 11, 37, 31, 47, + 25, 5, 50, 51, 23, 2, 93, 70, 40, 45 + }; + uint32_t particle_texture[NUM_PARTICLE_TEXTURES][PARTICLE_TEXTURE_SIZE * PARTICLE_TEXTURE_SIZE]; short zeroarray[MAXWIDTH]; @@ -176,11 +191,28 @@ namespace swrenderer } } + void R_UpdateFuzzPosFrameStart() + { + if (r_fuzzscale) + { + int next_random = 0; + + fuzzpos = (fuzzpos + fuzz_random_x_offset[next_random] * FUZZTABLE / 100) % FUZZTABLE; + + next_random++; + if (next_random == FUZZ_RANDOM_X_SIZE) + next_random = 0; + } + } + void R_UpdateFuzzPos(const SpriteDrawerArgs &args) { - int yl = MAX(args.FuzzY1(), 1); - int yh = MIN(args.FuzzY2(), fuzzviewheight); - if (yl <= yh) - fuzzpos = (fuzzpos + yh - yl + 1) % FUZZTABLE; + if (!r_fuzzscale) + { + int yl = MAX(args.FuzzY1(), 1); + int yh = MIN(args.FuzzY2(), fuzzviewheight); + if (yl <= yh) + fuzzpos = (fuzzpos + yh - yl + 1) % FUZZTABLE; + } } } diff --git a/src/swrenderer/drawers/r_draw.h b/src/swrenderer/drawers/r_draw.h index b29ea8512..4672a4fd3 100644 --- a/src/swrenderer/drawers/r_draw.h +++ b/src/swrenderer/drawers/r_draw.h @@ -17,6 +17,7 @@ EXTERN_CVAR(Int, r_drawfuzz); EXTERN_CVAR(Bool, r_drawtrans); EXTERN_CVAR(Float, transsouls); EXTERN_CVAR(Bool, r_dynlights); +EXTERN_CVAR(Bool, r_fuzzscale); class DrawerCommandQueue; typedef std::shared_ptr DrawerCommandQueuePtr; @@ -41,7 +42,9 @@ namespace swrenderer // Spectre/Invisibility. #define FUZZTABLE 50 + #define FUZZ_RANDOM_X_SIZE 100 extern int fuzzoffset[FUZZTABLE + 1]; + extern int fuzz_random_x_offset[FUZZ_RANDOM_X_SIZE]; extern int fuzzpos; extern int fuzzviewheight; @@ -99,5 +102,6 @@ namespace swrenderer void R_InitFuzzTable(int fuzzoff); void R_InitParticleTexture(); + void R_UpdateFuzzPosFrameStart(); void R_UpdateFuzzPos(const SpriteDrawerArgs &args); } diff --git a/src/swrenderer/drawers/r_draw_pal.cpp b/src/swrenderer/drawers/r_draw_pal.cpp index d991a99ae..a5c644b9e 100644 --- a/src/swrenderer/drawers/r_draw_pal.cpp +++ b/src/swrenderer/drawers/r_draw_pal.cpp @@ -1834,6 +1834,60 @@ namespace swrenderer } } + ///////////////////////////////////////////////////////////////////////////// + + DrawScaledFuzzColumnPalCommand::DrawScaledFuzzColumnPalCommand(const SpriteDrawerArgs &drawerargs) + { + _x = drawerargs.FuzzX(); + _yl = drawerargs.FuzzY1(); + _yh = drawerargs.FuzzY2(); + _destorg = drawerargs.Viewport()->GetDest(0, 0); + _pitch = drawerargs.Viewport()->RenderTarget->GetPitch(); + _fuzzpos = fuzzpos; + _fuzzviewheight = fuzzviewheight; + } + + void DrawScaledFuzzColumnPalCommand::Execute(DrawerThread *thread) + { + int x = _x; + int yl = MAX(_yl, 1); + int yh = MIN(_yh, _fuzzviewheight); + + int count = thread->count_for_thread(yl, yh - yl + 1); + if (count <= 0) return; + + int pitch = _pitch; + uint8_t *dest = _pitch * yl + x + (uint8_t*)_destorg; + + int scaled_x = x * 200 / _fuzzviewheight; + int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + _fuzzpos; + + fixed_t fuzzstep = (200 << FRACBITS) / _fuzzviewheight; + fixed_t fuzzcount = FUZZTABLE << FRACBITS; + fixed_t fuzz = (fuzz_x << FRACBITS) + yl * fuzzstep; + + dest = thread->dest_for_thread(yl, pitch, dest); + pitch *= thread->num_cores; + + fuzz += fuzzstep * thread->skipped_by_thread(yl); + fuzz %= fuzzcount; + fuzzstep *= thread->num_cores; + + uint8_t *map = NormalLight.Maps; + + while (count > 0) + { + int offset = fuzzoffset[fuzz >> FRACBITS] << 8; + *dest = map[offset + *dest]; + dest += pitch; + + fuzz += fuzzstep; + if (fuzz >= fuzzcount) fuzz -= fuzzcount; + + count--; + } + } + ///////////////////////////////////////////////////////////////////////// DrawFuzzColumnPalCommand::DrawFuzzColumnPalCommand(const SpriteDrawerArgs &args) diff --git a/src/swrenderer/drawers/r_draw_pal.h b/src/swrenderer/drawers/r_draw_pal.h index e3b2b9572..76fdb9eb4 100644 --- a/src/swrenderer/drawers/r_draw_pal.h +++ b/src/swrenderer/drawers/r_draw_pal.h @@ -90,6 +90,23 @@ namespace swrenderer int _fuzzviewheight; }; + class DrawScaledFuzzColumnPalCommand : public DrawerCommand + { + public: + DrawScaledFuzzColumnPalCommand(const SpriteDrawerArgs &drawerargs); + void Execute(DrawerThread *thread) override; + FString DebugInfo() override { return "DrawScaledFuzzColumnPalCommand"; } + + private: + int _x; + int _yl; + int _yh; + uint8_t *_destorg; + int _pitch; + int _fuzzpos; + int _fuzzviewheight; + }; + class PalSpanCommand : public DrawerCommand { public: @@ -245,7 +262,14 @@ namespace swrenderer void FillAddClampColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } void FillSubClampColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } void FillRevSubClampColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } - void DrawFuzzColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); R_UpdateFuzzPos(args); } + void DrawFuzzColumn(const SpriteDrawerArgs &args) override + { + if (r_fuzzscale) + Queue->Push(args); + else + Queue->Push(args); + R_UpdateFuzzPos(args); + } void DrawAddColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } void DrawTranslatedColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } void DrawTranslatedAddColumn(const SpriteDrawerArgs &args) override { Queue->Push(args); } diff --git a/src/swrenderer/drawers/r_draw_rgba.cpp b/src/swrenderer/drawers/r_draw_rgba.cpp index ae3c563f3..e9685e874 100644 --- a/src/swrenderer/drawers/r_draw_rgba.cpp +++ b/src/swrenderer/drawers/r_draw_rgba.cpp @@ -142,7 +142,10 @@ namespace swrenderer void SWTruecolorDrawers::DrawFuzzColumn(const SpriteDrawerArgs &args) { - Queue->Push(args); + if (r_fuzzscale) + Queue->Push(args); + else + Queue->Push(args); R_UpdateFuzzPos(args); } @@ -248,6 +251,69 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////////// + DrawScaledFuzzColumnRGBACommand::DrawScaledFuzzColumnRGBACommand(const SpriteDrawerArgs &drawerargs) + { + _x = drawerargs.FuzzX(); + _yl = drawerargs.FuzzY1(); + _yh = drawerargs.FuzzY2(); + _destorg = drawerargs.Viewport()->GetDest(0, 0); + _pitch = drawerargs.Viewport()->RenderTarget->GetPitch(); + _fuzzpos = fuzzpos; + _fuzzviewheight = fuzzviewheight; + } + + void DrawScaledFuzzColumnRGBACommand::Execute(DrawerThread *thread) + { + int x = _x; + int yl = MAX(_yl, 1); + int yh = MIN(_yh, _fuzzviewheight); + + int count = thread->count_for_thread(yl, yh - yl + 1); + if (count <= 0) return; + + int pitch = _pitch; + uint32_t *dest = _pitch * yl + x + (uint32_t*)_destorg; + + int scaled_x = x * 200 / _fuzzviewheight; + int fuzz_x = fuzz_random_x_offset[scaled_x % FUZZ_RANDOM_X_SIZE] + _fuzzpos; + + fixed_t fuzzstep = (200 << FRACBITS) / _fuzzviewheight; + fixed_t fuzzcount = FUZZTABLE << FRACBITS; + fixed_t fuzz = (fuzz_x << FRACBITS) + yl * fuzzstep; + + dest = thread->dest_for_thread(yl, pitch, dest); + pitch *= thread->num_cores; + + fuzz += fuzzstep * thread->skipped_by_thread(yl); + fuzz %= fuzzcount; + fuzzstep *= thread->num_cores; + + while (count > 0) + { + int alpha = 32 - fuzzoffset[fuzz >> FRACBITS]; + + uint32_t bg = *dest; + uint32_t red = (RPART(bg) * alpha) >> 5; + uint32_t green = (GPART(bg) * alpha) >> 5; + uint32_t blue = (BPART(bg) * alpha) >> 5; + + *dest = 0xff000000 | (red << 16) | (green << 8) | blue; + dest += pitch; + + fuzz += fuzzstep; + if (fuzz >= fuzzcount) fuzz -= fuzzcount; + + count--; + } + } + + FString DrawScaledFuzzColumnRGBACommand::DebugInfo() + { + return "DrawScaledFuzzColumn"; + } + + ///////////////////////////////////////////////////////////////////////////// + DrawFuzzColumnRGBACommand::DrawFuzzColumnRGBACommand(const SpriteDrawerArgs &drawerargs) { _x = drawerargs.FuzzX(); diff --git a/src/swrenderer/drawers/r_draw_rgba.h b/src/swrenderer/drawers/r_draw_rgba.h index 6cafb2f1e..6676486b2 100644 --- a/src/swrenderer/drawers/r_draw_rgba.h +++ b/src/swrenderer/drawers/r_draw_rgba.h @@ -86,6 +86,22 @@ namespace swrenderer FString DebugInfo() override; }; + class DrawScaledFuzzColumnRGBACommand : public DrawerCommand + { + int _x; + int _yl; + int _yh; + uint8_t * RESTRICT _destorg; + int _pitch; + int _fuzzpos; + int _fuzzviewheight; + + public: + DrawScaledFuzzColumnRGBACommand(const SpriteDrawerArgs &drawerargs); + void Execute(DrawerThread *thread) override; + FString DebugInfo() override; + }; + class FillSpanRGBACommand : public DrawerCommand { int _x1; diff --git a/src/swrenderer/scene/r_scene.cpp b/src/swrenderer/scene/r_scene.cpp index 5948a5c4a..53c1d5325 100644 --- a/src/swrenderer/scene/r_scene.cpp +++ b/src/swrenderer/scene/r_scene.cpp @@ -152,6 +152,8 @@ namespace swrenderer // Link the polyobjects right before drawing the scene to reduce the amounts of calls to this function PO_LinkToSubsectors(); + R_UpdateFuzzPosFrameStart(); + ActorRenderFlags savedflags = MainThread()->Viewport->viewpoint.camera->renderflags; // Never draw the player unless in chasecam mode if (!MainThread()->Viewport->viewpoint.showviewer) diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index de77d385b..e07f4bf7d 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1816,6 +1816,7 @@ DSPLYMNU_ATTACHEDSURFACES = "Use attached surfaces"; // Not used DSPLYMNU_SKYMODE = "Sky render mode"; DSPLYMNU_LINEARSKY = "Linear skies"; DSPLYMNU_GZDFULLBRIGHT = "Fullbright overrides sector color"; +DSPLYMNU_SCALEFUZZ = "Scale fuzz effect"; DSPLYMNU_DRAWFUZZ = "Use fuzz effect"; DSPLYMNU_OLDTRANS = "Classic Transparency"; DSPLYMNU_TRANSSOUL = "Lost Soul translucency"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 09a4a9fc4..a7e6cc4e9 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -725,6 +725,7 @@ OptionMenu "SWROptions" protected Option "$DSPLYMNU_SKYMODE", "r_skymode", "SkyModes" Option "$DSPLYMNU_LINEARSKY", "r_linearsky", "OnOff" Option "$DSPLYMNU_GZDFULLBRIGHT", "r_fullbrightignoresectorcolor", "OnOff" + Option "$DSPLYMNU_SCALEFUZZ", "r_fuzzscale", "OnOff" } OptionMenu "VideoOptions" protected