From f3ba92f03ce181fc07161017c7b18ff7b3e59acb Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 23 Sep 2017 14:14:59 +0200 Subject: [PATCH] - Add dynamic light to sprites --- src/polyrenderer/drawers/poly_draw_args.h | 3 ++ src/polyrenderer/drawers/poly_drawer32_sse2.h | 18 ++++--- src/polyrenderer/scene/poly_sprite.cpp | 49 +++++++++++++++++++ src/polyrenderer/scene/poly_sprite.h | 1 + 4 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/polyrenderer/drawers/poly_draw_args.h b/src/polyrenderer/drawers/poly_draw_args.h index c3a685c880..34ef56eb25 100644 --- a/src/polyrenderer/drawers/poly_draw_args.h +++ b/src/polyrenderer/drawers/poly_draw_args.h @@ -81,6 +81,7 @@ public: void SetTransform(const TriMatrix *objectToClip) { mObjectToClip = objectToClip; } void SetColor(uint32_t bgra, uint8_t palindex); void SetLights(PolyLight *lights, int numLights) { mLights = lights; mNumLights = numLights; } + void SetDynLightColor(uint32_t color) { mDynLightColor = color; } void DrawArray(PolyRenderThread *thread, const TriVertex *vertices, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles); const TriMatrix *ObjectToClip() const { return mObjectToClip; } @@ -129,6 +130,7 @@ public: PolyLight *Lights() const { return mLights; } int NumLights() const { return mNumLights; } + uint32_t DynLightColor() const { return mDynLightColor; } const FVector3 &Normal() const { return mNormal; } void SetNormal(const FVector3 &normal) { mNormal = normal; } @@ -172,6 +174,7 @@ private: PolyLight *mLights = nullptr; int mNumLights = 0; FVector3 mNormal; + uint32_t mDynLightColor = 0; }; class RectDrawArgs diff --git a/src/polyrenderer/drawers/poly_drawer32_sse2.h b/src/polyrenderer/drawers/poly_drawer32_sse2.h index f4d3cb3928..8c245eec97 100644 --- a/src/polyrenderer/drawers/poly_drawer32_sse2.h +++ b/src/polyrenderer/drawers/poly_drawer32_sse2.h @@ -149,9 +149,10 @@ namespace TriScreenDrawerModes return fgcolor; } - FORCEINLINE __m128i VECTORCALL CalcDynamicLight(const PolyLight *lights, int num_lights, __m128 worldpos, __m128 worldnormal) + FORCEINLINE __m128i VECTORCALL CalcDynamicLight(const PolyLight *lights, int num_lights, __m128 worldpos, __m128 worldnormal, uint32_t dynlightcolor) { - __m128i lit = _mm_setzero_si128(); + __m128i lit = _mm_unpacklo_epi8(_mm_cvtsi32_si128(dynlightcolor), _mm_setzero_si128()); + lit = _mm_shuffle_epi32(lit, _MM_SHUFFLE(1, 0, 1, 0)); for (int i = 0; i != num_lights; i++) { @@ -396,6 +397,7 @@ private: auto lights = args->uniforms->Lights(); auto num_lights = args->uniforms->NumLights(); __m128 worldnormal = _mm_setr_ps(args->uniforms->Normal().X, args->uniforms->Normal().Y, args->uniforms->Normal().Z, 0.0f); + uint32_t dynlightcolor = args->uniforms->DynLightColor(); // Calculate gradients const ShadedTriVertex &v1 = *args->v1; @@ -476,7 +478,7 @@ private: __m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W); __m128 worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosY.WorldX), mrcpW); - __m128i dynlight = CalcDynamicLight(lights, num_lights, worldpos, worldnormal); + __m128i dynlight = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor); ScreenTriangleStepVariables blockPosX = blockPosY; blockPosX.W += gradientX.W; @@ -498,7 +500,7 @@ private: mrcpW = _mm_set1_ps(1.0f / blockPosX.W); worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosX.WorldX), mrcpW); - __m128i dynlightnext = CalcDynamicLight(lights, num_lights, worldpos, worldnormal); + __m128i dynlightnext = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor); __m128i dynlightstep = _mm_srai_epi16(_mm_sub_epi16(dynlightnext, dynlight), 3); dynlight = _mm_max_epi16(_mm_min_epi16(_mm_add_epi16(dynlight, _mm_and_si128(dynlightstep, _mm_set_epi32(0xffff,0xffff,0,0))), _mm_set1_epi16(256)), _mm_setzero_si128()); dynlightstep = _mm_slli_epi16(dynlightstep, 1); @@ -579,7 +581,7 @@ private: __m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W); __m128 worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosY.WorldX), mrcpW); - __m128i dynlight = CalcDynamicLight(lights, num_lights, worldpos, worldnormal); + __m128i dynlight = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor); ScreenTriangleStepVariables blockPosX = blockPosY; blockPosX.W += gradientX.W; @@ -601,7 +603,7 @@ private: mrcpW = _mm_set1_ps(1.0f / blockPosX.W); worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosX.WorldX), mrcpW); - __m128i dynlightnext = CalcDynamicLight(lights, num_lights, worldpos, worldnormal); + __m128i dynlightnext = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor); __m128i dynlightstep = _mm_srai_epi16(_mm_sub_epi16(dynlightnext, dynlight), 3); dynlight = _mm_max_epi16(_mm_min_epi16(_mm_add_epi16(dynlight, _mm_and_si128(dynlightstep, _mm_set_epi32(0xffff, 0xffff, 0, 0))), _mm_set1_epi16(256)), _mm_setzero_si128()); dynlightstep = _mm_slli_epi16(dynlightstep, 1); @@ -689,7 +691,7 @@ private: __m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W); __m128 worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosY.WorldX), mrcpW); - __m128i dynlight = CalcDynamicLight(lights, num_lights, worldpos, worldnormal); + __m128i dynlight = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor); ScreenTriangleStepVariables blockPosX = blockPosY; blockPosX.W += gradientX.W; @@ -711,7 +713,7 @@ private: mrcpW = _mm_set1_ps(1.0f / blockPosX.W); worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosX.WorldX), mrcpW); - __m128i dynlightnext = CalcDynamicLight(lights, num_lights, worldpos, worldnormal); + __m128i dynlightnext = CalcDynamicLight(lights, num_lights, worldpos, worldnormal, dynlightcolor); __m128i dynlightstep = _mm_srai_epi16(_mm_sub_epi16(dynlightnext, dynlight), 3); dynlight = _mm_max_epi16(_mm_min_epi16(_mm_add_epi16(dynlight, _mm_and_si128(dynlightstep, _mm_set_epi32(0xffff, 0xffff, 0, 0))), _mm_set1_epi16(256)), _mm_setzero_si128()); dynlightstep = _mm_slli_epi16(dynlightstep, 1); diff --git a/src/polyrenderer/scene/poly_sprite.cpp b/src/polyrenderer/scene/poly_sprite.cpp index 51a5bca519..b2590c357a 100644 --- a/src/polyrenderer/scene/poly_sprite.cpp +++ b/src/polyrenderer/scene/poly_sprite.cpp @@ -154,6 +154,7 @@ void RenderPolySprite::Render(PolyRenderThread *thread, const TriMatrix &worldTo int lightlevel = fullbrightSprite ? 255 : thing->Sector->lightlevel + actualextralight; PolyDrawArgs args; + SetDynlight(thing, args); args.SetLight(GetColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], true), lightlevel, PolyRenderer::Instance()->Light.SpriteGlobVis(foggy), fullbrightSprite); args.SetTransform(&worldToClip); args.SetFaceCullCCW(true); @@ -368,3 +369,51 @@ FTexture *RenderPolySprite::GetSpriteTexture(AActor *thing, /*out*/ bool &flipX) } } } + +void RenderPolySprite::SetDynlight(AActor *thing, PolyDrawArgs &args) +{ + float lit_red = 0; + float lit_green = 0; + float lit_blue = 0; + auto node = thing->Sector->lighthead; + while (node != nullptr) + { + ADynamicLight *light = node->lightsource; + if (light->visibletoplayer && !(light->flags2&MF2_DORMANT) && (!(light->lightflags&LF_DONTLIGHTSELF) || light->target != thing) && !(light->lightflags&LF_DONTLIGHTACTORS)) + { + float lx = (float)(light->X() - thing->X()); + float ly = (float)(light->Y() - thing->Y()); + float lz = (float)(light->Z() - thing->Center()); + float LdotL = lx * lx + ly * ly + lz * lz; + float radius = node->lightsource->GetRadius(); + if (radius * radius >= LdotL) + { + float distance = sqrt(LdotL); + float attenuation = 1.0f - distance / radius; + if (attenuation > 0.0f) + { + float red = light->GetRed() * (1.0f / 255.0f); + float green = light->GetGreen() * (1.0f / 255.0f); + float blue = light->GetBlue() * (1.0f / 255.0f); + /*if (light->IsSubtractive()) + { + float bright = FVector3(lr, lg, lb).Length(); + FVector3 lightColor(lr, lg, lb); + red = (bright - lr) * -1; + green = (bright - lg) * -1; + blue = (bright - lb) * -1; + }*/ + + lit_red += red * attenuation; + lit_green += green * attenuation; + lit_blue += blue * attenuation; + } + } + } + node = node->nextLight; + } + lit_red = clamp(lit_red * 255.0f, 0.0f, 255.0f); + lit_green = clamp(lit_green * 255.0f, 0.0f, 255.0f); + lit_blue = clamp(lit_blue * 255.0f, 0.0f, 255.0f); + args.SetDynLightColor((((uint32_t)lit_red) << 16) | (((uint32_t)lit_green) << 8) | ((uint32_t)lit_blue)); +} diff --git a/src/polyrenderer/scene/poly_sprite.h b/src/polyrenderer/scene/poly_sprite.h index f634d74692..84c4905dc3 100644 --- a/src/polyrenderer/scene/poly_sprite.h +++ b/src/polyrenderer/scene/poly_sprite.h @@ -37,6 +37,7 @@ private: static double PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, double spriteheight, double z); static double GetSpriteFloorZ(AActor *thing, const DVector2 &thingpos); static double GetSpriteCeilingZ(AActor *thing, const DVector2 &thingpos); + static void SetDynlight(AActor *thing, PolyDrawArgs &args); }; class PolyTranslucentThing : public PolyTranslucentObject