Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members   File Members  

provider_pcx.cpp

Go to the documentation of this file.
00001 /*
00002         $Id: provider_pcx.cpp,v 1.1 2001/03/06 15:09:22 mbn Exp $
00003 
00004         ------------------------------------------------------------------------
00005         ClanLib, the platform independent game SDK.
00006 
00007         This library is distributed under the GNU LIBRARY GENERAL PUBLIC LICENSE
00008         version 2. See COPYING for details.
00009 
00010         For a total list of contributers see CREDITS.
00011 
00012         ------------------------------------------------------------------------
00013 
00014         File purpose:
00015                 PCX SurfaceProvider
00016 */
00017 
00018 #include "Core/precomp.h"
00019 #include "API/Display/Display/pixelformat.h"
00020 #include "API/Display/Display/palette.h"
00021 #include "API/Core/IOData/inputsource.h"
00022 #include "API/Core/IOData/inputsource_provider.h"
00023 #include "API/Display/SurfaceProviders/provider_pcx.h"
00024 #include "API/Core/System/error.h" 
00025 #include "API/Core/System/cl_assert.h"
00026 #include "API/Display/Display/res_surface.h"
00027 #include "API/Core/Resources/resourceoptions.h"
00028 #include <iostream.h>
00029 
00030 CL_Surface *CL_PCXProvider::create(
00031         std::string handle, 
00032         CL_InputSourceProvider *provider, 
00033         bool transparent, 
00034         unsigned char trans_col)
00035 {
00036         return CL_Surface::create(new CL_PCXProvider(
00037                 handle, 
00038                 provider, 
00039                 transparent, 
00040                 trans_col), true);
00041 }
00042 
00043 CL_PCXProvider::CL_PCXProvider(
00044         std::string _name, 
00045         CL_InputSourceProvider *_provider, 
00046         bool _transparent, 
00047         unsigned char _trans_col)
00048 {
00049         provider = _provider != NULL ? _provider->clone() : 
00050                                                                 CL_InputSourceProvider::create_file_provider(".");
00051         pitch = height = 0;
00052         bounding_left = bounding_top = bounding_right = bounding_bottom = 0;
00053         
00054         transparent = _transparent;
00055         if (!transparent) trans_col = -1;
00056         else trans_col = _trans_col;
00057         
00058         name = _name;
00059         palette = NULL;
00060         image = NULL;
00061         pixelformat = PAL8;
00062 }
00063 
00064 CL_PCXProvider::~CL_PCXProvider()
00065 {
00066         perform_unlock();
00067         delete provider;
00068 }
00069 /*
00070 EPixelFormat CL_PCXProvider::get_pixel_format() const
00071 {
00072         return pixelformat;
00073 }
00074 */
00075 
00076 unsigned int CL_PCXProvider::get_depth() const
00077 {
00078         switch (pixelformat)
00079         {
00080         case RGBA8888:
00081                 return 32;
00082         default:
00083                 return 8;
00084         }
00085 }
00086 
00087 unsigned int CL_PCXProvider::get_red_mask() const
00088 {
00089         return 0xff000000;
00090 }
00091 
00092 unsigned int CL_PCXProvider::get_green_mask() const
00093 {
00094         return 0x00ff0000;
00095 }
00096 
00097 unsigned int CL_PCXProvider::get_blue_mask() const
00098 {
00099         return 0x0000ff00;
00100 }
00101 
00102 unsigned int CL_PCXProvider::get_alpha_mask() const
00103 {
00104         return 0x000000ff;
00105 }
00106 void CL_PCXProvider::read_header(CL_InputSource *_datafile)
00107 {
00108         //: This method was created to breakup the PCX decoding code
00109         //: so the initializing code was separated from the actual
00110         //: decoding algorithm
00111         
00112         unsigned char header[128];  
00113         
00114         int read = _datafile->read(header, 128);
00115         if (read != 128)
00116                 throw CL_Error("Invalid pcx file!?");
00117         
00118         pcx_version = header[1];
00119 
00120         // int compressed = header[2];
00121 
00122         bits_per_pixel_per_plane = header[3];
00123 
00124         short xmin = header[5] * 256 + header[4];       
00125         short ymin = header[7] * 256 + header[6];
00126         short xmax = header[9] * 256 + header[8];
00127         short ymax = header[11] * 256 + header[10];
00128 
00129         height = ymax - ymin + 1;
00130 
00131         num_planes = header[65];
00132         dest_num_planes = num_planes;
00133         decode_pitch = header[67] * 256 + header[66];
00134 
00135         //decide which pixelformat to use (8 bit palette or 32 bit)
00136         switch (num_planes)             
00137         {
00138         case 1:
00139                 {
00140                         //palettized image
00141                         //Deluxe Paint IIe compatible 4 color CGA or
00142                         //Monochrome or
00143                         //256 color palette based image
00144                         //force the final image to 8 bit/palette.
00145                         dest_num_planes = 1;
00146                         pixelformat = PAL8;
00147                 }
00148                 break;
00149         case 2:
00150                 {
00151                         //force the final image to 8 bit/palette.
00152                         dest_num_planes = 1;
00153                         pixelformat = PAL8;
00154                 }
00155                 break;
00156         case 3:
00157                 {
00158                         if (bits_per_pixel_per_plane == 1)
00159                         {
00160                                 //This means 8 color/palette
00161                                 pixelformat = PAL8;
00162                                 dest_num_planes = 1;
00163                         }
00164                         else
00165                         {
00166                                 //This means it is 24 bit RGB.
00167                                 //24 bit images are being forced into 32 bit.
00168                                 //Pixelformat RGB888 did not appear to work at the time
00169                                 //of this PCX decoder rewrite.
00170                                 pixelformat = RGBA8888;
00171                                 dest_num_planes = 4;
00172                         }
00173                 }
00174                 break;
00175         case 4:
00176                 {
00177                         //no palette
00178                         //force the final image to 8 bit/palette.
00179                         //This case represents 16 color EGA or 4 color CGA where only
00180                         //1 bit is stored in each plane.  The 4th plane is the
00181                         //intensity bit.
00182                         dest_num_planes = 1;
00183                         pixelformat = PAL8;
00184                 }
00185                 break;
00186         default:
00187                 {
00188                         throw CL_Error("Unrecognized or invalid pcx file!?");
00189                 }
00190                 break;
00191         }
00192 
00193         //set bytes per scanline of final image.  Requires dest_num_planes to be defined.
00194         pitch = (xmax - xmin  + 1) * dest_num_planes;
00195         
00196         if (transparent)
00197         {
00198                 bounding_left = pitch / dest_num_planes;
00199                 bounding_top = height;
00200                 bounding_right = 0;
00201                 bounding_bottom = 0;
00202         }
00203         else
00204         {
00205                 bounding_left = 0;
00206                 bounding_top = 0;
00207                 bounding_right = pitch / dest_num_planes;
00208                 bounding_bottom = height;
00209         }
00210 
00211         //get number of bites in encoded data (including possible palette after data)
00212         size_data = _datafile->size() - 128;
00213 
00214         //Now we deal with the palette which can be in the header,
00215         //or at the end of the file, or defined here.  It is possible that these
00216         //palette definitions should have been placed in palette.h
00217         if (pixelformat == PAL8)
00218         {
00219                 //If the pcx version is 5, the palette may be at the end of the file.
00220                 //Otherwise it is in the header.
00221                 if (pcx_version >= 5)   
00222                 {
00223                         if (num_planes == 1)
00224                         {
00225                                 //The palette information is stored at the end of the file.
00226                                 //read the last 768 bytes from the file.
00227                                 unsigned char *temp_pal = new unsigned char[768];
00228                                 _datafile->seek(128+size_data-768,CL_InputSource::seek_set);
00229                                 read = _datafile->read(temp_pal, 768);
00230                                 palette = new CL_Palette(temp_pal);
00231                         }
00232                         else
00233                         {
00234                                 //The palette information is stored in the header.
00235                                 palette = new CL_Palette(&header[16],16);
00236                         }
00237                 }
00238                 else
00239                 {
00240                         //The palette information is stored in the header.
00241                         palette = new CL_Palette(&header[16],16);
00242                 }
00243                 
00244                 //Setup palette for PCX types that rely on a pre-defined palette
00245                 //(MONO, CGA, EGA)
00246                 switch (num_planes)
00247                 {
00248                 case 1:
00249                         {       
00250                                 //1 color plane, 1 bit per pixel per plane
00251                                 if (bits_per_pixel_per_plane == 1)
00252                                 {
00253                                         //Simulate a monochrome display.
00254                                         //Assign "Black" and "White" colors to palette
00255                                         //(assume "White" assigned to "On" bits)
00256                                         //It works!
00257                                         unsigned char mono_pal[6] = 
00258                                                 { 0,0,0,
00259                                                 255,255,255 };
00260                                         delete palette;
00261                                         palette = new CL_Palette(mono_pal, 2);
00262                                 }
00263 
00264                                 //1 color plane, 2 bits per pixel per plane
00265                                 if (bits_per_pixel_per_plane == 2)
00266                                 {
00267                                         //CGA 4 color
00268                                         //It works!
00269                                         unsigned char cga_pal[12];
00270 
00271                                         if (header[19] & 64)
00272                                         {
00273                                                 //Use background/cyan/magenta/white palette
00274                                                 unsigned char cga_pal1[12] = 
00275                                                         { 0,0,0,
00276                                                         0,255,255,
00277                                                         255,0,255,
00278                                                         255,255,255 };
00279                                                 memcpy (cga_pal, cga_pal1, 12);
00280                                         }
00281                                         //eveything from here forward was not tested for this mode.
00282                                         else
00283                                         {
00284                                                 //Use background/green/red/yellow palette
00285                                                 unsigned char cga_pal2[12] = 
00286                                                         { 0,0,0,
00287                                                         0,255,0,
00288                                                         255,0,0,
00289                                                         255,255,0 };
00290                                                 memcpy (cga_pal, cga_pal2, 12);
00291                                         }
00292                                         
00293                                         //set the background color palette
00294                                         unsigned char backcolors[3][16] =
00295                                                 { {0,0,0,
00296                                                 0,0,128,
00297                                                 0,128,0,
00298                                                 0,128,128,
00299                                                 128,0,0,
00300                                                 128},{0,128,
00301                                                 192,96,0,
00302                                                 192,192,192,
00303                                                 128,128,128,
00304                                                 0,0,255,
00305                                                 0,255},{0,
00306                                                 0,255,255,
00307                                                 255,0,0,
00308                                                 255,0,255,
00309                                                 255,255,0,
00310                                                 255,255,255}};
00311                                          memcpy (cga_pal, &backcolors[0][header[16] & 240 >> 4], 3);
00312 
00313                                         //set the intensity
00314                                         for (int x=3;x < 12; x++)
00315                                         {
00316                                                 if (!(header[19] & 32) && cga_pal[x])
00317                                                 {
00318                                                         cga_pal[x] = 128;
00319                                                 }
00320                                         }
00321 
00322                                         delete palette;
00323                                         palette = new CL_Palette(cga_pal, 4);
00324                                 }
00325 
00326                                 //1 color plane, 4 bits per pixel per plane                             
00327                                 if (bits_per_pixel_per_plane == 4)
00328                                 {
00329                                         //This is an EGA image.
00330                                         //the palette needs to normalized
00331                                         
00332                                         //normalize the EGA palette before loading it
00333                                         //Clanlib needs palette manipulation functions...  
00334                                         if (bits_per_pixel_per_plane == 4)
00335                                         {
00336                                                 for (int x = 0; x < 48; x++)
00337                                                 {
00338 
00339                                                         header[16+x]=header[16+x]/64*64;
00340                                                 }
00341                                         }
00342                                         palette = new CL_Palette(&header[16],16);
00343                                 }
00344                         }
00345                         break;
00346                 case 2:
00347                         //nothing special to do here.  A 4 color palette is used (already loaded).
00348                         break;
00349                 case 3:
00350                         {
00351                                 if (bits_per_pixel_per_plane == 1)
00352                                 {
00353                                         //Assign the 8 possible combinations of RGB to the palette 
00354                                         //to simulate 8 color RGB display.  Otherwise, it is a 256
00355                                         //color picture.  
00356                                         //8 color untested.  256 color working.
00357                                         unsigned char rgb3_pal[24] = 
00358                                                 { 0,0,0,
00359                                                 0,0,255,
00360                                                 0,255,0,
00361                                                 0,255,255,
00362                                                 255,0,0,
00363                                                 255,0,255,
00364                                                 255,255,0,
00365                                                 255,255,255 };
00366                                         delete palette;
00367                                         palette = new CL_Palette(rgb3_pal, 8);
00368                                 }
00369                         }
00370                         break;
00371                 case 4:
00372                         //This is a 16 color arbitrary palette image.
00373                         //working.
00374                         break; 
00375                 }
00376         }
00377         else
00378         {
00379                 //This is an RGBA8888 image.
00380                 palette = NULL;
00381         }
00382 
00383         //This is number of bytes to allocate for the final image
00384         bytes_to_allocate = (8 / bits_per_pixel_per_plane) * pitch * height * dest_num_planes;
00385 
00386         //allocate the image
00387         image = new unsigned char[bytes_to_allocate];
00388         cl_assert(image != NULL);
00389 
00390         if (pixelformat == RGBA8888)
00391         {
00392                 //Set all pixels to be opaque for RGBA8888
00393                 memset(image, 255, bytes_to_allocate);
00394         }
00395         else
00396         {
00397                 //initialize bits to 0 so that bitwise operations work correctly
00398                 memset(image, 0, bytes_to_allocate);
00399         }
00400 }
00401 
00402 void CL_PCXProvider::read_data()
00403 {
00404         // Do not run if we already have image data
00405         if (image != NULL) return;
00406 
00407         // open the file and make sure its valid
00408         cl_assert(provider != NULL);
00409         CL_InputSource *datafile = provider->open_source(name.c_str());
00410         cl_assert(datafile != NULL);
00411         
00412         // Read the file header and initialize the variables
00413         read_header(datafile);
00414 
00415         // This section reads the file data into memory
00416         datafile->seek(128, CL_InputSource::seek_set);
00417         int size_data = datafile->size() - 128;
00418         unsigned char *temp = new unsigned char[size_data];
00419         int read = datafile->read(temp, size_data);
00420         if (read != size_data)
00421                 throw CL_Error("Invalid pcx file!?");
00422         delete datafile;
00423         
00424         //init decoding variables
00425         unsigned char *p = temp;
00426         unsigned char *cur_line = image;
00427         // unsigned char *base = image;
00428         unsigned char packed_byte;
00429         unsigned char bitmask = 0;
00430         int skip_planes = 0;
00431 
00432         //used later to select bits in bit depths less than 8.
00433         switch (bits_per_pixel_per_plane)
00434         {
00435         case 1:
00436                 bitmask = 0x01;
00437                 break;
00438         case 2:
00439                 bitmask = 0x03;
00440                 break;
00441         case 4:
00442                 bitmask = 0x0F;
00443                 break;
00444         case 8:
00445                 bitmask = 0xFF;
00446                 break;
00447         }
00448 
00449         if (pixelformat == RGBA8888)
00450                         skip_planes = 1;
00451         
00452         //This section decodes the PCX data.
00453         for (int scanline=0;scanline<height;scanline++)
00454         {
00455                 //For every scanline
00456                 for (int plane = num_planes - 1; plane >= 0; plane--)
00457                 {
00458                         //for every plane (count backward to convert from RGB to ABGR)
00459 
00460                         //tracks bytes decoded from data
00461                         int decoded_bytes = 0;
00462                         //tracks position within final image
00463                         int line_position = 0;
00464 
00465                         while (decoded_bytes < decode_pitch)
00466                         {
00467                                 //while we have not reached the end of the decoded line
00468                                 
00469                                 //increment the data pointer
00470                                 packed_byte = *(p++);
00471 
00472                                 if (packed_byte < 192)
00473                                 {
00474                                         // top two bits are off... this byte is data
00475                                         //The processing is now broken down to bit depths of 1, 2, 4, or 8.
00476                                         for (int bitcounter = 0; bitcounter < 8; bitcounter += bits_per_pixel_per_plane)
00477                                         {
00478                                                 //For every pixel to be decoded (8 / bits_per_pixel_per_plane
00479 
00480                                                 if (bits_per_pixel_per_plane < 8)
00481                                                 {
00482                                                         //The bit depth is below 8.  Because we are converting all
00483                                                         //bit depths below 8 to 8, the current line_position is
00484                                                         //always where we are writing data.    
00485                                                         
00486                                                         //This line pulls the packed bits out of the data.
00487                                                         unsigned char packed_bits = ((packed_byte >> (8 - bits_per_pixel_per_plane - bitcounter)) & bitmask);
00488                                                         
00489                                                         //This part pulls bits from multiple planes.  Because the bits
00490                                                         //of a palette reference may be spread across multiple planes,
00491                                                         //we modify the data that is already at the line position
00492                                                         //(rather than simply overwriting it).
00493                                                         packed_bits = (packed_bits << (num_planes - plane - 1));
00494                                                         
00495                                                         //Add bits to current position.  In the case of a 
00496                                                         //palette that is referenced by bits in only one plane, 
00497                                                         //this is only executed once per line_position.
00498                                                         cur_line[line_position] = cur_line[line_position] + packed_bits;
00499                                                 }
00500                                                 else
00501                                                 {
00502                                                         //The image is 8 bit/pallete or 24 bit.  In either case,
00503                                                         //we simply add the number of color planes to the line position.
00504                                                         //Then we add 1 plane for alpha support in a 24(32) bit image
00505                                                         //to skip over the alpha channel (which we assume has been set
00506                                                         //to 0xFF).
00507                                                         int image_dest = line_position *dest_num_planes + plane + skip_planes;                                          
00508                                                         cur_line[image_dest] = packed_byte; 
00509                                                 }
00510                                                 line_position++;
00511                                         }
00512                                         if (transparent && packed_byte != trans_col)
00513                                         {
00514                                                 if (decoded_bytes < bounding_left) bounding_left = decoded_bytes;
00515                                                 if (scanline < bounding_top) bounding_top = scanline;
00516                                                 if (decoded_bytes > bounding_right) bounding_right = decoded_bytes;
00517                                                 if (scanline > bounding_bottom) bounding_bottom = scanline;
00518                                         }
00519                                         decoded_bytes++;
00520                                 }
00521                                 else 
00522                                 // top two bits are on... This is a run.  The other bits contain
00523                                 // a run count for the RLE compression.  The next byte will
00524                                 // contain data to repeat.
00525                                 { 
00526                                         unsigned char rle_count = packed_byte&0x3f;
00527                                         packed_byte = *(p++);   
00528                                         //get data byte to repeat.
00529 
00530                                         for(unsigned char rle_iterator = 0; rle_iterator < rle_count; rle_iterator++)
00531                                         //repeat data value based on rle_count
00532                                         {
00533                                                 //check for end of plane
00534                                                 if (decoded_bytes >= decode_pitch)
00535                                                 {
00536                                                         plane--;
00537                                                         decoded_bytes = 0;
00538                                                         line_position = 0;
00539                                                 }
00540                                                 
00541                                                 //The processing is now broken down to bit depths of 1, 2, 4, or 8
00542                                                 for (int bitcounter = 0; bitcounter < 8; bitcounter += bits_per_pixel_per_plane)
00543                                                 {
00544                                                         // The decoding process here is the same as above (in the non-RLE code)
00545                                                         if (bits_per_pixel_per_plane < 8)
00546                                                         {
00547                                                                 unsigned char packed_bits = ((packed_byte >> (8 - bits_per_pixel_per_plane - bitcounter)) & bitmask);
00548                                                                 packed_bits = (packed_bits << (num_planes - plane - 1));
00549                                                                 cur_line[line_position] = cur_line[line_position] + packed_bits;
00550                                                         }
00551                                                         else
00552                                                         {
00553                                                                 int image_dest = line_position *dest_num_planes + plane + skip_planes;                                          
00554                                                                 cur_line[image_dest] = packed_byte; 
00555                                                         }
00556                                                         line_position++;
00557                                                 }                                               
00558                                                 if (transparent && packed_byte != trans_col)
00559                                                 {
00560                                                         if ((decoded_bytes+rle_iterator) < bounding_left) bounding_left = decoded_bytes+rle_iterator;
00561                                                         if (scanline < bounding_top) bounding_top = scanline;
00562                                                         if ((decoded_bytes+rle_iterator) > bounding_right) bounding_right = decoded_bytes+rle_iterator;
00563                                                         if (scanline > bounding_bottom) bounding_bottom = scanline;
00564                                                 }
00565                                                 decoded_bytes++;
00566                                         }
00567                                 }
00568                         }
00569                 }
00570                 cur_line += pitch;
00571         }       
00572         delete[] temp;
00573 }
00574 void CL_PCXProvider::perform_lock()
00575 {
00576         //The PCX decoding code was moved to read_data() and read_header()
00577         //to make it easier to follow the code.
00578         read_data();
00579 }
00580 
00581 void CL_PCXProvider::perform_unlock()
00582 {
00583         delete[] image;
00584         delete palette;
00585 
00586         image = NULL;
00587         palette = NULL;
00588 }

Generated at Wed Apr 4 19:54:02 2001 for ClanLib by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001