Added bicubic interpolation when generating mipmaps

This commit is contained in:
Magnus Norddahl 2016-06-25 12:14:15 +02:00
parent 7705463966
commit 3b6d177787
5 changed files with 178 additions and 0 deletions

View file

@ -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

View file

@ -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;
}

View file

@ -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 <vector>
// 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<int> L_vector;
std::vector<float> c_vector[4];
std::vector<float> h_vector;
};
#endif

View file

@ -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;

View file

@ -276,6 +276,7 @@ protected:
void CreatePixelsBgraWithMipmaps();
void GenerateBgraMipmaps();
void GenerateBgraMipmapsFast();
int MipmapLevels() const;
public: