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

pandatool/src/egg-palettize/imageFile.cxx

Go to the documentation of this file.
00001 // Filename: imageFile.cxx
00002 // Created by:  drose (29Nov00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "imageFile.h"
00020 #include "palettizer.h"
00021 #include "filenameUnifier.h"
00022 #include "paletteGroup.h"
00023 
00024 #include "pnmImage.h"
00025 #include "pnmFileType.h"
00026 #include "eggTexture.h"
00027 #include "datagram.h"
00028 #include "datagramIterator.h"
00029 #include "bamReader.h"
00030 #include "bamWriter.h"
00031 
00032 TypeHandle ImageFile::_type_handle;
00033 
00034 ////////////////////////////////////////////////////////////////////
00035 //     Function: ImageFile::Constructor
00036 //       Access: Public
00037 //  Description:
00038 ////////////////////////////////////////////////////////////////////
00039 ImageFile::
00040 ImageFile() {
00041   _alpha_file_channel = 0;
00042   _size_known = false;
00043   _x_size = 0;
00044   _y_size = 0;
00045 }
00046 
00047 ////////////////////////////////////////////////////////////////////
00048 //     Function: ImageFile::make_shadow_image
00049 //       Access: Public
00050 //  Description: Sets up the ImageFile as a "shadow image" of a
00051 //               particular PaletteImage.  This is a temporary
00052 //               ImageFile that's used to read and write the shadow
00053 //               palette image, which is used to keep a working copy
00054 //               of the palette.
00055 ////////////////////////////////////////////////////////////////////
00056 void ImageFile::
00057 make_shadow_image(const string &basename) {
00058   _properties._color_type = pal->_shadow_color_type;
00059   _properties._alpha_type = pal->_shadow_alpha_type;
00060 
00061   set_filename(pal->_shadow_dirname, basename);
00062 }
00063 
00064 ////////////////////////////////////////////////////////////////////
00065 //     Function: ImageFile::is_size_known
00066 //       Access: Public
00067 //  Description: Returns true if the size of the image file is known,
00068 //               false otherwise.
00069 ////////////////////////////////////////////////////////////////////
00070 bool ImageFile::
00071 is_size_known() const {
00072   return _size_known;
00073 }
00074 
00075 ////////////////////////////////////////////////////////////////////
00076 //     Function: ImageFile::get_x_size
00077 //       Access: Public
00078 //  Description: Returns the size of the image file in pixels in the X
00079 //               direction.  It is an error to call this unless
00080 //               is_size_known() returns true.
00081 ////////////////////////////////////////////////////////////////////
00082 int ImageFile::
00083 get_x_size() const {
00084   nassertr(is_size_known(), 0);
00085   return _x_size;
00086 }
00087 
00088 ////////////////////////////////////////////////////////////////////
00089 //     Function: ImageFile::get_y_size
00090 //       Access: Public
00091 //  Description: Returns the size of the image file in pixels in the Y
00092 //               direction.  It is an error to call this unless
00093 //               is_size_known() returns true.
00094 ////////////////////////////////////////////////////////////////////
00095 int ImageFile::
00096 get_y_size() const {
00097   nassertr(is_size_known(), 0);
00098   return _y_size;
00099 }
00100 
00101 ////////////////////////////////////////////////////////////////////
00102 //     Function: ImageFile::has_num_channels
00103 //       Access: Public
00104 //  Description: Returns true if the number of channels in the image
00105 //               is known, false otherwise.
00106 ////////////////////////////////////////////////////////////////////
00107 bool ImageFile::
00108 has_num_channels() const {
00109   return _properties.has_num_channels();
00110 }
00111 
00112 ////////////////////////////////////////////////////////////////////
00113 //     Function: ImageFile::get_num_channels
00114 //       Access: Public
00115 //  Description: Returns the number of channels of the image.  It is
00116 //               an error to call this unless has_num_channels()
00117 //               returns true.
00118 ////////////////////////////////////////////////////////////////////
00119 int ImageFile::
00120 get_num_channels() const {
00121   return _properties.get_num_channels();
00122 }
00123 
00124 ////////////////////////////////////////////////////////////////////
00125 //     Function: ImageFile::get_properties
00126 //       Access: Public
00127 //  Description: Returns the grouping properties of the image.
00128 ////////////////////////////////////////////////////////////////////
00129 const TextureProperties &ImageFile::
00130 get_properties() const {
00131   return _properties;
00132 }
00133 
00134 ////////////////////////////////////////////////////////////////////
00135 //     Function: ImageFile::clear_basic_properties
00136 //       Access: Public
00137 //  Description: Resets the properties to a neutral state, for
00138 //               instance in preparation for calling
00139 //               update_properties() with all the known contributing
00140 //               properties.
00141 ////////////////////////////////////////////////////////////////////
00142 void ImageFile::
00143 clear_basic_properties() {
00144   _properties.clear_basic();
00145 }
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: ImageFile::update_properties
00149 //       Access: Public
00150 //  Description: If the indicate TextureProperties structure is more
00151 //               specific than this one, updates this one.
00152 ////////////////////////////////////////////////////////////////////
00153 void ImageFile::
00154 update_properties(const TextureProperties &properties) {
00155   _properties.update_properties(properties);
00156 }
00157 
00158 ////////////////////////////////////////////////////////////////////
00159 //     Function: ImageFile::set_filename
00160 //       Access: Public
00161 //  Description: Sets the filename, and if applicable, the
00162 //               alpha_filename, from the indicated basename.  The
00163 //               extension appropriate to the image file type
00164 //               specified in _color_type (and _alpha_type) is
00165 //               automatically applied.
00166 ////////////////////////////////////////////////////////////////////
00167 void ImageFile::
00168 set_filename(PaletteGroup *group, const string &basename) {
00169   // Synthesize the directory name based on the map_dirname set to the
00170   // palettizer, and the group's dirname.
00171   string dirname;
00172   string::iterator pi;
00173   pi = pal->_map_dirname.begin();
00174   while (pi != pal->_map_dirname.end()) {
00175     if (*pi == '%') {
00176       ++pi;
00177       switch (*pi) {
00178       case '%':
00179         dirname += '%';
00180         break;
00181 
00182       case 'g':
00183         if (group != (PaletteGroup *)NULL) {
00184           dirname += group->get_dirname();
00185         }
00186         break;
00187       }
00188     } else {
00189       dirname += *pi;
00190     }
00191     ++pi;
00192   }
00193 
00194   set_filename(dirname, basename);
00195 }
00196 
00197 ////////////////////////////////////////////////////////////////////
00198 //     Function: ImageFile::set_filename
00199 //       Access: Public
00200 //  Description: Sets the filename, and if applicable, the
00201 //               alpha_filename, from the indicated basename.  The
00202 //               extension appropriate to the image file type
00203 //               specified in _color_type (and _alpha_type) is
00204 //               automatically applied.
00205 ////////////////////////////////////////////////////////////////////
00206 void ImageFile::
00207 set_filename(const string &dirname, const string &basename) {
00208   _filename = Filename(dirname, basename);
00209 
00210   // Since we use set_extension() here, if the file already contains a
00211   // filename extension it will be lost.
00212 
00213   // It is particularly important to note that a single embedded dot
00214   // will appear to begin a filename extension, so if the filename
00215   // does *not* contain an extension, but does contain an embedded
00216   // dot, the filename will be truncated at that dot.  It is therefore
00217   // important that the supplied basename always contains either an
00218   // extension or a terminating dot.
00219 
00220   if (_properties._color_type != (PNMFileType *)NULL) {
00221     _filename.set_extension
00222       (_properties._color_type->get_suggested_extension());
00223   }
00224 
00225   if (_properties._alpha_type != (PNMFileType *)NULL) {
00226     _alpha_filename = _filename.get_fullpath_wo_extension() + "_a.";
00227     _alpha_filename.set_extension
00228       (_properties._alpha_type->get_suggested_extension());
00229   }
00230 }
00231 
00232 ////////////////////////////////////////////////////////////////////
00233 //     Function: ImageFile::get_filename
00234 //       Access: Public
00235 //  Description: Returns the primary filename of the image file.
00236 ////////////////////////////////////////////////////////////////////
00237 const Filename &ImageFile::
00238 get_filename() const {
00239   return _filename;
00240 }
00241 
00242 ////////////////////////////////////////////////////////////////////
00243 //     Function: ImageFile::get_alpha_filename
00244 //       Access: Public
00245 //  Description: Returns the alpha filename of the image file.  This
00246 //               is the name of the file that contains the alpha
00247 //               channel, if it is stored in a separate file, or the
00248 //               empty string if it is not.
00249 ////////////////////////////////////////////////////////////////////
00250 const Filename &ImageFile::
00251 get_alpha_filename() const {
00252   return _alpha_filename;
00253 }
00254 
00255 ////////////////////////////////////////////////////////////////////
00256 //     Function: ImageFile::get_alpha_file_channel
00257 //       Access: Public
00258 //  Description: Returns the particular channel number of the alpha
00259 //               image file from which the alpha channel should be
00260 //               extracted.  This is normally 0 to represent the
00261 //               grayscale combination of r, g, and b; or it may be a
00262 //               1-based channel number (for instance, 4 for the alpha
00263 //               channel of a 4-component image).
00264 ////////////////////////////////////////////////////////////////////
00265 int ImageFile::
00266 get_alpha_file_channel() const {
00267   return _alpha_file_channel;
00268 }
00269 
00270 
00271 ////////////////////////////////////////////////////////////////////
00272 //     Function: ImageFile::exists
00273 //       Access: Public
00274 //  Description: Returns true if the file or files named by the image
00275 //               file exist, false otherwise.
00276 ////////////////////////////////////////////////////////////////////
00277 bool ImageFile::
00278 exists() const {
00279   if (!_filename.exists()) {
00280     return false;
00281   }
00282   if (_properties._alpha_type != (PNMFileType *)NULL &&
00283       _properties.uses_alpha() &&
00284       !_alpha_filename.empty()) {
00285     if (!_alpha_filename.exists()) {
00286       return false;
00287     }
00288   }
00289 
00290   return true;
00291 }
00292 
00293 ////////////////////////////////////////////////////////////////////
00294 //     Function: ImageFile::read
00295 //       Access: Public
00296 //  Description: Reads in the image (or images, if the alpha_filename
00297 //               is separate) and stores it in the indicated PNMImage.
00298 //               Returns true on success, false on failure.
00299 ////////////////////////////////////////////////////////////////////
00300 bool ImageFile::
00301 read(PNMImage &image) const {
00302   nassertr(!_filename.empty(), false);
00303 
00304   image.set_type(_properties._color_type);
00305   nout << "Reading " << FilenameUnifier::make_user_filename(_filename) << "\n";
00306   if (!image.read(_filename)) {
00307     nout << "Unable to read.\n";
00308     return false;
00309   }
00310 
00311   if (!_alpha_filename.empty() && _alpha_filename.exists()) {
00312     // Read in a separate color image and an alpha channel image.
00313     PNMImage alpha_image;
00314     alpha_image.set_type(_properties._alpha_type);
00315     nout << "Reading " << FilenameUnifier::make_user_filename(_alpha_filename) << "\n";
00316     if (!alpha_image.read(_alpha_filename)) {
00317       nout << "Unable to read.\n";
00318       return false;
00319     }
00320     if (image.get_x_size() != alpha_image.get_x_size() ||
00321         image.get_y_size() != alpha_image.get_y_size()) {
00322       return false;
00323     }
00324 
00325     image.add_alpha();
00326 
00327     if (_alpha_file_channel == 4 || 
00328         (_alpha_file_channel == 2 && alpha_image.get_num_channels() == 2)) {
00329       // Use the alpha channel.
00330       for (int x = 0; x < image.get_x_size(); x++) {
00331         for (int y = 0; y < image.get_y_size(); y++) {
00332           image.set_alpha(x, y, alpha_image.get_alpha(x, y));
00333         }
00334       }
00335       
00336     } else if (_alpha_file_channel >= 1 && _alpha_file_channel <= 3 &&
00337                alpha_image.get_num_channels() >= 3) {
00338       // Use the appropriate red, green, or blue channel.
00339       for (int x = 0; x < image.get_x_size(); x++) {
00340         for (int y = 0; y < image.get_y_size(); y++) {
00341           image.set_alpha(x, y, alpha_image.get_channel_val(x, y, _alpha_file_channel - 1));
00342         }
00343       }
00344       
00345     } else {
00346       // Use the grayscale channel.
00347       for (int x = 0; x < image.get_x_size(); x++) {
00348         for (int y = 0; y < image.get_y_size(); y++) {
00349           image.set_alpha(x, y, alpha_image.get_gray(x, y));
00350         }
00351       }
00352     }
00353   }
00354 
00355   return true;
00356 }
00357 
00358 ////////////////////////////////////////////////////////////////////
00359 //     Function: ImageFile::write
00360 //       Access: Public
00361 //  Description: Writes out the image in the indicated PNMImage to the
00362 //               _filename and/or _alpha_filename.  Returns true on
00363 //               success, false on failure.
00364 ////////////////////////////////////////////////////////////////////
00365 bool ImageFile::
00366 write(const PNMImage &image) const {
00367   nassertr(!_filename.empty(), false);
00368 
00369   if (!image.has_alpha() ||
00370       _properties._alpha_type == (PNMFileType *)NULL) {
00371     if (!_alpha_filename.empty() && _alpha_filename.exists()) {
00372       nout << "Deleting " << FilenameUnifier::make_user_filename(_alpha_filename) << "\n";
00373       _alpha_filename.unlink();
00374     }
00375     nout << "Writing " << FilenameUnifier::make_user_filename(_filename) << "\n";
00376     _filename.make_dir();
00377     if (!image.write(_filename, _properties._color_type)) {
00378       nout << "Unable to write.\n";
00379       return false;
00380     }
00381     return true;
00382   }
00383 
00384   // Write out a separate color image and an alpha channel image.
00385   PNMImage alpha_image(image.get_x_size(), image.get_y_size(), 1,
00386                        image.get_maxval());
00387   for (int y = 0; y < image.get_y_size(); y++) {
00388     for (int x = 0; x < image.get_x_size(); x++) {
00389       alpha_image.set_gray_val(x, y, image.get_alpha_val(x, y));
00390     }
00391   }
00392 
00393   PNMImage image_copy(image);
00394   image_copy.remove_alpha();
00395   nout << "Writing " << FilenameUnifier::make_user_filename(_filename) << "\n";
00396   _filename.make_dir();
00397   if (!image_copy.write(_filename, _properties._color_type)) {
00398     nout << "Unable to write.\n";
00399     return false;
00400   }
00401 
00402   nout << "Writing " << FilenameUnifier::make_user_filename(_alpha_filename) << "\n";
00403   _alpha_filename.make_dir();
00404   if (!alpha_image.write(_alpha_filename, _properties._alpha_type)) {
00405     nout << "Unable to write.\n";
00406     return false;
00407   }
00408   return true;
00409 }
00410 
00411 ////////////////////////////////////////////////////////////////////
00412 //     Function: ImageFile::unlink
00413 //       Access: Public
00414 //  Description: Deletes the image file or files.
00415 ////////////////////////////////////////////////////////////////////
00416 void ImageFile::
00417 unlink() {
00418   if (!_filename.empty() && _filename.exists()) {
00419     nout << "Deleting " << FilenameUnifier::make_user_filename(_filename) << "\n";
00420     _filename.unlink();
00421   }
00422   if (!_alpha_filename.empty() && _alpha_filename.exists()) {
00423     nout << "Deleting " << FilenameUnifier::make_user_filename(_alpha_filename) << "\n";
00424     _alpha_filename.unlink();
00425   }
00426 }
00427 
00428 ////////////////////////////////////////////////////////////////////
00429 //     Function: ImageFile::update_egg_tex
00430 //       Access: Public
00431 //  Description: Sets the indicated EggTexture to refer to this file.
00432 ////////////////////////////////////////////////////////////////////
00433 void ImageFile::
00434 update_egg_tex(EggTexture *egg_tex) const {
00435   nassertv(egg_tex != (EggTexture *)NULL);
00436 
00437   egg_tex->set_filename(FilenameUnifier::make_egg_filename(_filename));
00438 
00439   if (_properties.uses_alpha() &&
00440       !_alpha_filename.empty()) {
00441     egg_tex->set_alpha_filename(FilenameUnifier::make_egg_filename(_alpha_filename));
00442     egg_tex->set_alpha_file_channel(_alpha_file_channel);
00443   } else {
00444     egg_tex->clear_alpha_filename();
00445     egg_tex->clear_alpha_file_channel();
00446   }
00447 
00448   _properties.update_egg_tex(egg_tex);
00449 }
00450 
00451 ////////////////////////////////////////////////////////////////////
00452 //     Function: ImageFile::output_filename
00453 //       Access: Public
00454 //  Description: Writes the filename (or pair of filenames) to the
00455 //               indicated output stream.
00456 ////////////////////////////////////////////////////////////////////
00457 void ImageFile::
00458 output_filename(ostream &out) const {
00459   out << FilenameUnifier::make_user_filename(_filename); 
00460   if (_properties.uses_alpha() && !_alpha_filename.empty()) {
00461     out << " " << FilenameUnifier::make_user_filename(_alpha_filename);
00462   }
00463 }
00464 
00465 ////////////////////////////////////////////////////////////////////
00466 //     Function: ImageFile::write_datagram
00467 //       Access: Public, Virtual
00468 //  Description: Fills the indicated datagram up with a binary
00469 //               representation of the current object, in preparation
00470 //               for writing to a Bam file.
00471 ////////////////////////////////////////////////////////////////////
00472 void ImageFile::
00473 write_datagram(BamWriter *writer, Datagram &datagram) {
00474   TypedWritable::write_datagram(writer, datagram);
00475   _properties.write_datagram(writer, datagram);
00476   datagram.add_string(FilenameUnifier::make_bam_filename(_filename));
00477   datagram.add_string(FilenameUnifier::make_bam_filename(_alpha_filename));
00478   datagram.add_uint8(_alpha_file_channel);
00479   datagram.add_bool(_size_known);
00480   datagram.add_int32(_x_size);
00481   datagram.add_int32(_y_size);
00482 }
00483 
00484 ////////////////////////////////////////////////////////////////////
00485 //     Function: ImageFile::complete_pointers
00486 //       Access: Public, Virtual
00487 //  Description: Called after the object is otherwise completely read
00488 //               from a Bam file, this function's job is to store the
00489 //               pointers that were retrieved from the Bam file for
00490 //               each pointer object written.  The return value is the
00491 //               number of pointers processed from the list.
00492 ////////////////////////////////////////////////////////////////////
00493 int ImageFile::
00494 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00495   int pi = TypedWritable::complete_pointers(p_list, manager);
00496 
00497   pi += _properties.complete_pointers(p_list + pi, manager);
00498 
00499   return pi;
00500 }
00501 
00502 ////////////////////////////////////////////////////////////////////
00503 //     Function: ImageFile::fillin
00504 //       Access: Protected
00505 //  Description: Reads the binary data from the given datagram
00506 //               iterator, which was written by a previous call to
00507 //               write_datagram().
00508 ////////////////////////////////////////////////////////////////////
00509 void ImageFile::
00510 fillin(DatagramIterator &scan, BamReader *manager) {
00511   TypedWritable::fillin(scan, manager);
00512   _properties.fillin(scan, manager);
00513   _filename = FilenameUnifier::get_bam_filename(scan.get_string());
00514   _alpha_filename = FilenameUnifier::get_bam_filename(scan.get_string());
00515   if (Palettizer::_read_pi_version >= 10) {
00516     _alpha_file_channel = scan.get_uint8();
00517   } else {
00518     _alpha_file_channel = 0;
00519   }
00520   _size_known = scan.get_bool();
00521   _x_size = scan.get_int32();
00522   _y_size = scan.get_int32();
00523 }

Generated on Fri May 2 03:17:41 2003 for Panda-Tool by doxygen1.3