00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00071
00072
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
00109
00110
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
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
00136 switch (num_planes)
00137 {
00138 case 1:
00139 {
00140
00141
00142
00143
00144
00145 dest_num_planes = 1;
00146 pixelformat = PAL8;
00147 }
00148 break;
00149 case 2:
00150 {
00151
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
00161 pixelformat = PAL8;
00162 dest_num_planes = 1;
00163 }
00164 else
00165 {
00166
00167
00168
00169
00170 pixelformat = RGBA8888;
00171 dest_num_planes = 4;
00172 }
00173 }
00174 break;
00175 case 4:
00176 {
00177
00178
00179
00180
00181
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
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
00212 size_data = _datafile->size() - 128;
00213
00214
00215
00216
00217 if (pixelformat == PAL8)
00218 {
00219
00220
00221 if (pcx_version >= 5)
00222 {
00223 if (num_planes == 1)
00224 {
00225
00226
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
00235 palette = new CL_Palette(&header[16],16);
00236 }
00237 }
00238 else
00239 {
00240
00241 palette = new CL_Palette(&header[16],16);
00242 }
00243
00244
00245
00246 switch (num_planes)
00247 {
00248 case 1:
00249 {
00250
00251 if (bits_per_pixel_per_plane == 1)
00252 {
00253
00254
00255
00256
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
00265 if (bits_per_pixel_per_plane == 2)
00266 {
00267
00268
00269 unsigned char cga_pal[12];
00270
00271 if (header[19] & 64)
00272 {
00273
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
00282 else
00283 {
00284
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
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
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
00327 if (bits_per_pixel_per_plane == 4)
00328 {
00329
00330
00331
00332
00333
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
00348 break;
00349 case 3:
00350 {
00351 if (bits_per_pixel_per_plane == 1)
00352 {
00353
00354
00355
00356
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
00373
00374 break;
00375 }
00376 }
00377 else
00378 {
00379
00380 palette = NULL;
00381 }
00382
00383
00384 bytes_to_allocate = (8 / bits_per_pixel_per_plane) * pitch * height * dest_num_planes;
00385
00386
00387 image = new unsigned char[bytes_to_allocate];
00388 cl_assert(image != NULL);
00389
00390 if (pixelformat == RGBA8888)
00391 {
00392
00393 memset(image, 255, bytes_to_allocate);
00394 }
00395 else
00396 {
00397
00398 memset(image, 0, bytes_to_allocate);
00399 }
00400 }
00401
00402 void CL_PCXProvider::read_data()
00403 {
00404
00405 if (image != NULL) return;
00406
00407
00408 cl_assert(provider != NULL);
00409 CL_InputSource *datafile = provider->open_source(name.c_str());
00410 cl_assert(datafile != NULL);
00411
00412
00413 read_header(datafile);
00414
00415
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
00425 unsigned char *p = temp;
00426 unsigned char *cur_line = image;
00427
00428 unsigned char packed_byte;
00429 unsigned char bitmask = 0;
00430 int skip_planes = 0;
00431
00432
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
00453 for (int scanline=0;scanline<height;scanline++)
00454 {
00455
00456 for (int plane = num_planes - 1; plane >= 0; plane--)
00457 {
00458
00459
00460
00461 int decoded_bytes = 0;
00462
00463 int line_position = 0;
00464
00465 while (decoded_bytes < decode_pitch)
00466 {
00467
00468
00469
00470 packed_byte = *(p++);
00471
00472 if (packed_byte < 192)
00473 {
00474
00475
00476 for (int bitcounter = 0; bitcounter < 8; bitcounter += bits_per_pixel_per_plane)
00477 {
00478
00479
00480 if (bits_per_pixel_per_plane < 8)
00481 {
00482
00483
00484
00485
00486
00487 unsigned char packed_bits = ((packed_byte >> (8 - bits_per_pixel_per_plane - bitcounter)) & bitmask);
00488
00489
00490
00491
00492
00493 packed_bits = (packed_bits << (num_planes - plane - 1));
00494
00495
00496
00497
00498 cur_line[line_position] = cur_line[line_position] + packed_bits;
00499 }
00500 else
00501 {
00502
00503
00504
00505
00506
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
00523
00524
00525 {
00526 unsigned char rle_count = packed_byte&0x3f;
00527 packed_byte = *(p++);
00528
00529
00530 for(unsigned char rle_iterator = 0; rle_iterator < rle_count; rle_iterator++)
00531
00532 {
00533
00534 if (decoded_bytes >= decode_pitch)
00535 {
00536 plane--;
00537 decoded_bytes = 0;
00538 line_position = 0;
00539 }
00540
00541
00542 for (int bitcounter = 0; bitcounter < 8; bitcounter += bits_per_pixel_per_plane)
00543 {
00544
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
00577
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 }