Panda3D

pnmFileTypeSoftImage.cxx

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 &params) {
00791   return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
00792 }
00793 
00794 #endif  // HAVE_SOFTIMAGE_PIC
 All Classes Functions Variables Enumerations