#include "PreCompile.h"
#include "TargaReader.h"
#include "CommonBuffer.h"
TargaReader::TargaReader()
{
}
TargaReader::~TargaReader()
{
}
const int TYPE_NO_IMAGE = 0;
const int TYPE_UNCOMPRESSED_COLORMAP = 1;
const int TYPE_UNCOMPRESSED_BGR = 2;
const int TYPE_UNCOMPRESSED_MONO = 3;
const int TYPE_RLE_COLORMAP = 9;
const int TYPE_RLE_BGR = 10;
const int TYPE_RLE_MONO = 11;
//const int TGA_T_TO_B_BIT = 32;
void TargaReader::Load(const string& fileName)
{
FILE *pFile = NULL;
try
{
// Open for binary reading
pFile = fopen(fileName.c_str(), "rb");
if (!pFile)
throw RacException("Could not load targa from " , fileName);
// first read in the header
int bytesRead = (int)fread((void*)&m_targaHeader, sizeof(m_targaHeader), 1, pFile);
if (bytesRead != 1)
throw RacException("Cannot read targa file header " , fileName);
m_dataSize = m_targaHeader.m_width*m_targaHeader.m_height*m_targaHeader.m_bitsPerPixel/8;
Allocator<char> &bufferOut = g_commonBuffer.GetBufferOut();
bufferOut.Init(m_dataSize);
m_pData = bufferOut.GetCache();
switch (m_targaHeader.m_imageType)
{
case TYPE_UNCOMPRESSED_BGR:
case TYPE_UNCOMPRESSED_MONO:
// load directly into output buffer
bytesRead = fread(m_pData, m_dataSize, 1, pFile);
if (bytesRead != 1)
throw RacException("Error reading file " , fileName);
break;
case TYPE_RLE_BGR:
case TYPE_RLE_MONO:
ReadRLE(pFile);
break;
default:
throw RacException("Unsupported targa type " , fileName);
}
fclose(pFile);
}
catch (RacException e)
{
if (pFile) fclose(pFile);
throw(e);
}
}
void TargaReader::ReadRLE(FILE *pFile)
{
Allocator<char> &bufferIn = g_commonBuffer.GetBufferIn();
fseek(pFile, 0, 2 /* SEEK_END */);
int bufferInSize = (int)ftell(pFile) - sizeof(m_targaHeader);
bufferIn.Init(bufferInSize);
fseek(pFile, sizeof(m_targaHeader), 0 /* SEEK_SET */);
int bytesRead = fread(bufferIn.GetCache(), bufferInSize, 1, pFile);
if (bytesRead != 1)
throw RacException("Error reading targa file");
if (m_targaHeader.m_bitsPerPixel == 16)
ReadRLE16(bufferIn.GetCache(), bufferInSize, m_targaHeader.m_width*m_targaHeader.m_height);
else if (m_targaHeader.m_bitsPerPixel == 32)
ReadRLE32(bufferIn.GetCache(), bufferInSize, m_targaHeader.m_width*m_targaHeader.m_height);
else if (m_targaHeader.m_bitsPerPixel == 24)
ReadRLE24(bufferIn.GetCache(), bufferInSize, m_targaHeader.m_width*m_targaHeader.m_height);
else
throw RacException("Unsupported targa bits per pixel ", m_targaHeader.m_bitsPerPixel);
}
void TargaReader::ReadRLE16(const char* pDataIn, int bufferInSize, int totalPixels)
{
char byte;
short* pDataOutShort = (short*)g_commonBuffer.GetBufferOut().GetCache();
short* pDataOutShortLast = pDataOutShort + totalPixels;
const char* pDataInLast = pDataIn + bufferInSize;
short pixel;
short* pBlockEnd;
int count;
int bytesCopied;
while (pDataOutShort < pDataOutShortLast)
{
byte = *pDataIn;
pDataIn++;
count = (byte & 0x7f)+1;
if (byte & 0x80)
{
pixel = *((short*)pDataIn);
pDataIn += 2;
pBlockEnd = pDataOutShort + count;
// memset16(pDataIn, pixel, count);
do
{
*pDataOutShort = pixel;
pDataOutShort++;
} while (pDataOutShort < pBlockEnd);
}
else /* RAW packet */
{
bytesCopied = count<<1; // bytes = count*2 (2 bytes per pixel)
memcpy(pDataOutShort, pDataIn, bytesCopied);
pDataOutShort += count;
pDataIn += bytesCopied;
}
}
if (pDataIn > pDataInLast)
throw RacException("error reading Targa RLE block");
}
void TargaReader::ReadRLE32(const char* pDataIn, int bufferInSize, int totalPixels)
{
char byte;
int* pDataOutInt = (int*)g_commonBuffer.GetBufferOut().GetCache();
int* pDataOutIntLast = pDataOutInt + totalPixels;
const char* pDataInLast = pDataIn + bufferInSize;
int pixel;
int* pBlockEnd;
int count;
int bytesCopied;
while (pDataOutInt < pDataOutIntLast)
{
byte = *pDataIn;
pDataIn++;
count = (byte & 0x7f)+1;
if (byte & 0x80)
{
pixel = *((int*)pDataIn);
pDataIn += 4;
pBlockEnd = pDataOutInt + count;
// memset16(pDataIn, pixel, count);
do
{
*pDataOutInt = pixel;
pDataOutInt++;
} while (pDataOutInt < pBlockEnd);
}
else /* RAW packet */
{
bytesCopied = count<<2; // bytes = count*4 (4 bytes per pixel)
memcpy(pDataOutInt, pDataIn, bytesCopied);
pDataOutInt += count;
pDataIn += bytesCopied;
}
}
if (pDataIn > pDataInLast)
throw RacException("error reading Targa RLE block");
}
void TargaReader::ReadRLE24(const char* pDataIn, int bufferInSize, int totalPixels)
{
char byte;
char* pDataOut = g_commonBuffer.GetBufferOut().GetCache();
char* pDataOutLast = pDataOut + totalPixels*3;
const char* pDataInLast = pDataIn + bufferInSize;
char* pBlockEnd;
int count;
char red, green, blue;
while (pDataOut < pDataOutLast)
{
byte = *pDataIn;
pDataIn++;
count = ((byte & 0x7f)+1)*3;
if (byte & 0x80)
{
red = *pDataIn;
pDataIn++;
green = *pDataIn;
pDataIn++;
blue = *pDataIn;
pDataIn++;
pBlockEnd = pDataOut + count;
do
{
*pDataOut = red;
pDataOut++;
*pDataOut = green;
pDataOut++;
*pDataOut = blue;
pDataOut++;
} while (pDataOut < pBlockEnd);
}
else /* RAW packet */
{
memcpy(pDataOut, pDataIn, count);
pDataOut += count;
pDataIn += count;
}
}
if (pDataIn > pDataInLast)
throw RacException("error reading Targa RLE block");
}