Files
firestorm/Gameleap/code/mw4/Libraries/Proxies/Targa.cpp
T
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

695 lines
18 KiB
C++

#include "ProxyHeaders.hpp"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Proxies::WriteTargaFile(
const char* filename,
int width,
int height,
DynamicArrayOf<TargaColor> &data
)
{
Check_Pointer(filename);
Check_Object(&data);
//
//---------------------------------------------
// Get the size of the image we will be copying
//---------------------------------------------
//
TargaHeader targa_header;
memset(&targa_header, 0, sizeof(targa_header));
targa_header.widthLow = static_cast<unsigned char>(width & 255);
targa_header.widthHigh = static_cast<unsigned char>(width >> 8);
targa_header.heightLow = static_cast<unsigned char>(height & 255);
targa_header.heightHigh = static_cast<unsigned char>(height >> 8);
targa_header.imageType = TargaHeader::RLERGB;
targa_header.pixelSize = 24;
targa_header.flags = TargaHeader::YReversed;
//
//---------------------
// Write out the header
//---------------------
//
Check_Object(FileStreamManager::Instance);
FileStream targa_file(filename, FileStream::WriteOnly);
targa_file.WriteBytes(&targa_header, sizeof(targa_header));
//
//----------------------------------------------
// See if we need to deal with the alpha channel
//----------------------------------------------
//
unsigned channel_size = height * width;
Verify(channel_size == data.GetLength());
unsigned pixel_size = 3;
unsigned buffer_size = channel_size * pixel_size;
DynamicArrayOf<BYTE> buffer(buffer_size);
unsigned p = 0;
unsigned max_row = Min(width, 128);
//
//-------------------------------------
// Start trying to make an RLE encoding
//-------------------------------------
//
int i=0;
while (i<channel_size)
{
unsigned rle_count;
int rle_type = 0;
unsigned j = i+1;
unsigned base = i;
unsigned max_run = max_row - (i%max_row);
for (rle_count = 1; rle_count<max_run && j<channel_size; ++rle_count, ++j)
{
//
//-------------------------------------
// See if the next pixel matches or not
//-------------------------------------
//
bool match =
data[j].red == data[base].red
&& data[j].blue == data[base].blue
&& data[j].green == data[base].green;
//
//----------------------------------------------------------------
// If it matches, we break the run if this is a singleton run. We
// will always try to match matching pixels in a run
//----------------------------------------------------------------
//
if (match)
{
if (rle_type == -1)
{
--j;
--rle_count;
break;
}
//
//----------------------------------------------------
// Matching runs can go one longer than singleton runs
//----------------------------------------------------
//
else if (!rle_type)
rle_type = 1;
}
//
//-------------------------------------------------------
// It didn't match, so we better not be in a matching run. If we
// aren't, reset the base to this pixel
//-------------------------------------------------------
//
else
{
if (rle_type == 1)
break;
base = j;
rle_type = -1;
}
}
//
//----------------------------------------------------------------------
// Write out the run based upon its type after making sure that there is
// enough room in the buffer
//----------------------------------------------------------------------
//
if (rle_type == 1)
{
if (buffer_size-p < pixel_size+1)
goto No_RLE;
Verify(rle_count > 0 && rle_count <= 128);
buffer[p++] = static_cast<BYTE>(rle_count + 127);
buffer[p++] = data[i].blue;
buffer[p++] = data[i].green;
buffer[p++] = data[i].red;
i = j;
}
//
//-------------------------------------------------------------
// This is a singleton run, so check out its space requirements
//-------------------------------------------------------------
//
else
{
if (buffer_size-p < (pixel_size*rle_count)+1)
goto No_RLE;
//
//---------------
// Write them out
//---------------
//
Verify(rle_count > 0 && rle_count <= 128);
buffer[p++] = static_cast<BYTE>(rle_count-1);
for (; i<j; ++i)
{
buffer[p++] = data[i].blue;
buffer[p++] = data[i].green;
buffer[p++] = data[i].red;
}
}
}
goto Write_File;
//
//-----------------------------------------------------------------------
// Interleave the channels w/no RLE. This should only be used if the RLE
// takes more space than the buffer allows
//-----------------------------------------------------------------------
//
No_RLE:
targa_file.Close();
targa_file.Open(filename, FileStream::WriteOnly);
targa_header.imageType = TargaHeader::RGB;
targa_file.WriteBytes(&targa_header, sizeof(targa_header));
for (i=0,p=0; i<channel_size; ++i)
{
buffer[p++] = data[i].blue;
buffer[p++] = data[i].green;
buffer[p++] = data[i].red;
}
goto Write_File;
//
//------------------------------------
// Write out the buffer and discard it
//------------------------------------
//
Write_File:
Verify(i == channel_size);
Verify(p <= buffer_size);
targa_file.WriteBytes(&buffer[0], p);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Proxies::WriteTargaFile(
const char* filename,
int width,
int height,
DynamicArrayOf<TargaColorA> &data
)
{
Check_Pointer(filename);
Check_Object(&data);
//
//---------------------------------------------
// Get the size of the image we will be copying
//---------------------------------------------
//
TargaHeader targa_header;
memset(&targa_header, 0, sizeof(targa_header));
targa_header.widthLow = static_cast<unsigned char>(width & 255);
targa_header.widthHigh = static_cast<unsigned char>(width >> 8);
targa_header.heightLow = static_cast<unsigned char>(height & 255);
targa_header.heightHigh = static_cast<unsigned char>(height >> 8);
targa_header.imageType = TargaHeader::RLERGB;
targa_header.pixelSize = 32;
targa_header.flags = TargaHeader::YReversed;
//
//---------------------
// Write out the header
//---------------------
//
Check_Object(FileStreamManager::Instance);
FileStream targa_file(filename, FileStream::WriteOnly);
targa_file.WriteBytes(&targa_header, sizeof(targa_header));
//
//----------------------------------------------
// See if we need to deal with the alpha channel
//----------------------------------------------
//
unsigned channel_size = height * width;
Verify(channel_size == data.GetLength());
unsigned pixel_size = 4;
unsigned buffer_size = channel_size * pixel_size;
DynamicArrayOf<BYTE> buffer(buffer_size);
unsigned p = 0;
unsigned max_row = Min(width, 128);
//
//-------------------------------------
// Start trying to make an RLE encoding
//-------------------------------------
//
int i=0;
while (i<channel_size)
{
unsigned rle_count;
int rle_type = 0;
unsigned j = i+1;
unsigned base = i;
unsigned max_run = max_row - (i%max_row);
for (rle_count = 1; rle_count<max_run && j<channel_size; ++rle_count, ++j)
{
//
//-------------------------------------
// See if the next pixel matches or not
//-------------------------------------
//
bool match =
data[j].red == data[base].red
&& data[j].blue == data[base].blue
&& data[j].green == data[base].green
&& data[j].alpha == data[base].alpha;
//
//----------------------------------------------------------------
// If it matches, we break the run if this is a singleton run. We
// will always try to match matching pixels in a run
//----------------------------------------------------------------
//
if (match)
{
if (rle_type == -1)
{
--j;
--rle_count;
break;
}
//
//----------------------------------------------------
// Matching runs can go one longer than singleton runs
//----------------------------------------------------
//
else if (!rle_type)
rle_type = 1;
}
//
//-------------------------------------------------------
// It didn't match, so we better not be in a matching run. If we
// aren't, reset the base to this pixel
//-------------------------------------------------------
//
else
{
if (rle_type == 1)
break;
base = j;
rle_type = -1;
}
}
//
//----------------------------------------------------------------------
// Write out the run based upon its type after making sure that there is
// enough room in the buffer
//----------------------------------------------------------------------
//
if (rle_type == 1)
{
if (buffer_size-p < pixel_size+1)
goto No_RLE;
Verify(rle_count > 0 && rle_count <= 128);
buffer[p++] = static_cast<BYTE>(rle_count + 127);
buffer[p++] = data[i].blue;
buffer[p++] = data[i].green;
buffer[p++] = data[i].red;
buffer[p++] = data[i].alpha;
i = j;
}
//
//-------------------------------------------------------------
// This is a singleton run, so check out its space requirements
//-------------------------------------------------------------
//
else
{
if (buffer_size-p < (pixel_size*rle_count)+1)
goto No_RLE;
//
//---------------
// Write them out
//---------------
//
Verify(rle_count > 0 && rle_count <= 128);
buffer[p++] = static_cast<BYTE>(rle_count-1);
for (; i<j; ++i)
{
buffer[p++] = data[i].blue;
buffer[p++] = data[i].green;
buffer[p++] = data[i].red;
buffer[p++] = data[i].alpha;
}
}
}
goto Write_File;
//
//-----------------------------------------------------------------------
// Interleave the channels w/no RLE. This should only be used if the RLE
// takes more space than the buffer allows
//-----------------------------------------------------------------------
//
No_RLE:
targa_file.Close();
targa_file.Open(filename, FileStream::WriteOnly);
targa_header.imageType = TargaHeader::RGB;
targa_file.WriteBytes(&targa_header, sizeof(targa_header));
for (i=0,p=0; i<channel_size; ++i)
{
buffer[p++] = data[i].blue;
buffer[p++] = data[i].green;
buffer[p++] = data[i].red;
buffer[p++] = data[i].alpha;
}
goto Write_File;
//
//------------------------------------
// Write out the buffer and discard it
//------------------------------------
//
Write_File:
Verify(i == channel_size);
Verify(p <= buffer_size);
targa_file.WriteBytes(&buffer[0], p);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Proxies::ReadTargaHeader(
TargaHeader *header,
MemoryStream *file,
int *width,
int *height,
unsigned *red_depth,
unsigned *green_depth,
unsigned *blue_depth,
unsigned *alpha_depth
)
{
Check_Pointer(header);
Check_Object(file);
Check_Pointer(width);
Check_Pointer(height);
Check_Pointer(red_depth);
Check_Pointer(green_depth);
Check_Pointer(blue_depth);
Check_Pointer(alpha_depth);
//
//---------------------------------------------
// Get the size of the image we will be copying
//---------------------------------------------
//
file->ReadBytes(header, sizeof(*header));
*width =
static_cast<int>(header->widthLow)
+ (static_cast<int>(header->widthHigh)<<8);
*height =
static_cast<int>(header->heightLow)
+ (static_cast<int>(header->heightHigh)<<8);
Verify(header->pixelSize == 24 || header->pixelSize == 32);
*red_depth = 8;
*green_depth = 8;
*blue_depth = 8;
*alpha_depth = (header->pixelSize == 24) ? 0 : 8;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Proxies::ReadTargaChannels(
MemoryStream *file,
TargaHeader *header,
DynamicArrayOf<TargaColor> *data
)
{
Check_Object(file);
Check_Pointer(header);
Check_Object(data);
//
//----------------------------
// Read the file into a buffer
//----------------------------
//
unsigned len = file->GetBytesRemaining();
DynamicArrayOf<BYTE> buffer(len);
file->ReadBytes(&buffer[0], len);
//
//-----------------------------
// Set up the process variables
//-----------------------------
//
bool
x_reversed = ((header->flags & TargaHeader::XReversed) != 0),
y_reversed = ((header->flags & TargaHeader::YReversed) != 0),
compressed = (header->imageType == TargaHeader::RLERGB);
unsigned width =
static_cast<int>(header->widthLow)
+ (static_cast<int>(header->widthHigh)<<8);
unsigned height =
static_cast<int>(header->heightLow)
+ (static_cast<int>(header->heightHigh)<<8);
BYTE
run_count = 0,
copy_count = 0,
control_byte = 0,
red = 0,
green = 0,
blue = 0;
unsigned
dest = ((y_reversed) ? 0 : width * (height-1)),
source = 0;
if (x_reversed)
dest += width;
//
//------------------------
// Spin through each texel
//------------------------
//
for (unsigned y=0; y<height; ++y)
{
for (unsigned x=0; x<width; ++x)
{
Verify(
dest == ((y_reversed)?y:(height-1-y))*width + (x_reversed)?(width-x):x
);
//
//-----------------------------------------
// Handle the control bytes for compression
//-----------------------------------------
//
if (compressed)
{
if (!copy_count && !run_count)
control_byte=buffer[source++];
if (!run_count)
{
blue = buffer[source++];
green = buffer[source++];
red = buffer[source++];
}
if (!copy_count && !run_count)
{
if (control_byte >= 128)
run_count = static_cast<BYTE>(control_byte-128);
else
copy_count = control_byte;
}
else if (run_count)
run_count--;
else if (copy_count)
copy_count--;
}
//
//-----------------------------------
// Otherwise, just get the next color
//-----------------------------------
//
else
{
blue = buffer[source++];
green = buffer[source++];
red = buffer[source++];
}
//
//------------------------------
// Put the color in the channels
//------------------------------
//
if (x_reversed)
{
(*data)[--dest].red = red;
(*data)[dest].green = green;
(*data)[dest].blue = blue;
}
else
{
(*data)[dest].red = red;
(*data)[dest].green = green;
(*data)[dest++].blue = blue;
}
}
//
//-----------------------------
// Move the destination pointer
//-----------------------------
//
if (x_reversed == y_reversed)
dest += ((y_reversed) ? 2 : -2) * width;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Proxies::ReadTargaChannels(
MemoryStream *file,
TargaHeader *header,
DynamicArrayOf<TargaColorA> *data
)
{
Check_Object(file);
Check_Pointer(header);
Check_Object(data);
//
//----------------------------
// Read the file into a buffer
//----------------------------
//
unsigned len = file->GetBytesRemaining();
DynamicArrayOf<BYTE> buffer(len);
file->ReadBytes(&buffer[0], len);
//
//-----------------------------
// Set up the process variables
//-----------------------------
//
bool
x_reversed = ((header->flags & TargaHeader::XReversed) != 0),
y_reversed = ((header->flags & TargaHeader::YReversed) != 0),
compressed = (header->imageType == TargaHeader::RLERGB);
unsigned width =
static_cast<int>(header->widthLow)
+ (static_cast<int>(header->widthHigh)<<8);
unsigned height =
static_cast<int>(header->heightLow)
+ (static_cast<int>(header->heightHigh)<<8);
BYTE
run_count = 0,
copy_count = 0,
control_byte = 0,
red = 0,
green = 0,
blue = 0,
alpha = 0;
unsigned
dest = ((y_reversed) ? 0 : width * (height-1)),
source = 0;
if (x_reversed)
dest += width;
//
//------------------------
// Spin through each texel
//------------------------
//
for (unsigned y=0; y<height; ++y)
{
for (unsigned x=0; x<width; ++x)
{
Verify(
dest == ((y_reversed)?y:(height-1-y))*width + (x_reversed)?(width-x):x
);
//
//-----------------------------------------
// Handle the control bytes for compression
//-----------------------------------------
//
if (compressed)
{
if (!copy_count && !run_count)
control_byte=buffer[source++];
if (!run_count)
{
blue = buffer[source++];
green = buffer[source++];
red = buffer[source++];
alpha = buffer[source++];
}
if (!copy_count && !run_count)
{
if (control_byte >= 128)
run_count = static_cast<BYTE>(control_byte-128);
else
copy_count = control_byte;
}
else if (run_count)
run_count--;
else if (copy_count)
copy_count--;
}
//
//-----------------------------------
// Otherwise, just get the next color
//-----------------------------------
//
else
{
blue = buffer[source++];
green = buffer[source++];
red = buffer[source++];
alpha = buffer[source++];
}
//
//------------------------------
// Put the color in the channels
//------------------------------
//
if (x_reversed)
{
(*data)[--dest].red = red;
(*data)[dest].green = green;
(*data)[dest].blue = blue;
(*data)[dest].alpha = alpha;
}
else
{
(*data)[dest].red = red;
(*data)[dest].green = green;
(*data)[dest].blue = blue;
(*data)[dest++].alpha = alpha;
}
}
//
//-----------------------------
// Move the destination pointer
//-----------------------------
//
if (x_reversed == y_reversed)
dest += ((y_reversed) ? 2 : -2) * width;
}
}