diff --git a/src/r_draw.cpp b/src/r_draw.cpp index 6e159243a..f476e9538 100644 --- a/src/r_draw.cpp +++ b/src/r_draw.cpp @@ -62,6 +62,7 @@ namespace swrenderer extern int wallshade; double dc_texturemid; + FLightNode *dc_light_list; int ylookup[MAXHEIGHT]; uint8_t shadetables[NUMCOLORMAPS * 16 * 256]; @@ -100,6 +101,10 @@ namespace swrenderer uint8_t *dc_destorg; int dc_destheight; int dc_count; + FVector3 dc_viewpos; + FVector3 dc_viewpos_step; + TriLight *dc_lights; + int dc_num_lights; uint32_t dc_wall_texturefrac[4]; uint32_t dc_wall_iscale[4]; uint8_t *dc_wall_colormap[4]; diff --git a/src/r_draw.h b/src/r_draw.h index 88ac2338d..a337b4943 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -4,6 +4,8 @@ #include "r_defs.h" struct FSWColormap; +struct FLightNode; +struct TriLight; EXTERN_CVAR(Bool, r_multithreaded); EXTERN_CVAR(Bool, r_magfilter); @@ -34,6 +36,7 @@ namespace swrenderer }; extern double dc_texturemid; + extern FLightNode *dc_light_list; namespace drawerargs { @@ -63,6 +66,10 @@ namespace swrenderer extern uint8_t *dc_destorg; extern int dc_destheight; extern int dc_count; + extern FVector3 dc_viewpos; + extern FVector3 dc_viewpos_step; + extern TriLight *dc_lights; + extern int dc_num_lights; extern bool drawer_needs_pal_input; diff --git a/src/r_draw_rgba.cpp b/src/r_draw_rgba.cpp index 7b4763855..2928ac73e 100644 --- a/src/r_draw_rgba.cpp +++ b/src/r_draw_rgba.cpp @@ -221,26 +221,11 @@ namespace swrenderer if (args.source2[0] == nullptr) args.flags |= DrawWallArgs::nearest_filter; + args.z = 0.0f; + args.step_z = 0.0f; args.dynlights = nullptr; args.num_dynlights = 0; - /* - static TriLight fakelight; - static bool first = true; - if (first) - { - fakelight.x = 100.0f; - fakelight.y = 0.0f; - fakelight.z = 100.0f; - fakelight.color = 0xffffff00; - fakelight.radius = 256.0f / 1000.0f; - first = false; - } - args.z = 0.0f; - args.step_z = 1.0f; - args.dynlights = &fakelight; - args.num_dynlights = 1; - */ DetectRangeError(args.dest, args.dest_y, args.count); } @@ -299,10 +284,10 @@ namespace swrenderer if (args.source2[0] == nullptr) args.flags |= DrawWallArgs::nearest_filter; - args.z = 0.0f; - args.step_z = 0.0f; - args.dynlights = nullptr; - args.num_dynlights = 0; + args.z = dc_viewpos.Z; + args.step_z = dc_viewpos_step.Z; + args.dynlights = dc_lights; + args.num_dynlights = dc_num_lights; DetectRangeError(args.dest, args.dest_y, args.count); } diff --git a/src/r_segs.cpp b/src/r_segs.cpp index 41a8a9166..14abcfc24 100644 --- a/src/r_segs.cpp +++ b/src/r_segs.cpp @@ -60,7 +60,7 @@ namespace swrenderer { using namespace drawerargs; - void R_DrawWallSegment(FTexture *rw_pic, int x1, int x2, short *walltop, short *wallbottom, float *swall, fixed_t *lwall, double yscale, double top, double bottom, bool mask); + void R_DrawWallSegment(FTexture *rw_pic, int x1, int x2, short *walltop, short *wallbottom, float *swall, fixed_t *lwall, double yscale, double top, double bottom, bool mask, FLightNode *light_list = nullptr); void R_DrawDrawSeg(drawseg_t *ds, int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat); #define HEIGHTBITS 12 @@ -1139,6 +1139,8 @@ void R_RenderSegLoop () } if(fake3D & 7) return; + FLightNode *light_list = (curline && curline->sidedef) ? curline->sidedef->lighthead : nullptr; + // draw the wall tiers if (midtexture) { // one sided line @@ -1165,7 +1167,7 @@ void R_RenderSegLoop () { rw_offset = -rw_offset; } - R_DrawWallSegment(rw_pic, x1, x2, walltop, wallbottom, swall, lwall, yscale, MAX(rw_frontcz1, rw_frontcz2), MIN(rw_frontfz1, rw_frontfz2), false); + R_DrawWallSegment(rw_pic, x1, x2, walltop, wallbottom, swall, lwall, yscale, MAX(rw_frontcz1, rw_frontcz2), MIN(rw_frontfz1, rw_frontfz2), false, light_list); } fillshort (ceilingclip+x1, x2-x1, viewheight); fillshort (floorclip+x1, x2-x1, 0xffff); @@ -1201,7 +1203,7 @@ void R_RenderSegLoop () { rw_offset = -rw_offset; } - R_DrawWallSegment(rw_pic, x1, x2, walltop, wallupper, swall, lwall, yscale, MAX(rw_frontcz1, rw_frontcz2), MIN(rw_backcz1, rw_backcz2), false); + R_DrawWallSegment(rw_pic, x1, x2, walltop, wallupper, swall, lwall, yscale, MAX(rw_frontcz1, rw_frontcz2), MIN(rw_backcz1, rw_backcz2), false, light_list); } memcpy (ceilingclip+x1, wallupper+x1, (x2-x1)*sizeof(short)); } @@ -1240,7 +1242,7 @@ void R_RenderSegLoop () { rw_offset = -rw_offset; } - R_DrawWallSegment(rw_pic, x1, x2, walllower, wallbottom, swall, lwall, yscale, MAX(rw_backfz1, rw_backfz2), MIN(rw_frontfz1, rw_frontfz2), false); + R_DrawWallSegment(rw_pic, x1, x2, walllower, wallbottom, swall, lwall, yscale, MAX(rw_backfz1, rw_backfz2), MIN(rw_frontfz1, rw_frontfz2), false, light_list); } memcpy (floorclip+x1, walllower+x1, (x2-x1)*sizeof(short)); } diff --git a/src/r_walldraw.cpp b/src/r_walldraw.cpp index dcdfa4b89..ad82f54dc 100644 --- a/src/r_walldraw.cpp +++ b/src/r_walldraw.cpp @@ -42,6 +42,8 @@ #include "r_3dfloors.h" #include "v_palette.h" #include "r_data/colormaps.h" +#include "gl/dynlights/gl_dynlight.h" +#include "r_drawers.h" namespace swrenderer { @@ -537,6 +539,53 @@ static void Draw1Column(int x, int y1, int y2, WallSampler &sampler, void(*draw1 { if (r_swtruecolor) { + // Find column position in view space + float w1 = 1.0f / WallC.sz1; + float w2 = 1.0f / WallC.sz2; + float t = (x - WallC.sx1 + 0.5f) / (WallC.sx2 - WallC.sx1); + float wcol = w1 * (1.0f - t) + w2 * t; + float zcol = 1.0f / wcol; + float xcol = (WallC.tleft.X * w1 * (1.0f - t) + WallC.tright.X * w2 * t) * zcol; + float ycol = (WallC.tleft.Y * w1 * (1.0f - t) + WallC.tright.Y * w2 * t) * zcol; + dc_viewpos.X = xcol; + dc_viewpos.Y = ycol; + dc_viewpos.Z = (float)((CenterY - y1 - 0.5) / InvZtoScale * zcol); + dc_viewpos_step.Z = (float)(-zcol / InvZtoScale); + + static TriLight lightbuffer[64 * 1024]; + static int nextlightindex = 0; + + // Setup lights for column + dc_num_lights = 0; + dc_lights = lightbuffer + nextlightindex; + FLightNode *cur_node = dc_light_list; + while (cur_node && nextlightindex < 64 * 1024) + { + uint32_t red = cur_node->lightsource->GetRed(); + uint32_t green = cur_node->lightsource->GetGreen(); + uint32_t blue = cur_node->lightsource->GetBlue(); + + double lightX = cur_node->lightsource->X() - ViewPos.X; + double lightY = cur_node->lightsource->Y() - ViewPos.Y; + double lightZ = cur_node->lightsource->Z() - ViewPos.Z; + + nextlightindex++; + auto &light = dc_lights[dc_num_lights++]; + light.x = (float)(lightX * ViewSin - lightY * ViewCos) - dc_viewpos.X; + light.y = (float)(lightX * ViewTanCos + lightY * ViewTanSin) - dc_viewpos.Y; + light.z = (float)lightZ; + light.radius = 256.0f / cur_node->lightsource->GetRadius(); + light.color = 0xff000000 | (red << 16) | (green << 8) | blue; + + // Precalculate the constant part of the dot here so the drawer doesn't have to. + light.x = light.x * light.x + light.y * light.y; + + cur_node = cur_node->nextLight; + } + + if (nextlightindex == 64 * 1024) + nextlightindex = 0; + int count = y2 - y1; dc_source = sampler.source; @@ -738,6 +787,25 @@ static void ProcessWallWorker( float light = rw_light; + double xmagnitude = 1.0; + +#if !defined(NO_DYNAMIC_SWLIGHTS) + for (int x = x1; x < x2; x++, light += rw_lightstep) + { + int y1 = uwal[x]; + int y2 = dwal[x]; + if (y2 <= y1) + continue; + + if (!fixed) + R_SetColorMapLight(basecolormap, light, wallshade); + + if (x + 1 < x2) xmagnitude = fabs(FIXED2DBL(lwal[x + 1]) - FIXED2DBL(lwal[x])); + + WallSampler sampler(y1, swal[x], yrepeat, lwal[x] + xoffset, xmagnitude, rw_pic, getcol); + Draw1Column(x, y1, y2, sampler, draw1column); + } +#else // Calculate where 4 column alignment begins and ends: int aligned_x1 = clamp((x1 + 3) / 4 * 4, x1, x2); int aligned_x2 = clamp(x2 / 4 * 4, x1, x2); @@ -872,6 +940,7 @@ static void ProcessWallWorker( WallSampler sampler(y1, swal[x], yrepeat, lwal[x] + xoffset, xmagnitude, rw_pic, getcol); Draw1Column(x, y1, y2, sampler, draw1column); } +#endif NetUpdate(); } @@ -1077,8 +1146,9 @@ void R_DrawDrawSeg(drawseg_t *ds, int x1, int x2, short *uwal, short *dwal, floa } -void R_DrawWallSegment(FTexture *rw_pic, int x1, int x2, short *walltop, short *wallbottom, float *swall, fixed_t *lwall, double yscale, double top, double bottom, bool mask) +void R_DrawWallSegment(FTexture *rw_pic, int x1, int x2, short *walltop, short *wallbottom, float *swall, fixed_t *lwall, double yscale, double top, double bottom, bool mask, FLightNode *light_list) { + dc_light_list = light_list; if (rw_pic->GetHeight() != 1 << rw_pic->HeightBits) { ProcessWallNP2(x1, x2, walltop, wallbottom, swall, lwall, yscale, top, bottom, false); @@ -1087,6 +1157,7 @@ void R_DrawWallSegment(FTexture *rw_pic, int x1, int x2, short *walltop, short * { ProcessWall(x1, x2, walltop, wallbottom, swall, lwall, yscale, false); } + dc_light_list = nullptr; } void R_DrawSkySegment(visplane_t *pl, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, const BYTE *(*getcol)(FTexture *tex, int x)) diff --git a/tools/drawergen/fixedfunction/drawwallcodegen.cpp b/tools/drawergen/fixedfunction/drawwallcodegen.cpp index 1ec00df76..6f546b9b3 100644 --- a/tools/drawergen/fixedfunction/drawwallcodegen.cpp +++ b/tools/drawergen/fixedfunction/drawwallcodegen.cpp @@ -107,6 +107,9 @@ void DrawWallCodegen::Generate(DrawWallVariant variant, bool fourColumns, SSAVal one[i] = ((0x80000000 + textureheight[i] - 1) / textureheight[i]) * 2 + 1; } + start_z = start_z + step_z * SSAFloat(skipped_by_thread(dest_y, thread)); + step_z = step_z * SSAFloat(thread.num_cores); + SSAIfBlock branch; branch.if_block(is_simple_shade); LoopShade(variant, fourColumns, true);