aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/etc2comp/EtcFilter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/etc2comp/EtcFilter.cpp')
-rw-r--r--thirdparty/etc2comp/EtcFilter.cpp401
1 files changed, 401 insertions, 0 deletions
diff --git a/thirdparty/etc2comp/EtcFilter.cpp b/thirdparty/etc2comp/EtcFilter.cpp
new file mode 100644
index 000000000..bc899a533
--- /dev/null
+++ b/thirdparty/etc2comp/EtcFilter.cpp
@@ -0,0 +1,401 @@
+#include <stdlib.h>
+#include <math.h>
+#include "EtcFilter.h"
+
+
+namespace Etc
+{
+
+static const double PiConst = 3.14159265358979323846;
+
+inline double sinc(double x)
+{
+ if ( x == 0.0 )
+ {
+ return 1.0;
+ }
+
+ return sin(PiConst * x) / (PiConst * x);
+}
+
+//inline float sincf( float x )
+//{
+// x *= F_PI;
+// if (x < 0.01f && x > -0.01f)
+// {
+// return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f);
+// }
+//
+// return sinf(x)/x;
+//}
+//
+//double bessel0(double x)
+//{
+// const double EPSILON_RATIO = 1E-16;
+// double xh, sum, pow, ds;
+// int k;
+//
+// xh = 0.5 * x;
+// sum = 1.0;
+// pow = 1.0;
+// k = 0;
+// ds = 1.0;
+// while (ds > sum * EPSILON_RATIO)
+// {
+// ++k;
+// pow = pow * (xh / k);
+// ds = pow * pow;
+// sum = sum + ds;
+// }
+//
+// return sum;
+//}
+
+//**--------------------------------------------------------------------------
+//** Name: kaiser(double alpha, double half_width, double x)
+//** Returns:
+//** Description: Alpha controls shape of filter. We are using 4.
+//**--------------------------------------------------------------------------
+//inline double kaiser(double alpha, double half_width, double x)
+//{
+// double ratio = (x / half_width);
+// return bessel0(alpha * sqrt(1 - ratio * ratio)) / bessel0(alpha);
+//}
+//
+//float Filter_Lanczos4Sinc(float x)
+//{
+// if (x <= -4.0f || x >= 4.0f) // half-width of 4
+// {
+// return 0.0;
+// }
+//
+// return sinc(0.875f * x) * sinc(0.25f * x);
+//}
+//
+//double Filter_Kaiser4( double t )
+//{
+// return kaiser( 4.0, 3.0, t);
+//}
+//
+//double Filter_KaiserOptimal( double t )
+//{
+// return kaiser( 8.93, 3.0f, t);
+//}
+
+double FilterLanczos3( double t )
+{
+ if ( t <= -3.0 || t >= 3.0 )
+ {
+ return 0.0;
+ }
+
+ return sinc( t ) * sinc( t / 3.0 );
+}
+
+double FilterBox( double t )
+{
+ return ( t > -0.5 && t < 0.5) ? 1.0 : 0.0;
+}
+
+double FilterLinear( double t )
+{
+ if (t < 0.0) t = -t;
+
+ return (t < 1.0) ? (1.0 - t) : 0.0;
+}
+
+
+//**--------------------------------------------------------------------------
+//** Name: CalcContributions( int srcSize,
+//** int destSize,
+//** double filterSize,
+//** bool wrap,
+//** double (*FilterProc)(double),
+//** FilterWeights contrib[] )
+//** Returns: void
+//** Description:
+//**--------------------------------------------------------------------------
+void CalcContributions( int srcSize, int destSize, double filterSize, bool wrap, double (*FilterProc)(double), FilterWeights contrib[] )
+{
+ double scale;
+ double filterScale;
+ double center;
+ double totalWeight;
+ double weight;
+ int iRight;
+ int iLeft;
+ int iDest;
+
+ scale = (double)destSize / srcSize;
+ if ( scale < 1.0 )
+ {
+ filterSize = filterSize / scale;
+ filterScale = scale;
+ }
+ else
+ {
+ filterScale = 1.0;
+ }
+
+ if ( filterSize > (double)MaxFilterSize )
+ {
+ filterSize = (double)MaxFilterSize;
+ }
+
+ for ( iDest = 0; iDest < destSize; ++iDest )
+ {
+ center = (double)iDest / scale;
+
+ iLeft = (int)ceil(center - filterSize);
+ iRight = (int)floor(center + filterSize);
+
+ if ( !wrap )
+ {
+ if ( iLeft < 0 )
+ {
+ iLeft = 0;
+ }
+
+ if ( iRight >= srcSize )
+ {
+ iRight = srcSize - 1;
+ }
+ }
+
+ int numWeights = iRight - iLeft + 1;
+
+ contrib[iDest].first = iLeft;
+ contrib[iDest].numWeights = numWeights;
+
+ totalWeight = 0;
+ double t = ((double)iLeft - center) * filterScale;
+ for (int i = 0; i < numWeights; i++)
+ {
+ weight = (*FilterProc)(t) * filterScale;
+ totalWeight += weight;
+ contrib[iDest].weight[i] = weight;
+ t += filterScale;
+ }
+
+ //**--------------------------------------------------------
+ //** Normalize weights by dividing by the sum of the weights
+ //**--------------------------------------------------------
+ if ( totalWeight > 0.0 )
+ {
+ for ( int i = 0; i < numWeights; i++)
+ {
+ contrib[iDest].weight[i] /= totalWeight;
+ }
+ }
+ }
+}
+
+//**-------------------------------------------------------------------------
+//** 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.
+//**-------------------------------------------------------------------------
+int FilterTwoPass( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
+ RGBCOLOR *pDestImage, int destWidth, int destHeight, unsigned int wrapFlags, double (*FilterProc)(double) )
+{
+ FilterWeights *contrib;
+ RGBCOLOR *pPixel;
+ RGBCOLOR *pSrcPixel;
+ RGBCOLOR *pTempImage;
+ int iRow;
+ int iCol;
+ int iSrcCol;
+ int iSrcRow;
+ int iWeight;
+ double dRed;
+ double dGreen;
+ double dBlue;
+ double dAlpha;
+ double filterSize = 3.0;
+
+ int maxDim = (srcWidth>srcHeight)?srcWidth:srcHeight;
+ contrib = (FilterWeights*)malloc(maxDim * sizeof(FilterWeights));
+
+ //**------------------------------------------------------------------------
+ //** Need to create a temporary image to stuff the horizontally scaled image
+ //**------------------------------------------------------------------------
+ pTempImage = (RGBCOLOR *)malloc( destWidth * srcHeight * sizeof(RGBCOLOR) );
+ 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 ( iRow = 0; iRow < srcHeight; iRow++ )
+ {
+ for ( iCol = 0; iCol < destWidth; iCol++ )
+ {
+ dRed = 0;
+ dGreen = 0;
+ dBlue = 0;
+ dAlpha = 0;
+
+ for ( iWeight = 0; iWeight < contrib[iCol].numWeights; iWeight++ )
+ {
+ iSrcCol = iWeight + contrib[iCol].first;
+ if (bWrapHorizontal)
+ {
+ iSrcCol = (iSrcCol < 0) ? (srcWidth + iSrcCol) : (iSrcCol >= srcWidth) ? (iSrcCol - srcWidth) : iSrcCol;
+ }
+ pSrcPixel = pSrcImage + (iRow * srcWidth) + iSrcCol;
+ dRed += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[0];
+ dGreen += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[1];
+ dBlue += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[2];
+ dAlpha += contrib[iCol].weight[iWeight] * pSrcPixel->rgba[3];
+ }
+
+ pPixel = pTempImage + (iRow * destWidth) + iCol;
+ pPixel->rgba[0] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dRed)));
+ pPixel->rgba[1] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dGreen)));
+ pPixel->rgba[2] = static_cast<unsigned char>(std::max(0.0, std::min(255.0, dBlue)));
+ pPixel->rgba[3] = static_cast<unsigned char>(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 ( iCol = 0; iCol < destWidth; iCol++ )
+ {
+ for ( iRow = 0; iRow < destHeight; iRow++ )
+ {
+ dRed = 0;
+ dGreen = 0;
+ dBlue = 0;
+ dAlpha = 0;
+
+ for ( iWeight = 0; iWeight < contrib[iRow].numWeights; iWeight++ )
+ {
+ iSrcRow = iWeight + contrib[iRow].first;
+ if (bWrapVertical)
+ {
+ iSrcRow = (iSrcRow < 0) ? (srcHeight + iSrcRow) : (iSrcRow >= srcHeight) ? (iSrcRow - srcHeight) : iSrcRow;
+ }
+ pSrcPixel = pTempImage + (iSrcRow * destWidth) + iCol;
+ dRed += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[0];
+ dGreen += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[1];
+ dBlue += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[2];
+ dAlpha += contrib[iRow].weight[iWeight] * pSrcPixel->rgba[3];
+ }
+
+ pPixel = pDestImage + (iRow * destWidth) + iCol;
+ pPixel->rgba[0] = (unsigned char)(std::max( 0.0, std::min( 255.0, dRed)));
+ pPixel->rgba[1] = (unsigned char)(std::max( 0.0, std::min( 255.0, dGreen)));
+ pPixel->rgba[2] = (unsigned char)(std::max( 0.0, std::min( 255.0, dBlue)));
+ pPixel->rgba[3] = (unsigned char)(std::max( 0.0, std::min( 255.0, dAlpha)));
+ }
+ }
+
+ free( pTempImage );
+ free( contrib );
+
+ return 1;
+}
+
+//**-------------------------------------------------------------------------
+//** Name: FilterResample(RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
+//** RGBCOLOR *pDstImage, int dstWidth, int dstHeight)
+//** Returns: 1
+//** Description: This function runs a 2d box filter over the srouce image
+//** to produce the destination image.
+//**-------------------------------------------------------------------------
+void FilterResample( RGBCOLOR *pSrcImage, int srcWidth, int srcHeight,
+ RGBCOLOR *pDstImage, int dstWidth, int dstHeight )
+{
+ int iRow;
+ int iCol;
+ int iSampleRow;
+ int iSampleCol;
+ int iFirstSampleRow;
+ int iFirstSampleCol;
+ int iLastSampleRow;
+ int iLastSampleCol;
+ int red;
+ int green;
+ int blue;
+ int alpha;
+ int samples;
+ float xScale;
+ float yScale;
+
+ RGBCOLOR *pSrcPixel;
+ RGBCOLOR *pDstPixel;
+
+ xScale = (float)srcWidth / dstWidth;
+ yScale = (float)srcHeight / dstHeight;
+
+ for ( iRow = 0; iRow < dstHeight; iRow++ )
+ {
+ for ( iCol = 0; iCol < dstWidth; iCol++ )
+ {
+ 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;
+ green = 0;
+ blue = 0;
+ alpha = 0;
+ for ( iSampleRow = iFirstSampleRow; iSampleRow <= iLastSampleRow; iSampleRow++ )
+ {
+ for ( iSampleCol = iFirstSampleCol; iSampleCol <= iLastSampleCol; iSampleCol++ )
+ {
+ pSrcPixel = pSrcImage + iSampleRow * srcWidth + iSampleCol;
+ red += pSrcPixel->rgba[0];
+ green += pSrcPixel->rgba[1];
+ blue += pSrcPixel->rgba[2];
+ alpha += pSrcPixel->rgba[3];
+
+ samples++;
+ }
+ }
+
+ pDstPixel = pDstImage + iRow * dstWidth + iCol;
+ if ( samples > 0 )
+ {
+ pDstPixel->rgba[0] = static_cast<uint8_t>(red / samples);
+ pDstPixel->rgba[1] = static_cast<uint8_t>(green / samples);
+ pDstPixel->rgba[2] = static_cast<uint8_t>(blue / samples);
+ pDstPixel->rgba[3] = static_cast<uint8_t>(alpha / samples);
+ }
+ else
+ {
+ pDstPixel->rgba[0] = static_cast<uint8_t>(red);
+ pDstPixel->rgba[1] = static_cast<uint8_t>(green);
+ pDstPixel->rgba[2] = static_cast<uint8_t>(blue);
+ pDstPixel->rgba[3] = static_cast<uint8_t>(alpha);
+ }
+ }
+ }
+}
+
+
+} \ No newline at end of file