forked from valve/halflife-sdk
198 lines
3.9 KiB
C++
198 lines
3.9 KiB
C++
|
|
#include <string.h>
|
|
#include "fileimage.h"
|
|
|
|
|
|
// TGA header.
|
|
#pragma pack(1)
|
|
class TGAFileHeader
|
|
{
|
|
public:
|
|
unsigned char m_IDLength;
|
|
unsigned char m_ColorMapType;
|
|
unsigned char m_ImageType;
|
|
unsigned short m_CMapStart;
|
|
unsigned short m_CMapLength;
|
|
unsigned char m_CMapDepth;
|
|
unsigned short m_XOffset;
|
|
unsigned short m_YOffset;
|
|
unsigned short m_Width;
|
|
unsigned short m_Height;
|
|
unsigned char m_PixelDepth;
|
|
unsigned char m_ImageDescriptor;
|
|
};
|
|
#pragma pack()
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------- //
|
|
// FileImageStream_Memory.
|
|
// ---------------------------------------------------------------------------------------- //
|
|
FileImageStream_Memory::FileImageStream_Memory(void *pData, int dataLen)
|
|
{
|
|
m_pData = (unsigned char*)pData;
|
|
m_DataLen = dataLen;
|
|
m_CurPos = 0;
|
|
m_bError = false;
|
|
}
|
|
|
|
void FileImageStream_Memory::Read(void *pData, int len)
|
|
{
|
|
unsigned char *pOut;
|
|
int i;
|
|
|
|
pOut = (unsigned char*)pData;
|
|
for(i=0; i < len; i++)
|
|
{
|
|
if(m_CurPos < m_DataLen)
|
|
{
|
|
pOut[i] = m_pData[m_CurPos];
|
|
++m_CurPos;
|
|
}
|
|
else
|
|
{
|
|
pOut[i] = 0;
|
|
m_bError = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FileImageStream_Memory::ErrorStatus()
|
|
{
|
|
bool ret=m_bError;
|
|
m_bError=false;
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------------------- //
|
|
// Encode/decode functions.
|
|
// ---------------------------------------------------------------------------------------- //
|
|
static void WriteRun(unsigned char *pColor, FILE *fp, int runLength)
|
|
{
|
|
unsigned char runCount;
|
|
|
|
runCount = runLength - 1;
|
|
runCount |= (1 << 7);
|
|
fwrite(&runCount, 1, 1, fp);
|
|
fwrite(pColor, 1, 4, fp);
|
|
}
|
|
|
|
|
|
// Load in a 32-bit TGA file.
|
|
bool Load32BitTGA(
|
|
FileImageStream *fp,
|
|
FileImage *pImage)
|
|
{
|
|
TGAFileHeader hdr;
|
|
char dummyChar;
|
|
int i, x, y;
|
|
long color;
|
|
int runLength, curOut;
|
|
unsigned char *pLine;
|
|
unsigned char packetHeader;
|
|
|
|
|
|
pImage->Term();
|
|
|
|
// Read and verify the header.
|
|
fp->Read(&hdr, sizeof(hdr));
|
|
if(hdr.m_PixelDepth != 32 || hdr.m_ImageType != 10)
|
|
return false;
|
|
|
|
// Skip the ID area..
|
|
for(i=0; i < hdr.m_IDLength; i++)
|
|
fp->Read(&dummyChar, 1);
|
|
|
|
pImage->m_Width = hdr.m_Width;
|
|
pImage->m_Height = hdr.m_Height;
|
|
pImage->m_pData = new unsigned char[hdr.m_Width * hdr.m_Height * 4];
|
|
if(!pImage->m_pData)
|
|
return false;
|
|
|
|
// Read in the data..
|
|
for(y=pImage->m_Height-1; y >= 0; y--)
|
|
{
|
|
pLine = &pImage->m_pData[y*pImage->m_Width*4];
|
|
|
|
curOut = 0;
|
|
while(curOut < pImage->m_Width)
|
|
{
|
|
fp->Read(&packetHeader, 1);
|
|
|
|
runLength = (int)(packetHeader & ~(1 << 7)) + 1;
|
|
if(curOut + runLength > pImage->m_Width)
|
|
return false;
|
|
|
|
if(packetHeader & (1 << 7))
|
|
{
|
|
fp->Read(&color, 4);
|
|
for(x=0; x < runLength; x++)
|
|
{
|
|
*((long*)pLine) = color;
|
|
pLine += 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(x=0; x < runLength; x++)
|
|
{
|
|
fp->Read(&color, 4);
|
|
*((long*)pLine) = color;
|
|
pLine += 4;
|
|
}
|
|
}
|
|
|
|
curOut += runLength;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// Write a 32-bit TGA file.
|
|
void Save32BitTGA(
|
|
FILE *fp,
|
|
FileImage *pImage)
|
|
{
|
|
TGAFileHeader hdr;
|
|
int y, runStart, x;
|
|
unsigned char *pLine;
|
|
|
|
|
|
memset(&hdr, 0, sizeof(hdr));
|
|
hdr.m_PixelDepth = 32;
|
|
hdr.m_ImageType = 10; // Run-length encoded RGB.
|
|
hdr.m_Width = pImage->m_Width;
|
|
hdr.m_Height = pImage->m_Height;
|
|
|
|
fwrite(&hdr, 1, sizeof(hdr), fp);
|
|
|
|
// Lines are written bottom-up.
|
|
for(y=pImage->m_Height-1; y >= 0; y--)
|
|
{
|
|
pLine = &pImage->m_pData[y*pImage->m_Width*4];
|
|
|
|
runStart = 0;
|
|
for(x=0; x < pImage->m_Width; x++)
|
|
{
|
|
if((x - runStart) >= 128 ||
|
|
*((long*)&pLine[runStart*4]) != *((long*)&pLine[x*4]))
|
|
{
|
|
// Encode this run.
|
|
WriteRun(&pLine[runStart*4], fp, x - runStart);
|
|
runStart = x;
|
|
}
|
|
}
|
|
|
|
// Encode the last run.
|
|
if(x - runStart > 0)
|
|
{
|
|
WriteRun(&pLine[runStart*4], fp, x - runStart);
|
|
}
|
|
}
|
|
}
|
|
|
|
|