- Add dynamic light to sprites

This commit is contained in:
Magnus Norddahl 2017-09-23 14:14:59 +02:00
parent abc8e4deac
commit f3ba92f03c
4 changed files with 63 additions and 8 deletions

View file

@ -81,6 +81,7 @@ public:
void SetTransform(const TriMatrix *objectToClip) { mObjectToClip = objectToClip; } void SetTransform(const TriMatrix *objectToClip) { mObjectToClip = objectToClip; }
void SetColor(uint32_t bgra, uint8_t palindex); void SetColor(uint32_t bgra, uint8_t palindex);
void SetLights(PolyLight *lights, int numLights) { mLights = lights; mNumLights = numLights; } 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); void DrawArray(PolyRenderThread *thread, const TriVertex *vertices, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles);
const TriMatrix *ObjectToClip() const { return mObjectToClip; } const TriMatrix *ObjectToClip() const { return mObjectToClip; }
@ -129,6 +130,7 @@ public:
PolyLight *Lights() const { return mLights; } PolyLight *Lights() const { return mLights; }
int NumLights() const { return mNumLights; } int NumLights() const { return mNumLights; }
uint32_t DynLightColor() const { return mDynLightColor; }
const FVector3 &Normal() const { return mNormal; } const FVector3 &Normal() const { return mNormal; }
void SetNormal(const FVector3 &normal) { mNormal = normal; } void SetNormal(const FVector3 &normal) { mNormal = normal; }
@ -172,6 +174,7 @@ private:
PolyLight *mLights = nullptr; PolyLight *mLights = nullptr;
int mNumLights = 0; int mNumLights = 0;
FVector3 mNormal; FVector3 mNormal;
uint32_t mDynLightColor = 0;
}; };
class RectDrawArgs class RectDrawArgs

View file

@ -149,9 +149,10 @@ namespace TriScreenDrawerModes
return fgcolor; 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++) for (int i = 0; i != num_lights; i++)
{ {
@ -396,6 +397,7 @@ private:
auto lights = args->uniforms->Lights(); auto lights = args->uniforms->Lights();
auto num_lights = args->uniforms->NumLights(); 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); __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 // Calculate gradients
const ShadedTriVertex &v1 = *args->v1; const ShadedTriVertex &v1 = *args->v1;
@ -476,7 +478,7 @@ private:
__m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W); __m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W);
__m128 worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosY.WorldX), mrcpW); __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; ScreenTriangleStepVariables blockPosX = blockPosY;
blockPosX.W += gradientX.W; blockPosX.W += gradientX.W;
@ -498,7 +500,7 @@ private:
mrcpW = _mm_set1_ps(1.0f / blockPosX.W); mrcpW = _mm_set1_ps(1.0f / blockPosX.W);
worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosX.WorldX), mrcpW); 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); __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()); 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); dynlightstep = _mm_slli_epi16(dynlightstep, 1);
@ -579,7 +581,7 @@ private:
__m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W); __m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W);
__m128 worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosY.WorldX), mrcpW); __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; ScreenTriangleStepVariables blockPosX = blockPosY;
blockPosX.W += gradientX.W; blockPosX.W += gradientX.W;
@ -601,7 +603,7 @@ private:
mrcpW = _mm_set1_ps(1.0f / blockPosX.W); mrcpW = _mm_set1_ps(1.0f / blockPosX.W);
worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosX.WorldX), mrcpW); 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); __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()); 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); dynlightstep = _mm_slli_epi16(dynlightstep, 1);
@ -689,7 +691,7 @@ private:
__m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W); __m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W);
__m128 worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosY.WorldX), mrcpW); __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; ScreenTriangleStepVariables blockPosX = blockPosY;
blockPosX.W += gradientX.W; blockPosX.W += gradientX.W;
@ -711,7 +713,7 @@ private:
mrcpW = _mm_set1_ps(1.0f / blockPosX.W); mrcpW = _mm_set1_ps(1.0f / blockPosX.W);
worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosX.WorldX), mrcpW); 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); __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()); 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); dynlightstep = _mm_slli_epi16(dynlightstep, 1);

View file

@ -154,6 +154,7 @@ void RenderPolySprite::Render(PolyRenderThread *thread, const TriMatrix &worldTo
int lightlevel = fullbrightSprite ? 255 : thing->Sector->lightlevel + actualextralight; int lightlevel = fullbrightSprite ? 255 : thing->Sector->lightlevel + actualextralight;
PolyDrawArgs args; 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.SetLight(GetColorTable(sub->sector->Colormap, sub->sector->SpecialColors[sector_t::sprites], true), lightlevel, PolyRenderer::Instance()->Light.SpriteGlobVis(foggy), fullbrightSprite);
args.SetTransform(&worldToClip); args.SetTransform(&worldToClip);
args.SetFaceCullCCW(true); 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));
}

View file

@ -37,6 +37,7 @@ private:
static double PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, double spriteheight, double z); static double PerformSpriteClipAdjustment(AActor *thing, const DVector2 &thingpos, double spriteheight, double z);
static double GetSpriteFloorZ(AActor *thing, const DVector2 &thingpos); static double GetSpriteFloorZ(AActor *thing, const DVector2 &thingpos);
static double GetSpriteCeilingZ(AActor *thing, const DVector2 &thingpos); static double GetSpriteCeilingZ(AActor *thing, const DVector2 &thingpos);
static void SetDynlight(AActor *thing, PolyDrawArgs &args);
}; };
class PolyTranslucentThing : public PolyTranslucentObject class PolyTranslucentThing : public PolyTranslucentObject