From d15af1524cebd3e000bbd7971d9b5e51205cfde6 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Tue, 21 Jun 2016 09:38:47 +0200 Subject: [PATCH] Added mipmap support for floor and ceiling --- src/r_draw.cpp | 6 +-- src/r_draw.h | 2 +- src/r_draw_rgba.cpp | 119 +++++++++++++++++++++++++++++++++++++----- src/r_draw_rgba.h | 33 ++++++++++++ src/r_draw_rgba_sse.h | 9 ++-- src/r_plane.cpp | 5 +- src/r_swrenderer.cpp | 1 + src/v_draw.cpp | 2 +- 8 files changed, 150 insertions(+), 27 deletions(-) diff --git a/src/r_draw.cpp b/src/r_draw.cpp index 83c4ac8d40..73ddb72f88 100644 --- a/src/r_draw.cpp +++ b/src/r_draw.cpp @@ -1062,13 +1062,13 @@ extern "C" BYTE *ds_curcolormap, *ds_cursource, *ds_curtiltedsource; // //========================================================================== -void R_SetSpanSource(const BYTE *pixels) +void R_SetSpanSource(FTexture *tex) { - ds_source = pixels; + R_SetMipmappedSpanSource(tex); #ifdef X86_ASM if (!r_swtruecolor && ds_cursource != ds_source) { - R_SetSpanSource_ASM(pixels); + R_SetSpanSource_ASM(ds_source); } #endif } diff --git a/src/r_draw.h b/src/r_draw.h index d5ecbd289d..b662ddcee3 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -122,7 +122,7 @@ extern void (*R_DrawTranslatedColumn)(void); extern void (*R_DrawSpan)(void); void R_SetupSpanBits(FTexture *tex); void R_SetSpanColormap(FDynamicColormap *colormap, int shade); -void R_SetSpanSource(const BYTE *pixels); +void R_SetSpanSource(FTexture *tex); // Span drawing for masked textures. extern void (*R_DrawSpanMasked)(void); diff --git a/src/r_draw_rgba.cpp b/src/r_draw_rgba.cpp index 869edaba1d..9cdcdbf802 100644 --- a/src/r_draw_rgba.cpp +++ b/src/r_draw_rgba.cpp @@ -59,6 +59,7 @@ extern int wallshade; CVAR(Bool, r_multithreaded, true, 0) CVAR(Bool, r_bilinear, true, 0) +CVAR(Bool, r_mipmap, true, 0) #ifndef NO_SSE @@ -1502,6 +1503,7 @@ class DrawSpanRGBACommand : public DrawerCommand BYTE * RESTRICT _destorg; fixed_t _light; ShadeConstants _shade_constants; + bool _magnifying; public: DrawSpanRGBACommand() @@ -1519,6 +1521,7 @@ public: _destorg = dc_destorg; _light = ds_light; _shade_constants = ds_shade_constants; + _magnifying = !span_sampler_setup(_source, _xbits, _ybits, _xstep, _ystep); } void Execute(DrawerThread *thread) override @@ -1548,12 +1551,7 @@ public: uint32_t light = calc_light_multiplier(_light); ShadeConstants shade_constants = _shade_constants; - fixed_t xmagnitude = abs((fixed_t)xstep) >> (32 - _xbits - FRACBITS); - fixed_t ymagnitude = abs((fixed_t)ystep) >> (32 - _ybits - FRACBITS); - fixed_t magnitude = xmagnitude + ymagnitude; - - bool magnifying = !r_bilinear || magnitude >> (FRACBITS - 1) == 0; - if (magnifying) + if (_magnifying) { if (_xbits == 6 && _ybits == 6) { @@ -1634,6 +1632,7 @@ class DrawSpanMaskedRGBACommand : public DrawerCommand fixed_t _ystep; int _xbits; int _ybits; + bool _magnifying; public: DrawSpanMaskedRGBACommand() @@ -1651,6 +1650,7 @@ public: _ystep = ds_ystep; _xbits = ds_xbits; _ybits = ds_ybits; + _magnifying = !span_sampler_setup(_source, _xbits, _ybits, _xstep, _ystep); } void Execute(DrawerThread *thread) override @@ -1680,12 +1680,7 @@ public: xstep = _xstep; ystep = _ystep; - fixed_t xmagnitude = abs((fixed_t)xstep) >> (32 - _xbits - FRACBITS); - fixed_t ymagnitude = abs((fixed_t)ystep) >> (32 - _ybits - FRACBITS); - fixed_t magnitude = xmagnitude + ymagnitude; - - bool magnifying = !r_bilinear || magnitude >> (FRACBITS - 1) == 0; - if (magnifying) + if (_magnifying) { if (_xbits == 6 && _ybits == 6) { @@ -3677,6 +3672,106 @@ void ApplySpecialColormapRGBACommand::Execute(DrawerThread *thread) ///////////////////////////////////////////////////////////////////////////// +#include + +class MipmappedTexture +{ +public: + MipmappedTexture(FTexture *texture) + { + const uint32_t *base_texture = texture->GetPixelsBgra(); + Width = texture->GetWidth(); + Height = texture->GetHeight(); + Levels = MAX(texture->WidthBits, texture->HeightBits); + + // I bet there is a better way to calculate this.. + int buffersize = 0; + for (int i = 0; i < Levels; i++) + { + int w = MAX(Width >> i, 2); // 2 instead of 1 because we texelGather in 2x2 blocks + int h = MAX(Height >> i, 2); + buffersize += w * h; + } + Pixels.resize(buffersize); + + // Base level: + memcpy(Pixels.data(), base_texture, Width * Height * 4); + + // Mipmap levels: + uint32_t *src = Pixels.data(); + uint32_t *dest = src + Width * Height; + for (int i = 1; i < Levels; i++) + { + int srch = MAX(Height >> (i - 1), 2); + int w = MAX(Width >> i, 2); + int h = MAX(Height >> i, 2); + + for (int x = 0; x < w; x++) + { + for (int y = 0; y < h; y++) + { + uint32_t src00 = src[y * 2 + x * 2 * srch]; + uint32_t src01 = src[y * 2 + 1 + x * 2 * srch]; + uint32_t src10 = src[y * 2 + (x * 2 + 1) * srch]; + uint32_t src11 = src[y * 2 + 1 + (x * 2 + 1) * srch]; + + uint32_t alpha = (APART(src00) + APART(src01) + APART(src10) + APART(src11) + 2) / 4; + uint32_t red = (RPART(src00) + RPART(src01) + RPART(src10) + RPART(src11) + 2) / 4; + uint32_t green = (GPART(src00) + GPART(src01) + GPART(src10) + GPART(src11) + 2) / 4; + uint32_t blue = (BPART(src00) + BPART(src01) + BPART(src10) + BPART(src11) + 2) / 4; + + dest[y + x * h] = (alpha << 24) | (red << 16) | (green << 8) | blue; + } + } + + src = dest; + dest += w * h; + } + } + + int Width = 0; + int Height = 0; + int Levels = 0; + std::vector Pixels; +}; + +class TextureMipmapper +{ +public: + static std::map> &Textures() + { + static std::map> textures; + return textures; + } +}; + +void R_SetMipmappedSpanSource(FTexture *tex) +{ + if (r_swtruecolor) + { + if (r_mipmap) + { + auto &mipmap = TextureMipmapper::Textures()[tex]; + if (!mipmap) + mipmap = std::make_shared(tex); + ds_source = (const BYTE*)mipmap->Pixels.data(); + } + else + { + ds_source = (const BYTE*)tex->GetPixelsBgra(); + } + } + else + { + ds_source = tex->GetPixels(); + } +} + +void R_ClearMipmapCache() +{ + TextureMipmapper::Textures().clear(); +} + void R_BeginDrawerCommands() { DrawerCommandQueue::Begin(); diff --git a/src/r_draw_rgba.h b/src/r_draw_rgba.h index 0900e89977..37dc1a70a1 100644 --- a/src/r_draw_rgba.h +++ b/src/r_draw_rgba.h @@ -108,6 +108,9 @@ void tmvline4_revsubclamp_rgba(); void R_FillColumnHoriz_rgba(); void R_FillSpan_rgba(); +void R_SetMipmappedSpanSource(FTexture *tex); +void R_ClearMipmapCache(); + ///////////////////////////////////////////////////////////////////////////// // Multithreaded rendering infrastructure: @@ -185,6 +188,7 @@ public: }; EXTERN_CVAR(Bool, r_multithreaded) +EXTERN_CVAR(Bool, r_mipmap) // Manages queueing up commands and executing them on worker threads class DrawerCommandQueue @@ -426,6 +430,35 @@ FORCEINLINE uint32_t alpha_blend(uint32_t fg, uint32_t bg) return 0xff000000 | (red << 16) | (green << 8) | blue; } +inline bool span_sampler_setup(const uint32_t *&source, int &xbits, int &ybits, fixed_t xstep, fixed_t ystep) +{ + if (!r_bilinear) + return false; + + // Is this a magfilter or minfilter? + fixed_t xmagnitude = abs(xstep) >> (32 - xbits - FRACBITS); + fixed_t ymagnitude = abs(ystep) >> (32 - ybits - FRACBITS); + fixed_t magnitude = (xmagnitude + ymagnitude) * 3 + (1 << (FRACBITS -1)); + if (magnitude >> FRACBITS == 0) + return false; + + if (r_mipmap) + { + int level = magnitude >> (FRACBITS + 1); + while (level != 0) + { + if (xbits <= 2 || ybits <= 2) + break; + + source += (1 << (xbits)) * (1 << (ybits)); + xbits -= 1; + ybits -= 1; + level >>= 1; + } + } + return true; +} + FORCEINLINE uint32_t sample_bilinear(const uint32_t *col0, const uint32_t *col1, uint32_t texturefracx, uint32_t texturefracy, int ybits) { uint32_t half = 1 << (ybits - 1); diff --git a/src/r_draw_rgba_sse.h b/src/r_draw_rgba_sse.h index 7214717249..4002a55356 100644 --- a/src/r_draw_rgba_sse.h +++ b/src/r_draw_rgba_sse.h @@ -25,6 +25,7 @@ class VecCommand(DrawSpanRGBA) : public DrawerCommand BYTE * RESTRICT _destorg; fixed_t _light; ShadeConstants _shade_constants; + bool _magnifying; public: VecCommand(DrawSpanRGBA)() @@ -42,6 +43,7 @@ public: _destorg = dc_destorg; _light = ds_light; _shade_constants = ds_shade_constants; + _magnifying = !span_sampler_setup(_source, _xbits, _ybits, _xstep, _ystep); } void Execute(DrawerThread *thread) override @@ -71,12 +73,7 @@ public: uint32_t light = calc_light_multiplier(_light); ShadeConstants shade_constants = _shade_constants; - fixed_t xmagnitude = abs((fixed_t)xstep) >> (32 - _xbits - FRACBITS); - fixed_t ymagnitude = abs((fixed_t)ystep) >> (32 - _ybits - FRACBITS); - fixed_t magnitude = xmagnitude + ymagnitude; - - bool magnifying = !r_bilinear || magnitude >> (FRACBITS - 1) == 0; - if (magnifying) + if (_magnifying) { if (_xbits == 6 && _ybits == 6) { diff --git a/src/r_plane.cpp b/src/r_plane.cpp index 807066f77d..6913db9183 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -1178,10 +1178,7 @@ void R_DrawSinglePlane (visplane_t *pl, fixed_t alpha, bool additive, bool maske R_SetupSpanBits(tex); double xscale = pl->xform.xScale * tex->Scale.X; double yscale = pl->xform.yScale * tex->Scale.Y; - if (r_swtruecolor) - ds_source = (const BYTE*)tex->GetPixelsBgra(); - else - ds_source = tex->GetPixels(); + R_SetSpanSource(tex); basecolormap = pl->colormap; planeshade = LIGHT2SHADE(pl->lightlevel); diff --git a/src/r_swrenderer.cpp b/src/r_swrenderer.cpp index c81d2a1103..c1e2d4bd0f 100644 --- a/src/r_swrenderer.cpp +++ b/src/r_swrenderer.cpp @@ -170,6 +170,7 @@ void FSoftwareRenderer::RenderView(player_t *player) R_InitColumnDrawers(); } + R_ClearMipmapCache(); R_BeginDrawerCommands(); R_RenderActorView (player->mo); // [RH] Let cameras draw onto textures that were visible this frame. diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 6a8dad0477..fd12a15871 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -1404,7 +1404,7 @@ void DCanvas::FillSimplePoly(FTexture *tex, FVector2 *points, int npoints, R_SetSpanColormap(colormap, clamp(shade >> FRACBITS, 0, NUMCOLORMAPS - 1)); else R_SetSpanColormap(&identitycolormap, 0); - R_SetSpanSource(r_swtruecolor ? (const BYTE*)tex->GetPixelsBgra() : tex->GetPixels()); + R_SetSpanSource(tex); scalex = double(1u << (32 - ds_xbits)) / scalex; scaley = double(1u << (32 - ds_ybits)) / scaley; ds_xstep = xs_RoundToInt(cosrot * scalex);