summaryrefslogtreecommitdiff
path: root/bitmap/bitmap.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 /bitmap/bitmap.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'bitmap/bitmap.cpp')
-rw-r--r--bitmap/bitmap.cpp461
1 files changed, 461 insertions, 0 deletions
diff --git a/bitmap/bitmap.cpp b/bitmap/bitmap.cpp
new file mode 100644
index 0000000..e9f30af
--- /dev/null
+++ b/bitmap/bitmap.cpp
@@ -0,0 +1,461 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "bitmap/bitmap.h"
+#include "dbg.h"
+
+// Should be last include
+#include "tier0/memdbgon.h"
+
+bool Bitmap_t::IsValid() const
+{
+ if ( m_nWidth <= 0 || m_nHeight <= 0 || m_pBits == NULL )
+ {
+ Assert( m_nWidth == 0 );
+ Assert( m_nHeight == 0 );
+ Assert( m_pBits == NULL );
+ return false;
+ }
+ return true;
+}
+
+void Bitmap_t::Clear()
+{
+ if ( m_pBits && m_bOwnsBuffer )
+ {
+ free( m_pBits );
+ }
+ Reset();
+}
+
+void Bitmap_t::Init( int xs, int ys, ImageFormat imageFormat, int nStride )
+{
+
+ // Check for bogus allocation sizes
+ if (xs <= 0 || ys <= 0 )
+ {
+ Assert( xs == 0 );
+ Assert( ys == 0 );
+ Clear();
+ return;
+ }
+
+ int nPixSize = ImageLoader::SizeInBytes( imageFormat );
+
+ // Auto detect stride
+ if ( nStride == 0 )
+ {
+ nStride = nPixSize * xs;
+ }
+
+ // Check for NOP
+ if (
+ m_pBits
+ && m_bOwnsBuffer
+ && m_nWidth == xs
+ && m_nHeight == ys
+ && nStride == m_nStride
+ && nPixSize == m_nPixelSize )
+ {
+ // We're already got a buffer of the right size.
+ // The only thing that might be wrong is the pixel format.
+ m_ImageFormat = imageFormat;
+ return;
+ }
+
+ // Free up anything already allocated
+ Clear();
+
+ // Remember dimensions and pixel format
+ m_nWidth = xs;
+ m_nHeight = ys;
+ m_ImageFormat = imageFormat;
+ m_nPixelSize = nPixSize;
+ m_nStride = nStride;
+
+ // Allocate buffer. Because this is a PC game,
+ // failure is impossible....right?
+ m_pBits = (byte *)malloc( ys * m_nStride );
+
+ // Assume ownership
+ m_bOwnsBuffer = true;
+}
+
+void Bitmap_t::SetBuffer( int nWidth, int nHeight, ImageFormat imageFormat, unsigned char *pBits, bool bAssumeOwnership, int nStride )
+{
+ Assert( pBits );
+ Assert( nWidth > 0 );
+ Assert( nHeight > 0 );
+
+ // Free up anything already allocated
+ Clear();
+
+ // Remember dimensions and pixel format
+ m_nWidth = nWidth;
+ m_nHeight = nHeight;
+ m_ImageFormat = imageFormat;
+ m_nPixelSize = ImageLoader::SizeInBytes( imageFormat );
+ if ( nStride == 0 )
+ {
+ m_nStride = m_nPixelSize * nWidth;
+ }
+ else
+ {
+ m_nStride = nStride;
+ }
+
+ // Set our buffer pointer
+ m_pBits = pBits;
+
+ // Assume ownership of the buffer, if requested
+ m_bOwnsBuffer = bAssumeOwnership;
+
+ // We should be good to go
+ Assert( IsValid() );
+}
+
+Color Bitmap_t::GetColor( int x, int y ) const
+{
+ Assert( x >= 0 && x < m_nWidth );
+ Assert( y >= 0 && y < m_nHeight );
+ Assert( m_pBits );
+
+ // Get pointer to pixel data
+ byte *ptr = m_pBits + (y*m_nStride) + x* m_nPixelSize;
+
+ // Check supported image formats
+ switch ( m_ImageFormat )
+ {
+ case IMAGE_FORMAT_RGBA8888:
+ return Color( ptr[0], ptr[1], ptr[2], ptr[3] );
+
+ case IMAGE_FORMAT_ABGR8888:
+ return Color( ptr[3], ptr[2], ptr[1], ptr[0] );
+
+ default:
+ Assert( !"Unsupport image format!");
+ return Color( 255,0,255,255 );
+ }
+}
+
+void Bitmap_t::SetColor( int x, int y, Color c )
+{
+ Assert( x >= 0 && x < m_nWidth );
+ Assert( y >= 0 && y < m_nHeight );
+ Assert( m_pBits );
+
+ // Get pointer to pixel data
+ byte *ptr = m_pBits + (y*m_nStride) + x* m_nPixelSize;
+
+ // Check supported image formats
+ switch ( m_ImageFormat )
+ {
+ case IMAGE_FORMAT_RGBA8888:
+ ptr[0] = c.r();
+ ptr[1] = c.g();
+ ptr[2] = c.b();
+ ptr[3] = c.a();
+ break;
+
+ case IMAGE_FORMAT_ABGR8888:
+ ptr[0] = c.a();
+ ptr[1] = c.b();
+ ptr[2] = c.g();
+ ptr[3] = c.r();
+ break;
+
+ default:
+ Assert( !"Unsupport image format!");
+ break;
+ }
+}
+
+//bool LoadVTF( const char *pszFilename )
+//{
+//
+// // Load the raw file data
+// CUtlBuffer fileData;
+// if ( !filesystem->ReadFile( pszFilename, "game", fileData ) )
+// {
+// Warning( "Failed to load %s\n", pszFilename);
+// return false;
+// }
+//
+// return LoadVTFFromBuffer( fileData, pszFilename );
+//}
+//
+//bool LoadVTFFromBuffer( CUtlBuffer fileData, const char *pszDebugName = "buffer" )
+//{
+//
+// // Parse it into VTF object
+// IVTFTexture *pVTFTexture( CreateVTFTexture() );
+// if ( !pVTFTexture->Unserialize( fileData ) )
+// {
+// DestroyVTFTexture( pVTFTexture );
+// Warning( "Failed to deserialize VTF %s\n", pszDebugName);
+// return false;
+// }
+//
+// // We are re-reading our own files, so they should be 8888's
+// if ( pVTFTexture->Format() != IMAGE_FORMAT_RGBA8888 )
+// {
+// DestroyVTFTexture( pVTFTexture );
+// Warning( "%s isn't RGBA8888\n", pszDebugName);
+// return false;
+// }
+//
+// // Copy the image data
+// Allocate( pVTFTexture->Width(), pVTFTexture->Height() );
+// for ( int y = 0 ; y < m_nHeight ; ++y )
+// {
+// memcpy( PixPtr(0, y), pVTFTexture->ImageData(0, 0, 0, 0, y), m_nWidth*4 );
+// }
+//
+// // Clean up
+// DestroyVTFTexture( pVTFTexture );
+// return true;
+//}
+//
+//bool SaveVTF( CUtlBuffer &outBuffer )
+//{
+// // Create the VTF to write into
+// IVTFTexture *pVTFTexture( CreateVTFTexture() );
+// const int nFlags = TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_SRGB;
+// if ( !pVTFTexture->Init( m_nWidth, m_nHeight, 1, IMAGE_FORMAT_RGBA8888, nFlags, 1, 1 ) )
+// {
+// DestroyVTFTexture( pVTFTexture );
+// return false;
+// }
+//
+// // write the rgba image to the vtf texture using the pixel writer
+// CPixelWriter pixelWriter;
+// pixelWriter.SetPixelMemory( pVTFTexture->Format(), pVTFTexture->ImageData(), pVTFTexture->RowSizeInBytes( 0 ) );
+//
+// for (int y = 0; y < m_nHeight; ++y)
+// {
+// pixelWriter.Seek( 0, y );
+// for (int x = 0; x < m_nWidth; ++x)
+// {
+// Color c = GetPix( x, y );
+// pixelWriter.WritePixel( c.r(), c.g(), c.b(), c.a() );
+// }
+// }
+//
+// // Serialize to the buffer
+// if ( !pVTFTexture->Serialize( outBuffer ) )
+// {
+// DestroyVTFTexture( pVTFTexture );
+// return false;
+// }
+// DestroyVTFTexture( pVTFTexture );
+// return true;
+//}
+
+//void Resize( int nNewSizeX, int nNewSizeY, const Image *pImgSrc = NULL )
+//{
+// if ( pImgSrc == NULL )
+// {
+// pImgSrc = this;
+// }
+//
+// if ( nNewSizeX == m_nWidth && nNewSizeY == m_nHeight && pImgSrc == this )
+// {
+// return;
+// }
+//
+// byte *pNewData = (byte *)malloc( nNewSizeX * nNewSizeY * 4 );
+// ImgUtl_StretchRGBAImage( pImgSrc->m_pBits, pImgSrc->m_nWidth, pImgSrc->m_nHeight, pNewData, nNewSizeX, nNewSizeY );
+// Clear();
+// m_pBits = pNewData;
+// m_nWidth = nNewSizeX;
+// m_nHeight = nNewSizeY;
+//}
+//
+//void Crop( int x0, int y0, int nNewSizeX, int nNewSizeY, const Image *pImgSrc )
+//{
+// if ( pImgSrc == NULL )
+// {
+// pImgSrc = this;
+// }
+//
+// if ( nNewSizeX == m_nWidth && nNewSizeY == m_nHeight && pImgSrc == this )
+// {
+// return;
+// }
+//
+//
+// Assert( x0 >= 0 );
+// Assert( y0 >= 0 );
+// Assert( x0 + nNewSizeX <= pImgSrc->m_nWidth );
+// Assert( y0 + nNewSizeY <= pImgSrc->m_nHeight );
+//
+// // Allocate new buffer
+// int nRowSize = nNewSizeX * 4;
+// byte *pNewData = (byte *)malloc( nNewSizeY * nRowSize );
+//
+// // Copy data, one row at a time
+// for ( int y = 0 ; y < nNewSizeY ; ++y )
+// {
+// memcpy( pNewData + y*nRowSize, pImgSrc->PixPtr(x0, y0+y), nRowSize );
+// }
+//
+// // Replace current buffer with the new one
+// Clear();
+// m_pBits = pNewData;
+// m_nWidth = nNewSizeX;
+// m_nHeight = nNewSizeY;
+//}
+
+void Bitmap_t::MakeLogicalCopyOf( Bitmap_t &src, bool bTransferBufferOwnership )
+{
+ // What does it mean to make a logical copy of an
+ // invalid bitmap? I'll tell you what it means: you have a bug.
+ Assert( src.IsValid() );
+
+ // Free up anything we already own
+ Clear();
+
+ // Copy all of the member variables so we are
+ // a logical copy of the source bitmap
+ m_nWidth = src.m_nWidth;
+ m_nHeight = src.m_nHeight;
+ m_nPixelSize = src.m_nPixelSize;
+ m_nStride = src.m_nStride;
+ m_ImageFormat = src.m_ImageFormat;
+ m_pBits = src.m_pBits;
+ Assert( !m_bOwnsBuffer );
+
+ // Check for assuming ownership of the buffer
+ if ( bTransferBufferOwnership )
+ {
+ if ( src.m_bOwnsBuffer )
+ {
+ m_bOwnsBuffer = true;
+ src.m_bOwnsBuffer = false;
+ }
+ else
+ {
+ // They don't own the buffer? Then who does?
+ // Maybe nobody, and it would safe to assume
+ // ownership. But more than likely, this is a
+ // bug.
+ Assert( src.m_bOwnsBuffer );
+
+ // And a leak is better than a double-free.
+ // Don't assume ownership of the buffer.
+ }
+ }
+}
+
+void Bitmap_t::Crop( int x0, int y0, int nWidth, int nHeight, const Bitmap_t *pImgSource )
+{
+ // Check for cropping in place, then save off our data to a temp
+ Bitmap_t temp;
+ if ( pImgSource == this || !pImgSource )
+ {
+ temp.MakeLogicalCopyOf( *this, m_bOwnsBuffer );
+ pImgSource = &temp;
+ }
+
+ // No source image?
+ if ( !pImgSource->IsValid() )
+ {
+ Assert( pImgSource->IsValid() );
+ return;
+ }
+
+ // Sanity check crop rectangle
+ Assert( x0 >= 0 );
+ Assert( y0 >= 0 );
+ Assert( x0 + nWidth <= pImgSource->Width() );
+ Assert( y0 + nHeight <= pImgSource->Height() );
+
+ // Allocate buffer
+ Init( nWidth, nHeight, pImgSource->Format() );
+
+ // Something wrong?
+ if ( !IsValid() )
+ {
+ Assert( IsValid() );
+ return;
+ }
+
+ // Copy the data a row at a time
+ int nRowSize = m_nWidth * m_nPixelSize;
+ for ( int y = 0 ; y < m_nHeight ; ++y )
+ {
+ memcpy( GetPixel(0,y), pImgSource->GetPixel( x0, y + y0 ), nRowSize );
+ }
+}
+
+void Bitmap_t::SetPixelData( const Bitmap_t &src, int nSrcX1, int nSrcY1, int nCopySizeX, int nCopySizeY, int nDestX1, int nDestY1 )
+{
+ // Safety
+ if ( !src.IsValid() )
+ {
+ Assert( src.IsValid() );
+ return;
+ }
+ if ( !IsValid() )
+ {
+ Assert( IsValid() );
+ return;
+ }
+
+ // You need to specify a valid source rectangle, we cannot clip that for you
+ if ( nSrcX1 < 0 || nSrcY1 < 0 || nSrcX1 + nCopySizeX > src.Width() || nSrcY1 + nCopySizeY > src.Height() )
+ {
+ Assert( nSrcX1 >= 0 );
+ Assert( nSrcY1 >= 0 );
+ Assert( nSrcX1 + nCopySizeX <= src.Width() );
+ Assert( nSrcY1 + nCopySizeY <= src.Height() );
+ return;
+ }
+
+ // But we can clip the rectangle if it extends outside the destination image in a perfectly
+ // reasonable way
+ if ( nDestX1 < 0 )
+ {
+ nCopySizeX += nDestX1;
+ nDestX1 = 0;
+ }
+ if ( nDestX1 + nCopySizeX > Width() )
+ {
+ nCopySizeX = Width() - nDestX1;
+ }
+ if ( nDestY1 < 0 )
+ {
+ nCopySizeY += nDestY1;
+ nDestY1 = 0;
+ }
+ if ( nDestY1 + nCopySizeY > Height() )
+ {
+ nCopySizeY = Height() - nDestY1;
+ }
+ if ( nCopySizeX <= 0 || nCopySizeY <= 0 )
+ {
+ return;
+ }
+
+ // Copy the pixel data
+ for ( int y = 0 ; y < nCopySizeY ; ++y )
+ {
+ // Wow, this could be a lot faster in the common case
+ // that the pixe formats are the same. But...this code
+ // is simple and works, and is NOT the root of all evil.
+ for ( int x = 0 ; x < nCopySizeX ; ++x )
+ {
+ Color c = src.GetColor( nSrcX1 + x, nSrcY1 + y );
+ SetColor( nDestX1 + x, nDestY1 + y, c );
+ }
+ }
+}
+
+void Bitmap_t::SetPixelData( const Bitmap_t &src, int nDestX1, int nDestY1 )
+{
+ SetPixelData( src, 0, 0, src.Width(), src.Height(), nDestX1, nDestY1 );
+}
+