Panda3D
|
00001 // Filename: pnmFileTypeSoftImage.cxx 00002 // Created by: drose (17Jun00) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "pnmFileTypeSoftImage.h" 00016 00017 #ifdef HAVE_SOFTIMAGE_PIC 00018 00019 #include "config_pnmimagetypes.h" 00020 00021 #include "pnmFileTypeRegistry.h" 00022 #include "bamReader.h" 00023 00024 static const float imageVersionNumber = 3.0; 00025 static const int imageCommentLength = 80; 00026 static const char imageComment[imageCommentLength+1] = 00027 "Written by pnmimage."; 00028 00029 // Values to indicate compressed/uncompressed types 00030 #define UNCOMPRESSED 0x00 00031 #define MIXED_RUN_LENGTH 0x02 00032 00033 // Bits to indicate channel type 00034 #define RGB_CHANNEL 0xe0 00035 #define ALPHA_CHANNEL 0x10 00036 00037 // SoftImage magic number: high word, low word 00038 #define SOFTIMAGE_MAGIC1 0x5380 00039 #define SOFTIMAGE_MAGIC2 0xf634 00040 00041 static const char * const extensions_softimage[] = { 00042 "pic", "soft" 00043 }; 00044 static const int num_extensions_softimage = sizeof(extensions_softimage) / sizeof(const char *); 00045 00046 TypeHandle PNMFileTypeSoftImage::_type_handle; 00047 00048 inline float 00049 read_float(istream *file) { 00050 long l; 00051 00052 if (pm_readbiglong(file, &l)==0) { 00053 return *(float *)&l; 00054 } else { 00055 return 0.0; 00056 } 00057 } 00058 00059 inline unsigned short 00060 read_ushort_SI(istream *file) { 00061 unsigned short x; 00062 return pm_readbigshort(file, (short *)&x)==0 ? x : 0; 00063 } 00064 00065 inline unsigned char 00066 read_uchar_SI(istream *file) { 00067 int x; 00068 x = file->get(); 00069 return (x!=EOF) ? (unsigned char)x : 0; 00070 } 00071 00072 inline void 00073 write_ushort_SI(ostream *file, unsigned short x) { 00074 pm_writebigshort(file, (short)x); 00075 } 00076 00077 inline void 00078 write_uchar_SI(ostream *file, unsigned char x) { 00079 file->put(x); 00080 } 00081 00082 inline void 00083 write_float(ostream *file, float x) { 00084 pm_writebiglong(file, *(long *)&x); 00085 } 00086 00087 static int 00088 read_channel_pkt(istream *file, 00089 int &chained, int &size, int &type, int &channel) { 00090 chained = read_uchar_SI(file); 00091 size = read_uchar_SI(file); 00092 type = read_uchar_SI(file); 00093 channel = read_uchar_SI(file); 00094 00095 if (file->eof() || file->fail()) { 00096 return false; 00097 } 00098 00099 if (size!=8) { 00100 pnmimage_soft_cat.error() 00101 << "Don't know how to interpret " << size << " bits per pixel!\n"; 00102 return false; 00103 } 00104 00105 return true; 00106 } 00107 00108 static void 00109 read_rgb(xel *row_data, xelval *, istream *file, int x, int repeat) { 00110 xelval red, grn, blu; 00111 red = read_uchar_SI(file); 00112 grn = read_uchar_SI(file); 00113 blu = read_uchar_SI(file); 00114 00115 while (repeat>0) { 00116 PPM_ASSIGN(row_data[x], red, grn, blu); 00117 x++; 00118 repeat--; 00119 } 00120 } 00121 00122 static void 00123 read_alpha(xel *, xelval *alpha_data, istream *file, int x, int repeat) { 00124 xelval alpha = read_uchar_SI(file); 00125 00126 while (repeat>0) { 00127 alpha_data[x] = alpha; 00128 x++; 00129 repeat--; 00130 } 00131 } 00132 00133 static void 00134 read_rgba(xel *row_data, xelval *alpha_data, istream *file, int x, int repeat) { 00135 xelval red, grn, blu, alpha; 00136 red = read_uchar_SI(file); 00137 grn = read_uchar_SI(file); 00138 blu = read_uchar_SI(file); 00139 alpha = read_uchar_SI(file); 00140 00141 while (repeat>0) { 00142 PPM_ASSIGN(row_data[x], red, grn, blu); 00143 alpha_data[x] = alpha; 00144 x++; 00145 repeat--; 00146 } 00147 } 00148 00149 00150 static int 00151 read_scanline(xel *row_data, xelval *alpha_data, int cols, istream *file, 00152 void (*read_data)(xel *row_data, xelval *alpha_data, istream *file, 00153 int x, int repeat), 00154 int ctype) { 00155 if (ctype==UNCOMPRESSED) { 00156 for (int x = 0; x<cols; x++) { 00157 read_data(row_data, alpha_data, file, x, 1); 00158 } 00159 return true; 00160 } else { 00161 int x; 00162 int num; 00163 00164 x = 0; 00165 while (x < cols) { 00166 num = read_uchar_SI(file); 00167 00168 if (num<128) { 00169 // Sequence of non-repeated values. 00170 num++; 00171 if (x+num > cols) { 00172 return false; 00173 } 00174 while (num>0) { 00175 read_data(row_data, alpha_data, file, x, 1); 00176 if (file->eof() || file->fail()) { 00177 return false; 00178 } 00179 x++; 00180 num--; 00181 } 00182 } else { 00183 // Sequence of repeated values. 00184 if (num==128) { 00185 num = read_ushort_SI(file); 00186 } else { 00187 num -= 127; 00188 } 00189 if (x+num > cols) { 00190 return false; 00191 } 00192 read_data(row_data, alpha_data, file, x, num); 00193 if (file->eof() || file->fail()) { 00194 return false; 00195 } 00196 x += num; 00197 } 00198 } 00199 00200 return (x==cols); 00201 } 00202 } 00203 00204 //////////////////////////////////////////////////////////////////// 00205 // Function: PNMFileTypeSoftImage::Constructor 00206 // Access: Public 00207 // Description: 00208 //////////////////////////////////////////////////////////////////// 00209 PNMFileTypeSoftImage:: 00210 PNMFileTypeSoftImage() { 00211 } 00212 00213 //////////////////////////////////////////////////////////////////// 00214 // Function: PNMFileTypeSoftImage::get_name 00215 // Access: Public, Virtual 00216 // Description: Returns a few words describing the file type. 00217 //////////////////////////////////////////////////////////////////// 00218 string PNMFileTypeSoftImage:: 00219 get_name() const { 00220 return "SoftImage"; 00221 } 00222 00223 //////////////////////////////////////////////////////////////////// 00224 // Function: PNMFileTypeSoftImage::get_num_extensions 00225 // Access: Public, Virtual 00226 // Description: Returns the number of different possible filename 00227 // extensions_softimage associated with this particular file type. 00228 //////////////////////////////////////////////////////////////////// 00229 int PNMFileTypeSoftImage:: 00230 get_num_extensions() const { 00231 return num_extensions_softimage; 00232 } 00233 00234 //////////////////////////////////////////////////////////////////// 00235 // Function: PNMFileTypeSoftImage::get_extension 00236 // Access: Public, Virtual 00237 // Description: Returns the nth possible filename extension 00238 // associated with this particular file type, without a 00239 // leading dot. 00240 //////////////////////////////////////////////////////////////////// 00241 string PNMFileTypeSoftImage:: 00242 get_extension(int n) const { 00243 nassertr(n >= 0 && n < num_extensions_softimage, string()); 00244 return extensions_softimage[n]; 00245 } 00246 00247 //////////////////////////////////////////////////////////////////// 00248 // Function: PNMFileTypeSoftImage::get_suggested_extension 00249 // Access: Public, Virtual 00250 // Description: Returns a suitable filename extension (without a 00251 // leading dot) to suggest for files of this type, or 00252 // empty string if no suggestions are available. 00253 //////////////////////////////////////////////////////////////////// 00254 string PNMFileTypeSoftImage:: 00255 get_suggested_extension() const { 00256 return "pic"; 00257 } 00258 00259 //////////////////////////////////////////////////////////////////// 00260 // Function: PNMFileTypeSoftImage::has_magic_number 00261 // Access: Public, Virtual 00262 // Description: Returns true if this particular file type uses a 00263 // magic number to identify it, false otherwise. 00264 //////////////////////////////////////////////////////////////////// 00265 bool PNMFileTypeSoftImage:: 00266 has_magic_number() const { 00267 return true; 00268 } 00269 00270 //////////////////////////////////////////////////////////////////// 00271 // Function: PNMFileTypeSoftImage::matches_magic_number 00272 // Access: Public, Virtual 00273 // Description: Returns true if the indicated "magic number" byte 00274 // stream (the initial few bytes read from the file) 00275 // matches this particular file type, false otherwise. 00276 //////////////////////////////////////////////////////////////////// 00277 bool PNMFileTypeSoftImage:: 00278 matches_magic_number(const string &magic_number) const { 00279 nassertr(magic_number.size() >= 2, false); 00280 int mn = 00281 ((unsigned char)magic_number[0] << 8) | 00282 ((unsigned char)magic_number[1]); 00283 return (mn == SOFTIMAGE_MAGIC1); 00284 } 00285 00286 //////////////////////////////////////////////////////////////////// 00287 // Function: PNMFileTypeSoftImage::make_reader 00288 // Access: Public, Virtual 00289 // Description: Allocates and returns a new PNMReader suitable for 00290 // reading from this file type, if possible. If reading 00291 // from this file type is not supported, returns NULL. 00292 //////////////////////////////////////////////////////////////////// 00293 PNMReader *PNMFileTypeSoftImage:: 00294 make_reader(istream *file, bool owns_file, const string &magic_number) { 00295 init_pnm(); 00296 return new Reader(this, file, owns_file, magic_number); 00297 } 00298 00299 //////////////////////////////////////////////////////////////////// 00300 // Function: PNMFileTypeSoftImage::make_writer 00301 // Access: Public, Virtual 00302 // Description: Allocates and returns a new PNMWriter suitable for 00303 // reading from this file type, if possible. If writing 00304 // files of this type is not supported, returns NULL. 00305 //////////////////////////////////////////////////////////////////// 00306 PNMWriter *PNMFileTypeSoftImage:: 00307 make_writer(ostream *file, bool owns_file) { 00308 init_pnm(); 00309 return new Writer(this, file, owns_file); 00310 } 00311 00312 00313 //////////////////////////////////////////////////////////////////// 00314 // Function: PNMFileTypeSoftImage::Reader::Constructor 00315 // Access: Public 00316 // Description: 00317 //////////////////////////////////////////////////////////////////// 00318 PNMFileTypeSoftImage::Reader:: 00319 Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) : 00320 PNMReader(type, file, owns_file) 00321 { 00322 if (!read_magic_number(_file, magic_number, 4)) { 00323 // No magic number, no image. 00324 if (pnmimage_soft_cat.is_debug()) { 00325 pnmimage_soft_cat.debug() 00326 << "SoftImage image file appears to be empty.\n"; 00327 } 00328 _is_valid = false; 00329 return; 00330 } 00331 00332 int magic1 = 00333 ((unsigned char)magic_number[0] << 8) | 00334 ((unsigned char)magic_number[1]); 00335 int magic2 = 00336 ((unsigned char)magic_number[2] << 8) | 00337 ((unsigned char)magic_number[3]); 00338 00339 if (magic1 != SOFTIMAGE_MAGIC1 || magic2 != SOFTIMAGE_MAGIC2) { 00340 _is_valid = false; 00341 return; 00342 } 00343 00344 // skip version number 00345 read_float(_file); 00346 00347 // Skip comment 00348 _file->seekg(imageCommentLength, ios::cur); 00349 00350 char pict_id[4]; 00351 _file->read(pict_id, 4); 00352 if (_file->gcount() < 4) { 00353 _is_valid = false; 00354 return; 00355 } 00356 00357 if (memcmp(pict_id, "PICT", 4)!=0) { 00358 _is_valid = false; 00359 return; 00360 } 00361 00362 _x_size = read_ushort_SI(_file); 00363 _y_size = read_ushort_SI(_file); 00364 00365 /* float ratio = */ read_float(_file); 00366 /* int fields = */ read_ushort_SI(_file); 00367 read_ushort_SI(_file); 00368 00369 int chained, size, channel; 00370 if (!read_channel_pkt(_file, chained, size, rgb_ctype, channel)) { 00371 _is_valid = false; 00372 return; 00373 } 00374 00375 soft_color = unknown; 00376 00377 if (channel == (RGB_CHANNEL | ALPHA_CHANNEL)) { 00378 // Four components in the first part: RGBA. 00379 soft_color = rgba; 00380 00381 } else if (channel == RGB_CHANNEL) { 00382 // Three components in the first part: RGB. 00383 soft_color = rgb; 00384 00385 if (chained) { 00386 if (!read_channel_pkt(_file, chained, size, alpha_ctype, channel)) { 00387 _is_valid = false; 00388 return; 00389 } 00390 00391 if (channel == ALPHA_CHANNEL) { 00392 // Alpha component in the second part: RGBA. 00393 soft_color = rgb_a; 00394 } 00395 } 00396 } 00397 00398 switch (soft_color) { 00399 case rgb: 00400 _num_channels = 3; 00401 break; 00402 00403 case rgba: 00404 case rgb_a: 00405 _num_channels = 4; 00406 break; 00407 00408 default: 00409 pnmimage_soft_cat.error() 00410 << "Image is not RGB or RGBA!\n"; 00411 _is_valid = false; 00412 return; 00413 } 00414 00415 if (chained) { 00416 pnmimage_soft_cat.error() 00417 << "Unexpected additional channels in image file.\n"; 00418 _is_valid = false; 00419 return; 00420 } 00421 00422 _maxval = 255; 00423 00424 if (pnmimage_soft_cat.is_debug()) { 00425 pnmimage_soft_cat.debug() 00426 << "Reading SoftImage " << *this << "\n"; 00427 } 00428 } 00429 00430 00431 //////////////////////////////////////////////////////////////////// 00432 // Function: PNMFileTypeSoftImage::Reader::supports_read_row 00433 // Access: Public, Virtual 00434 // Description: Returns true if this particular PNMReader supports a 00435 // streaming interface to reading the data: that is, it 00436 // is capable of returning the data one row at a time, 00437 // via repeated calls to read_row(). Returns false if 00438 // the only way to read from this file is all at once, 00439 // via read_data(). 00440 //////////////////////////////////////////////////////////////////// 00441 bool PNMFileTypeSoftImage::Reader:: 00442 supports_read_row() const { 00443 return true; 00444 } 00445 00446 //////////////////////////////////////////////////////////////////// 00447 // Function: PNMFileTypeSoftImage::Reader::read_row 00448 // Access: Public, Virtual 00449 // Description: If supports_read_row(), above, returns true, this 00450 // function may be called repeatedly to read the image, 00451 // one horizontal row at a time, beginning from the top. 00452 // Returns true if the row is successfully read, false 00453 // if there is an error or end of file. 00454 //////////////////////////////////////////////////////////////////// 00455 bool PNMFileTypeSoftImage::Reader:: 00456 read_row(xel *row_data, xelval *alpha_data, int x_size, int) { 00457 if (!is_valid()) { 00458 return false; 00459 } 00460 switch (soft_color) { 00461 case rgb: 00462 if (!read_scanline(row_data, alpha_data, x_size, _file, 00463 read_rgb, rgb_ctype)) { 00464 return false; 00465 } 00466 break; 00467 00468 case rgba: 00469 if (!read_scanline(row_data, alpha_data, x_size, _file, 00470 read_rgba, rgb_ctype)) { 00471 return false; 00472 } 00473 break; 00474 00475 case rgb_a: 00476 if (!read_scanline(row_data, alpha_data, x_size, _file, 00477 read_rgb, rgb_ctype)) { 00478 return false; 00479 } 00480 if (!read_scanline(row_data, alpha_data, x_size, _file, 00481 read_alpha, alpha_ctype)) { 00482 return false; 00483 } 00484 break; 00485 00486 default: 00487 break; 00488 } 00489 00490 return true; 00491 } 00492 00493 00494 static void 00495 write_channel_pkt(ostream *file, 00496 int chained, int size, int type, int channel) { 00497 write_uchar_SI(file, chained); 00498 write_uchar_SI(file, size); 00499 write_uchar_SI(file, type); 00500 write_uchar_SI(file, channel); 00501 } 00502 00503 static void 00504 write_rgb(xel *row_data, xelval *, ostream *file, int x) { 00505 write_uchar_SI(file, PPM_GETR(row_data[x])); 00506 write_uchar_SI(file, PPM_GETG(row_data[x])); 00507 write_uchar_SI(file, PPM_GETB(row_data[x])); 00508 } 00509 00510 static int 00511 compare_rgb(xel *row_data, xelval *, int x1, int x2) { 00512 return PPM_EQUAL(row_data[x1], row_data[x2]); 00513 } 00514 00515 static void 00516 write_gray(xel *row_data, xelval *, ostream *file, int x) { 00517 write_uchar_SI(file, PPM_GETB(row_data[x])); 00518 write_uchar_SI(file, PPM_GETB(row_data[x])); 00519 write_uchar_SI(file, PPM_GETB(row_data[x])); 00520 } 00521 00522 static int 00523 compare_gray(xel *row_data, xelval *, int x1, int x2) { 00524 return (PPM_GETB(row_data[x1])==PPM_GETB(row_data[x2])); 00525 } 00526 00527 static void 00528 write_alpha(xel *, xelval *alpha_data, ostream *file, int x) { 00529 write_uchar_SI(file, alpha_data[x]); 00530 } 00531 00532 static int 00533 compare_alpha(xel *, xelval *alpha_data, int x1, int x2) { 00534 return (alpha_data[x1]==alpha_data[x2]); 00535 } 00536 00537 static void 00538 write_diff(xel *row_data, xelval *alpha_data, ostream *file, 00539 void (*write_data)(xel *row_data, xelval *alpha_data, ostream *file, 00540 int x), 00541 int tox, int length) { 00542 if (length>0) { 00543 nassertv(length<=128); 00544 00545 write_uchar_SI(file, length-1); 00546 while (length>0) { 00547 length--; 00548 write_data(row_data, alpha_data, file, tox-length); 00549 } 00550 } 00551 } 00552 00553 static void 00554 write_same(xel *row_data, xelval *alpha_data, ostream *file, 00555 void (*write_data)(xel *row_data, xelval *alpha_data, ostream *file, 00556 int x), 00557 int tox, int length) { 00558 if (length==1) { 00559 write_diff(row_data, alpha_data, file, write_data, tox, length); 00560 00561 } else if (length>0) { 00562 if (length<128) { 00563 write_uchar_SI(file, length+127); 00564 } else { 00565 write_uchar_SI(file, 128); 00566 write_ushort_SI(file, length); 00567 } 00568 write_data(row_data, alpha_data, file, tox); 00569 } 00570 } 00571 00572 00573 static void 00574 write_scanline(xel *row_data, xelval *alpha_data, int cols, ostream *file, 00575 int (*compare_data)(xel *row_data, xelval *alpha_data, 00576 int x1, int x2), 00577 void (*write_data)(xel *row_data, xelval *alpha_data, 00578 ostream *file, int x)) { 00579 int run_length = 0; 00580 00581 int x = 0; 00582 int same = true; 00583 00584 // Go through each value in the scanline, from beginning to end, looking 00585 // for runs of identical values. 00586 while (x < cols) { 00587 00588 if (same) { 00589 00590 // We have been scanning past a run of identical values. In this case, 00591 // the run is the sequence of values from x-run_length to x-1. 00592 00593 if (!compare_data(row_data, alpha_data, x, x-run_length)) { 00594 // Oops, the end of a run. 00595 00596 if (run_length <= 1) { 00597 // If run_length is only 1, no big deal--this is actually the 00598 // beginning of a different-valued run. 00599 00600 same = false; 00601 00602 } else { 00603 // Write out the old run and begin a new one. We'll be optimistic 00604 // and hope the new run will also represent a sequence of identical 00605 // values (until we find otherwise). 00606 00607 write_same(row_data, alpha_data, file, write_data, x-1, run_length); 00608 same = true; 00609 run_length = 0; 00610 } 00611 } 00612 00613 } else { // !same 00614 00615 // We have been scanning past a run of different values. In this case, 00616 // the run is the sequence of values from x-run_length to x-1. 00617 00618 if (run_length>128) { 00619 // We can't have different runs of more than 128 characters. Close 00620 // off the old run. 00621 00622 int excess = run_length - 128; 00623 write_diff(row_data, alpha_data, file, write_data, x-excess-1, 128); 00624 run_length = excess; 00625 00626 } else if (run_length > 2 && 00627 compare_data(row_data, alpha_data, x, x-1) && 00628 compare_data(row_data, alpha_data, x, x-2)) { 00629 00630 // If the last three values have been the same, then it's time to 00631 // begin a new run of similar values. Close off the old run. 00632 00633 write_diff(row_data, alpha_data, file, write_data, x-3, run_length-2); 00634 same = true; 00635 run_length = 2; 00636 } 00637 } 00638 00639 x++; 00640 run_length++; 00641 } 00642 00643 // We made it all the way to the end. Flush out the last run. 00644 00645 if (run_length>0) { 00646 if (same) { 00647 write_same(row_data, alpha_data, file, write_data, cols-1, run_length); 00648 } else { 00649 00650 // Mighty unlikely, but we might have just run over the 00651 // 128-pixel limit. 00652 if (run_length>128) { 00653 int excess = run_length - 128; 00654 write_diff(row_data, alpha_data, file, write_data, cols-excess-1, 128); 00655 run_length = excess; 00656 } 00657 00658 write_diff(row_data, alpha_data, file, write_data, cols-1, run_length); 00659 } 00660 } 00661 } 00662 00663 //////////////////////////////////////////////////////////////////// 00664 // Function: PNMFileTypeSoftImage::Writer::Constructor 00665 // Access: Public 00666 // Description: 00667 //////////////////////////////////////////////////////////////////// 00668 PNMFileTypeSoftImage::Writer:: 00669 Writer(PNMFileType *type, ostream *file, bool owns_file) : 00670 PNMWriter(type, file, owns_file) 00671 { 00672 } 00673 00674 //////////////////////////////////////////////////////////////////// 00675 // Function: PNMFileTypeSoftImage::Writer::supports_write_row 00676 // Access: Public, Virtual 00677 // Description: Returns true if this particular PNMWriter supports a 00678 // streaming interface to writing the data: that is, it 00679 // is capable of writing the image one row at a time, 00680 // via repeated calls to write_row(). Returns false if 00681 // the only way to write from this file is all at once, 00682 // via write_data(). 00683 //////////////////////////////////////////////////////////////////// 00684 bool PNMFileTypeSoftImage::Writer:: 00685 supports_write_row() const { 00686 return true; 00687 } 00688 00689 //////////////////////////////////////////////////////////////////// 00690 // Function: PNMFileTypeSoftImage::Writer::write_header 00691 // Access: Public, Virtual 00692 // Description: If supports_write_row(), above, returns true, this 00693 // function may be called to write out the image header 00694 // in preparation to writing out the image data one row 00695 // at a time. Returns true if the header is 00696 // successfully written, false if there is an error. 00697 // 00698 // It is the user's responsibility to fill in the header 00699 // data via calls to set_x_size(), set_num_channels(), 00700 // etc., or copy_header_from(), before calling 00701 // write_header(). 00702 //////////////////////////////////////////////////////////////////// 00703 bool PNMFileTypeSoftImage::Writer:: 00704 write_header() { 00705 write_ushort_SI(_file, SOFTIMAGE_MAGIC1); 00706 write_ushort_SI(_file, SOFTIMAGE_MAGIC2); 00707 write_float(_file, imageVersionNumber); 00708 00709 _file->write(imageComment, imageCommentLength); 00710 _file->write("PICT", 4); 00711 00712 write_ushort_SI(_file, _x_size); 00713 write_ushort_SI(_file, _y_size); 00714 00715 write_float(_file, 1.0); // pixel aspect ratio; we don't know. 00716 write_ushort_SI(_file, 3); // fields value; we don't really know either. 00717 write_ushort_SI(_file, 0); // padding 00718 00719 // There doesn't seem to be a variation on SoftImage image formats for 00720 // grayscale images. We'll write out grayscale as a 3-channel image. 00721 00722 if (has_alpha()) { 00723 write_channel_pkt(_file, 1, 8, MIXED_RUN_LENGTH, RGB_CHANNEL); 00724 write_channel_pkt(_file, 0, 8, MIXED_RUN_LENGTH, ALPHA_CHANNEL); 00725 } else { 00726 write_channel_pkt(_file, 0, 8, MIXED_RUN_LENGTH, RGB_CHANNEL); 00727 } 00728 00729 return true; 00730 } 00731 00732 //////////////////////////////////////////////////////////////////// 00733 // Function: PNMFileTypeSoftImage::Writer::write_row 00734 // Access: Public, Virtual 00735 // Description: If supports_write_row(), above, returns true, this 00736 // function may be called repeatedly to write the image, 00737 // one horizontal row at a time, beginning from the top. 00738 // Returns true if the row is successfully written, 00739 // false if there is an error. 00740 // 00741 // You must first call write_header() before writing the 00742 // individual rows. It is also important to delete the 00743 // PNMWriter class after successfully writing the last 00744 // row. Failing to do this may result in some data not 00745 // getting flushed! 00746 //////////////////////////////////////////////////////////////////// 00747 bool PNMFileTypeSoftImage::Writer:: 00748 write_row(xel *row_data, xelval *alpha_data) { 00749 if (is_grayscale()) { 00750 write_scanline(row_data, alpha_data, _x_size, _file, compare_gray, write_gray); 00751 00752 } else { 00753 write_scanline(row_data, alpha_data, _x_size, _file, compare_rgb, write_rgb); 00754 } 00755 00756 if (has_alpha()) { 00757 write_scanline(row_data, alpha_data, _x_size, _file, compare_alpha, write_alpha); 00758 } 00759 00760 return !_file->fail(); 00761 } 00762 00763 00764 00765 //////////////////////////////////////////////////////////////////// 00766 // Function: PNMFileTypeSoftImage::register_with_read_factory 00767 // Access: Public, Static 00768 // Description: Registers the current object as something that can be 00769 // read from a Bam file. 00770 //////////////////////////////////////////////////////////////////// 00771 void PNMFileTypeSoftImage:: 00772 register_with_read_factory() { 00773 BamReader::get_factory()-> 00774 register_factory(get_class_type(), make_PNMFileTypeSoftImage); 00775 } 00776 00777 //////////////////////////////////////////////////////////////////// 00778 // Function: PNMFileTypeSoftImage::make_PNMFileTypeSoftImage 00779 // Access: Protected, Static 00780 // Description: This method is called by the BamReader when an object 00781 // of this type is encountered in a Bam file; it should 00782 // allocate and return a new object with all the data 00783 // read. 00784 // 00785 // In the case of the PNMFileType objects, since these 00786 // objects are all shared, we just pull the object from 00787 // the registry. 00788 //////////////////////////////////////////////////////////////////// 00789 TypedWritable *PNMFileTypeSoftImage:: 00790 make_PNMFileTypeSoftImage(const FactoryParams ¶ms) { 00791 return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type()); 00792 } 00793 00794 #endif // HAVE_SOFTIMAGE_PIC