diff --git a/src/swrenderer/drawers/r_draw.h b/src/swrenderer/drawers/r_draw.h index e6fa8ea4d..8ce1d904f 100644 --- a/src/swrenderer/drawers/r_draw.h +++ b/src/swrenderer/drawers/r_draw.h @@ -134,8 +134,8 @@ namespace swrenderer virtual void DrawWallAddClampColumn() = 0; virtual void DrawWallSubClampColumn() = 0; virtual void DrawWallRevSubClampColumn() = 0; - virtual void DrawSingleSkyColumn(uint32_t solid_top, uint32_t solid_bottom) = 0; - virtual void DrawDoubleSkyColumn(uint32_t solid_top, uint32_t solid_bottom) = 0; + virtual void DrawSingleSkyColumn(uint32_t solid_top, uint32_t solid_bottom, bool fadeSky) = 0; + virtual void DrawDoubleSkyColumn(uint32_t solid_top, uint32_t solid_bottom, bool fadeSky) = 0; virtual void DrawColumn() = 0; virtual void FillColumn() = 0; virtual void FillAddColumn() = 0; diff --git a/src/swrenderer/drawers/r_draw_pal.cpp b/src/swrenderer/drawers/r_draw_pal.cpp index b0938572d..ef77ee1eb 100644 --- a/src/swrenderer/drawers/r_draw_pal.cpp +++ b/src/swrenderer/drawers/r_draw_pal.cpp @@ -560,7 +560,7 @@ namespace swrenderer ///////////////////////////////////////////////////////////////////////// - PalSkyCommand::PalSkyCommand(uint32_t solid_top, uint32_t solid_bottom) : solid_top(solid_top), solid_bottom(solid_bottom) + PalSkyCommand::PalSkyCommand(uint32_t solid_top, uint32_t solid_bottom, bool fadeSky) : solid_top(solid_top), solid_bottom(solid_bottom), fadeSky(fadeSky) { using namespace drawerargs; @@ -588,7 +588,39 @@ namespace swrenderer int32_t frac = _texturefrac[0]; int32_t fracstep = _iscale[0]; + // Find bands for top solid color, top fade, center textured, bottom fade, bottom solid color: int start_fade = 2; // How fast it should fade out + int fade_length = (1 << (24 - start_fade)); + int start_fadetop_y = (-frac) / fracstep; + int end_fadetop_y = (fade_length - frac) / fracstep; + int start_fadebottom_y = ((2 << 24) - fade_length - frac) / fracstep; + int end_fadebottom_y = ((2 << 24) - frac) / fracstep; + start_fadetop_y = clamp(start_fadetop_y, 0, count); + end_fadetop_y = clamp(end_fadetop_y, 0, count); + start_fadebottom_y = clamp(start_fadebottom_y, 0, count); + end_fadebottom_y = clamp(end_fadebottom_y, 0, count); + + int num_cores = thread->num_cores; + int skipped = thread->skipped_by_thread(_dest_y); + dest = thread->dest_for_thread(_dest_y, pitch, dest); + frac += fracstep * skipped; + fracstep *= num_cores; + pitch *= num_cores; + + if (!fadeSky) + { + count = thread->count_for_thread(_dest_y, count); + + for (int index = 0; index < count; index++) + { + uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; + *dest = source0[sample_index]; + dest += pitch; + frac += fracstep; + } + + return; + } int solid_top_r = RPART(solid_top); int solid_top_g = GPART(solid_top); @@ -596,49 +628,83 @@ namespace swrenderer int solid_bottom_r = RPART(solid_bottom); int solid_bottom_g = GPART(solid_bottom); int solid_bottom_b = BPART(solid_bottom); + uint8_t solid_top_fill = RGB32k.RGB[(solid_top_r >> 3)][(solid_top_g >> 3)][(solid_top_b >> 3)]; + uint8_t solid_bottom_fill = RGB32k.RGB[(solid_bottom_r >> 3)][(solid_bottom_g >> 3)][(solid_bottom_b >> 3)]; - count = thread->count_for_thread(_dest_y, count); - if (count <= 0) - return; + const uint32_t *palette = (const uint32_t *)GPalette.BaseColors; - int skipped = thread->skipped_by_thread(_dest_y); - dest = thread->dest_for_thread(_dest_y, pitch, dest); - frac += fracstep * skipped; - fracstep *= thread->num_cores; - pitch *= thread->num_cores; + int index = skipped; - for (int index = 0; index < count; index++) + // Top solid color: + while (index < start_fadetop_y) + { + *dest = solid_top_fill; + dest += pitch; + frac += fracstep; + index += num_cores; + } + + // Top fade: + while (index < end_fadetop_y) { uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; uint8_t fg = source0[sample_index]; + uint32_t c = palette[fg]; int alpha_top = MAX(MIN(frac >> (16 - start_fade), 256), 0); - int alpha_bottom = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0); - - if (alpha_top == 256 && alpha_bottom == 256) - { - *dest = fg; - } - else - { - int inv_alpha_top = 256 - alpha_top; - int inv_alpha_bottom = 256 - alpha_bottom; - - const auto &c = GPalette.BaseColors[fg]; - int c_red = c.r; - int c_green = c.g; - int c_blue = c.b; - c_red = (c_red * alpha_top + solid_top_r * inv_alpha_top) >> 8; - c_green = (c_green * alpha_top + solid_top_g * inv_alpha_top) >> 8; - c_blue = (c_blue * alpha_top + solid_top_b * inv_alpha_top) >> 8; - c_red = (c_red * alpha_bottom + solid_bottom_r * inv_alpha_bottom) >> 8; - c_green = (c_green * alpha_bottom + solid_bottom_g * inv_alpha_bottom) >> 8; - c_blue = (c_blue * alpha_bottom + solid_bottom_b * inv_alpha_bottom) >> 8; - *dest = RGB256k.RGB[(c_red >> 2)][(c_green >> 2)][(c_blue >> 2)]; - } + int inv_alpha_top = 256 - alpha_top; + int c_red = RPART(c); + int c_green = GPART(c); + int c_blue = BPART(c); + c_red = (c_red * alpha_top + solid_top_r * inv_alpha_top) >> 8; + c_green = (c_green * alpha_top + solid_top_g * inv_alpha_top) >> 8; + c_blue = (c_blue * alpha_top + solid_top_b * inv_alpha_top) >> 8; + *dest = RGB256k.RGB[(c_red >> 2)][(c_green >> 2)][(c_blue >> 2)]; frac += fracstep; dest += pitch; + index += num_cores; + } + + // Textured center: + while (index < start_fadebottom_y) + { + uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; + *dest = source0[sample_index]; + + frac += fracstep; + dest += pitch; + index += num_cores; + } + + // Fade bottom: + while (index < end_fadebottom_y) + { + uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; + uint8_t fg = source0[sample_index]; + + uint32_t c = palette[fg]; + int alpha_bottom = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0); + int inv_alpha_bottom = 256 - alpha_bottom; + int c_red = RPART(c); + int c_green = GPART(c); + int c_blue = BPART(c); + c_red = (c_red * alpha_bottom + solid_bottom_r * inv_alpha_bottom) >> 8; + c_green = (c_green * alpha_bottom + solid_bottom_g * inv_alpha_bottom) >> 8; + c_blue = (c_blue * alpha_bottom + solid_bottom_b * inv_alpha_bottom) >> 8; + *dest = RGB256k.RGB[(c_red >> 2)][(c_green >> 2)][(c_blue >> 2)]; + + frac += fracstep; + dest += pitch; + index += num_cores; + } + + // Bottom solid color: + while (index < count) + { + *dest = solid_bottom_fill; + dest += pitch; + index += num_cores; } } @@ -655,7 +721,46 @@ namespace swrenderer int32_t frac = _texturefrac[0]; int32_t fracstep = _iscale[0]; + // Find bands for top solid color, top fade, center textured, bottom fade, bottom solid color: int start_fade = 2; // How fast it should fade out + int fade_length = (1 << (24 - start_fade)); + int start_fadetop_y = (-frac) / fracstep; + int end_fadetop_y = (fade_length - frac) / fracstep; + int start_fadebottom_y = ((2 << 24) - fade_length - frac) / fracstep; + int end_fadebottom_y = ((2 << 24) - frac) / fracstep; + start_fadetop_y = clamp(start_fadetop_y, 0, count); + end_fadetop_y = clamp(end_fadetop_y, 0, count); + start_fadebottom_y = clamp(start_fadebottom_y, 0, count); + end_fadebottom_y = clamp(end_fadebottom_y, 0, count); + + int num_cores = thread->num_cores; + int skipped = thread->skipped_by_thread(_dest_y); + dest = thread->dest_for_thread(_dest_y, pitch, dest); + frac += fracstep * skipped; + fracstep *= num_cores; + pitch *= num_cores; + + if (!fadeSky) + { + count = thread->count_for_thread(_dest_y, count); + + for (int index = 0; index < count; index++) + { + uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; + uint8_t fg = source0[sample_index]; + if (fg == 0) + { + uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + fg = source1[sample_index2]; + } + + *dest = fg; + dest += pitch; + frac += fracstep; + } + + return; + } int solid_top_r = RPART(solid_top); int solid_top_g = GPART(solid_top); @@ -663,18 +768,24 @@ namespace swrenderer int solid_bottom_r = RPART(solid_bottom); int solid_bottom_g = GPART(solid_bottom); int solid_bottom_b = BPART(solid_bottom); + uint8_t solid_top_fill = RGB32k.RGB[(solid_top_r >> 3)][(solid_top_g >> 3)][(solid_top_b >> 3)]; + uint8_t solid_bottom_fill = RGB32k.RGB[(solid_bottom_r >> 3)][(solid_bottom_g >> 3)][(solid_bottom_b >> 3)]; - count = thread->count_for_thread(_dest_y, count); - if (count <= 0) - return; + const uint32_t *palette = (const uint32_t *)GPalette.BaseColors; - int skipped = thread->skipped_by_thread(_dest_y); - dest = thread->dest_for_thread(_dest_y, pitch, dest); - frac += fracstep * skipped; - fracstep *= thread->num_cores; - pitch *= thread->num_cores; + int index = skipped; - for (int index = 0; index < count; index++) + // Top solid color: + while (index < start_fadetop_y) + { + *dest = solid_top_fill; + dest += pitch; + frac += fracstep; + index += num_cores; + } + + // Top fade: + while (index < end_fadetop_y) { uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; uint8_t fg = source0[sample_index]; @@ -684,33 +795,72 @@ namespace swrenderer fg = source1[sample_index2]; } + uint32_t c = palette[fg]; int alpha_top = MAX(MIN(frac >> (16 - start_fade), 256), 0); - int alpha_bottom = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0); - - if (alpha_top == 256 && alpha_bottom == 256) - { - *dest = fg; - } - else - { - int inv_alpha_top = 256 - alpha_top; - int inv_alpha_bottom = 256 - alpha_bottom; - - const auto &c = GPalette.BaseColors[fg]; - int c_red = c.r; - int c_green = c.g; - int c_blue = c.b; - c_red = (c_red * alpha_top + solid_top_r * inv_alpha_top) >> 8; - c_green = (c_green * alpha_top + solid_top_g * inv_alpha_top) >> 8; - c_blue = (c_blue * alpha_top + solid_top_b * inv_alpha_top) >> 8; - c_red = (c_red * alpha_bottom + solid_bottom_r * inv_alpha_bottom) >> 8; - c_green = (c_green * alpha_bottom + solid_bottom_g * inv_alpha_bottom) >> 8; - c_blue = (c_blue * alpha_bottom + solid_bottom_b * inv_alpha_bottom) >> 8; - *dest = RGB256k.RGB[(c_red >> 2)][(c_green >> 2)][(c_blue >> 2)]; - } + int inv_alpha_top = 256 - alpha_top; + int c_red = RPART(c); + int c_green = GPART(c); + int c_blue = BPART(c); + c_red = (c_red * alpha_top + solid_top_r * inv_alpha_top) >> 8; + c_green = (c_green * alpha_top + solid_top_g * inv_alpha_top) >> 8; + c_blue = (c_blue * alpha_top + solid_top_b * inv_alpha_top) >> 8; + *dest = RGB256k.RGB[(c_red >> 2)][(c_green >> 2)][(c_blue >> 2)]; frac += fracstep; dest += pitch; + index += num_cores; + } + + // Textured center: + while (index < start_fadebottom_y) + { + uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; + uint8_t fg = source0[sample_index]; + if (fg == 0) + { + uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + fg = source1[sample_index2]; + } + *dest = fg; + + frac += fracstep; + dest += pitch; + index += num_cores; + } + + // Fade bottom: + while (index < end_fadebottom_y) + { + uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; + uint8_t fg = source0[sample_index]; + if (fg == 0) + { + uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + fg = source1[sample_index2]; + } + + uint32_t c = palette[fg]; + int alpha_bottom = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0); + int inv_alpha_bottom = 256 - alpha_bottom; + int c_red = RPART(c); + int c_green = GPART(c); + int c_blue = BPART(c); + c_red = (c_red * alpha_bottom + solid_bottom_r * inv_alpha_bottom) >> 8; + c_green = (c_green * alpha_bottom + solid_bottom_g * inv_alpha_bottom) >> 8; + c_blue = (c_blue * alpha_bottom + solid_bottom_b * inv_alpha_bottom) >> 8; + *dest = RGB256k.RGB[(c_red >> 2)][(c_green >> 2)][(c_blue >> 2)]; + + frac += fracstep; + dest += pitch; + index += num_cores; + } + + // Bottom solid color: + while (index < count) + { + *dest = solid_bottom_fill; + dest += pitch; + index += num_cores; } } diff --git a/src/swrenderer/drawers/r_draw_pal.h b/src/swrenderer/drawers/r_draw_pal.h index a96660f84..e2d33f63e 100644 --- a/src/swrenderer/drawers/r_draw_pal.h +++ b/src/swrenderer/drawers/r_draw_pal.h @@ -42,12 +42,13 @@ namespace swrenderer class PalSkyCommand : public DrawerCommand { public: - PalSkyCommand(uint32_t solid_top, uint32_t solid_bottom); + PalSkyCommand(uint32_t solid_top, uint32_t solid_bottom, bool fadeSky); FString DebugInfo() override { return "PalSkyCommand"; } protected: uint32_t solid_top; uint32_t solid_bottom; + bool fadeSky; uint8_t *_dest; int _count; @@ -249,8 +250,8 @@ namespace swrenderer void DrawWallAddClampColumn() override { DrawerCommandQueue::QueueCommand(); } void DrawWallSubClampColumn() override { DrawerCommandQueue::QueueCommand(); } void DrawWallRevSubClampColumn() override { DrawerCommandQueue::QueueCommand(); } - void DrawSingleSkyColumn(uint32_t solid_top, uint32_t solid_bottom) override { DrawerCommandQueue::QueueCommand(solid_top, solid_bottom); } - void DrawDoubleSkyColumn(uint32_t solid_top, uint32_t solid_bottom) override { DrawerCommandQueue::QueueCommand(solid_top, solid_bottom); } + void DrawSingleSkyColumn(uint32_t solid_top, uint32_t solid_bottom, bool fadeSky) override { DrawerCommandQueue::QueueCommand(solid_top, solid_bottom, fadeSky); } + void DrawDoubleSkyColumn(uint32_t solid_top, uint32_t solid_bottom, bool fadeSky) override { DrawerCommandQueue::QueueCommand(solid_top, solid_bottom, fadeSky); } void DrawColumn() override { DrawerCommandQueue::QueueCommand(); } void FillColumn() override { DrawerCommandQueue::QueueCommand(); } void FillAddColumn() override { DrawerCommandQueue::QueueCommand(); } diff --git a/src/swrenderer/drawers/r_draw_rgba.cpp b/src/swrenderer/drawers/r_draw_rgba.cpp index 434497f99..a520d28ae 100644 --- a/src/swrenderer/drawers/r_draw_rgba.cpp +++ b/src/swrenderer/drawers/r_draw_rgba.cpp @@ -310,7 +310,7 @@ namespace swrenderer return d; } - DrawSkyLLVMCommand::DrawSkyLLVMCommand(uint32_t solid_top, uint32_t solid_bottom) + DrawSkyLLVMCommand::DrawSkyLLVMCommand(uint32_t solid_top, uint32_t solid_bottom, bool fadeSky) { using namespace drawerargs; diff --git a/src/swrenderer/drawers/r_draw_rgba.h b/src/swrenderer/drawers/r_draw_rgba.h index e1ed70350..0d40c63ed 100644 --- a/src/swrenderer/drawers/r_draw_rgba.h +++ b/src/swrenderer/drawers/r_draw_rgba.h @@ -157,7 +157,7 @@ namespace swrenderer WorkerThreadData ThreadData(DrawerThread *thread); public: - DrawSkyLLVMCommand(uint32_t solid_top, uint32_t solid_bottom); + DrawSkyLLVMCommand(uint32_t solid_top, uint32_t solid_bottom, bool fadeSky); FString DebugInfo() override; }; @@ -353,8 +353,8 @@ namespace swrenderer void DrawWallAddClampColumn() override { DrawerCommandQueue::QueueCommand(); } void DrawWallSubClampColumn() override { DrawerCommandQueue::QueueCommand(); } void DrawWallRevSubClampColumn() override { DrawerCommandQueue::QueueCommand(); } - void DrawSingleSkyColumn(uint32_t solid_top, uint32_t solid_bottom) override { DrawerCommandQueue::QueueCommand(solid_top, solid_bottom); } - void DrawDoubleSkyColumn(uint32_t solid_top, uint32_t solid_bottom) override { DrawerCommandQueue::QueueCommand(solid_top, solid_bottom); } + void DrawSingleSkyColumn(uint32_t solid_top, uint32_t solid_bottom, bool skyFade) override { DrawerCommandQueue::QueueCommand(solid_top, solid_bottom, skyFade); } + void DrawDoubleSkyColumn(uint32_t solid_top, uint32_t solid_bottom, bool skyFade) override { DrawerCommandQueue::QueueCommand(solid_top, solid_bottom, skyFade); } void DrawColumn() override { DrawerCommandQueue::QueueCommand(); } void FillColumn() override { DrawerCommandQueue::QueueCommand(); } void FillAddColumn() override { DrawerCommandQueue::QueueCommand(); } diff --git a/src/swrenderer/line/r_walldraw.cpp b/src/swrenderer/line/r_walldraw.cpp index 391d54ce3..43aaa38bc 100644 --- a/src/swrenderer/line/r_walldraw.cpp +++ b/src/swrenderer/line/r_walldraw.cpp @@ -59,24 +59,7 @@ namespace swrenderer FTexture *rw_pic; } - static const uint8_t *R_GetColumn(FTexture *tex, int col) - { - int width; - - // If the texture's width isn't a power of 2, then we need to make it a - // positive offset for proper clamping. - if (col < 0 && (width = tex->GetWidth()) != (1 << tex->WidthBits)) - { - col = width + (col % width); - } - - if (r_swtruecolor) - return (const uint8_t *)tex->GetColumnBgra(col, nullptr); - else - return tex->GetColumn(col, nullptr); - } - - WallSampler::WallSampler(int y1, double texturemid, float swal, double yrepeat, fixed_t xoffset, double xmagnitude, FTexture *texture, const BYTE*(*getcol)(FTexture *texture, int x)) + WallSampler::WallSampler(int y1, double texturemid, float swal, double yrepeat, fixed_t xoffset, double xmagnitude, FTexture *texture) { xoffset += FLOAT2FIXED(xmagnitude * 0.5); @@ -109,7 +92,21 @@ namespace swrenderer uv_max = 1; } - source = getcol(texture, xoffset >> FRACBITS); + int col = xoffset >> FRACBITS; + + // If the texture's width isn't a power of 2, then we need to make it a + // positive offset for proper clamping. + int width; + if (col < 0 && (width = texture->GetWidth()) != (1 << texture->WidthBits)) + { + col = width + (col % width); + } + + if (r_swtruecolor) + source = (const uint8_t *)texture->GetColumnBgra(col, nullptr); + else + source = texture->GetColumn(col, nullptr); + source2 = nullptr; texturefracx = 0; } @@ -134,64 +131,54 @@ namespace swrenderer uv_max = 0; // Texture mipmap and filter selection: - if (getcol != R_GetColumn) + double ymagnitude = fabs(uv_stepd); + double magnitude = MAX(ymagnitude, xmagnitude); + double min_lod = -1000.0; + double lod = MAX(log2(magnitude) + r_lod_bias, min_lod); + bool magnifying = lod < 0.0f; + + int mipmap_offset = 0; + int mip_width = texture->GetWidth(); + int mip_height = texture->GetHeight(); + if (r_mipmap && texture->Mipmapped() && mip_width > 1 && mip_height > 1) { - source = getcol(texture, xoffset >> FRACBITS); + uint32_t xpos = (uint32_t)((((uint64_t)xoffset) << FRACBITS) / mip_width); + + int level = (int)lod; + while (level > 0 && mip_width > 1 && mip_height > 1) + { + mipmap_offset += mip_width * mip_height; + level--; + mip_width = MAX(mip_width >> 1, 1); + mip_height = MAX(mip_height >> 1, 1); + } + xoffset = (xpos >> FRACBITS) * mip_width; + } + + const uint32_t *pixels = texture->GetPixelsBgra() + mipmap_offset; + + bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter); + if (filter_nearest) + { + int tx = (xoffset >> FRACBITS) % mip_width; + if (tx < 0) + tx += mip_width; + source = (BYTE*)(pixels + tx * mip_height); source2 = nullptr; - height = texture->GetHeight(); + height = mip_height; texturefracx = 0; } else { - double ymagnitude = fabs(uv_stepd); - double magnitude = MAX(ymagnitude, xmagnitude); - double min_lod = -1000.0; - double lod = MAX(log2(magnitude) + r_lod_bias, min_lod); - bool magnifying = lod < 0.0f; - - int mipmap_offset = 0; - int mip_width = texture->GetWidth(); - int mip_height = texture->GetHeight(); - if (r_mipmap && texture->Mipmapped() && mip_width > 1 && mip_height > 1) - { - uint32_t xpos = (uint32_t)((((uint64_t)xoffset) << FRACBITS) / mip_width); - - int level = (int)lod; - while (level > 0 && mip_width > 1 && mip_height > 1) - { - mipmap_offset += mip_width * mip_height; - level--; - mip_width = MAX(mip_width >> 1, 1); - mip_height = MAX(mip_height >> 1, 1); - } - xoffset = (xpos >> FRACBITS) * mip_width; - } - - const uint32_t *pixels = texture->GetPixelsBgra() + mipmap_offset; - - bool filter_nearest = (magnifying && !r_magfilter) || (!magnifying && !r_minfilter); - if (filter_nearest) - { - int tx = (xoffset >> FRACBITS) % mip_width; - if (tx < 0) - tx += mip_width; - source = (BYTE*)(pixels + tx * mip_height); - source2 = nullptr; - height = mip_height; - texturefracx = 0; - } - else - { - xoffset -= FRACUNIT / 2; - int tx0 = (xoffset >> FRACBITS) % mip_width; - if (tx0 < 0) - tx0 += mip_width; - int tx1 = (tx0 + 1) % mip_width; - source = (BYTE*)(pixels + tx0 * mip_height); - source2 = (BYTE*)(pixels + tx1 * mip_height); - height = mip_height; - texturefracx = (xoffset >> (FRACBITS - 4)) & 15; - } + xoffset -= FRACUNIT / 2; + int tx0 = (xoffset >> FRACBITS) % mip_width; + if (tx0 < 0) + tx0 += mip_width; + int tx1 = (tx0 + 1) % mip_width; + source = (BYTE*)(pixels + tx0 * mip_height); + source2 = (BYTE*)(pixels + tx1 * mip_height); + height = mip_height; + texturefracx = (xoffset >> (FRACBITS - 4)) & 15; } } } @@ -339,7 +326,7 @@ namespace swrenderer const FWallCoords &WallC, int x1, int x2, short *uwal, short *dwal, double texturemid, float *swal, fixed_t *lwal, double yrepeat, int wallshade, fixed_t xoffset, float light, float lightstep, FDynamicColormap *basecolormap, FLightNode *light_list, - const BYTE *(*getcol)(FTexture *tex, int x), DrawerFunc drawcolumn) + DrawerFunc drawcolumn) { if (rw_pic->UseType == FTexture::TEX_Null) return; @@ -394,41 +381,41 @@ namespace swrenderer if (x + 1 < x2) xmagnitude = fabs(FIXED2DBL(lwal[x + 1]) - FIXED2DBL(lwal[x])); - WallSampler sampler(y1, texturemid, swal[x], yrepeat, lwal[x] + xoffset, xmagnitude, rw_pic, getcol); + WallSampler sampler(y1, texturemid, swal[x], yrepeat, lwal[x] + xoffset, xmagnitude, rw_pic); Draw1Column(WallC, x, y1, y2, sampler, light_list, drawcolumn); } NetUpdate(); } - static void ProcessNormalWall(const FWallCoords &WallC, int x1, int x2, short *uwal, short *dwal, double texturemid, float *swal, fixed_t *lwal, double yrepeat, int wallshade, fixed_t xoffset, float light, float lightstep, FDynamicColormap *basecolormap, FLightNode *light_list, const BYTE *(*getcol)(FTexture *tex, int x) = R_GetColumn) + static void ProcessNormalWall(const FWallCoords &WallC, int x1, int x2, short *uwal, short *dwal, double texturemid, float *swal, fixed_t *lwal, double yrepeat, int wallshade, fixed_t xoffset, float light, float lightstep, FDynamicColormap *basecolormap, FLightNode *light_list) { - ProcessWallWorker(WallC, x1, x2, uwal, dwal, texturemid, swal, lwal, yrepeat, wallshade, xoffset, light, lightstep, basecolormap, light_list, getcol, &SWPixelFormatDrawers::DrawWallColumn); + ProcessWallWorker(WallC, x1, x2, uwal, dwal, texturemid, swal, lwal, yrepeat, wallshade, xoffset, light, lightstep, basecolormap, light_list, &SWPixelFormatDrawers::DrawWallColumn); } - static void ProcessMaskedWall(const FWallCoords &WallC, int x1, int x2, short *uwal, short *dwal, double texturemid, float *swal, fixed_t *lwal, double yrepeat, int wallshade, fixed_t xoffset, float light, float lightstep, FDynamicColormap *basecolormap, FLightNode *light_list, const BYTE *(*getcol)(FTexture *tex, int x) = R_GetColumn) + static void ProcessMaskedWall(const FWallCoords &WallC, int x1, int x2, short *uwal, short *dwal, double texturemid, float *swal, fixed_t *lwal, double yrepeat, int wallshade, fixed_t xoffset, float light, float lightstep, FDynamicColormap *basecolormap, FLightNode *light_list) { if (!rw_pic->bMasked) // Textures that aren't masked can use the faster ProcessNormalWall. { - ProcessNormalWall(WallC, x1, x2, uwal, dwal, texturemid, swal, lwal, yrepeat, wallshade, xoffset, light, lightstep, basecolormap, light_list, getcol); + ProcessNormalWall(WallC, x1, x2, uwal, dwal, texturemid, swal, lwal, yrepeat, wallshade, xoffset, light, lightstep, basecolormap, light_list); } else { - ProcessWallWorker(WallC, x1, x2, uwal, dwal, texturemid, swal, lwal, yrepeat, wallshade, xoffset, light, lightstep, basecolormap, light_list, getcol, &SWPixelFormatDrawers::DrawWallMaskedColumn); + ProcessWallWorker(WallC, x1, x2, uwal, dwal, texturemid, swal, lwal, yrepeat, wallshade, xoffset, light, lightstep, basecolormap, light_list, &SWPixelFormatDrawers::DrawWallMaskedColumn); } } - static void ProcessTranslucentWall(const FWallCoords &WallC, int x1, int x2, short *uwal, short *dwal, double texturemid, float *swal, fixed_t *lwal, double yrepeat, int wallshade, fixed_t xoffset, float light, float lightstep, FDynamicColormap *basecolormap, FLightNode *light_list, const BYTE *(*getcol)(FTexture *tex, int x) = R_GetColumn) + static void ProcessTranslucentWall(const FWallCoords &WallC, int x1, int x2, short *uwal, short *dwal, double texturemid, float *swal, fixed_t *lwal, double yrepeat, int wallshade, fixed_t xoffset, float light, float lightstep, FDynamicColormap *basecolormap, FLightNode *light_list) { DrawerFunc drawcol1 = R_GetTransMaskDrawer(); if (drawcol1 == nullptr) { // The current translucency is unsupported, so draw with regular ProcessMaskedWall instead. - ProcessMaskedWall(WallC, x1, x2, uwal, dwal, texturemid, swal, lwal, yrepeat, wallshade, xoffset, light, lightstep, basecolormap, light_list, getcol); + ProcessMaskedWall(WallC, x1, x2, uwal, dwal, texturemid, swal, lwal, yrepeat, wallshade, xoffset, light, lightstep, basecolormap, light_list); } else { - ProcessWallWorker(WallC, x1, x2, uwal, dwal, texturemid, swal, lwal, yrepeat, wallshade, xoffset, light, lightstep, basecolormap, light_list, getcol, drawcol1); + ProcessWallWorker(WallC, x1, x2, uwal, dwal, texturemid, swal, lwal, yrepeat, wallshade, xoffset, light, lightstep, basecolormap, light_list, drawcol1); } } @@ -608,11 +595,4 @@ namespace swrenderer ProcessWall(frontsector, curline, WallC, x1, x2, walltop, wallbottom, texturemid, swall, lwall, yscale, wallshade, xoffset, light, lightstep, false, foggy, basecolormap, light_list); } } - - void R_DrawSkySegment(FTexture *pic, int x1, int x2, short *uwal, short *dwal, double texturemid, float *swal, fixed_t *lwal, double yrepeat, int wallshade, fixed_t xoffset, float light, float lightstep, FDynamicColormap *basecolormap, const uint8_t *(*getcol)(FTexture *tex, int x)) - { - rw_pic = pic; - FWallCoords wallC; // Not used. To do: don't use r_walldraw to draw the sky!! - ProcessNormalWall(wallC, x1, x2, uwal, dwal, texturemid, swal, lwal, yrepeat, wallshade, xoffset, light, lightstep, basecolormap, nullptr, getcol); - } } diff --git a/src/swrenderer/line/r_walldraw.h b/src/swrenderer/line/r_walldraw.h index f7debf908..a74a21a89 100644 --- a/src/swrenderer/line/r_walldraw.h +++ b/src/swrenderer/line/r_walldraw.h @@ -25,7 +25,7 @@ namespace swrenderer struct WallSampler { WallSampler() { } - WallSampler(int y1, double texturemid, float swal, double yrepeat, fixed_t xoffset, double xmagnitude, FTexture *texture, const BYTE*(*getcol)(FTexture *texture, int x)); + WallSampler(int y1, double texturemid, float swal, double yrepeat, fixed_t xoffset, double xmagnitude, FTexture *texture); uint32_t uv_pos; uint32_t uv_step; @@ -38,6 +38,5 @@ namespace swrenderer }; void R_DrawWallSegment(sector_t *frontsector, seg_t *curline, const FWallCoords &WallC, FTexture *rw_pic, int x1, int x2, short *walltop, short *wallbottom, double texturemid, float *swall, fixed_t *lwall, double yscale, double top, double bottom, bool mask, int wallshade, fixed_t xoffset, float light, float lightstep, FLightNode *light_list, bool foggy, FDynamicColormap *basecolormap); - void R_DrawSkySegment(FTexture *rw_pic, int x1, int x2, short *uwal, short *dwal, double texturemid, float *swal, fixed_t *lwal, double yrepeat, int wallshade, fixed_t xoffset, float light, float lightstep, FDynamicColormap *basecolormap, const uint8_t *(*getcol)(FTexture *tex, int col)); void R_DrawDrawSeg(sector_t *frontsector, seg_t *curline, const FWallCoords &WallC, FTexture *rw_pic, drawseg_t *ds, int x1, int x2, short *uwal, short *dwal, double texturemid, float *swal, fixed_t *lwal, double yrepeat, int wallshade, fixed_t xoffset, float light, float lightstep, bool foggy, FDynamicColormap *basecolormap); } diff --git a/src/swrenderer/plane/r_skyplane.cpp b/src/swrenderer/plane/r_skyplane.cpp index a4c8bec2c..f2602eb1b 100644 --- a/src/swrenderer/plane/r_skyplane.cpp +++ b/src/swrenderer/plane/r_skyplane.cpp @@ -165,130 +165,6 @@ namespace swrenderer fixedcolormap = NULL; } - - // Get a column of sky when there is only one sky texture. - const uint8_t *RenderSkyPlane::GetOneSkyColumn(FTexture *fronttex, int x) - { - int tx; - if (r_linearsky) - { - angle_t xangle = (angle_t)((0.5 - x / (double)viewwidth) * FocalTangent * ANGLE_90); - angle_t column = (skyangle + xangle) ^ skyflip; - tx = (UMulScale16(column, frontcyl) + frontpos) >> FRACBITS; - } - else - { - angle_t column = (skyangle + xtoviewangle[x]) ^ skyflip; - tx = (UMulScale16(column, frontcyl) + frontpos) >> FRACBITS; - } - - if (!r_swtruecolor) - return fronttex->GetColumn(tx, NULL); - else - { - return (const uint8_t *)fronttex->GetColumnBgra(tx, NULL); - } - } - - // Get a column of sky when there are two overlapping sky textures - const uint8_t *RenderSkyPlane::GetTwoSkyColumns(FTexture *fronttex, int x) - { - uint32_t ang, angle1, angle2; - - if (r_linearsky) - { - angle_t xangle = (angle_t)((0.5 - x / (double)viewwidth) * FocalTangent * ANGLE_90); - ang = (skyangle + xangle) ^ skyflip; - } - else - { - ang = (skyangle + xtoviewangle[x]) ^ skyflip; - } - angle1 = (uint32_t)((UMulScale16(ang, frontcyl) + frontpos) >> FRACBITS); - angle2 = (uint32_t)((UMulScale16(ang, backcyl) + backpos) >> FRACBITS); - - // Check if this column has already been built. If so, there's - // no reason to waste time building it again. - uint32_t skycol = (angle1 << 16) | angle2; - int i; - - if (!r_swtruecolor) - { - for (i = 0; i < 4; ++i) - { - if (lastskycol[i] == skycol) - { - return skybuf[i]; - } - } - - lastskycol[skycolplace] = skycol; - uint8_t *composite = skybuf[skycolplace]; - skycolplace = (skycolplace + 1) & 3; - - // The ordering of the following code has been tuned to allow VC++ to optimize - // it well. In particular, this arrangement lets it keep count in a register - // instead of on the stack. - const uint8_t *front = fronttex->GetColumn(angle1, NULL); - const uint8_t *back = backskytex->GetColumn(angle2, NULL); - - int count = MIN(512, MIN(backskytex->GetHeight(), fronttex->GetHeight())); - i = 0; - do - { - if (front[i]) - { - composite[i] = front[i]; - } - else - { - composite[i] = back[i]; - } - } while (++i, --count); - return composite; - } - else - { - //return GetOneSkyColumn(fronttex, x); - for (i = skycolplace_bgra - 4; i < skycolplace_bgra; ++i) - { - int ic = (i % MAXSKYBUF); // i "checker" - can wrap around the ends of the array - if (lastskycol_bgra[ic] == skycol) - { - return (uint8_t*)(skybuf_bgra[ic]); - } - } - - lastskycol_bgra[skycolplace_bgra] = skycol; - uint32_t *composite = skybuf_bgra[skycolplace_bgra]; - skycolplace_bgra = (skycolplace_bgra + 1) % MAXSKYBUF; - - // The ordering of the following code has been tuned to allow VC++ to optimize - // it well. In particular, this arrangement lets it keep count in a register - // instead of on the stack. - const uint32_t *front = (const uint32_t *)fronttex->GetColumnBgra(angle1, NULL); - const uint32_t *back = (const uint32_t *)backskytex->GetColumnBgra(angle2, NULL); - - //[SP] Paletted version is used for comparison only - const uint8_t *frontcompare = fronttex->GetColumn(angle1, NULL); - - int count = MIN(512, MIN(backskytex->GetHeight(), fronttex->GetHeight())); - i = 0; - do - { - if (frontcompare[i]) - { - composite[i] = front[i]; - } - else - { - composite[i] = back[i]; - } - } while (++i, --count); - return (uint8_t*)composite; - } - } - void RenderSkyPlane::DrawSkyColumnStripe(int start_x, int y1, int y2, int columns, double scale, double texturemid, double yrepeat) { using namespace drawerargs; @@ -348,10 +224,12 @@ namespace swrenderer uint32_t solid_top = frontskytex->GetSkyCapColor(false); uint32_t solid_bottom = frontskytex->GetSkyCapColor(true); + bool fadeSky = (r_skymode == 2 && !(level.flags & LEVEL_FORCETILEDSKY)); + if (!backskytex) - R_Drawers()->DrawSingleSkyColumn(solid_top, solid_bottom); + R_Drawers()->DrawSingleSkyColumn(solid_top, solid_bottom, fadeSky); else - R_Drawers()->DrawDoubleSkyColumn(solid_top, solid_bottom); + R_Drawers()->DrawDoubleSkyColumn(solid_top, solid_bottom, fadeSky); } void RenderSkyPlane::DrawSkyColumn(int start_x, int y1, int y2, int columns) @@ -374,7 +252,7 @@ namespace swrenderer } } - void RenderSkyPlane::DrawCapSky(visplane_t *pl) + void RenderSkyPlane::DrawSky(visplane_t *pl) { int x1 = pl->left; int x2 = pl->right; @@ -391,125 +269,4 @@ namespace swrenderer DrawSkyColumn(x, y1, y2, 1); } } - - void RenderSkyPlane::DrawSky(visplane_t *pl) - { - if (r_skymode == 2 && !(level.flags & LEVEL_FORCETILEDSKY)) - { - DrawCapSky(pl); - return; - } - - int x; - float swal; - - if (pl->left >= pl->right) - return; - - swal = skyiscale; - for (x = pl->left; x < pl->right; ++x) - { - swall[x] = swal; - } - - RenderPortal *renderportal = RenderPortal::Instance(); - - if (renderportal->MirrorFlags & RF_XFLIP) - { - for (x = pl->left; x < pl->right; ++x) - { - lwall[x] = (viewwidth - x) << FRACBITS; - } - } - else - { - for (x = pl->left; x < pl->right; ++x) - { - lwall[x] = x << FRACBITS; - } - } - - for (x = 0; x < 4; ++x) - { - lastskycol[x] = 0xffffffff; - lastskycol_bgra[x] = 0xffffffff; - } - - frontyScale = frontskytex->Scale.Y; - double texturemid = skymid * frontyScale; - - if (1 << frontskytex->HeightBits == frontskytex->GetHeight()) - { // The texture tiles nicely - for (x = 0; x < 4; ++x) - { - lastskycol[x] = 0xffffffff; - lastskycol_bgra[x] = 0xffffffff; - } - R_DrawSkySegment(frontskytex, pl->left, pl->right, (short *)pl->top, (short *)pl->bottom, texturemid, swall, lwall, - frontyScale, 0, 0, 0.0f, 0.0f, nullptr, backskytex == nullptr ? RenderSkyPlane::GetOneSkyColumn : RenderSkyPlane::GetTwoSkyColumns); - } - else - { // The texture does not tile nicely - frontyScale *= skyscale; - frontiScale = 1 / frontyScale; - DrawSkyStriped(pl); - } - } - - void RenderSkyPlane::DrawSkyStriped(visplane_t *pl) - { - short drawheight = short(frontskytex->GetHeight() * frontyScale); - double topfrac; - double iscale = frontiScale; - short top[MAXWIDTH], bot[MAXWIDTH]; - short yl, yh; - int x; - - topfrac = fmod(skymid + iscale * (1 - CenterY), frontskytex->GetHeight()); - if (topfrac < 0) topfrac += frontskytex->GetHeight(); - yl = 0; - yh = short((frontskytex->GetHeight() - topfrac) * frontyScale); - double texturemid = topfrac - iscale * (1 - CenterY); - - while (yl < viewheight) - { - for (x = pl->left; x < pl->right; ++x) - { - top[x] = MAX(yl, (short)pl->top[x]); - bot[x] = MIN(yh, (short)pl->bottom[x]); - } - for (x = 0; x < 4; ++x) - { - lastskycol[x] = 0xffffffff; - lastskycol_bgra[x] = 0xffffffff; - } - R_DrawSkySegment(frontskytex, pl->left, pl->right, top, bot, texturemid, swall, lwall, frontskytex->Scale.Y, 0, 0, 0.0f, 0.0f, nullptr, backskytex == nullptr ? RenderSkyPlane::GetOneSkyColumn : RenderSkyPlane::GetTwoSkyColumns); - yl = yh; - yh += drawheight; - texturemid = iscale * (centery - yl - 1); - } - } - - FTexture *RenderSkyPlane::frontskytex; - FTexture *RenderSkyPlane::backskytex; - angle_t RenderSkyPlane::skyflip; - int RenderSkyPlane::frontpos; - int RenderSkyPlane::backpos; - double RenderSkyPlane::frontyScale; - fixed_t RenderSkyPlane::frontcyl; - fixed_t RenderSkyPlane::backcyl; - double RenderSkyPlane::skymid; - angle_t RenderSkyPlane::skyangle; - double RenderSkyPlane::frontiScale; - - // Allow for layer skies up to 512 pixels tall. This is overkill, - // since the most anyone can ever see of the sky is 500 pixels. - // We need 4 skybufs because DrawSkySegment can draw up to 4 columns at a time. - // Need two versions - one for true color and one for palette - uint8_t RenderSkyPlane::skybuf[4][512]; - uint32_t RenderSkyPlane::skybuf_bgra[MAXSKYBUF][512]; - uint32_t RenderSkyPlane::lastskycol[4]; - uint32_t RenderSkyPlane::lastskycol_bgra[MAXSKYBUF]; - int RenderSkyPlane::skycolplace; - int RenderSkyPlane::skycolplace_bgra; } diff --git a/src/swrenderer/plane/r_skyplane.h b/src/swrenderer/plane/r_skyplane.h index 3acf4d53a..8deacaf18 100644 --- a/src/swrenderer/plane/r_skyplane.h +++ b/src/swrenderer/plane/r_skyplane.h @@ -20,40 +20,21 @@ namespace swrenderer class RenderSkyPlane { public: - static void Render(visplane_t *pl); + void Render(visplane_t *pl); private: - static void DrawSky(visplane_t *pl); - static void DrawSkyStriped(visplane_t *pl); - static void DrawCapSky(visplane_t *pl); - static void DrawSkyColumnStripe(int start_x, int y1, int y2, int columns, double scale, double texturemid, double yrepeat); - static void DrawSkyColumn(int start_x, int y1, int y2, int columns); + void DrawSky(visplane_t *pl); + void DrawSkyColumnStripe(int start_x, int y1, int y2, int columns, double scale, double texturemid, double yrepeat); + void DrawSkyColumn(int start_x, int y1, int y2, int columns); - static const uint8_t *GetOneSkyColumn(FTexture *fronttex, int x); - static const uint8_t *GetTwoSkyColumns(FTexture *fronttex, int x); - - static FTexture *frontskytex; - static FTexture *backskytex; - static angle_t skyflip; - static int frontpos; - static int backpos; - static double frontyScale; - static fixed_t frontcyl; - static fixed_t backcyl; - static double skymid; - static angle_t skyangle; - static double frontiScale; - - // Allow for layer skies up to 512 pixels tall. This is overkill, - // since the most anyone can ever see of the sky is 500 pixels. - // We need 4 skybufs because R_DrawSkySegment can draw up to 4 columns at a time. - // Need two versions - one for true color and one for palette - enum { MAXSKYBUF = 3072 }; - static uint8_t skybuf[4][512]; - static uint32_t skybuf_bgra[MAXSKYBUF][512]; - static uint32_t lastskycol[4]; - static uint32_t lastskycol_bgra[MAXSKYBUF]; - static int skycolplace; - static int skycolplace_bgra; + FTexture *frontskytex = nullptr; + FTexture *backskytex = nullptr; + angle_t skyflip = 0; + int frontpos = 0; + int backpos = 0; + fixed_t frontcyl = 0; + fixed_t backcyl = 0; + double skymid = 0.0; + angle_t skyangle = 0; }; } diff --git a/src/swrenderer/plane/r_visibleplane.cpp b/src/swrenderer/plane/r_visibleplane.cpp index a1928bbb8..a1d7dc8dd 100644 --- a/src/swrenderer/plane/r_visibleplane.cpp +++ b/src/swrenderer/plane/r_visibleplane.cpp @@ -82,7 +82,8 @@ namespace swrenderer if (picnum == skyflatnum) // sky flat { - RenderSkyPlane::Render(this); + RenderSkyPlane renderer; + renderer.Render(this); } else // regular flat {