diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8c0a30ea0..042da0c8f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1190,6 +1190,7 @@ set (PCH_SOURCES textures/texturemanager.cpp textures/tgatexture.cpp textures/warptexture.cpp + textures/bicubic_interpolation.cpp thingdef/olddecorations.cpp thingdef/thingdef.cpp thingdef/thingdef_codeptr.cpp diff --git a/src/textures/bicubic_interpolation.cpp b/src/textures/bicubic_interpolation.cpp new file mode 100644 index 000000000..2c8a3049d --- /dev/null +++ b/src/textures/bicubic_interpolation.cpp @@ -0,0 +1,107 @@ + +#include "doomtype.h" +#include "bicubic_interpolation.h" + +void BicubicInterpolation::ScaleImage(uint32_t *dest_data, int dest_width, int dest_height, const uint32_t *src_data, int src_width, int src_height) +{ + if (dest_width <= 0 || dest_height <= 0 || src_width <= 0 || src_height <= 0) + return; + + // Scale factor as a rational number r = n / d + int n = dest_width; + int d = src_width; + + const unsigned char *src_ptr = (const unsigned char *)src_data; + unsigned char *dest_ptr = (unsigned char *)dest_data; + + scale(n, d, src_width, src_width * 4, src_height, src_ptr + 0, dest_width, dest_width * 4, dest_height, dest_ptr + 0); + scale(n, d, src_width, src_width * 4, src_height, src_ptr + 1, dest_width, dest_width * 4, dest_height, dest_ptr + 1); + scale(n, d, src_width, src_width * 4, src_height, src_ptr + 2, dest_width, dest_width * 4, dest_height, dest_ptr + 2); + scale(n, d, src_width, src_width * 4, src_height, src_ptr + 3, dest_width, dest_width * 4, dest_height, dest_ptr + 3); +} + +void BicubicInterpolation::scale(int n, int d, int in_width, int in_pitch, int in_height, const unsigned char *f, int out_width, int out_pitch, int out_height, unsigned char *g) +{ + // Implementation of Michael J. Aramini's Efficient Image Magnification by Bicubic Spline Interpolation + + int dimension_size = (out_width > out_height) ? out_width : out_height; + L_vector.resize(dimension_size); + + for (int i=0;i<4;i++) + c_vector[i].resize(dimension_size); + h_vector.resize(in_width); + + int larger_out_dimension; + int j, k, l, m, index; + int *L = &L_vector[0]; + float x; + float *c[4] = { &c_vector[0][0], &c_vector[1][0], &c_vector[2][0], &c_vector[3][0] }; + float *h = &h_vector[0]; + + larger_out_dimension = (out_width > out_height) ? out_width : out_height; + + for (k = 0; k < larger_out_dimension; k++) + L[k] = (k * d) / n; + + for (k = 0; k < n; k++) + { + x = (float)((k * d) % n) / (float)n; + c[0][k] = C0(x); + c[1][k] = C1(x); + c[2][k] = C2(x); + c[3][k] = C3(x); + } + for (k = n; k < larger_out_dimension; k++) + for (l = 0; l < 4; l++) + c[l][k] = c[l][k % n]; + + for (k = 0; k < out_height; k++) + { + for (j = 0; j < in_width; j++) + { + h[j] = 0.0f; + for (l = 0; l < 4; l++) + { + index = L[k] + l - 1; + if ((index >= 0) && (index < in_height)) + h[j] += f[index*in_pitch+j*4] * c[3 - l][k]; + } + } + for (m = 0; m < out_width; m++) + { + x = 0.5f; + for (l = 0; l < 4; l++) + { + index = L[m] + l - 1; + if ((index >= 0) && (index < in_width)) + x += h[index] * c[3 - l][m]; + } + if (x <= 0.0f) + g[k*out_pitch+m*4] = 0; + else if (x >= 255) + g[k*out_pitch+m*4] = 255; + else + g[k*out_pitch+m*4] = (unsigned char)x; + } + } +} + +inline float BicubicInterpolation::C0(float t) +{ + return -a * t * t * t + a * t * t; +} + +inline float BicubicInterpolation::C1(float t) +{ + return -(a + 2.0f) * t * t * t + (2.0f * a + 3.0f) * t * t - a * t; +} + +inline float BicubicInterpolation::C2(float t) +{ + return (a + 2.0f) * t * t * t - (a + 3.0f) * t * t + 1.0f; +} + +inline float BicubicInterpolation::C3(float t) +{ + return a * t * t * t - 2.0f * a * t * t + a * t; +} diff --git a/src/textures/bicubic_interpolation.h b/src/textures/bicubic_interpolation.h new file mode 100644 index 000000000..da547ad83 --- /dev/null +++ b/src/textures/bicubic_interpolation.h @@ -0,0 +1,50 @@ +/* +** Bicubic Image Scaler +** Copyright (c) 2016 Magnus Norddahl +** +** This software is provided 'as-is', without any express or implied +** warranty. In no event will the authors be held liable for any damages +** arising from the use of this software. +** +** Permission is granted to anyone to use this software for any purpose, +** including commercial applications, and to alter it and redistribute it +** freely, subject to the following restrictions: +** +** 1. The origin of this software must not be misrepresented; you must not +** claim that you wrote the original software. If you use this software +** in a product, an acknowledgment in the product documentation would be +** appreciated but is not required. +** 2. Altered source versions must be plainly marked as such, and must not be +** misrepresented as being the original software. +** 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef __BICUBIC_INTERPOLATION_H__ +#define __BICUBIC_INTERPOLATION_H__ + +#pragma once + +#include + +// Bicubic image scaler +class BicubicInterpolation +{ +public: + void ScaleImage(uint32_t *dest, int dest_width, int dest_height, const uint32_t *src, int src_width, int src_height); + +private: + void scale(int n, int d, int in_width, int in_pitch, int in_height, const unsigned char *in_data, int out_width, int out_pitch, int out_height, unsigned char *out_data); + + float a = -0.5f; // a is a spline parameter such that -1 <= a <= 0 + + inline float C0(float t); + inline float C1(float t); + inline float C2(float t); + inline float C3(float t); + + std::vector L_vector; + std::vector c_vector[4]; + std::vector h_vector; +}; + +#endif diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp index f5e4d4aa8..7ff5c9ba2 100644 --- a/src/textures/texture.cpp +++ b/src/textures/texture.cpp @@ -45,6 +45,7 @@ #include "v_video.h" #include "m_fixed.h" #include "textures/textures.h" +#include "textures/bicubic_interpolation.h" #include "v_palette.h" typedef bool (*CheckFunc)(FileReader & file); @@ -381,6 +382,24 @@ int FTexture::MipmapLevels() const } void FTexture::GenerateBgraMipmaps() +{ + BicubicInterpolation bicubic; + + uint32_t *src = PixelsBgra.data(); + uint32_t *dest = src + Width * Height; + int levels = MipmapLevels(); + for (int i = 1; i < levels; i++) + { + int w = MAX(Width >> i, 1); + int h = MAX(Height >> i, 1); + + bicubic.ScaleImage(dest, h, w, src, Height, Width); + + dest += w * h; + } +} + +void FTexture::GenerateBgraMipmapsFast() { uint32_t *src = PixelsBgra.data(); uint32_t *dest = src + Width * Height; diff --git a/src/textures/textures.h b/src/textures/textures.h index bb83f79e7..ff1093a49 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -276,6 +276,7 @@ protected: void CreatePixelsBgraWithMipmaps(); void GenerateBgraMipmaps(); + void GenerateBgraMipmapsFast(); int MipmapLevels() const; public: