fallout2-ce/src/pcx.cc

179 lines
4.5 KiB
C++

#include "pcx.h"
#include "memory_manager.h"
// 0x519DC8
unsigned char gPcxLastRunLength = 0;
// 0x519DC9
unsigned char gPcxLastValue = 0;
// NOTE: The reading method in this function is a little bit odd. It does not
// use high level reading functions, which can read right into struct. Instead
// they read everything into temporary variables. There are no error checks.
//
// 0x4961D4
void pcxReadHeader(PcxHeader* pcxHeader, File* stream)
{
pcxHeader->identifier = fileReadChar(stream);
pcxHeader->version = fileReadChar(stream);
pcxHeader->encoding = fileReadChar(stream);
pcxHeader->bitsPerPixel = fileReadChar(stream);
short minX;
fileRead(&minX, 2, 1, stream);
pcxHeader->minX = minX;
short minY;
fileRead(&minY, 2, 1, stream);
pcxHeader->minY = minY;
short maxX;
fileRead(&maxX, 2, 1, stream);
pcxHeader->maxX = maxX;
short maxY;
fileRead(&maxY, 2, 1, stream);
pcxHeader->maxY = maxY;
short horizontalResolution;
fileRead(&horizontalResolution, 2, 1, stream);
pcxHeader->horizontalResolution = horizontalResolution;
short verticalResolution;
fileRead(&verticalResolution, 2, 1, stream);
pcxHeader->verticalResolution = verticalResolution;
for (int index = 0; index < 48; index++) {
pcxHeader->palette[index] = fileReadChar(stream);
}
pcxHeader->reserved1 = fileReadChar(stream);
pcxHeader->planeCount = fileReadChar(stream);
short bytesPerLine;
fileRead(&bytesPerLine, 2, 1, stream);
pcxHeader->bytesPerLine = bytesPerLine;
short paletteType;
fileRead(&paletteType, 2, 1, stream);
pcxHeader->paletteType = paletteType;
short horizontalScreenSize;
fileRead(&horizontalScreenSize, 2, 1, stream);
pcxHeader->horizontalScreenSize = horizontalScreenSize;
short verticalScreenSize;
fileRead(&verticalScreenSize, 2, 1, stream);
pcxHeader->verticalScreenSize = verticalScreenSize;
for (int index = 0; index < 54; index++) {
pcxHeader->reserved2[index] = fileReadChar(stream);
}
}
// 0x49636C
int pcxReadLine(unsigned char* data, int size, File* stream)
{
unsigned char runLength = gPcxLastRunLength;
unsigned char value = gPcxLastValue;
int uncompressedSize = 0;
int index = 0;
do {
uncompressedSize += runLength;
while (runLength > 0 && index < size) {
data[index] = value;
runLength--;
index++;
}
gPcxLastRunLength = runLength;
gPcxLastValue = value;
if (runLength != 0) {
uncompressedSize -= runLength;
break;
}
value = fileReadChar(stream);
if ((value & 0xC0) == 0xC0) {
gPcxLastRunLength = value & 0x3F;
value = fileReadChar(stream);
runLength = gPcxLastRunLength;
} else {
runLength = 1;
}
} while (index < size);
gPcxLastRunLength = runLength;
gPcxLastValue = value;
return uncompressedSize;
}
// 0x49641C
int pcxReadPalette(PcxHeader* pcxHeader, unsigned char* palette, File* stream)
{
if (pcxHeader->version != 5) {
return 0;
}
long pos = fileTell(stream);
long size = fileGetSize(stream);
fileSeek(stream, size - 769, SEEK_SET);
if (fileReadChar(stream) != 12) {
fileSeek(stream, pos, SEEK_SET);
return 0;
}
for (int index = 0; index < 768; index++) {
palette[index] = fileReadChar(stream);
}
fileSeek(stream, pos, SEEK_SET);
return 1;
}
// 0x496494
unsigned char* pcxRead(const char* path, int* widthPtr, int* heightPtr, unsigned char* palette)
{
File* stream = fileOpen(path, "rb");
if (stream == NULL) {
return NULL;
}
PcxHeader pcxHeader;
pcxReadHeader(&pcxHeader, stream);
int width = pcxHeader.maxX - pcxHeader.minX + 1;
int height = pcxHeader.maxY - pcxHeader.minY + 1;
*widthPtr = width;
*heightPtr = height;
int bytesPerLine = pcxHeader.planeCount * pcxHeader.bytesPerLine;
unsigned char* data = (unsigned char*)internal_malloc_safe(bytesPerLine * height, __FILE__, __LINE__); // "..\\int\\PCX.C", 195
if (data == NULL) {
// NOTE: This code is unreachable, internal_malloc_safe never fails.
fileClose(stream);
return NULL;
}
gPcxLastRunLength = 0;
gPcxLastValue = 0;
unsigned char* ptr = data;
for (int y = 0; y < height; y++) {
pcxReadLine(ptr, bytesPerLine, stream);
ptr += width;
}
pcxReadPalette(&pcxHeader, palette, stream);
fileClose(stream);
return data;
}