Panda3D
|
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 }