From dd8a114bb821ccc5e3a15e34151de71a3d907ffd Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 21 Sep 2017 05:39:16 +0200 Subject: [PATCH] - Initial dynamic light support for softpoly --- src/polyrenderer/drawers/poly_draw_args.h | 13 +++ src/polyrenderer/drawers/poly_drawer32_sse2.h | 110 ++++++++++++++++-- src/polyrenderer/drawers/poly_triangle.cpp | 6 + src/polyrenderer/drawers/screen_triangle.h | 14 ++- src/polyrenderer/scene/poly_plane.cpp | 60 ++++++++++ src/polyrenderer/scene/poly_plane.h | 1 + src/polyrenderer/scene/poly_wall.cpp | 61 ++++++++++ src/polyrenderer/scene/poly_wall.h | 2 + 8 files changed, 257 insertions(+), 10 deletions(-) diff --git a/src/polyrenderer/drawers/poly_draw_args.h b/src/polyrenderer/drawers/poly_draw_args.h index c53b0260f..6417669a0 100644 --- a/src/polyrenderer/drawers/poly_draw_args.h +++ b/src/polyrenderer/drawers/poly_draw_args.h @@ -55,6 +55,13 @@ struct TriVertex float u, v; }; +struct PolyLight +{ + uint32_t color; + float x, y, z; + float radius; +}; + class PolyDrawArgs { public: @@ -73,6 +80,7 @@ public: void SetStyle(const FRenderStyle &renderstyle, double alpha, uint32_t fillcolor, uint32_t translationID, FTexture *texture, bool fullbright); 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 DrawArray(PolyRenderThread *thread, const TriVertex *vertices, int vcount, PolyDrawMode mode = PolyDrawMode::Triangles); const TriMatrix *ObjectToClip() const { return mObjectToClip; } @@ -119,6 +127,9 @@ public: bool NearestFilter() const { return mNearestFilter; } bool FixedLight() const { return mFixedLight; } + PolyLight *Lights() const { return mLights; } + int NumLights() const { return mNumLights; } + private: const TriMatrix *mObjectToClip = nullptr; const TriVertex *mVertices = nullptr; @@ -155,6 +166,8 @@ private: bool mSimpleShade = true; bool mNearestFilter = true; bool mFixedLight = false; + PolyLight *mLights = nullptr; + int mNumLights = 0; }; class RectDrawArgs diff --git a/src/polyrenderer/drawers/poly_drawer32_sse2.h b/src/polyrenderer/drawers/poly_drawer32_sse2.h index a88b92bd6..1cef53719 100644 --- a/src/polyrenderer/drawers/poly_drawer32_sse2.h +++ b/src/polyrenderer/drawers/poly_drawer32_sse2.h @@ -142,9 +142,64 @@ namespace TriScreenDrawerModes } } - template - FORCEINLINE __m128i VECTORCALL Shade32(__m128i fgcolor, __m128i mlight, unsigned int ifgcolor0, unsigned int ifgcolor1, int desaturate, __m128i inv_desaturate, __m128i shade_fade, __m128i shade_light) + FORCEINLINE __m128i VECTORCALL AddLights(__m128i material, __m128i fgcolor, const PolyLight *lights, int num_lights, __m128 worldpos, __m128 worldnormal) { + __m128i lit = _mm_setzero_si128(); + + for (int i = 0; i != num_lights; i++) + { + __m128 m256 = _mm_set1_ps(256.0f); + __m128 mSignBit = _mm_set1_ps(-0.0f); + + __m128 lightpos = _mm_loadu_ps(&lights[i].x); + __m128 light_radius = _mm_load_ss(&lights[i].radius); + + __m128 is_attenuated = _mm_cmpge_ss(light_radius, _mm_setzero_ps()); + is_attenuated = _mm_shuffle_ps(is_attenuated, is_attenuated, _MM_SHUFFLE(0, 0, 0, 0)); + light_radius = _mm_andnot_ps(mSignBit, light_radius); + + // L = light-pos + // dist = sqrt(dot(L, L)) + // distance_attenuation = 1 - MIN(dist * (1/radius), 1) + __m128 L = _mm_sub_ps(lightpos, worldpos); + __m128 dist2 = _mm_mul_ps(L, L); + dist2 = _mm_add_ss(dist2, _mm_add_ss(_mm_shuffle_ps(dist2, dist2, _MM_SHUFFLE(0, 0, 0, 1)), _mm_shuffle_ps(dist2, dist2, _MM_SHUFFLE(0, 0, 0, 2)))); + __m128 rcp_dist = _mm_rsqrt_ss(dist2); + __m128 dist = _mm_mul_ss(dist2, rcp_dist); + __m128 distance_attenuation = _mm_sub_ss(m256, _mm_min_ss(_mm_mul_ss(dist, light_radius), m256)); + distance_attenuation = _mm_shuffle_ps(distance_attenuation, distance_attenuation, _MM_SHUFFLE(0, 0, 0, 0)); + + // The simple light type + __m128 simple_attenuation = distance_attenuation; + + // The point light type + // diffuse = dot(N,L) * attenuation + __m128 dotNL = _mm_mul_ps(worldnormal, L); + dotNL = _mm_add_ss(dotNL, _mm_add_ss(_mm_shuffle_ps(dotNL, dotNL, _MM_SHUFFLE(0, 0, 0, 1)), _mm_shuffle_ps(dotNL, dotNL, _MM_SHUFFLE(0, 0, 0, 2)))); + __m128 point_attenuation = _mm_mul_ss(dotNL, distance_attenuation); + point_attenuation = _mm_shuffle_ps(point_attenuation, point_attenuation, _MM_SHUFFLE(0, 0, 0, 0)); + + __m128i attenuation = _mm_cvtps_epi32(_mm_or_ps(_mm_and_ps(is_attenuated, simple_attenuation), _mm_andnot_ps(is_attenuated, point_attenuation))); + attenuation = _mm_packs_epi32(_mm_shuffle_epi32(attenuation, _MM_SHUFFLE(0, 0, 0, 0)), _mm_shuffle_epi32(attenuation, _MM_SHUFFLE(1, 1, 1, 1))); + + __m128i light_color = _mm_cvtsi32_si128(lights[i].color); + light_color = _mm_unpacklo_epi8(light_color, _mm_setzero_si128()); + light_color = _mm_shuffle_epi32(light_color, _MM_SHUFFLE(1, 0, 1, 0)); + + lit = _mm_add_epi16(lit, _mm_srli_epi16(_mm_mullo_epi16(light_color, attenuation), 8)); + } + + lit = _mm_min_epi16(lit, _mm_set1_epi16(256)); + + fgcolor = _mm_add_epi16(fgcolor, _mm_srli_epi16(_mm_mullo_epi16(material, lit), 8)); + fgcolor = _mm_min_epi16(fgcolor, _mm_set1_epi16(255)); + return fgcolor; + } + + template + FORCEINLINE __m128i VECTORCALL Shade32(__m128i fgcolor, __m128i mlight, unsigned int ifgcolor0, unsigned int ifgcolor1, int desaturate, __m128i inv_desaturate, __m128i shade_fade, __m128i shade_light, const PolyLight *lights, int num_lights, __m128 worldpos, __m128 worldnormal) + { + __m128i material = fgcolor; if (ShadeModeT::Mode == (int)ShadeMode::Simple) { fgcolor = _mm_srli_epi16(_mm_mullo_epi16(fgcolor, mlight), 8); @@ -168,7 +223,8 @@ namespace TriScreenDrawerModes fgcolor = _mm_srli_epi16(_mm_add_epi16(shade_fade, fgcolor), 8); fgcolor = _mm_srli_epi16(_mm_mullo_epi16(fgcolor, shade_light), 8); } - return fgcolor; + + return AddLights(material, fgcolor, lights, num_lights, worldpos, worldnormal); } template @@ -333,6 +389,11 @@ private: int fuzzpos = (ScreenTriangle::FuzzStart + destX * 123 + destY) % FUZZTABLE; + auto lights = args->uniforms->Lights(); + auto num_lights = args->uniforms->NumLights(); + __m128 worldpos = _mm_setzero_ps(); + __m128 worldnormal = _mm_setzero_ps(); + // Calculate gradients const ShadedTriVertex &v1 = *args->v1; ScreenTriangleStepVariables gradientX = args->gradientX; @@ -341,9 +402,15 @@ private: blockPosY.W = v1.w + gradientX.W * (destX - v1.x) + gradientY.W * (destY - v1.y); blockPosY.U = v1.u * v1.w + gradientX.U * (destX - v1.x) + gradientY.U * (destY - v1.y); blockPosY.V = v1.v * v1.w + gradientX.V * (destX - v1.x) + gradientY.V * (destY - v1.y); + blockPosY.WorldX = v1.worldX * v1.w + gradientX.WorldX * (destX - v1.x) + gradientY.WorldX * (destY - v1.y); + blockPosY.WorldY = v1.worldY * v1.w + gradientX.WorldY * (destX - v1.x) + gradientY.WorldY * (destY - v1.y); + blockPosY.WorldZ = v1.worldZ * v1.w + gradientX.WorldZ * (destX - v1.x) + gradientY.WorldZ * (destY - v1.y); gradientX.W *= 8.0f; gradientX.U *= 8.0f; gradientX.V *= 8.0f; + gradientX.WorldX *= 8.0f; + gradientX.WorldY *= 8.0f; + gradientX.WorldZ *= 8.0f; // Output uint32_t * RESTRICT destOrg = (uint32_t*)args->dest; @@ -404,10 +471,16 @@ private: fixed_t lightpos = FRACUNIT - (int)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + __m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W); + worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosY.WorldX), mrcpW); + ScreenTriangleStepVariables blockPosX = blockPosY; blockPosX.W += gradientX.W; blockPosX.U += gradientX.U; blockPosX.V += gradientX.V; + blockPosX.WorldX += gradientX.WorldX; + blockPosX.WorldY += gradientX.WorldY; + blockPosX.WorldZ += gradientX.WorldZ; rcpW = 0x01000000 / blockPosX.W; int32_t nextU = (int32_t)(blockPosX.U * rcpW); @@ -462,7 +535,7 @@ private: // Shade and blend __m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128()); - fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light); + fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light, lights, num_lights, worldpos, worldnormal); __m128i outcolor = Blend32(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha); // Store result @@ -472,6 +545,9 @@ private: blockPosY.W += gradientY.W; blockPosY.U += gradientY.U; blockPosY.V += gradientY.V; + blockPosY.WorldX += gradientY.WorldX; + blockPosY.WorldY += gradientY.WorldY; + blockPosY.WorldZ += gradientY.WorldZ; dest += pitch; } @@ -488,10 +564,16 @@ private: fixed_t lightpos = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + __m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W); + worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosY.WorldX), mrcpW); + ScreenTriangleStepVariables blockPosX = blockPosY; blockPosX.W += gradientX.W; blockPosX.U += gradientX.U; blockPosX.V += gradientX.V; + blockPosX.WorldX += gradientX.WorldX; + blockPosX.WorldY += gradientX.WorldY; + blockPosX.WorldZ += gradientX.WorldZ; rcpW = 0x01000000 / blockPosX.W; int32_t nextU = (int32_t)(blockPosX.U * rcpW); @@ -551,7 +633,7 @@ private: // Shade and blend __m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128()); - fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light); + fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light, lights, num_lights, worldpos, worldnormal); __m128i outcolor = Blend32(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha); // Store result @@ -565,6 +647,9 @@ private: blockPosY.W += gradientY.W; blockPosY.U += gradientY.U; blockPosY.V += gradientY.V; + blockPosY.WorldX += gradientY.WorldX; + blockPosY.WorldY += gradientY.WorldY; + blockPosY.WorldZ += gradientY.WorldZ; dest += pitch; } @@ -579,10 +664,16 @@ private: fixed_t lightpos = FRACUNIT - (fixed_t)(clamp(shade - MIN(24.0f / 32.0f, globVis * blockPosY.W), 0.0f, 31.0f / 32.0f) * (float)FRACUNIT); lightpos = (lightpos & lightmask) | ((light << 8) & ~lightmask); + __m128 mrcpW = _mm_set1_ps(1.0f / blockPosY.W); + worldpos = _mm_mul_ps(_mm_loadu_ps(&blockPosY.WorldX), mrcpW); + ScreenTriangleStepVariables blockPosX = blockPosY; blockPosX.W += gradientX.W; blockPosX.U += gradientX.U; blockPosX.V += gradientX.V; + blockPosX.WorldX += gradientX.WorldX; + blockPosX.WorldY += gradientX.WorldY; + blockPosX.WorldZ += gradientX.WorldZ; rcpW = 0x01000000 / blockPosX.W; int32_t nextU = (int32_t)(blockPosX.U * rcpW); @@ -642,7 +733,7 @@ private: // Shade and blend __m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128()); - fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light); + fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light, lights, num_lights, worldpos, worldnormal); __m128i outcolor = Blend32(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha); // Store result @@ -656,6 +747,9 @@ private: blockPosY.W += gradientY.W; blockPosY.U += gradientY.U; blockPosY.V += gradientY.V; + blockPosY.WorldX += gradientY.WorldX; + blockPosY.WorldY += gradientY.WorldY; + blockPosY.WorldZ += gradientY.WorldZ; dest += pitch; } @@ -798,7 +892,7 @@ private: // Shade and blend __m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128()); - fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light); + fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light, nullptr, 0, _mm_setzero_ps(), _mm_setzero_ps()); __m128i outcolor = Blend32(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha); // Store result @@ -826,7 +920,7 @@ private: // Shade and blend __m128i fgcolor = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i*)ifgcolor), _mm_setzero_si128()); - fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light); + fgcolor = Shade32(fgcolor, mlight, ifgcolor[0], ifgcolor[1], desaturate, inv_desaturate, shade_fade_lit, shade_light, nullptr, 0, _mm_setzero_ps(), _mm_setzero_ps()); __m128i outcolor = Blend32(fgcolor, bgcolor, ifgcolor[0], ifgcolor[1], ifgshade[0], ifgshade[1], srcalpha, destalpha); // Store result diff --git a/src/polyrenderer/drawers/poly_triangle.cpp b/src/polyrenderer/drawers/poly_triangle.cpp index 2448e2544..beb283498 100644 --- a/src/polyrenderer/drawers/poly_triangle.cpp +++ b/src/polyrenderer/drawers/poly_triangle.cpp @@ -155,6 +155,9 @@ ShadedTriVertex PolyTriangleDrawer::shade_vertex(const PolyDrawArgs &drawargs, c sv.w = position.W; sv.u = v.u; sv.v = v.v; + sv.worldX = v.x; + sv.worldY = v.y; + sv.worldZ = v.z; // Calculate gl_ClipDistance[i] for (int i = 0; i < 3; i++) @@ -446,6 +449,9 @@ int PolyTriangleDrawer::clipedge(const ShadedTriVertex *verts, ShadedTriVertex * v.w += verts[w].w * weight; v.u += verts[w].u * weight; v.v += verts[w].v * weight; + v.worldX += verts[w].worldX * weight; + v.worldY += verts[w].worldY * weight; + v.worldZ += verts[w].worldZ * weight; } } return inputverts; diff --git a/src/polyrenderer/drawers/screen_triangle.h b/src/polyrenderer/drawers/screen_triangle.h index d51c8b63e..a76dc4b46 100644 --- a/src/polyrenderer/drawers/screen_triangle.h +++ b/src/polyrenderer/drawers/screen_triangle.h @@ -46,11 +46,13 @@ struct ShadedTriVertex float x, y, z, w; float u, v; float clipDistance[3]; + float worldX, worldY, worldZ; }; struct ScreenTriangleStepVariables { float W, U, V; + float WorldX, WorldY, WorldZ, Padding; // Padding so it can be loaded directly into a XMM register }; struct TriDrawTriangleArgs @@ -79,11 +81,19 @@ struct TriDrawTriangleArgs return false; gradientX.W = FindGradientX(bottomX, 1.0f, 1.0f, 1.0f); - gradientY.W = FindGradientY(bottomY, 1.0f, 1.0f, 1.0f); gradientX.U = FindGradientX(bottomX, v1->u, v2->u, v3->u); - gradientY.U = FindGradientY(bottomY, v1->u, v2->u, v3->u); gradientX.V = FindGradientX(bottomX, v1->v, v2->v, v3->v); + gradientX.WorldX = FindGradientX(bottomX, v1->worldX, v2->worldX, v3->worldX); + gradientX.WorldY = FindGradientX(bottomX, v1->worldY, v2->worldY, v3->worldY); + gradientX.WorldZ = FindGradientX(bottomX, v1->worldZ, v2->worldZ, v3->worldZ); + + gradientY.W = FindGradientY(bottomY, 1.0f, 1.0f, 1.0f); + gradientY.U = FindGradientY(bottomY, v1->u, v2->u, v3->u); gradientY.V = FindGradientY(bottomY, v1->v, v2->v, v3->v); + gradientY.WorldX = FindGradientY(bottomY, v1->worldX, v2->worldX, v3->worldX); + gradientY.WorldY = FindGradientY(bottomY, v1->worldY, v2->worldY, v3->worldY); + gradientY.WorldZ = FindGradientY(bottomY, v1->worldZ, v2->worldZ, v3->worldZ); + return true; } diff --git a/src/polyrenderer/scene/poly_plane.cpp b/src/polyrenderer/scene/poly_plane.cpp index 668053a01..766d4260b 100644 --- a/src/polyrenderer/scene/poly_plane.cpp +++ b/src/polyrenderer/scene/poly_plane.cpp @@ -32,6 +32,7 @@ #include "polyrenderer/scene/poly_light.h" #include "polyrenderer/poly_renderthread.h" #include "p_lnspec.h" +#include "a_dynlight.h" EXTERN_CVAR(Int, r_3dfloors) @@ -253,6 +254,7 @@ void RenderPolyPlane::Render(PolyRenderThread *thread, const TriMatrix &worldToC if (!isSky) { + SetDynLights(thread, args, sub); args.SetTexture(tex); args.SetStyle(TriBlendMode::TextureOpaque); args.DrawArray(thread, vertices, sub->numlines, PolyDrawMode::TriangleFan); @@ -277,6 +279,64 @@ void RenderPolyPlane::Render(PolyRenderThread *thread, const TriMatrix &worldToC } } +void RenderPolyPlane::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub) +{ + FLightNode *light_list = sub->lighthead; + + auto cameraLight = PolyCameraLight::Instance(); + if ((cameraLight->FixedLightLevel() >= 0) || (cameraLight->FixedColormap() != nullptr)) + { + args.SetLights(nullptr, 0); // [SP] Don't draw dynlights if invul/lightamp active + return; + } + + // Calculate max lights that can touch the wall so we can allocate memory for the list + int max_lights = 0; + FLightNode *cur_node = light_list; + while (cur_node) + { + if (!(cur_node->lightsource->flags2&MF2_DORMANT)) + max_lights++; + cur_node = cur_node->nextLight; + } + + if (max_lights == 0) + { + args.SetLights(nullptr, 0); + return; + } + + int dc_num_lights = 0; + PolyLight *dc_lights = thread->FrameMemory->AllocMemory(max_lights); + + // Setup lights + cur_node = light_list; + while (cur_node) + { + if (!(cur_node->lightsource->flags2&MF2_DORMANT)) + { + //bool is_point_light = (cur_node->lightsource->lightflags & LF_ATTENUATE) != 0; + + // To do: cull lights not touching subsector + + uint32_t red = cur_node->lightsource->GetRed(); + uint32_t green = cur_node->lightsource->GetGreen(); + uint32_t blue = cur_node->lightsource->GetBlue(); + + auto &light = dc_lights[dc_num_lights++]; + light.x = (float)cur_node->lightsource->X(); + light.y = (float)cur_node->lightsource->Y(); + light.z = (float)cur_node->lightsource->Z(); + light.radius = 256.0f / cur_node->lightsource->GetRadius(); + light.color = (red << 16) | (green << 8) | blue; + } + + cur_node = cur_node->nextLight; + } + + args.SetLights(dc_lights, dc_num_lights); +} + void RenderPolyPlane::RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, sector_t *frontsector, FSectorPortal *portal, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight, const PolyPlaneUVTransform &transform) { for (uint32_t i = 0; i < sub->numlines; i++) diff --git a/src/polyrenderer/scene/poly_plane.h b/src/polyrenderer/scene/poly_plane.h index 918640369..2293f4f63 100644 --- a/src/polyrenderer/scene/poly_plane.h +++ b/src/polyrenderer/scene/poly_plane.h @@ -62,6 +62,7 @@ public: private: void Render(PolyRenderThread *thread, const TriMatrix &worldToClip, const PolyClipPlane &clipPlane, subsector_t *sub, uint32_t stencilValue, bool ceiling, double skyHeight, std::vector> §orPortals); void RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, sector_t *frontsector, FSectorPortal *portal, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight, const PolyPlaneUVTransform &transform); + void SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub); }; class Render3DFloorPlane diff --git a/src/polyrenderer/scene/poly_wall.cpp b/src/polyrenderer/scene/poly_wall.cpp index 57e24da37..c90052b22 100644 --- a/src/polyrenderer/scene/poly_wall.cpp +++ b/src/polyrenderer/scene/poly_wall.cpp @@ -35,6 +35,7 @@ #include "polyrenderer/scene/poly_light.h" #include "polyrenderer/poly_renderthread.h" #include "g_levellocals.h" +#include "a_dynlight.h" EXTERN_CVAR(Bool, r_drawmirrors) EXTERN_CVAR(Bool, r_fogboundary) @@ -326,6 +327,8 @@ void RenderPolyWall::Render(PolyRenderThread *thread, const TriMatrix &worldToCl args.SetTexture(Texture); args.SetClipPlane(0, clipPlane); + SetDynLights(thread, args); + if (FogBoundary) { args.SetStyle(TriBlendMode::FogBoundary); @@ -365,6 +368,64 @@ void RenderPolyWall::Render(PolyRenderThread *thread, const TriMatrix &worldToCl RenderPolyDecal::RenderWallDecals(thread, worldToClip, clipPlane, LineSeg, StencilValue); } +void RenderPolyWall::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args) +{ + FLightNode *light_list = (LineSeg && LineSeg->sidedef) ? LineSeg->sidedef->lighthead : nullptr; + + auto cameraLight = PolyCameraLight::Instance(); + if ((cameraLight->FixedLightLevel() >= 0) || (cameraLight->FixedColormap() != nullptr)) + { + args.SetLights(nullptr, 0); // [SP] Don't draw dynlights if invul/lightamp active + return; + } + + // Calculate max lights that can touch the wall so we can allocate memory for the list + int max_lights = 0; + FLightNode *cur_node = light_list; + while (cur_node) + { + if (!(cur_node->lightsource->flags2&MF2_DORMANT)) + max_lights++; + cur_node = cur_node->nextLight; + } + + if (max_lights == 0) + { + args.SetLights(nullptr, 0); + return; + } + + int dc_num_lights = 0; + PolyLight *dc_lights = thread->FrameMemory->AllocMemory(max_lights); + + // Setup lights + cur_node = light_list; + while (cur_node) + { + if (!(cur_node->lightsource->flags2&MF2_DORMANT)) + { + //bool is_point_light = (cur_node->lightsource->lightflags & LF_ATTENUATE) != 0; + + // To do: cull lights not touching wall + + uint32_t red = cur_node->lightsource->GetRed(); + uint32_t green = cur_node->lightsource->GetGreen(); + uint32_t blue = cur_node->lightsource->GetBlue(); + + auto &light = dc_lights[dc_num_lights++]; + light.x = (float)cur_node->lightsource->X(); + light.y = (float)cur_node->lightsource->Y(); + light.z = (float)cur_node->lightsource->Z(); + light.radius = 256.0f / cur_node->lightsource->GetRadius(); + light.color = (red << 16) | (green << 8) | blue; + } + + cur_node = cur_node->nextLight; + } + + args.SetLights(dc_lights, dc_num_lights); +} + void RenderPolyWall::DrawStripes(PolyRenderThread *thread, PolyDrawArgs &args, TriVertex *vertices) { const auto &lightlist = Line->frontsector->e->XFloor.lightlist; diff --git a/src/polyrenderer/scene/poly_wall.h b/src/polyrenderer/scene/poly_wall.h index 40b6d5509..6cb7aae2f 100644 --- a/src/polyrenderer/scene/poly_wall.h +++ b/src/polyrenderer/scene/poly_wall.h @@ -68,6 +68,8 @@ private: int GetLightLevel(); void DrawStripes(PolyRenderThread *thread, PolyDrawArgs &args, TriVertex *vertices); + void SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args); + static bool IsFogBoundary(sector_t *front, sector_t *back); static FTexture *GetTexture(const line_t *Line, const side_t *Side, side_t::ETexpart texpart); };