summaryrefslogtreecommitdiff
path: root/common/jpegloader_common.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /common/jpegloader_common.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'common/jpegloader_common.cpp')
-rw-r--r--common/jpegloader_common.cpp213
1 files changed, 213 insertions, 0 deletions
diff --git a/common/jpegloader_common.cpp b/common/jpegloader_common.cpp
new file mode 100644
index 0000000..c2e6fbb
--- /dev/null
+++ b/common/jpegloader_common.cpp
@@ -0,0 +1,213 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "jpegloader.h"
+#include "tier0/dbg.h"
+#include "tier1/utlvector.h"
+#include "tier0/vprof.h"
+#include "jpeglib/jpeglib.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Takes a RGBA image buffer and resizes it using linear interpolation.
+//
+// Params: bufRGBA should contain the current image, nWidth and nHeight should describe
+// the current images dimensions. nNewWidth and nNewHeight should be the new target size,
+// one, but not both, of these may be -1 which will indicate to preserve aspect ratio
+// and size that dimension to match the aspect ratio adjustment applied to the other
+// dimension which must then be specified explicitly. nNewWidth and nNewHeight may
+// be modified by the function and will specify the final width/height after the
+// function returns succesfully. If both nNewWidth and nNewHeight are specified
+// the content will be scaled without changing the aspect ratio and black letterboxing
+// will be added if appropriate
+//-----------------------------------------------------------------------------
+bool BResizeImageInternal( CUtlBuffer &bufImage, int nWidth, int nHeight, int &nNewWidth, int &nNewHeight, bool bIsRGBA = true )
+{
+ VPROF_BUDGET( "BResizeImageRGBA", VPROF_BUDGETGROUP_OTHER_VGUI );
+ CUtlBuffer bufImageOut;
+
+ if ( nWidth == 0 || nHeight == 0 )
+ return false;
+
+ // Must specify at least one, then we'll compute the other to preserve aspect ratio if it's set to -1
+ if ( nNewWidth == - 1 && nNewHeight == -1 )
+ return false;
+
+ if ( nNewHeight == -1 )
+ {
+ float flAspect = (float)nNewWidth/(float)nWidth;
+ nNewHeight = (int)(flAspect*nHeight);
+ }
+ else if ( nNewWidth == -1 )
+ {
+ float flAspect = (float)nNewHeight/(float)nHeight;
+ nNewWidth = (int)(flAspect*nWidth);
+ }
+
+ if ( nNewWidth == 0 || nNewHeight == 0 )
+ return false;
+
+ int nNewContentHeight = nNewHeight;
+ int nNewContentWidth = nNewWidth;
+
+ // Calculate the width/height of the actual content
+ if ( nWidth/(float)nHeight > nNewContentWidth/(float)nNewContentHeight )
+ nNewContentHeight = ( nNewContentWidth * nHeight )/nWidth;
+ else
+ nNewContentWidth = ( nNewContentHeight * nWidth )/nHeight;
+
+ int bytesPerPixel = bIsRGBA ? 4 : 3;
+
+ bufImageOut.EnsureCapacity( nNewWidth*nNewHeight*bytesPerPixel );
+ bufImageOut.SeekPut( CUtlBuffer::SEEK_HEAD, nNewWidth*nNewHeight*bytesPerPixel );
+
+
+ // Letterboxing
+ int nPaddingTop = (nNewHeight - nNewContentHeight)/2;
+ int nPaddingBottom = nNewHeight - nNewContentHeight - nPaddingTop;
+ int nPaddingLeft = (nNewWidth - nNewContentWidth)/2;
+ int nPaddingRight = nNewWidth - nNewContentWidth - nPaddingLeft;
+
+ Assert( nPaddingTop + nPaddingBottom + nNewContentHeight == nNewHeight );
+ Assert( nPaddingLeft + nPaddingRight + nNewContentWidth == nNewWidth );
+
+ if ( nPaddingLeft > 0 ||
+ nPaddingRight > 0 ||
+ nPaddingTop > 0 ||
+ nPaddingBottom > 0 )
+ {
+ Q_memset( bufImageOut.Base(), 0, nNewWidth*nNewHeight*bytesPerPixel );
+ }
+
+ byte *pBits = (byte*)bufImageOut.Base();
+
+ int nOriginalStride = nWidth;
+ int nTargetStride = nNewWidth;
+
+ float flXRatio = (float)(nWidth-1)/(float)nNewContentWidth;
+ float flYRatio = (float)(nHeight-1)/(float)nNewContentHeight;
+
+ byte *pSrcBits = (byte*)bufImage.Base();
+ for( int yNew=0; yNew<nNewContentHeight; ++yNew )
+ {
+ int y = (int)(flYRatio * yNew);
+ float yDiff = (flYRatio * yNew) - y;
+
+ for ( int xNew=0; xNew<nNewContentWidth; ++xNew )
+ {
+ int x = (int)(flXRatio * xNew);
+ float xDiff = (flXRatio * xNew) - x;
+
+ int aOffset = (x+(y*nOriginalStride))*bytesPerPixel;
+ int bOffset = aOffset+bytesPerPixel;
+ int cOffset = aOffset + (nOriginalStride*bytesPerPixel);
+ int dOffset = cOffset+bytesPerPixel;
+
+ byte red = (byte)(
+ pSrcBits[aOffset]*(1-xDiff)*(1-yDiff)
+ +pSrcBits[bOffset]*(xDiff)*(1-yDiff)
+ +pSrcBits[cOffset]*(yDiff)*(1-xDiff)
+ +pSrcBits[dOffset]*(xDiff)*(yDiff)
+ );
+
+ byte green = (byte)(
+ pSrcBits[aOffset+1]*(1-xDiff)*(1-yDiff)
+ +pSrcBits[bOffset+1]*(xDiff)*(1-yDiff)
+ +pSrcBits[cOffset+1]*(yDiff)*(1-xDiff)
+ +pSrcBits[dOffset+1]*(xDiff)*(yDiff)
+ );
+
+ byte blue = (byte)(
+ pSrcBits[aOffset+2]*(1-xDiff)*(1-yDiff)
+ +pSrcBits[bOffset+2]*(xDiff)*(1-yDiff)
+ +pSrcBits[cOffset+2]*(yDiff)*(1-xDiff)
+ +pSrcBits[dOffset+2]*(xDiff)*(yDiff)
+ );
+
+ byte alpha = 0;
+ if ( bytesPerPixel == 4 )
+ {
+ alpha = (byte)(
+ pSrcBits[aOffset+3]*(1-xDiff)*(1-yDiff)
+ +pSrcBits[bOffset+3]*(xDiff)*(1-yDiff)
+ +pSrcBits[cOffset+3]*(yDiff)*(1-xDiff)
+ +pSrcBits[dOffset+3]*(xDiff)*(yDiff)
+ );
+ }
+
+ int targetOffset = (nPaddingLeft+xNew+((nPaddingTop+yNew)*nTargetStride))*bytesPerPixel;
+
+ pBits[targetOffset] = red;
+ pBits[targetOffset+1] = green;
+ pBits[targetOffset+2] = blue;
+ if ( bytesPerPixel == 4 )
+ pBits[targetOffset+3] = alpha;
+ }
+ }
+ bufImage.Swap( bufImageOut );
+ return true;
+}
+
+// Resize an RGB image using linear interpolation
+bool BResizeImageRGB( CUtlBuffer &bufRGB, int nWidth, int nHeight, int &nNewWidth, int &nNewHeight )
+{
+ return BResizeImageInternal( bufRGB, nWidth, nHeight, nNewWidth, nNewHeight, false );
+}
+
+// Resize an RGBA image using linear interpolation
+bool BResizeImageRGBA( CUtlBuffer &bufRGB, int nWidth, int nHeight, int &nNewWidth, int &nNewHeight )
+{
+ return BResizeImageInternal( bufRGB, nWidth, nHeight, nNewWidth, nNewHeight, true );
+}
+
+// Convert an RGB image to RGBA with 100% opacity
+bool BConvertRGBToRGBA( CUtlBuffer &bufRGB, int nWidth, int nHeight )
+{
+ CUtlBuffer bufRGBA;
+ bufRGBA.EnsureCapacity( nWidth*nHeight*4 );
+ byte *pBits = (byte*)bufRGB.Base();
+ byte *pBitsOut = (byte*)bufRGBA.Base();
+
+ for( int y=0; y<nHeight; ++y )
+ {
+ for( int x=0; x<nWidth; ++x )
+ {
+ *pBitsOut = *pBits;
+ *(pBitsOut+1) = *(pBits+1);
+ *(pBitsOut+2) = *(pBits+2);
+ *(pBitsOut+3) = 255;
+
+ pBitsOut += 4;
+ pBits += 3;
+ }
+ }
+ bufRGB.Swap( bufRGBA );
+ return true;
+}
+
+// Convert an RGBA image to RGB using opacity against a given solid background
+bool BConvertRGBAToRGB( CUtlBuffer &bufRGBA, int nWidth, int nHeight, Color colorBG )
+{
+ CUtlBuffer bufRGB;
+ bufRGB.EnsureCapacity( nWidth*nHeight*3 );
+ byte *pBits = (byte*)bufRGBA.Base();
+ byte *pBitsOut = (byte*)bufRGB.Base();
+
+ for( int y=0; y<nHeight; ++y )
+ {
+ for( int x=0; x<nWidth; ++x )
+ {
+ float fOpacity = *(pBits+3) / 255.0;
+ *pBitsOut = *pBits * fOpacity + (1.0 - fOpacity) * colorBG.r();
+ *(pBitsOut+1) = *(pBits+1) * fOpacity + (1.0 - fOpacity) * colorBG.g();
+ *(pBitsOut+2) = *(pBits+2) * fOpacity + (1.0 - fOpacity) * colorBG.b();
+
+ pBitsOut += 3;
+ pBits += 4;
+ }
+ }
+ bufRGB.Swap( bufRGBA );
+ return true;
+} \ No newline at end of file