Panda3D

imageFile.cxx

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