summaryrefslogtreecommitdiff
path: root/bitmap/tgawriter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'bitmap/tgawriter.cpp')
-rw-r--r--bitmap/tgawriter.cpp353
1 files changed, 353 insertions, 0 deletions
diff --git a/bitmap/tgawriter.cpp b/bitmap/tgawriter.cpp
new file mode 100644
index 0000000..a73c996
--- /dev/null
+++ b/bitmap/tgawriter.cpp
@@ -0,0 +1,353 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "tier0/dbg.h"
+#include <malloc.h>
+#include "filesystem.h"
+#include "bitmap/tgawriter.h"
+#include "tier1/utlbuffer.h"
+#include "bitmap/imageformat.h"
+#include "tier2/tier2.h"
+#include "tier2/fileutils.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+namespace TGAWriter
+{
+
+#pragma pack(1)
+struct TGAHeader_t
+{
+ unsigned char id_length;
+ unsigned char colormap_type;
+ unsigned char image_type;
+ unsigned short colormap_index;
+ unsigned short colormap_length;
+ unsigned char colormap_size;
+ unsigned short x_origin;
+ unsigned short y_origin;
+ unsigned short width;
+ unsigned short height;
+ unsigned char pixel_size;
+ unsigned char attributes;
+};
+#pragma pack()
+
+#define fputc myfputc
+#define fwrite myfwrite
+
+static void fputLittleShort( unsigned short s, CUtlBuffer &buffer )
+{
+ buffer.PutChar( s & 0xff );
+ buffer.PutChar( s >> 8 );
+}
+
+static inline void myfputc( unsigned char c, FileHandle_t fileHandle )
+{
+ g_pFullFileSystem->Write( &c, 1, fileHandle );
+}
+
+static inline void myfwrite( void const *data, int size1, int size2, FileHandle_t fileHandle )
+{
+ g_pFullFileSystem->Write( data, size1 * size2, fileHandle );
+}
+
+
+//-----------------------------------------------------------------------------
+// FIXME: assumes that we don't need to do gamma correction.
+//-----------------------------------------------------------------------------
+bool WriteToBuffer( unsigned char *pImageData, CUtlBuffer &buffer, int width, int height,
+ ImageFormat srcFormat, ImageFormat dstFormat )
+{
+ TGAHeader_t header;
+
+ // Fix the dstFormat to match what actually is going to go into the file
+ switch( dstFormat )
+ {
+ case IMAGE_FORMAT_RGB888:
+ dstFormat = IMAGE_FORMAT_BGR888;
+ break;
+#if defined( _X360 )
+ case IMAGE_FORMAT_LINEAR_RGB888:
+ dstFormat = IMAGE_FORMAT_LINEAR_BGR888;
+ break;
+#endif
+ case IMAGE_FORMAT_RGBA8888:
+ dstFormat = IMAGE_FORMAT_BGRA8888;
+ break;
+ }
+
+ header.id_length = 0; // comment length
+ header.colormap_type = 0; // ???
+
+ switch( dstFormat )
+ {
+ case IMAGE_FORMAT_BGR888:
+#if defined( _X360 )
+ case IMAGE_FORMAT_LINEAR_BGR888:
+#endif
+ header.image_type = 2; // 24/32 bit uncompressed TGA
+ header.pixel_size = 24;
+ break;
+ case IMAGE_FORMAT_BGRA8888:
+ header.image_type = 2; // 24/32 bit uncompressed TGA
+ header.pixel_size = 32;
+ break;
+ case IMAGE_FORMAT_I8:
+ header.image_type = 1; // 8 bit uncompressed TGA
+ header.pixel_size = 8;
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ header.colormap_index = 0;
+ header.colormap_length = 0;
+ header.colormap_size = 0;
+ header.x_origin = 0;
+ header.y_origin = 0;
+ header.width = ( unsigned short )width;
+ header.height = ( unsigned short )height;
+ header.attributes = 0x20; // Makes it so we don't have to vertically flip the image
+
+ buffer.PutChar( header.id_length );
+ buffer.PutChar( header.colormap_type );
+ buffer.PutChar( header.image_type );
+ fputLittleShort( header.colormap_index, buffer );
+ fputLittleShort( header.colormap_length, buffer );
+ buffer.PutChar( header.colormap_size );
+ fputLittleShort( header.x_origin, buffer );
+ fputLittleShort( header.y_origin, buffer );
+ fputLittleShort( header.width, buffer );
+ fputLittleShort( header.height, buffer );
+ buffer.PutChar( header.pixel_size );
+ buffer.PutChar( header.attributes );
+
+ int nSizeInBytes = width * height * ImageLoader::SizeInBytes( dstFormat );
+ buffer.EnsureCapacity( buffer.TellPut() + nSizeInBytes );
+ unsigned char *pDst = (unsigned char*)buffer.PeekPut();
+
+ if ( !ImageLoader::ConvertImageFormat( pImageData, srcFormat, pDst, dstFormat, width, height ) )
+ return false;
+
+ buffer.SeekPut( CUtlBuffer::SEEK_CURRENT, nSizeInBytes );
+ return true;
+}
+
+bool WriteDummyFileNoAlloc( const char *fileName, int width, int height, enum ImageFormat dstFormat )
+{
+ TGAHeader_t tgaHeader;
+
+ Assert( g_pFullFileSystem );
+ if( !g_pFullFileSystem )
+ {
+ return false;
+ }
+ COutputFile fp( fileName );
+
+ int nBytesPerPixel, nImageType, nPixelSize;
+
+ switch( dstFormat )
+ {
+ case IMAGE_FORMAT_BGR888:
+#if defined( _X360 )
+ case IMAGE_FORMAT_LINEAR_BGR888:
+#endif
+ nBytesPerPixel = 3; // 24/32 bit uncompressed TGA
+ nPixelSize = 24;
+ nImageType = 2;
+ break;
+ case IMAGE_FORMAT_BGRA8888:
+ nBytesPerPixel = 4; // 24/32 bit uncompressed TGA
+ nPixelSize = 32;
+ nImageType = 2;
+ break;
+ case IMAGE_FORMAT_I8:
+ nBytesPerPixel = 1; // 8 bit uncompressed TGA
+ nPixelSize = 8;
+ nImageType = 1;
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ memset( &tgaHeader, 0, sizeof(tgaHeader) );
+ tgaHeader.id_length = 0;
+ tgaHeader.image_type = (unsigned char) nImageType;
+ tgaHeader.width = (unsigned short) width;
+ tgaHeader.height = (unsigned short) height;
+ tgaHeader.pixel_size = (unsigned char) nPixelSize;
+ tgaHeader.attributes = 0x20;
+
+ // Write the Targa header
+ fp.Write( &tgaHeader, sizeof(TGAHeader_t) );
+
+ // Write out width * height black pixels
+ unsigned char black[4] = { 0x1E, 0x9A, 0xFF, 0x00 };
+ for (int i = 0; i < width * height; i++)
+ {
+ fp.Write( black, nBytesPerPixel );
+ }
+
+ return true;
+}
+
+bool WriteTGAFile( const char *fileName, int width, int height, enum ImageFormat srcFormat, uint8 const *srcData, int nStride )
+{
+ TGAHeader_t tgaHeader;
+
+ COutputFile fp( fileName );
+
+ int nBytesPerPixel, nImageType, nPixelSize;
+
+ bool bMustConvert = false;
+ ImageFormat dstFormat = srcFormat;
+
+ switch( srcFormat )
+ {
+ case IMAGE_FORMAT_BGR888:
+#if defined( _X360 )
+ case IMAGE_FORMAT_LINEAR_BGR888:
+#endif
+ nBytesPerPixel = 3; // 24/32 bit uncompressed TGA
+ nPixelSize = 24;
+ nImageType = 2;
+ break;
+ case IMAGE_FORMAT_BGRA8888:
+ nBytesPerPixel = 4; // 24/32 bit uncompressed TGA
+ nPixelSize = 32;
+ nImageType = 2;
+ break;
+ case IMAGE_FORMAT_RGBA8888:
+ bMustConvert = true;
+ dstFormat = IMAGE_FORMAT_BGRA8888;
+ nBytesPerPixel = 4; // 24/32 bit uncompressed TGA
+ nPixelSize = 32;
+ nImageType = 2;
+ break;
+ case IMAGE_FORMAT_I8:
+ nBytesPerPixel = 1; // 8 bit uncompressed TGA
+ nPixelSize = 8;
+ nImageType = 1;
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ memset( &tgaHeader, 0, sizeof(tgaHeader) );
+ tgaHeader.id_length = 0;
+ tgaHeader.image_type = (unsigned char) nImageType;
+ tgaHeader.width = (unsigned short) width;
+ tgaHeader.height = (unsigned short) height;
+ tgaHeader.pixel_size = (unsigned char) nPixelSize;
+ tgaHeader.attributes = 0x20;
+
+ // Write the Targa header
+ fp.Write( &tgaHeader, sizeof(TGAHeader_t) );
+
+ // Write out image data
+ if ( bMustConvert )
+ {
+ uint8 *pLineBuf = new uint8[ nBytesPerPixel * width ];
+ while( height-- )
+ {
+ ImageLoader::ConvertImageFormat( srcData, srcFormat, pLineBuf, dstFormat, width, 1 );
+ fp.Write( pLineBuf, nBytesPerPixel * width );
+ srcData += nStride;
+ }
+ delete[] pLineBuf;
+ }
+ else
+ {
+ while( height-- )
+ {
+ fp.Write( srcData, nBytesPerPixel * width );
+ srcData += nStride;
+ }
+
+ }
+ return true;
+}
+
+
+bool WriteRectNoAlloc( unsigned char *pImageData, const char *fileName, int nXOrigin, int nYOrigin, int width, int height, int nStride, enum ImageFormat srcFormat )
+{
+ Assert( g_pFullFileSystem );
+ if( !g_pFullFileSystem )
+ {
+ return false;
+ }
+ FileHandle_t fp;
+ fp = g_pFullFileSystem->Open( fileName, "r+b" );
+
+ //
+ // Read in the targa header
+ //
+ TGAHeader_t tgaHeader;
+ g_pFullFileSystem->Read( &tgaHeader, sizeof(tgaHeader), fp );
+
+
+ int nBytesPerPixel, nPixelSize;
+
+ switch( srcFormat )
+ {
+ case IMAGE_FORMAT_BGR888:
+#if defined( _X360 )
+ case IMAGE_FORMAT_LINEAR_BGR888:
+#endif
+ nBytesPerPixel = 3; // 24/32 bit uncompressed TGA
+ nPixelSize = 24;
+ break;
+ case IMAGE_FORMAT_BGRA8888:
+ nBytesPerPixel = 4; // 24/32 bit uncompressed TGA
+ nPixelSize = 32;
+ break;
+ case IMAGE_FORMAT_I8:
+ nBytesPerPixel = 1; // 8 bit uncompressed TGA
+ nPixelSize = 8;
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ // Verify src data matches the targa we're going to write into
+ if ( nPixelSize != tgaHeader.pixel_size )
+ {
+ Warning( "TGA doesn't match source data.\n" );
+ return false;
+ }
+
+
+ // Seek to the origin of the target subrect from the beginning of the file
+ g_pFullFileSystem->Seek( fp, nBytesPerPixel * (tgaHeader.width * nYOrigin + nXOrigin), FILESYSTEM_SEEK_CURRENT );
+
+ unsigned char *pSrc = pImageData;
+
+ // Run through each scanline of the incoming rect
+ for (int row=0; row < height; row++ )
+ {
+ g_pFullFileSystem->Write( pSrc, nBytesPerPixel * width, fp );
+
+ // Advance src pointer to next scanline
+ pSrc += nBytesPerPixel * nStride;
+
+ // Seek ahead in the file
+ g_pFullFileSystem->Seek( fp, nBytesPerPixel * ( tgaHeader.width - width ), FILESYSTEM_SEEK_CURRENT );
+ }
+
+ g_pFullFileSystem->Close( fp );
+ return true;
+}
+
+} // end namespace TGAWriter
+