From 15159a3c19ab83b782f6f2211ce05f179d5ada92 Mon Sep 17 00:00:00 2001 From: nashmuhandes Date: Wed, 21 Apr 2021 22:36:44 +0800 Subject: [PATCH] Add sprite shadows for the hardware renderer --- src/rendering/hwrenderer/scene/hw_bsp.cpp | 26 ++++++++++++ .../hwrenderer/scene/hw_drawstructs.h | 2 +- src/rendering/hwrenderer/scene/hw_sprites.cpp | 41 ++++++++++++++++++- 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/src/rendering/hwrenderer/scene/hw_bsp.cpp b/src/rendering/hwrenderer/scene/hw_bsp.cpp index e37b768df6..8a1a63a334 100644 --- a/src/rendering/hwrenderer/scene/hw_bsp.cpp +++ b/src/rendering/hwrenderer/scene/hw_bsp.cpp @@ -49,6 +49,8 @@ CVAR(Bool, gl_multithread, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +EXTERN_CVAR(Float, r_actorspriteshadowdist) + thread_local bool isWorkerThread; ctpl::thread_pool renderPool(1); bool inited = false; @@ -547,6 +549,18 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector) if (CurrentMapSections[thing->subsector->mapsection]) { HWSprite sprite; + + // [Nash] draw sprite shadow + if (R_ShouldDrawSpriteShadow(thing)) + { + double dist = (thing->Pos() - vp.Pos).LengthSquared(); + double check = r_actorspriteshadowdist; + if (dist <= check * check) + { + sprite.Process(this, thing, sector, in_area, false, true); + } + } + sprite.Process(this, thing, sector, in_area, false); } } @@ -566,6 +580,18 @@ void HWDrawInfo::RenderThings(subsector_t * sub, sector_t * sector) } HWSprite sprite; + + // [Nash] draw sprite shadow + if (R_ShouldDrawSpriteShadow(thing)) + { + double dist = (thing->Pos() - vp.Pos).LengthSquared(); + double check = r_actorspriteshadowdist; + if (dist <= check * check) + { + sprite.Process(this, thing, sector, in_area, true, true); + } + } + sprite.Process(this, thing, sector, in_area, true); } } diff --git a/src/rendering/hwrenderer/scene/hw_drawstructs.h b/src/rendering/hwrenderer/scene/hw_drawstructs.h index 063be282a3..205f225d3d 100644 --- a/src/rendering/hwrenderer/scene/hw_drawstructs.h +++ b/src/rendering/hwrenderer/scene/hw_drawstructs.h @@ -385,7 +385,7 @@ public: void CreateVertices(HWDrawInfo *di); void PutSprite(HWDrawInfo *di, bool translucent); - void Process(HWDrawInfo *di, AActor* thing,sector_t * sector, area_t in_area, int thruportal = false); + void Process(HWDrawInfo *di, AActor* thing,sector_t * sector, area_t in_area, int thruportal = false, bool isSpriteShadow = false); void ProcessParticle (HWDrawInfo *di, particle_t *particle, sector_t *sector);//, int shade, int fakeside) void DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent); diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 65fc4c5b84..641c69294b 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -678,7 +678,7 @@ void HWSprite::PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingp // //========================================================================== -void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t in_area, int thruportal) +void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t in_area, int thruportal, bool isSpriteShadow) { sector_t rs; sector_t * rendersector; @@ -795,6 +795,12 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t y = thingpos.Y; if (spritetype == RF_FACESPRITE) z -= thing->Floorclip; // wall and flat sprites are to be considered di->Level-> geometry so this may not apply. + // snap shadow Z to the floor + if (isSpriteShadow) + { + z = thing->floorz; + } + // [RH] Make floatbobbing a renderer-only effect. if (thing->flags2 & MF2_FLOATBOB) { @@ -803,6 +809,13 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t } modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing->GetClass(), spritenum, thing->frame, !!(thing->flags & MF_DROPPED)); + + // don't bother drawing sprite shadows if this is a model (it will never look right) + if (modelframe && isSpriteShadow) + { + return; + } + if (!modelframe) { bool mirror = false; @@ -897,7 +910,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t if (thing->renderflags & RF_SPRITEFLIP) // [SP] Flip back thing->renderflags ^= RF_XFLIP; - r.Scale(sprscale.X, sprscale.Y); + r.Scale(sprscale.X, isSpriteShadow ? sprscale.Y * 0.15 : sprscale.Y); float SpriteOffY = thing->SpriteOffset.Y; float rightfac = -r.left - thing->SpriteOffset.X; @@ -1118,12 +1131,29 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t } } + // for sprite shadow, use a translucent stencil renderstyle + if (isSpriteShadow) + { + RenderStyle = STYLE_Stencil; + ThingColor = MAKEARGB(ColorMatcher.Pick(0, 0, 0), 0, 0, 0); + trans = 0.5f; + hw_styleflags = STYLEHW_NoAlphaTest; + } + if (trans == 0.0f) return; // end of light calculation actor = thing; index = thing->SpawnOrder; + + // sprite shadows should have a fixed index of -1 (ensuring they're drawn behind particles which have index 0) + // sorting should be irrelevant since they're always translucent + if (isSpriteShadow) + { + index = -1; + } + particle = nullptr; const bool drawWithXYBillboard = (!(actor->renderflags & RF_FORCEYBILLBOARD) @@ -1348,6 +1378,13 @@ void HWDrawInfo::ProcessActorsInPortal(FLinePortalSpan *glport, area_t in_area) th->Prev += newpos - savedpos; HWSprite spr; + + // [Nash] draw sprite shadow + if (R_ShouldDrawSpriteShadow(th)) + { + spr.Process(this, th, hw_FakeFlat(th->Sector, in_area, false, &fakesector), in_area, 2, true); + } + // This is called from the worker thread and must not alter the fake sector cache. spr.Process(this, th, hw_FakeFlat(th->Sector, in_area, false, &fakesector), in_area, 2); th->Angles.Yaw = savedangle;