mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-11 17:49:53 -10:00
Made some commandline variables fit the naming standard. Changed timerbar system not to run pushes and pops if its not in use. Put in a note about not uncommenting asserts. Fixed up a lot of missing POP's on early returns? Perhaps the motivation for Assert functionality getting commented out? Fixed up some bad asserts. Changed nebula poofs to render in 2D in htl, it makes it look how it used to in non htl. (neb.cpp,1248) Before the poofs were creating a nasty stripe effect where they intersected with ships hulls. Put in a special check for the signs of that D3D init bug I need to lock down.
874 lines
21 KiB
C++
874 lines
21 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* $Logfile: /Freespace2/code/PcxUtils/pcxutils.cpp $
|
|
* $Revision: 2.3 $
|
|
* $Date: 2003-11-19 20:37:24 $
|
|
* $Author: randomtiger $
|
|
*
|
|
* code to deal with pcx files
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
* Revision 2.2 2003/03/18 10:07:05 unknownplayer
|
|
* The big DX/main line merge. This has been uploaded to the main CVS since I can't manage to get it to upload to the DX branch. Apologies to all who may be affected adversely, but I'll work to debug it as fast as I can.
|
|
*
|
|
* Revision 2.1.2.2 2002/10/02 11:40:19 randomtiger
|
|
* Bmpmap has been reverted to an old non d3d8 version.
|
|
* All d3d8 code is now in the proper place.
|
|
* PCX code is now working to an extent. Problems with alpha though.
|
|
* Ani's work slowly with alpha problems.
|
|
* Also I have done a bit of tidying - RT
|
|
*
|
|
* Revision 2.1.2.1 2002/09/24 18:56:44 randomtiger
|
|
* DX8 branch commit
|
|
*
|
|
* This is the scub of UP's previous code with the more up to date RT code.
|
|
* For full details check previous dev e-mails
|
|
*
|
|
* Revision 2.1 2002/08/01 01:41:09 penguin
|
|
* The big include file move
|
|
*
|
|
* Revision 2.0 2002/06/03 04:02:27 penguin
|
|
* Warpcore CVS sync
|
|
*
|
|
* Revision 1.1 2002/05/02 18:03:12 mharris
|
|
* Initial checkin - converted filenames and includes to lower case
|
|
*
|
|
*
|
|
* 11 8/10/99 6:54p Dave
|
|
* Mad optimizations. Added paging to the nebula effect.
|
|
*
|
|
* 10 7/13/99 1:16p Dave
|
|
* 32 bit support. Whee!
|
|
*
|
|
* 9 2/05/99 12:52p Dave
|
|
* Fixed Glide nondarkening textures.
|
|
*
|
|
* 8 2/03/99 6:06p Dave
|
|
* Groundwork for FS2 PXO usertracker support. Gametracker support next.
|
|
*
|
|
* 7 2/03/99 11:44a Dave
|
|
* Fixed d3d transparent textures.
|
|
*
|
|
* 6 12/01/98 5:54p Dave
|
|
* Simplified the way pixel data is swizzled. Fixed tga bitmaps to work
|
|
* properly in D3D and Glide.
|
|
*
|
|
* 5 12/01/98 4:46p Dave
|
|
* Put in targa bitmap support (16 bit).
|
|
*
|
|
* 4 12/01/98 8:06a Dave
|
|
* Temporary checkin to fix some texture transparency problems in d3d.
|
|
*
|
|
* 3 11/30/98 1:07p Dave
|
|
* 16 bit conversion, first run.
|
|
*
|
|
* 2 10/07/98 10:53a Dave
|
|
* Initial checkin.
|
|
*
|
|
* 1 10/07/98 10:50a Dave
|
|
*
|
|
* 16 1/19/98 11:37p Lawrance
|
|
* Fixing Optimization build warnings
|
|
*
|
|
* 15 9/09/97 3:39p Sandeep
|
|
* warning level 4 bugs
|
|
*
|
|
* 14 9/03/97 4:32p John
|
|
* changed bmpman to only accept ani and pcx's. made passing .pcx or .ani
|
|
* to bm_load functions not needed. Made bmpman keep track of palettes
|
|
* for bitmaps not mapped into game palettes.
|
|
*
|
|
* 13 7/20/97 6:59p Lawrance
|
|
* fixed bug that was writing out PCX files with an extra bogus line
|
|
*
|
|
* 12 6/05/97 6:07p John
|
|
* fixed warning
|
|
*
|
|
* 11 6/05/97 3:59p John
|
|
* Fixed a bug in PCX reader
|
|
*
|
|
* 10 2/25/97 12:06p John
|
|
* fixed a pcx potential bug.
|
|
*
|
|
* 9 2/25/97 12:03p John
|
|
* fixed a pcx reading bug.
|
|
*
|
|
* 8 2/20/97 4:18p John
|
|
* fixed bug reading odd-width pcx files
|
|
*
|
|
* 7 11/26/96 9:28a Allender
|
|
* get palette info when getting pcx info
|
|
*
|
|
* 6 11/18/96 12:36p John
|
|
* Added code to dump screen to a PCX file.
|
|
*
|
|
* 5 11/13/96 4:51p Allender
|
|
* started overhaul of bitmap manager. bm_load no longer actually load
|
|
* the data, only the info for the bitmap. Locking the bitmap now forces
|
|
* load when no data present (or will if bpp changes)
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include "cfile/cfile.h"
|
|
#include "pcxutils/pcxutils.h"
|
|
#include "palman/palman.h"
|
|
#include "bmpman/bmpman.h"
|
|
#include "debugconsole/dbugfile.h"
|
|
|
|
|
|
|
|
/* PCX Header data type */
|
|
typedef struct {
|
|
ubyte Manufacturer;
|
|
ubyte Version;
|
|
ubyte Encoding;
|
|
ubyte BitsPerPixel;
|
|
short Xmin;
|
|
short Ymin;
|
|
short Xmax;
|
|
short Ymax;
|
|
short Hdpi;
|
|
short Vdpi;
|
|
ubyte ColorMap[16][3];
|
|
ubyte Reserved;
|
|
ubyte Nplanes;
|
|
short BytesPerLine;
|
|
ubyte filler[60];
|
|
} PCXHeader;
|
|
|
|
// reads header information from the PCX file into the bitmap pointer
|
|
int pcx_read_header(char *real_filename, int *w, int *h, ubyte *pal )
|
|
{
|
|
PCXHeader header;
|
|
CFILE * PCXfile;
|
|
char filename[MAX_FILENAME_LEN];
|
|
|
|
strcpy( filename, real_filename );
|
|
char *p = strchr( filename, '.' );
|
|
if ( p ) *p = 0;
|
|
strcat( filename, ".pcx" );
|
|
|
|
PCXfile = cfopen( filename , "rb" );
|
|
if ( !PCXfile )
|
|
return PCX_ERROR_OPENING;
|
|
|
|
// read 128 char PCX header
|
|
if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
|
|
cfclose( PCXfile );
|
|
return PCX_ERROR_NO_HEADER;
|
|
}
|
|
|
|
// Is it a 256 color PCX file?
|
|
if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
|
|
cfclose( PCXfile );
|
|
return PCX_ERROR_WRONG_VERSION;
|
|
}
|
|
|
|
if (w) *w = header.Xmax - header.Xmin + 1;
|
|
if (h) *h = header.Ymax - header.Ymin + 1;
|
|
|
|
if ( pal ) {
|
|
cfseek( PCXfile, -768, CF_SEEK_END );
|
|
cfread( pal, 3, 256, PCXfile );
|
|
}
|
|
|
|
cfclose(PCXfile);
|
|
return PCX_ERROR_NONE;
|
|
}
|
|
|
|
// static ubyte Pcx_load[1024*768 + 768 + sizeof(PCXHeader)];
|
|
// int Pcx_load_offset = 0;
|
|
// int Pcx_load_size = 0;
|
|
|
|
// #define GET_BUF() do { buffer = &Pcx_load[Pcx_load_offset]; if(Pcx_load_offset + buffer_size > Pcx_load_size) { buffer_size = Pcx_load_size - Pcx_load_offset; } } while(0);
|
|
int pcx_read_bitmap_8bpp( char * real_filename, ubyte *org_data, ubyte *palette )
|
|
{
|
|
PCXHeader header;
|
|
CFILE * PCXfile;
|
|
int row, col, count, xsize, ysize;
|
|
ubyte data=0;
|
|
int buffer_size, buffer_pos;
|
|
ubyte buffer[1024];
|
|
ubyte *pixdata;
|
|
char filename[MAX_FILENAME_LEN];
|
|
|
|
strcpy( filename, real_filename );
|
|
char *p = strchr( filename, '.' );
|
|
if ( p ) *p = 0;
|
|
strcat( filename, ".pcx" );
|
|
|
|
PCXfile = cfopen( filename , "rb" );
|
|
if ( !PCXfile )
|
|
return PCX_ERROR_OPENING;
|
|
|
|
// read 128 char PCX header
|
|
if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
|
|
cfclose( PCXfile );
|
|
return PCX_ERROR_NO_HEADER;
|
|
}
|
|
|
|
// Is it a 256 color PCX file?
|
|
if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
|
|
cfclose( PCXfile );
|
|
return PCX_ERROR_WRONG_VERSION;
|
|
}
|
|
|
|
// Find the size of the image
|
|
xsize = header.Xmax - header.Xmin + 1;
|
|
ysize = header.Ymax - header.Ymin + 1;
|
|
|
|
// Read the extended palette at the end of PCX file
|
|
// Read in a character which should be 12 to be extended palette file
|
|
|
|
cfseek( PCXfile, -768, CF_SEEK_END );
|
|
cfread( palette, 3, 256, PCXfile );
|
|
cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
|
|
|
|
buffer_size = 1024;
|
|
buffer_pos = 0;
|
|
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
|
|
count = 0;
|
|
|
|
for (row=0; row<ysize;row++) {
|
|
pixdata = org_data;
|
|
for (col=0; col<header.BytesPerLine;col++) {
|
|
if ( count == 0 ) {
|
|
data = buffer[buffer_pos++];
|
|
if ( buffer_pos == buffer_size ) {
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
Assert( buffer_size > 0 );
|
|
buffer_pos = 0;
|
|
}
|
|
if ((data & 0xC0) == 0xC0) {
|
|
count = data & 0x3F;
|
|
data = buffer[buffer_pos++];
|
|
if ( buffer_pos == buffer_size ) {
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
Assert( buffer_size > 0 );
|
|
buffer_pos = 0;
|
|
}
|
|
} else {
|
|
count = 1;
|
|
}
|
|
}
|
|
if ( col < xsize )
|
|
*pixdata++ = data;
|
|
count--;
|
|
}
|
|
org_data += xsize;
|
|
}
|
|
cfclose(PCXfile);
|
|
return PCX_ERROR_NONE;
|
|
}
|
|
|
|
int pcx_read_bitmap_16bpp( char * real_filename, ubyte *org_data )
|
|
{
|
|
|
|
PCXHeader header;
|
|
CFILE * PCXfile;
|
|
int row, col, count, xsize, ysize;
|
|
ubyte data=0;
|
|
int buffer_size, buffer_pos;
|
|
ubyte buffer[1024];
|
|
ubyte *pixdata;
|
|
char filename[MAX_FILENAME_LEN];
|
|
ubyte palette[768];
|
|
ushort bit_16;
|
|
ubyte r, g, b, al;
|
|
|
|
|
|
strcpy( filename, real_filename );
|
|
char *p = strchr( filename, '.' );
|
|
if ( p ) *p = 0;
|
|
strcat( filename, ".pcx" );
|
|
|
|
|
|
PCXfile = cfopen( filename , "rb" );
|
|
if ( !PCXfile ){
|
|
|
|
return PCX_ERROR_OPENING;
|
|
}
|
|
|
|
// read 128 char PCX header
|
|
if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
|
|
cfclose( PCXfile );
|
|
|
|
return PCX_ERROR_NO_HEADER;
|
|
}
|
|
|
|
// Is it a 256 color PCX file?
|
|
if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
|
|
cfclose( PCXfile );
|
|
|
|
return PCX_ERROR_WRONG_VERSION;
|
|
}
|
|
|
|
|
|
// Find the size of the image
|
|
xsize = header.Xmax - header.Xmin + 1;
|
|
ysize = header.Ymax - header.Ymin + 1;
|
|
|
|
// Read the extended palette at the end of PCX file
|
|
// Read in a character which should be 12 to be extended palette file
|
|
|
|
cfseek( PCXfile, -768, CF_SEEK_END );
|
|
cfread( palette, 3, 256, PCXfile );
|
|
cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
|
|
|
|
buffer_size = 1024;
|
|
buffer_pos = 0;
|
|
|
|
// Assert( buffer_size == 1024 ); // AL: removed to avoid optimized warning 'unreachable code'
|
|
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
|
|
|
|
count = 0;
|
|
|
|
for (row=0; row<ysize;row++) {
|
|
|
|
pixdata = org_data;
|
|
for (col=0; col<header.BytesPerLine;col++) {
|
|
if ( count == 0 ) {
|
|
data = buffer[buffer_pos++];
|
|
if ( buffer_pos == buffer_size ) {
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
Assert( buffer_size > 0 );
|
|
buffer_pos = 0;
|
|
}
|
|
if ((data & 0xC0) == 0xC0) {
|
|
count = data & 0x3F;
|
|
data = buffer[buffer_pos++];
|
|
if ( buffer_pos == buffer_size ) {
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
Assert( buffer_size > 0 );
|
|
buffer_pos = 0;
|
|
}
|
|
} else {
|
|
count = 1;
|
|
}
|
|
}
|
|
// stuff the pixel
|
|
if ( col < xsize ){
|
|
// stuff the 24 bit value
|
|
r = palette[data*3];
|
|
g = palette[data*3 + 1];
|
|
b = palette[data*3 + 2];
|
|
|
|
// clear the pixel
|
|
bit_16 = 0;
|
|
|
|
// if the color matches the transparent color, make it so
|
|
al = 255;
|
|
if((0 == (int)palette[data*3]) && (255 == (int)palette[data*3+1]) && (0 == (int)palette[data*3+2])){
|
|
r = b = 0;
|
|
g = 255;
|
|
al = 0;
|
|
}
|
|
|
|
// stuff the color
|
|
|
|
bm_set_components((ubyte*)&bit_16, &r, &g, &b, &al);
|
|
|
|
|
|
// stuff the pixel
|
|
*((ushort*)pixdata) = bit_16;
|
|
pixdata += 2;
|
|
}
|
|
count--;
|
|
}
|
|
|
|
org_data += (xsize * 2);
|
|
}
|
|
|
|
cfclose(PCXfile);
|
|
|
|
return PCX_ERROR_NONE;
|
|
}
|
|
|
|
int pcx_read_bitmap_16bpp_aabitmap( char * real_filename, ubyte *org_data )
|
|
{
|
|
PCXHeader header;
|
|
CFILE * PCXfile;
|
|
int row, col, count, xsize, ysize;
|
|
ubyte data=0;
|
|
int buffer_size, buffer_pos;
|
|
ubyte buffer[1024];
|
|
ubyte *pixdata;
|
|
char filename[MAX_FILENAME_LEN];
|
|
ubyte palette[768];
|
|
|
|
strcpy( filename, real_filename );
|
|
char *p = strchr( filename, '.' );
|
|
if ( p ) *p = 0;
|
|
|
|
strcat( filename, ".pcx" );
|
|
|
|
PCXfile = cfopen( filename , "rb" );
|
|
if ( !PCXfile ){
|
|
return PCX_ERROR_OPENING;
|
|
}
|
|
|
|
// read 128 char PCX header
|
|
if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
|
|
cfclose( PCXfile );
|
|
return PCX_ERROR_NO_HEADER;
|
|
}
|
|
|
|
// Is it a 256 color PCX file?
|
|
if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
|
|
cfclose( PCXfile );
|
|
return PCX_ERROR_WRONG_VERSION;
|
|
}
|
|
|
|
// Find the size of the image
|
|
xsize = header.Xmax - header.Xmin + 1;
|
|
ysize = header.Ymax - header.Ymin + 1;
|
|
|
|
// Read the extended palette at the end of PCX file
|
|
// Read in a character which should be 12 to be extended palette file
|
|
|
|
cfseek( PCXfile, -768, CF_SEEK_END );
|
|
cfread( palette, 3, 256, PCXfile );
|
|
cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
|
|
|
|
buffer_size = 1024;
|
|
buffer_pos = 0;
|
|
|
|
// Assert( buffer_size == 1024 ); // AL: removed to avoid optimized warning 'unreachable code'
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
|
|
count = 0;
|
|
|
|
for (row=0; row<ysize;row++) {
|
|
pixdata = org_data;
|
|
for (col=0; col<header.BytesPerLine;col++) {
|
|
if ( count == 0 ) {
|
|
data = buffer[buffer_pos++];
|
|
if ( buffer_pos == buffer_size ) {
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
Assert( buffer_size > 0 );
|
|
buffer_pos = 0;
|
|
}
|
|
if ((data & 0xC0) == 0xC0) {
|
|
count = data & 0x3F;
|
|
data = buffer[buffer_pos++];
|
|
if ( buffer_pos == buffer_size ) {
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
Assert( buffer_size > 0 );
|
|
buffer_pos = 0;
|
|
}
|
|
} else {
|
|
count = 1;
|
|
}
|
|
}
|
|
// stuff the pixel
|
|
if ( col < xsize ){
|
|
// stuff the pixel
|
|
// memcpy(pixdata, &data, 2);
|
|
*((ushort*)pixdata) = (ushort)data;
|
|
|
|
pixdata += 2;
|
|
}
|
|
count--;
|
|
}
|
|
|
|
org_data += (xsize * 2);
|
|
}
|
|
cfclose(PCXfile);
|
|
return PCX_ERROR_NONE;
|
|
}
|
|
|
|
int pcx_read_bitmap_16bpp_nondark( char * real_filename, ubyte *org_data )
|
|
{
|
|
PCXHeader header;
|
|
CFILE * PCXfile;
|
|
int row, col, count, xsize, ysize;
|
|
ubyte data=0;
|
|
int buffer_size, buffer_pos;
|
|
ubyte buffer[1024];
|
|
ubyte *pixdata;
|
|
char filename[MAX_FILENAME_LEN];
|
|
ubyte palette[768];
|
|
ushort bit_16;
|
|
ubyte r, g, b, al;
|
|
|
|
strcpy( filename, real_filename );
|
|
char *p = strchr( filename, '.' );
|
|
if ( p ) *p = 0;
|
|
strcat( filename, ".pcx" );
|
|
|
|
PCXfile = cfopen( filename , "rb" );
|
|
if ( !PCXfile ){
|
|
return PCX_ERROR_OPENING;
|
|
}
|
|
|
|
// read 128 char PCX header
|
|
if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
|
|
cfclose( PCXfile );
|
|
return PCX_ERROR_NO_HEADER;
|
|
}
|
|
|
|
// Is it a 256 color PCX file?
|
|
if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
|
|
cfclose( PCXfile );
|
|
return PCX_ERROR_WRONG_VERSION;
|
|
}
|
|
|
|
// Find the size of the image
|
|
xsize = header.Xmax - header.Xmin + 1;
|
|
ysize = header.Ymax - header.Ymin + 1;
|
|
|
|
// Read the extended palette at the end of PCX file
|
|
// Read in a character which should be 12 to be extended palette file
|
|
|
|
cfseek( PCXfile, -768, CF_SEEK_END );
|
|
cfread( palette, 3, 256, PCXfile );
|
|
cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
|
|
|
|
buffer_size = 1024;
|
|
buffer_pos = 0;
|
|
|
|
// Assert( buffer_size == 1024 ); // AL: removed to avoid optimized warning 'unreachable code'
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
|
|
count = 0;
|
|
|
|
for (row=0; row<ysize;row++) {
|
|
pixdata = org_data;
|
|
for (col=0; col<header.BytesPerLine;col++) {
|
|
if ( count == 0 ) {
|
|
data = buffer[buffer_pos++];
|
|
if ( buffer_pos == buffer_size ) {
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
Assert( buffer_size > 0 );
|
|
buffer_pos = 0;
|
|
}
|
|
if ((data & 0xC0) == 0xC0) {
|
|
count = data & 0x3F;
|
|
data = buffer[buffer_pos++];
|
|
if ( buffer_pos == buffer_size ) {
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
Assert( buffer_size > 0 );
|
|
buffer_pos = 0;
|
|
}
|
|
} else {
|
|
count = 1;
|
|
}
|
|
}
|
|
// stuff the pixel
|
|
if ( col < xsize ){
|
|
// stuff the 24 bit value
|
|
r = palette[data*3];
|
|
g = palette[data*3 + 1];
|
|
b = palette[data*3 + 2];
|
|
|
|
// if this is a nondarkening texture
|
|
// if this color matches a nondarkening pixel color, set the alpha to high
|
|
al = 0;
|
|
if(palman_is_nondarkening(r, g, b)){
|
|
al = 255;
|
|
}
|
|
|
|
// set the pixel
|
|
bit_16 = 0;
|
|
|
|
bm_set_components((ubyte*)&bit_16, &r, &g, &b, &al);
|
|
|
|
// stuff the pixel
|
|
*((ushort*)pixdata) = bit_16;
|
|
pixdata += 2;
|
|
}
|
|
count--;
|
|
}
|
|
|
|
org_data += (xsize * 2);
|
|
}
|
|
cfclose(PCXfile);
|
|
return PCX_ERROR_NONE;
|
|
}
|
|
|
|
int pcx_read_bitmap_32(char *real_filename, ubyte *org_data )
|
|
{
|
|
PCXHeader header;
|
|
CFILE * PCXfile;
|
|
ubyte data=0;
|
|
int row, col, count;
|
|
int buffer_pos;
|
|
char filename[MAX_FILENAME_LEN];
|
|
ubyte palette[768];
|
|
|
|
strcpy( filename, real_filename );
|
|
char *p = strchr( filename, '.' );
|
|
if ( p ) *p = 0;
|
|
strcat( filename, ".pcx" );
|
|
|
|
|
|
PCXfile = cfopen( filename , "rb" );
|
|
if ( !PCXfile ){
|
|
|
|
return PCX_ERROR_OPENING;
|
|
}
|
|
|
|
// read 128 char PCX header
|
|
if (cfread( &header, sizeof(PCXHeader), 1, PCXfile )!=1) {
|
|
cfclose( PCXfile );
|
|
|
|
return PCX_ERROR_OPENING;
|
|
}
|
|
|
|
// Is it a 256 color PCX file?
|
|
if ((header.Manufacturer != 10)||(header.Encoding != 1)||(header.Nplanes != 1)||(header.BitsPerPixel != 8)||(header.Version != 5)) {
|
|
cfclose( PCXfile );
|
|
return PCX_ERROR_OPENING;
|
|
}
|
|
|
|
// Find the size of the image
|
|
int src_xsize = header.Xmax - header.Xmin + 1;
|
|
int src_ysize = header.Ymax - header.Ymin + 1;
|
|
|
|
// Read the extended palette at the end of PCX file
|
|
// Read in a character which should be 12 to be extended palette file
|
|
cfseek( PCXfile, -768, CF_SEEK_END );
|
|
cfread( palette, 3, 256, PCXfile );
|
|
cfseek( PCXfile, sizeof(PCXHeader), CF_SEEK_SET );
|
|
|
|
int buffer_size = 1024;
|
|
ubyte buffer[1024];
|
|
buffer_pos = 0;
|
|
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
|
|
count = 0;
|
|
|
|
typedef struct {ubyte b,g,r,a;} COLOR32;
|
|
|
|
for (row=0; row < src_ysize;row++) {
|
|
|
|
COLOR32 *pixdata = (COLOR32 *) org_data;
|
|
|
|
for (col=0; col < header.BytesPerLine;col++) {
|
|
if ( count == 0 ) {
|
|
data = buffer[buffer_pos++];
|
|
if ( buffer_pos == buffer_size ) {
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
Assert( buffer_size > 0 );
|
|
buffer_pos = 0;
|
|
}
|
|
if ((data & 0xC0) == 0xC0) {
|
|
count = data & 0x3F;
|
|
data = buffer[buffer_pos++];
|
|
if ( buffer_pos == buffer_size ) {
|
|
buffer_size = cfread( buffer, 1, buffer_size, PCXfile );
|
|
Assert( buffer_size > 0 );
|
|
buffer_pos = 0;
|
|
}
|
|
} else {
|
|
count = 1;
|
|
}
|
|
}
|
|
// stuff the pixel
|
|
if ( col < src_xsize ){
|
|
|
|
if((0 == (int)palette[data*3]) && (255 == (int)palette[data*3+1]) && (0 == (int)palette[data*3+2])){
|
|
pixdata->r = pixdata->b = pixdata->g = pixdata->a = 0;
|
|
} else {
|
|
|
|
// stuff the 24 bit value
|
|
pixdata->r = palette[data*3];
|
|
pixdata->g = palette[data*3 + 1];
|
|
pixdata->b = palette[data*3 + 2];
|
|
|
|
pixdata->a = 255;
|
|
}
|
|
|
|
pixdata++;
|
|
}
|
|
count--;
|
|
}
|
|
|
|
org_data += (src_xsize * 4);
|
|
}
|
|
|
|
cfclose(PCXfile);
|
|
|
|
return PCX_ERROR_NONE;
|
|
}
|
|
|
|
// subroutine for writing an encoded byte pair
|
|
// returns count of bytes written, 0 if error
|
|
int pcx_encode_byte(ubyte byt, ubyte cnt, FILE * fid)
|
|
{
|
|
if (cnt) {
|
|
if ( (cnt==1) && (0xc0 != (0xc0 & byt)) ) {
|
|
if(EOF == putc((int)byt, fid))
|
|
return 0; // disk write error (probably full)
|
|
return 1;
|
|
} else {
|
|
if(EOF == putc((int)0xC0 | cnt, fid))
|
|
return 0; // disk write error
|
|
if(EOF == putc((int)byt, fid))
|
|
return 0; // disk write error
|
|
return 2;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// returns number of bytes written into outBuff, 0 if failed
|
|
int pcx_encode_line(ubyte *inBuff, int inLen, FILE * fp)
|
|
{
|
|
ubyte this_ptr, last;
|
|
|
|
int srcIndex, i;
|
|
register int total;
|
|
register ubyte runCount; // max single runlength is 63
|
|
total = 0;
|
|
last = *(inBuff);
|
|
runCount = 1;
|
|
|
|
for (srcIndex = 1; srcIndex < inLen; srcIndex++) {
|
|
this_ptr = *(++inBuff);
|
|
if (this_ptr == last) {
|
|
runCount++; // it encodes
|
|
if (runCount == 63) {
|
|
i = pcx_encode_byte(last, runCount, fp);
|
|
if(!i){
|
|
return(0);
|
|
}
|
|
total += i;
|
|
runCount = 0;
|
|
}
|
|
} else { // this_ptr != last
|
|
if (runCount) {
|
|
i = pcx_encode_byte(last, runCount, fp);
|
|
if (!i){
|
|
return(0);
|
|
}
|
|
total += i;
|
|
}
|
|
last = this_ptr;
|
|
runCount = 1;
|
|
}
|
|
}
|
|
|
|
if (runCount) { // finish up
|
|
i = pcx_encode_byte(last, runCount, fp);
|
|
if (!i){
|
|
return 0;
|
|
}
|
|
return total + i;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
|
|
int pcx_write_bitmap( char * real_filename, int w, int h, ubyte ** row_ptrs, ubyte * palette )
|
|
{
|
|
int retval;
|
|
int i;
|
|
ubyte data;
|
|
PCXHeader header;
|
|
FILE * PCXfile;
|
|
char filename[MAX_FILENAME_LEN];
|
|
|
|
strcpy( filename, real_filename );
|
|
char *p = strchr( filename, '.' );
|
|
if ( p ) *p = 0;
|
|
strcat( filename, ".pcx" );
|
|
|
|
memset( &header, 0, sizeof( PCXHeader ) );
|
|
|
|
header.Manufacturer = 10;
|
|
header.Encoding = 1;
|
|
header.Nplanes = 1;
|
|
header.BitsPerPixel = 8;
|
|
header.Version = 5;
|
|
header.Xmax = (short)(w-1);
|
|
header.Ymax = (short)(h-1);
|
|
header.Ymin = 0;
|
|
header.Xmin = 0;
|
|
header.BytesPerLine =(short)(w);
|
|
|
|
PCXfile = fopen( filename , "wb" );
|
|
if ( !PCXfile )
|
|
return PCX_ERROR_OPENING;
|
|
|
|
if ( fwrite( &header, sizeof( PCXHeader ), 1, PCXfile ) != 1 ) {
|
|
fclose( PCXfile );
|
|
return PCX_ERROR_WRITING;
|
|
}
|
|
|
|
for (i=0; i<h; i++ ) {
|
|
if (!pcx_encode_line( row_ptrs[i], w, PCXfile )) {
|
|
fclose( PCXfile );
|
|
return PCX_ERROR_WRITING;
|
|
}
|
|
}
|
|
|
|
// Mark an extended palette
|
|
data = 12;
|
|
if (fwrite( &data, 1, 1, PCXfile )!=1) {
|
|
fclose( PCXfile );
|
|
return PCX_ERROR_WRITING;
|
|
}
|
|
|
|
// Write the extended palette
|
|
// for (i=0; i<768; i++ )
|
|
// palette[i] <<= 2;
|
|
|
|
retval = fwrite( palette, 768, 1, PCXfile );
|
|
|
|
// for (i=0; i<768; i++ )
|
|
// palette[i] >>= 2;
|
|
|
|
if (retval !=1) {
|
|
fclose( PCXfile );
|
|
return PCX_ERROR_WRITING;
|
|
}
|
|
|
|
fclose( PCXfile );
|
|
return PCX_ERROR_NONE;
|
|
|
|
}
|
|
|
|
//text for error messges
|
|
char pcx_error_messages[] = {
|
|
"No error.\0"
|
|
"Error opening file.\0"
|
|
"Couldn't read PCX header.\0"
|
|
"Unsupported PCX version.\0"
|
|
"Error reading data.\0"
|
|
"Couldn't find palette information.\0"
|
|
"Error writing data.\0"
|
|
};
|
|
|
|
|
|
//function to return pointer to error message
|
|
char *pcx_errormsg(int error_number)
|
|
{
|
|
char *p = pcx_error_messages;
|
|
|
|
while (error_number--) {
|
|
|
|
if (!p) return NULL;
|
|
|
|
p += strlen(p)+1;
|
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|