From 5446a1a355077ab95b7abe788eb14a4c38018b8a Mon Sep 17 00:00:00 2001 From: nashmuhandes Date: Wed, 21 Apr 2021 22:15:05 +0800 Subject: [PATCH] Add sprite shadows for the software renderer --- src/playsim/actor.h | 2 + src/rendering/r_utility.cpp | 41 +++++++++++++++++++ src/rendering/r_utility.h | 1 + .../swrenderer/scene/r_opaque_pass.cpp | 21 ++++++++++ src/rendering/swrenderer/things/r_sprite.cpp | 11 ++++- src/rendering/swrenderer/things/r_sprite.h | 2 +- src/scripting/thingdef_data.cpp | 2 + 7 files changed, 77 insertions(+), 3 deletions(-) diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 1d82d3d2f..dc7f2da0c 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -459,7 +459,9 @@ enum ActorRenderFlag RF_SPRITEFLIP = 0x08000000, // sprite flipped on x-axis RF_ZDOOMTRANS = 0x10000000, // is not normally transparent in Vanilla Doom + RF_CASTSPRITESHADOW = 0x20000000, // actor will cast a sprite shadow RF_NOINTERPOLATEVIEW = 0x40000000, // don't interpolate the view next frame if this actor is a camera. + RF_NOSPRITESHADOW = 0x80000000, // actor will not cast a sprite shadow }; // This translucency value produces the closest match to Heretic's TINTTAB. diff --git a/src/rendering/r_utility.cpp b/src/rendering/r_utility.cpp index 157bef7bc..105cc06d3 100644 --- a/src/rendering/r_utility.cpp +++ b/src/rendering/r_utility.cpp @@ -105,6 +105,21 @@ CUSTOM_CVAR(Float, r_quakeintensity, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) else if (self > 1.f) self = 1.f; } +CUSTOM_CVARD(Int, r_actorspriteshadow, 1, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "render actor sprite shadows. 0 = off, 1 = default, 2 = always on") +{ + if (self < 0) + self = 0; + else if (self > 2) + self = 2; +} +CUSTOM_CVARD(Float, r_actorspriteshadowdist, 1500.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "how far sprite shadows should be rendered") +{ + if (self < 0.f) + self = 0.f; + else if (self > 8192.f) + self = 8192.f; +} + int viewwindowx; int viewwindowy; int viewwidth; @@ -1051,3 +1066,29 @@ CUSTOM_CVAR(Float, maxviewpitch, 90.f, CVAR_ARCHIVE | CVAR_SERVERINFO) players[consoleplayer].SendPitchLimits(); } } + +//========================================================================== +// +// R_ShouldDrawSpriteShadow +// +//========================================================================== + +bool R_ShouldDrawSpriteShadow(AActor *thing) +{ + switch (r_actorspriteshadow) + { + case 1: + return (thing->renderflags & RF_CASTSPRITESHADOW); + + case 2: + if (thing->renderflags & RF_CASTSPRITESHADOW) + { + return true; + } + return (thing->renderflags & RF_CASTSPRITESHADOW) || (!(thing->renderflags & RF_NOSPRITESHADOW) && ((thing->flags3 & MF3_ISMONSTER) || thing->player != nullptr)); + + default: + case 0: + return false; + } +} diff --git a/src/rendering/r_utility.h b/src/rendering/r_utility.h index be6f01b2f..b4ac93c9b 100644 --- a/src/rendering/r_utility.h +++ b/src/rendering/r_utility.h @@ -135,5 +135,6 @@ double R_ClampVisibility(double vis); extern void R_FreePastViewers (); extern void R_ClearPastViewer (AActor *actor); +bool R_ShouldDrawSpriteShadow(AActor *thing); #endif diff --git a/src/rendering/swrenderer/scene/r_opaque_pass.cpp b/src/rendering/swrenderer/scene/r_opaque_pass.cpp index c30210ea9..9bb69562c 100644 --- a/src/rendering/swrenderer/scene/r_opaque_pass.cpp +++ b/src/rendering/swrenderer/scene/r_opaque_pass.cpp @@ -79,6 +79,8 @@ extern uint32_t r_renderercaps; double model_distance_cull = 1e16; +EXTERN_CVAR(Float, r_actorspriteshadowdist) + namespace { double sprite_distance_cull = 1e16; @@ -965,6 +967,25 @@ namespace swrenderer else { RenderSprite::Project(Thread, thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thinglightlevel, foggy, thingColormap); + + // [Nash] draw sprite shadow + if (R_ShouldDrawSpriteShadow(thing)) + { + double dist = (thing->Pos() - Thread->Viewport->viewpoint.Pos).LengthSquared(); + double distCheck = r_actorspriteshadowdist; + if (dist <= distCheck * distCheck) + { + // squash Y scale + DVector2 shadowScale = sprite.spriteScale; + shadowScale.Y *= 0.15; + + // snap to floor Z + DVector3 shadowPos = sprite.pos; + shadowPos.Z = thing->floorz; + + RenderSprite::Project(Thread, thing, shadowPos, sprite.tex, shadowScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, thinglightlevel, foggy, thingColormap, true); + } + } } } } diff --git a/src/rendering/swrenderer/things/r_sprite.cpp b/src/rendering/swrenderer/things/r_sprite.cpp index 8f47c524b..3602afa11 100644 --- a/src/rendering/swrenderer/things/r_sprite.cpp +++ b/src/rendering/swrenderer/things/r_sprite.cpp @@ -74,7 +74,7 @@ EXTERN_CVAR(Int, gl_texture_hqresize_targets) namespace swrenderer { - void RenderSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FSoftwareTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap) + void RenderSprite::Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FSoftwareTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap, bool isSpriteShadow) { auto viewport = thread->Viewport.get(); @@ -195,7 +195,14 @@ namespace swrenderer bool fullbright = !vis->foggy && ((renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)); bool fadeToBlack = (vis->RenderStyle.Flags & STYLEF_FadeToBlack) != 0; - + + if (isSpriteShadow) + { + vis->RenderStyle = LegacyRenderStyles[STYLE_TranslucentStencil]; + vis->FillColor = 0; + vis->Alpha *= 0.5; + } + if (r_dynlights && gl_light_sprites) { float lit_red = 0; diff --git a/src/rendering/swrenderer/things/r_sprite.h b/src/rendering/swrenderer/things/r_sprite.h index d41504fc8..12f9170ab 100644 --- a/src/rendering/swrenderer/things/r_sprite.h +++ b/src/rendering/swrenderer/things/r_sprite.h @@ -7,7 +7,7 @@ namespace swrenderer class RenderSprite : public VisibleSprite { public: - static void Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FSoftwareTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap); + static void Project(RenderThread *thread, AActor *thing, const DVector3 &pos, FSoftwareTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int lightlevel, bool foggy, FDynamicColormap *basecolormap, bool isSpriteShadow = false); protected: void Render(RenderThread *thread, short *cliptop, short *clipbottom, int minZ, int maxZ, Fake3DTranslucent clip3DFloor) override; diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 8c074fa58..bcfced710 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -351,6 +351,8 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(RF, DONTINTERPOLATE, AActor, renderflags), DEFINE_FLAG(RF, SPRITEFLIP, AActor, renderflags), DEFINE_FLAG(RF, ZDOOMTRANS, AActor, renderflags), + DEFINE_FLAG(RF, CASTSPRITESHADOW, AActor, renderflags), + DEFINE_FLAG(RF, NOSPRITESHADOW, AActor, renderflags), // Bounce flags DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),