From 789214200cd8189cac2f2bef5f3f06f4d916e06d Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 23 Sep 2017 02:27:39 +0200 Subject: [PATCH] - Attenuated lights support --- src/polyrenderer/drawers/poly_draw_args.h | 4 ++++ src/polyrenderer/drawers/poly_drawer32_sse2.h | 7 ++++--- src/polyrenderer/scene/poly_plane.cpp | 11 ++++++++--- src/polyrenderer/scene/poly_plane.h | 2 +- src/polyrenderer/scene/poly_wall.cpp | 15 ++++++++++++++- 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/polyrenderer/drawers/poly_draw_args.h b/src/polyrenderer/drawers/poly_draw_args.h index 6417669a04..c3a685c880 100644 --- a/src/polyrenderer/drawers/poly_draw_args.h +++ b/src/polyrenderer/drawers/poly_draw_args.h @@ -130,6 +130,9 @@ public: PolyLight *Lights() const { return mLights; } int NumLights() const { return mNumLights; } + const FVector3 &Normal() const { return mNormal; } + void SetNormal(const FVector3 &normal) { mNormal = normal; } + private: const TriMatrix *mObjectToClip = nullptr; const TriVertex *mVertices = nullptr; @@ -168,6 +171,7 @@ private: bool mFixedLight = false; PolyLight *mLights = nullptr; int mNumLights = 0; + FVector3 mNormal; }; class RectDrawArgs diff --git a/src/polyrenderer/drawers/poly_drawer32_sse2.h b/src/polyrenderer/drawers/poly_drawer32_sse2.h index 0f69f5a4dc..f4d3cb3928 100644 --- a/src/polyrenderer/drawers/poly_drawer32_sse2.h +++ b/src/polyrenderer/drawers/poly_drawer32_sse2.h @@ -180,9 +180,10 @@ namespace TriScreenDrawerModes __m128 simple_attenuation = distance_attenuation; // The point light type - // diffuse = dot(N,L) * attenuation - __m128 dotNL = _mm_mul_ps(worldnormal, L); + // diffuse = max(dot(N,normalize(L)),0) * attenuation + __m128 dotNL = _mm_mul_ps(worldnormal, _mm_mul_ps(L, _mm_shuffle_ps(rcp_dist, rcp_dist, _MM_SHUFFLE(0, 0, 0, 0)))); 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)))); + dotNL = _mm_max_ss(dotNL, _mm_setzero_ps()); __m128 point_attenuation = _mm_mul_ss(dotNL, distance_attenuation); point_attenuation = _mm_shuffle_ps(point_attenuation, point_attenuation, _MM_SHUFFLE(0, 0, 0, 0)); @@ -394,7 +395,7 @@ private: auto lights = args->uniforms->Lights(); auto num_lights = args->uniforms->NumLights(); - __m128 worldnormal = _mm_setzero_ps(); + __m128 worldnormal = _mm_setr_ps(args->uniforms->Normal().X, args->uniforms->Normal().Y, args->uniforms->Normal().Z, 0.0f); // Calculate gradients const ShadedTriVertex &v1 = *args->v1; diff --git a/src/polyrenderer/scene/poly_plane.cpp b/src/polyrenderer/scene/poly_plane.cpp index 766d4260b8..2ec86327e6 100644 --- a/src/polyrenderer/scene/poly_plane.cpp +++ b/src/polyrenderer/scene/poly_plane.cpp @@ -254,7 +254,7 @@ void RenderPolyPlane::Render(PolyRenderThread *thread, const TriMatrix &worldToC if (!isSky) { - SetDynLights(thread, args, sub); + SetDynLights(thread, args, sub, ceiling); args.SetTexture(tex); args.SetStyle(TriBlendMode::TextureOpaque); args.DrawArray(thread, vertices, sub->numlines, PolyDrawMode::TriangleFan); @@ -279,7 +279,7 @@ void RenderPolyPlane::Render(PolyRenderThread *thread, const TriMatrix &worldToC } } -void RenderPolyPlane::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub) +void RenderPolyPlane::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, bool ceiling) { FLightNode *light_list = sub->lighthead; @@ -315,7 +315,7 @@ void RenderPolyPlane::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, { if (!(cur_node->lightsource->flags2&MF2_DORMANT)) { - //bool is_point_light = (cur_node->lightsource->lightflags & LF_ATTENUATE) != 0; + bool is_point_light = (cur_node->lightsource->lightflags & LF_ATTENUATE) != 0; // To do: cull lights not touching subsector @@ -329,12 +329,17 @@ void RenderPolyPlane::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, light.z = (float)cur_node->lightsource->Z(); light.radius = 256.0f / cur_node->lightsource->GetRadius(); light.color = (red << 16) | (green << 8) | blue; + if (is_point_light) + light.radius = -light.radius; } cur_node = cur_node->nextLight; } args.SetLights(dc_lights, dc_num_lights); + + DVector3 normal = ceiling ? sub->sector->ceilingplane.Normal() : sub->sector->floorplane.Normal(); + args.SetNormal({ (float)normal.X, (float)normal.Y, (float)normal.Z }); } void RenderPolyPlane::RenderSkyWalls(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, sector_t *frontsector, FSectorPortal *portal, PolyDrawSectorPortal *polyportal, bool ceiling, double skyHeight, const PolyPlaneUVTransform &transform) diff --git a/src/polyrenderer/scene/poly_plane.h b/src/polyrenderer/scene/poly_plane.h index 2293f4f633..74db247e6c 100644 --- a/src/polyrenderer/scene/poly_plane.h +++ b/src/polyrenderer/scene/poly_plane.h @@ -62,7 +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); + void SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args, subsector_t *sub, bool ceiling); }; class Render3DFloorPlane diff --git a/src/polyrenderer/scene/poly_wall.cpp b/src/polyrenderer/scene/poly_wall.cpp index c90052b228..aba99a85ab 100644 --- a/src/polyrenderer/scene/poly_wall.cpp +++ b/src/polyrenderer/scene/poly_wall.cpp @@ -404,7 +404,7 @@ void RenderPolyWall::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args) { if (!(cur_node->lightsource->flags2&MF2_DORMANT)) { - //bool is_point_light = (cur_node->lightsource->lightflags & LF_ATTENUATE) != 0; + bool is_point_light = (cur_node->lightsource->lightflags & LF_ATTENUATE) != 0; // To do: cull lights not touching wall @@ -418,12 +418,25 @@ void RenderPolyWall::SetDynLights(PolyRenderThread *thread, PolyDrawArgs &args) light.z = (float)cur_node->lightsource->Z(); light.radius = 256.0f / cur_node->lightsource->GetRadius(); light.color = (red << 16) | (green << 8) | blue; + if (is_point_light) + light.radius = -light.radius; } cur_node = cur_node->nextLight; } args.SetLights(dc_lights, dc_num_lights); + + // Face normal: + float dx = (float)(v2.X - v1.X); + float dy = (float)(v2.Y - v1.Y); + float nx = dy; + float ny = -dx; + float lensqr = nx * nx + ny * ny; + float rcplen = 1.0f / sqrt(lensqr); + nx *= rcplen; + ny *= rcplen; + args.SetNormal({ nx, ny, 0.0f }); } void RenderPolyWall::DrawStripes(PolyRenderThread *thread, PolyDrawArgs &args, TriVertex *vertices)