From c61e9c7fe2e3445270c8712efa3df44dcd2b8dc7 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 2 Jan 2017 06:52:50 +0100 Subject: [PATCH] Add attenuated point lights --- src/swrenderer/drawers/r_draw.cpp | 1 + src/swrenderer/drawers/r_draw.h | 1 + src/swrenderer/drawers/r_draw_pal.cpp | 28 +++++++++++++++---- src/swrenderer/line/r_walldraw.cpp | 12 +++++++- src/swrenderer/plane/r_flatplane.cpp | 12 ++++++-- .../fixedfunction/drawspancodegen.cpp | 17 +++++++++-- .../fixedfunction/drawwallcodegen.cpp | 17 +++++++++-- tools/drawergen/ssa/ssa_bool.cpp | 5 ++++ tools/drawergen/ssa/ssa_bool.h | 1 + 9 files changed, 80 insertions(+), 14 deletions(-) diff --git a/src/swrenderer/drawers/r_draw.cpp b/src/swrenderer/drawers/r_draw.cpp index 99a37a18a..413e7e156 100644 --- a/src/swrenderer/drawers/r_draw.cpp +++ b/src/swrenderer/drawers/r_draw.cpp @@ -102,6 +102,7 @@ namespace swrenderer uint8_t *dc_destorg; int dc_destheight; int dc_count; + FVector3 dc_normal; FVector3 dc_viewpos; FVector3 dc_viewpos_step; TriLight *dc_lights; diff --git a/src/swrenderer/drawers/r_draw.h b/src/swrenderer/drawers/r_draw.h index 6715589b3..195214658 100644 --- a/src/swrenderer/drawers/r_draw.h +++ b/src/swrenderer/drawers/r_draw.h @@ -66,6 +66,7 @@ namespace swrenderer extern uint8_t *dc_destorg; extern int dc_destheight; extern int dc_count; + extern FVector3 dc_normal; extern FVector3 dc_viewpos; extern FVector3 dc_viewpos_step; extern TriLight *dc_lights; diff --git a/src/swrenderer/drawers/r_draw_pal.cpp b/src/swrenderer/drawers/r_draw_pal.cpp index 94250ccd5..84b9745dd 100644 --- a/src/swrenderer/drawers/r_draw_pal.cpp +++ b/src/swrenderer/drawers/r_draw_pal.cpp @@ -128,12 +128,21 @@ namespace swrenderer // L = light-pos // dist = sqrt(dot(L, L)) - // attenuation = 1 - MIN(dist * (1/radius), 1) + // distance_attenuation = 1 - MIN(dist * (1/radius), 1) float Lxy2 = lights[i].x; // L.x*L.x + L.y*L.y float Lz = lights[i].z - viewpos_z; float dist2 = Lxy2 + Lz * Lz; - float dist = dist2 * _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&dist2))); - uint32_t attenuation = (uint32_t)(256.0f - MIN(dist * lights[i].radius, 256.0f)); + float rcp_dist = _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&dist2))); + float dist = dist2 * rcp_dist; + float distance_attenuation = (256.0f - MIN(dist * lights[i].radius, 256.0f)); + + // The simple light type + float simple_attenuation = distance_attenuation; + + // The point light type + // diffuse = dot(N,L) * attenuation + float point_attenuation = lights[i].y * rcp_dist * distance_attenuation; + uint32_t attenuation = (uint32_t)(lights[i].y == 0.0f ? simple_attenuation : point_attenuation); lit_r += (light_color_r * material_r * attenuation) >> 16; lit_g += (light_color_g * material_g * attenuation) >> 16; @@ -1733,8 +1742,17 @@ namespace swrenderer float Lyz2 = lights[i].y; // L.y*L.y + L.z*L.z float Lx = lights[i].x - viewpos_x; float dist2 = Lyz2 + Lx * Lx; - float dist = dist2 * _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&dist2))); - uint32_t attenuation = (uint32_t)(256.0f - MIN(dist * lights[i].radius, 256.0f)); + float rcp_dist = _mm_cvtss_f32(_mm_rsqrt_ss(_mm_load_ss(&dist2))); + float dist = dist2 * rcp_dist; + float distance_attenuation = (256.0f - MIN(dist * lights[i].radius, 256.0f)); + + // The simple light type + float simple_attenuation = distance_attenuation; + + // The point light type + // diffuse = dot(N,L) * attenuation + float point_attenuation = lights[i].z * rcp_dist * distance_attenuation; + uint32_t attenuation = (uint32_t)(lights[i].z == 0.0f ? simple_attenuation : point_attenuation); lit_r += (light_color_r * material_r * attenuation) >> 16; lit_g += (light_color_g * material_g * attenuation) >> 16; diff --git a/src/swrenderer/line/r_walldraw.cpp b/src/swrenderer/line/r_walldraw.cpp index da0206eec..3f22e62b7 100644 --- a/src/swrenderer/line/r_walldraw.cpp +++ b/src/swrenderer/line/r_walldraw.cpp @@ -227,11 +227,13 @@ namespace swrenderer float lz = (float)lightZ; // Precalculate the constant part of the dot here so the drawer doesn't have to. + bool is_point_light = (cur_node->lightsource->flags4 & MF4_ATTENUATE) != 0; float lconstant = lx * lx + ly * ly; + float nlconstant = is_point_light ? lx * dc_normal.X + ly * dc_normal.Y : 0.0f; // Include light only if it touches this column float radius = cur_node->lightsource->GetRadius(); - if (radius * radius >= lconstant) + if (radius * radius >= lconstant && nlconstant >= 0.0f) { uint32_t red = cur_node->lightsource->GetRed(); uint32_t green = cur_node->lightsource->GetGreen(); @@ -240,6 +242,7 @@ namespace swrenderer nextlightindex++; auto &light = dc_lights[dc_num_lights++]; light.x = lconstant; + light.y = nlconstant; light.z = lz; light.radius = 256.0f / cur_node->lightsource->GetRadius(); light.color = (red << 16) | (green << 8) | blue; @@ -365,6 +368,13 @@ namespace swrenderer else R_SetColorMapLight(basecolormap, 0, 0); + float dx = WallC.tright.X - WallC.tleft.X; + float dy = WallC.tright.Y - WallC.tleft.Y; + float length = sqrt(dx * dx + dy * dy); + dc_normal.X = dy / length; + dc_normal.Y = -dx / length; + dc_normal.Z = 0.0f; + float light = rw_light; double xmagnitude = 1.0; diff --git a/src/swrenderer/plane/r_flatplane.cpp b/src/swrenderer/plane/r_flatplane.cpp index 6d3206f23..e45e03a69 100644 --- a/src/swrenderer/plane/r_flatplane.cpp +++ b/src/swrenderer/plane/r_flatplane.cpp @@ -255,8 +255,13 @@ namespace swrenderer static TriLight lightbuffer[64 * 1024]; static int nextlightindex = 0; + + // Plane normal + dc_normal.X = 0.0f; + dc_normal.Y = 0.0f; + dc_normal.Z = (y >= CenterY) ? 1.0f : -1.0f; - // Setup lights for column + // Setup lights for row dc_num_lights = 0; dc_lights = lightbuffer + nextlightindex; visplane_light *cur_node = ds_light_list; @@ -271,11 +276,13 @@ namespace swrenderer float lz = (float)lightZ - dc_viewpos.Z; // Precalculate the constant part of the dot here so the drawer doesn't have to. + bool is_point_light = (cur_node->lightsource->flags4 & MF4_ATTENUATE) != 0; float lconstant = ly * ly + lz * lz; + float nlconstant = is_point_light ? lz * dc_normal.Z : 0.0f; // Include light only if it touches this row float radius = cur_node->lightsource->GetRadius(); - if (radius * radius >= lconstant) + if (radius * radius >= lconstant && nlconstant >= 0.0f) { uint32_t red = cur_node->lightsource->GetRed(); uint32_t green = cur_node->lightsource->GetGreen(); @@ -285,6 +292,7 @@ namespace swrenderer auto &light = dc_lights[dc_num_lights++]; light.x = lx; light.y = lconstant; + light.z = nlconstant; light.radius = 256.0f / radius; light.color = (red << 16) | (green << 8) | blue; } diff --git a/tools/drawergen/fixedfunction/drawspancodegen.cpp b/tools/drawergen/fixedfunction/drawspancodegen.cpp index 2272acf8d..0fdadaa84 100644 --- a/tools/drawergen/fixedfunction/drawspancodegen.cpp +++ b/tools/drawergen/fixedfunction/drawspancodegen.cpp @@ -248,7 +248,7 @@ SSAVec4i DrawSpanCodegen::Shade(SSAVec4i fg, bool isSimpleShade) SSAVec4i light_color = SSAUBytePtr(SSAValue(dynlights[light_index][0]).v).load_vec4ub(true); SSAFloat light_x = dynlights[light_index][1].load(true); SSAFloat light_y = dynlights[light_index][2].load(true); - //SSAFloat light_z = dynlights[light_index][3].load(true); + SSAFloat light_z = dynlights[light_index][3].load(true); SSAFloat light_rcp_radius = dynlights[light_index][4].load(true); // L = light-pos @@ -256,8 +256,19 @@ SSAVec4i DrawSpanCodegen::Shade(SSAVec4i fg, bool isSimpleShade) // attenuation = 1 - MIN(dist * (1/radius), 1) SSAFloat Lyz2 = light_y; // L.y*L.y + L.z*L.z SSAFloat Lx = light_x - viewpos_x; - SSAFloat dist = SSAFloat::fastsqrt(Lyz2 + Lx * Lx); - SSAInt attenuation = SSAInt(SSAFloat(256.0f) - SSAFloat::MIN(dist * light_rcp_radius, SSAFloat(256.0f)), true); + SSAFloat dist2 = Lyz2 + Lx * Lx; + SSAFloat rcp_dist = SSAFloat::rsqrt(dist2); + SSAFloat dist = dist2 * rcp_dist; + SSAFloat distance_attenuation = SSAFloat(256.0f) - SSAFloat::MIN(dist * light_rcp_radius, SSAFloat(256.0f)); + + // The simple light type + SSAFloat simple_attenuation = distance_attenuation; + + // The point light type + // diffuse = dot(N,L) * attenuation + SSAFloat point_attenuation = light_z * rcp_dist * distance_attenuation; + + SSAInt attenuation = SSAInt((light_z == SSAFloat(0.0f)).select(simple_attenuation, point_attenuation), true); SSAVec4i contribution = (light_color * fg * attenuation) >> 16; stack_lit_color.store(lit_color + contribution); diff --git a/tools/drawergen/fixedfunction/drawwallcodegen.cpp b/tools/drawergen/fixedfunction/drawwallcodegen.cpp index 055b132d1..9207fb63a 100644 --- a/tools/drawergen/fixedfunction/drawwallcodegen.cpp +++ b/tools/drawergen/fixedfunction/drawwallcodegen.cpp @@ -179,7 +179,7 @@ SSAVec4i DrawWallCodegen::Shade(SSAVec4i fg, bool isSimpleShade) { SSAVec4i light_color = SSAUBytePtr(SSAValue(dynlights[light_index][0]).v).load_vec4ub(true); SSAFloat light_x = dynlights[light_index][1].load(true); - //SSAFloat light_y = dynlights[light_index][2].load(true); + SSAFloat light_y = dynlights[light_index][2].load(true); SSAFloat light_z = dynlights[light_index][3].load(true); SSAFloat light_rcp_radius = dynlights[light_index][4].load(true); @@ -188,8 +188,19 @@ SSAVec4i DrawWallCodegen::Shade(SSAVec4i fg, bool isSimpleShade) // attenuation = 1 - MIN(dist * (1/radius), 1) SSAFloat Lxy2 = light_x; // L.x*L.x + L.y*L.y SSAFloat Lz = light_z - z; - SSAFloat dist = SSAFloat::fastsqrt(Lxy2 + Lz * Lz); - SSAInt attenuation = SSAInt(SSAFloat(256.0f) - SSAFloat::MIN(dist * light_rcp_radius, SSAFloat(256.0f)), true); + SSAFloat dist2 = Lxy2 + Lz * Lz; + SSAFloat rcp_dist = SSAFloat::rsqrt(dist2); + SSAFloat dist = dist2 * rcp_dist; + SSAFloat distance_attenuation = SSAFloat(256.0f) - SSAFloat::MIN(dist * light_rcp_radius, SSAFloat(256.0f)); + + // The simple light type + SSAFloat simple_attenuation = distance_attenuation; + + // The point light type + // diffuse = dot(N,L) * attenuation + SSAFloat point_attenuation = light_y * rcp_dist * distance_attenuation; + + SSAInt attenuation = SSAInt((light_y == SSAFloat(0.0f)).select(simple_attenuation, point_attenuation), true); SSAVec4i contribution = (light_color * fg * attenuation) >> 16; stack_lit_color.store(lit_color + contribution); diff --git a/tools/drawergen/ssa/ssa_bool.cpp b/tools/drawergen/ssa/ssa_bool.cpp index 7ce99b827..6eac90afb 100644 --- a/tools/drawergen/ssa/ssa_bool.cpp +++ b/tools/drawergen/ssa/ssa_bool.cpp @@ -58,6 +58,11 @@ SSAInt SSABool::select(SSAInt a, SSAInt b) return SSAValue::from_llvm(SSAScope::builder().CreateSelect(v, a.v, b.v, SSAScope::hint())); } +SSAFloat SSABool::select(SSAFloat a, SSAFloat b) +{ + return SSAValue::from_llvm(SSAScope::builder().CreateSelect(v, a.v, b.v, SSAScope::hint())); +} + SSAUByte SSABool::select(SSAUByte a, SSAUByte b) { return SSAValue::from_llvm(SSAScope::builder().CreateSelect(v, a.v, b.v, SSAScope::hint())); diff --git a/tools/drawergen/ssa/ssa_bool.h b/tools/drawergen/ssa/ssa_bool.h index 728c7b7e8..fbf5192d3 100644 --- a/tools/drawergen/ssa/ssa_bool.h +++ b/tools/drawergen/ssa/ssa_bool.h @@ -42,6 +42,7 @@ public: SSAInt zext_int(); SSAInt select(SSAInt a, SSAInt b); + SSAFloat select(SSAFloat a, SSAFloat b); SSAUByte select(SSAUByte a, SSAUByte b); SSAVec4i select(SSAVec4i a, SSAVec4i b);