godot/thirdparty/etc2comp/EtcFilter.h

244 lines
7.2 KiB
C++
Raw Normal View History

#pragma once
#include <stdint.h>
#include <algorithm>
namespace Etc
{
enum FilterEnums
{
MaxFilterSize = 32
};
enum WrapFlags
{
FILTER_WRAP_NONE = 0,
FILTER_WRAP_X = 0x1,
FILTER_WRAP_Y = 0x2
};
typedef struct tagFilterWeights
{
int first;
int numWeights;
double weight[MaxFilterSize * 2 + 1];
} FilterWeights;
typedef struct tagRGBCOLOR
{
union
{
uint32_t ulColor;
uint8_t rgba[4];
};
} RGBCOLOR;
double FilterBox( double t );
double FilterLinear( double t );
double FilterLanczos3( double t );
int FilterTwoPass( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
RGBCOLOR *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double (*FilterProc)(double) );
void FilterResample( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
RGBCOLOR *pDstImage, int dstWidth, int dstHeight );
void CalcContributions(int srcSize, int destSize, double filterSize, bool wrap, double(*FilterProc)(double), FilterWeights contrib[]);
template <typename T>
void FilterResample(T *pSrcImage, int srcWidth, int srcHeight, T *pDstImage, int dstWidth, int dstHeight)
{
float xScale;
float yScale;
T *pSrcPixel;
T *pDstPixel;
xScale = (float)srcWidth / dstWidth;
yScale = (float)srcHeight / dstHeight;
for (int iRow = 0; iRow < dstHeight; iRow++)
{
for (int iCol = 0; iCol < dstWidth; iCol++)
{
int samples;
int iFirstSampleRow;
int iFirstSampleCol;
int iLastSampleRow;
int iLastSampleCol;
float red;
float green;
float blue;
float alpha;
iFirstSampleRow = (int)(iRow * yScale);
iLastSampleRow = (int)ceil(iFirstSampleRow + yScale - 1);
if (iLastSampleRow >= srcHeight)
{
iLastSampleRow = srcHeight - 1;
}
iFirstSampleCol = (int)(iCol * xScale);
iLastSampleCol = (int)ceil(iFirstSampleCol + xScale - 1);
if (iLastSampleCol >= srcWidth)
{
iLastSampleCol = srcWidth - 1;
}
samples = 0;
red = 0.f;
green = 0.f;
blue = 0.f;
alpha = 0.f;
for (int iSampleRow = iFirstSampleRow; iSampleRow <= iLastSampleRow; iSampleRow++)
{
for (int iSampleCol = iFirstSampleCol; iSampleCol <= iLastSampleCol; iSampleCol++)
{
pSrcPixel = pSrcImage + (iSampleRow * srcWidth + iSampleCol) * 4;
red += static_cast<float>(pSrcPixel[0]);
green += static_cast<float>(pSrcPixel[1]);
blue += static_cast<float>(pSrcPixel[2]);
alpha += static_cast<float>(pSrcPixel[3]);
samples++;
}
}
pDstPixel = pDstImage + (iRow * dstWidth + iCol) * 4;
if (samples > 0)
{
pDstPixel[0] = static_cast<T>(red / samples);
pDstPixel[1] = static_cast<T>(green / samples);
pDstPixel[2] = static_cast<T>(blue / samples);
pDstPixel[3] = static_cast<T>(alpha / samples);
}
else
{
pDstPixel[0] = static_cast<T>(red);
pDstPixel[1] = static_cast<T>(green);
pDstPixel[2] = static_cast<T>(blue);
pDstPixel[3] = static_cast<T>(alpha);
}
}
}
}
//**-------------------------------------------------------------------------
//** Name: Filter_TwoPass( RGBCOLOR *pSrcImage,
//** int srcWidth, int srcHeight,
//** RGBCOLOR *pDestImage,
//** int destWidth, int destHeight,
//** double (*FilterProc)(double) )
//** Returns: 0 on failure and 1 on success
//** Description: Filters a 2d image with a two pass filter by averaging the
//** weighted contributions of the pixels within the filter region. The
//** contributions are determined by a weighting function parameter.
//**-------------------------------------------------------------------------
template <typename T>
int FilterTwoPass(T *pSrcImage, int srcWidth, int srcHeight,
T *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double(*FilterProc)(double))
{
const int numComponents = 4;
FilterWeights *contrib;
T *pPixel;
T *pTempImage;
double dRed;
double dGreen;
double dBlue;
double dAlpha;
double filterSize = 3.0;
int maxDim = (srcWidth>srcHeight) ? srcWidth : srcHeight;
contrib = new FilterWeights[maxDim];
//**------------------------------------------------------------------------
//** Need to create a temporary image to stuff the horizontally scaled image
//**------------------------------------------------------------------------
pTempImage = new T[destWidth * srcHeight * numComponents];
if (pTempImage == NULL)
{
return 0;
}
//**-------------------------------------------------------
//** Horizontally filter the image into the temporary image
//**-------------------------------------------------------
bool bWrapHorizontal = !!(wrapFlags&FILTER_WRAP_X);
CalcContributions(srcWidth, destWidth, filterSize, bWrapHorizontal, FilterProc, contrib);
for (int iRow = 0; iRow < srcHeight; iRow++)
{
for (int iCol = 0; iCol < destWidth; iCol++)
{
dRed = 0;
dGreen = 0;
dBlue = 0;
dAlpha = 0;
for (int iWeight = 0; iWeight < contrib[iCol].numWeights; iWeight++)
{
int iSrcCol = iWeight + contrib[iCol].first;
if(bWrapHorizontal)
{
iSrcCol = (iSrcCol < 0)?(srcWidth+iSrcCol):(iSrcCol >= srcWidth)?(iSrcCol-srcWidth):iSrcCol;
}
T* pSrcPixel = pSrcImage + ((iRow * srcWidth) + iSrcCol)*numComponents;
dRed += contrib[iCol].weight[iWeight] * pSrcPixel[0];
dGreen += contrib[iCol].weight[iWeight] * pSrcPixel[1];
dBlue += contrib[iCol].weight[iWeight] * pSrcPixel[2];
dAlpha += contrib[iCol].weight[iWeight] * pSrcPixel[3];
}
pPixel = pTempImage + ((iRow * destWidth) + iCol)*numComponents;
pPixel[0] = static_cast<T>(std::max(0.0, std::min(255.0, dRed)));
pPixel[1] = static_cast<T>(std::max(0.0, std::min(255.0, dGreen)));
pPixel[2] = static_cast<T>(std::max(0.0, std::min(255.0, dBlue)));
pPixel[3] = static_cast<T>(std::max(0.0, std::min(255.0, dAlpha)));
}
}
//**-------------------------------------------------------
//** Vertically filter the image into the destination image
//**-------------------------------------------------------
bool bWrapVertical = !!(wrapFlags&FILTER_WRAP_Y);
CalcContributions(srcHeight, destHeight, filterSize, bWrapVertical, FilterProc, contrib);
for (int iCol = 0; iCol < destWidth; iCol++)
{
for (int iRow = 0; iRow < destHeight; iRow++)
{
dRed = 0;
dGreen = 0;
dBlue = 0;
dAlpha = 0;
for (int iWeight = 0; iWeight < contrib[iRow].numWeights; iWeight++)
{
int iSrcRow = iWeight + contrib[iRow].first;
if (bWrapVertical)
{
iSrcRow = (iSrcRow < 0) ? (srcHeight + iSrcRow) : (iSrcRow >= srcHeight) ? (iSrcRow - srcHeight) : iSrcRow;
}
T* pSrcPixel = pTempImage + ((iSrcRow * destWidth) + iCol)*numComponents;
dRed += contrib[iRow].weight[iWeight] * pSrcPixel[0];
dGreen += contrib[iRow].weight[iWeight] * pSrcPixel[1];
dBlue += contrib[iRow].weight[iWeight] * pSrcPixel[2];
dAlpha += contrib[iRow].weight[iWeight] * pSrcPixel[3];
}
pPixel = pDestImage + ((iRow * destWidth) + iCol)*numComponents;
pPixel[0] = static_cast<T>(std::max(0.0, std::min(255.0, dRed)));
pPixel[1] = static_cast<T>(std::max(0.0, std::min(255.0, dGreen)));
pPixel[2] = static_cast<T>(std::max(0.0, std::min(255.0, dBlue)));
pPixel[3] = static_cast<T>(std::max(0.0, std::min(255.0, dAlpha)));
}
}
delete[] pTempImage;
delete[] contrib;
return 1;
}
}