/*! \file loadpcxc.cpp \brief Loading and storing images in PCX format, written in C There is also an optimized assembler version for the DOS version around which is called #loadpcx.cpp , but not used any more. */ /* This file is part of Advanced Strategic Command; http://www.asc-hq.de Copyright (C) 1994-2005 Martin Bickel and Marc Schellenberger This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "basestrm.h" #include "tpascal.inc" #include "basegfx.h" #include "misc.h" #pragma pack(1) struct tpcxheader{ char manufacturer; char version ; char encoding ; char bitsperpixel; Uint16 xmin,ymin ; Uint16 xmax,ymax ; Uint16 hdpi,vdpi ; char colormap[48]; char reserved ; char nplanes ; Uint16 bytesperline; Uint16 paletteinfo ; Uint16 hscreensize ; Uint16 vscreensize ; char dummy[50] ; int size; // patch to be able to read pcx files without seeking void read ( tnstream* stream ); void write ( tnstream* stream ); }; void tpcxheader::read ( tnstream* stream ) { manufacturer = stream->readChar(); version = stream->readChar(); encoding = stream->readChar(); bitsperpixel = stream->readChar(); xmin = stream->readWord(); ymin = stream->readWord(); xmax = stream->readWord(); ymax = stream->readWord(); hdpi = stream->readWord(); vdpi = stream->readWord(); stream->readdata ( colormap, 48); reserved = stream->readChar(); nplanes = stream->readChar(); bytesperline= stream->readWord(); paletteinfo = stream->readWord(); hscreensize = stream->readWord(); vscreensize = stream->readWord(); stream->readdata ( dummy, 50 ) ; size = stream->readInt(); // patch to be able to read pcx files without seeking } void tpcxheader::write ( tnstream* stream ) { stream->writeChar( manufacturer ); stream->writeChar( version ); stream->writeChar( encoding ); stream->writeChar( bitsperpixel ); stream->writeWord( xmin ); stream->writeWord( ymin ); stream->writeWord( xmax ); stream->writeWord( ymax ); stream->writeWord( hdpi ); stream->writeWord( vdpi ); stream->writedata ( colormap, 48); stream->writeChar( reserved ); stream->writeChar( nplanes ); stream->writeWord( bytesperline); stream->writeWord( paletteinfo ); stream->writeWord( hscreensize ); stream->writeWord( vscreensize ); stream->writedata ( dummy, 50 ) ; stream->writeInt( size ); // patch to be able to read pcx files without seeking } #pragma pack() int pcxGetColorDepth ( const ASCString& filename, int* width, int* height ) { tnfilestream stream ( filename.c_str(), tnstream::reading ); tpcxheader header; header.read ( &stream ); if ( width ) *width = header.xmax - header.xmin + 1 ; if ( height ) *height = header.ymax - header.ymin + 1; return header.nplanes * header.bitsperpixel; } char loadpcxxy( pnstream stream, int x, int y, bool setpalette, int* xsize, int* ysize ) { int read = 0; // int m = y * agmp-> scanlinelength * agmp->byteperpix + x; tpcxheader header; header.read( stream ); read += sizeof(header); if ( !header.size ) { if ( stream->getSize() < 0 ) return 12; else header.size = stream->getSize(); } int width = header.xmax - header.xmin + 1 ; int height = header.ymax - header.ymin + 1; int pixels = width * height * header.nplanes; if ( xsize ) *xsize = width; if ( ysize ) *ysize = height; if ( header.manufacturer != 10 || header.bitsperpixel != 8 || header.xmax-header.xmin > agmp-> scanlinelength ) return 11; int colors = header.nplanes * header.bitsperpixel; int scanlineret[4]; if (agmp->byteperpix > 1) { scanlineret[0] = agmp-> redfieldposition / 8; scanlineret[1] = header.bytesperline * agmp->byteperpix - agmp->greenfieldposition / 8 + agmp-> redfieldposition / 8; scanlineret[2] = header.bytesperline * agmp->byteperpix - agmp->bluefieldposition / 8 + agmp-> greenfieldposition / 8; scanlineret[3] = -(agmp-> scanlinelength - header.bytesperline* agmp->byteperpix + agmp->redfieldposition / 8 - agmp->bluefieldposition / 8); } else { scanlineret[0]=0; scanlineret[1]= -(agmp->scanlinelength - header.bytesperline * agmp->byteperpix); } // int totalbytes = header.nplanes * header.bytesperline; int ttlbytes = 0; int xpos = 0; int planenum = 0; int byteperpix = agmp->byteperpix; // some simple buffering char* buf = new char[header.size]; // int bufdata = stream->readdata ( buf, header.size - sizeof( header )); int actpos = 0; char* dest = (char*) (agmp->linearaddress + x * agmp->byteperpix + y * agmp->bytesperscanline + scanlineret[0]); while ( pixels ) { char a; a = buf[actpos++]; read++; int count; if ( a >= 192 ) { count = a ^192; a = buf[actpos++]; read++; } else count = 1; while ( count ) { if ( xpos >= header.bytesperline ) { planenum++; dest -= scanlineret[planenum]; if ( planenum >= header.nplanes ) { planenum = 0; ttlbytes = 0; } xpos = 0; } if ( xpos < width ) { *dest = a; pixels--; } dest+= byteperpix; xpos++; ttlbytes++; count--; } /* endwhile */ } /* endwhile */ if ( setpalette && colors == 8 ) { if ( header.size ) { int dataend = header.size - sizeof ( dacpalette256 ) - 1 - sizeof ( header ); actpos = dataend; /* while ( read < dataend ) { char scratch[100]; int datalength; if ( 100 > dataend - read ) datalength = dataend - read; else datalength = 100; stream->readdata ( scratch, datalength ); read+= datalength;; } */ } char c = buf[actpos++]; if ( c == 12 ) { dacpalette256 pal; memcpy ( pal, &buf[actpos], sizeof ( pal )); // stream->readdata ( pal, sizeof ( pal ) ); for ( int i = 0; i < 3; i++ ) for ( int j = 0; j < 256; j++ ) pal[j][i] >>= 2; setvgapalette256 ( pal ); } } delete[] buf; return 0; } char loadpcxxy ( const ASCString& name, bool setpal, int xpos, int ypos, int* xsize, int* ysize ) { tnfilestream s ( name, tnstream::reading ); return loadpcxxy ( &s, xpos, ypos, setpal, xsize, ysize ); } void writepcx ( const ASCString& name, int x1, int y1, int x2, int y2, dacpalette256 pal ) { tpcxheader header; memset ( &header, 0, sizeof (header )); header.manufacturer = 10; header.version = 5; header.encoding = 1; header.bitsperpixel = 8; header.xmin = 0; header.xmax = x2 - x1 ; header.ymin = 0; header.ymax = y2 - y1 ; header.hdpi = 0; header.vdpi = 0; if ( agmp->byteperpix == 1 ) header.nplanes = 1; else header.nplanes = 3; // header.bytesperline = ((header.xmax - header.xmin) + 1) & 0xFFFE; header.bytesperline = x2 - x1 + 1 ; if ( header.bytesperline & 1 ) header.bytesperline++; header.paletteinfo = 1; int fsize = 0; tn_file_buf_stream stream ( name, tnstream::writing ); header.write ( &stream ); fsize += sizeof ( header ); for ( int y = y1; y <= y2; y++ ) for ( int plane = 0; plane < header.nplanes; plane++ ) { int lastbyte = -1; int count = 0; for ( int x = x1; x < x1 + header.bytesperline; x++ ) { char c = (getpixel( x, y ) >> ( plane * 8 )) & 0xff; if ( (lastbyte == c && count < 63) || lastbyte == -1 ) { count ++; lastbyte = c; } else { if ( count > 1 || lastbyte >= 192 ) { char d = 192 + count; stream.writeChar ( d ); fsize += sizeof ( d ); } char lstbyte = lastbyte; stream.writeChar ( lstbyte ); fsize += sizeof ( lstbyte ); count = 1; lastbyte = c; } } if ( count > 1 || lastbyte >= 192 ) { char d = 192 + count; stream.writeChar ( d ); fsize += sizeof ( d ); } char lstbyte = lastbyte; stream.writeChar ( lstbyte ); fsize += sizeof ( lstbyte ); } if ( header.nplanes == 1 ) { char d = 12; stream.writeChar ( d ); fsize += sizeof ( d ); dacpalette256 pal2; for ( int i = 0; i < 3; i++ ) for ( int j = 0; j < 256; j++ ) pal2[j][i] = pal[j][i] << 2; stream.writedata ( &pal2, 768 ); // endian ok !!! fsize += 768 ; } stream.seek ( 0 ); header.size = fsize; header.write ( &stream ); }