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

pandatool/src/egg-palettize/paletteImage.cxx

Go to the documentation of this file.
00001 // Filename: paletteImage.cxx
00002 // Created by:  drose (01Dec00)
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 "paletteImage.h"
00020 #include "palettePage.h"
00021 #include "paletteGroup.h"
00022 #include "texturePlacement.h"
00023 #include "palettizer.h"
00024 #include "textureImage.h"
00025 #include "sourceTextureImage.h"
00026 #include "filenameUnifier.h"
00027 
00028 #include <indent.h>
00029 #include <datagram.h>
00030 #include <datagramIterator.h>
00031 #include <bamReader.h>
00032 #include <bamWriter.h>
00033 
00034 #include <algorithm>
00035 
00036 TypeHandle PaletteImage::_type_handle;
00037 
00038 ////////////////////////////////////////////////////////////////////
00039 //     Function: PaletteImage::ClearedRegion::Default Constructor
00040 //       Access: Public
00041 //  Description: The default constructor is only for the convenience
00042 //               of the bam reader.
00043 ////////////////////////////////////////////////////////////////////
00044 PaletteImage::ClearedRegion::
00045 ClearedRegion() {
00046   _x = 0;
00047   _y = 0;
00048   _x_size = 0;
00049   _y_size = 0;
00050 }
00051 
00052 ////////////////////////////////////////////////////////////////////
00053 //     Function: PaletteImage::ClearedRegion::Constructor
00054 //       Access: Public
00055 //  Description:
00056 ////////////////////////////////////////////////////////////////////
00057 PaletteImage::ClearedRegion::
00058 ClearedRegion(TexturePlacement *placement) {
00059   _x = placement->get_placed_x();
00060   _y = placement->get_placed_y();
00061   _x_size = placement->get_placed_x_size();
00062   _y_size = placement->get_placed_y_size();
00063 }
00064 
00065 ////////////////////////////////////////////////////////////////////
00066 //     Function: PaletteImage::ClearedRegion::Copy Constructor
00067 //       Access: Public
00068 //  Description:
00069 ////////////////////////////////////////////////////////////////////
00070 PaletteImage::ClearedRegion::
00071 ClearedRegion(const PaletteImage::ClearedRegion &copy) :
00072   _x(copy._x),
00073   _y(copy._y),
00074   _x_size(copy._x_size),
00075   _y_size(copy._y_size)
00076 {
00077 }
00078 
00079 ////////////////////////////////////////////////////////////////////
00080 //     Function: PaletteImage::ClearedRegion::Copy Assignment Operator
00081 //       Access: Public
00082 //  Description:
00083 ////////////////////////////////////////////////////////////////////
00084 void PaletteImage::ClearedRegion::
00085 operator = (const PaletteImage::ClearedRegion &copy) {
00086   _x = copy._x;
00087   _y = copy._y;
00088   _x_size = copy._x_size;
00089   _y_size = copy._y_size;
00090 }
00091 
00092 ////////////////////////////////////////////////////////////////////
00093 //     Function: PaletteImage::ClearedRegion::clear
00094 //       Access: Public
00095 //  Description: Sets the appropriate region of the image to black.
00096 ////////////////////////////////////////////////////////////////////
00097 void PaletteImage::ClearedRegion::
00098 clear(PNMImage &image) {
00099   for (int y = _y; y < _y + _y_size; y++) {
00100     for (int x = _x; x < _x + _x_size; x++) {
00101       image.set_xel_val(x, y, 0);
00102     }
00103   }
00104   if (image.has_alpha()) {
00105     for (int y = _y; y < _y + _y_size; y++) {
00106       for (int x = _x; x < _x + _x_size; x++) {
00107         image.set_alpha_val(x, y, 0);
00108       }
00109     }
00110   }
00111 }
00112 
00113 ////////////////////////////////////////////////////////////////////
00114 //     Function: PaletteImage::ClearedRegion::write_datagram
00115 //       Access: Public
00116 //  Description: Writes the contents of the ClearedRegion to the
00117 //               indicated datagram.
00118 ////////////////////////////////////////////////////////////////////
00119 void PaletteImage::ClearedRegion::
00120 write_datagram(Datagram &datagram) const {
00121   datagram.add_int32(_x);
00122   datagram.add_int32(_y);
00123   datagram.add_int32(_x_size);
00124   datagram.add_int32(_y_size);
00125 }
00126 
00127 ////////////////////////////////////////////////////////////////////
00128 //     Function: PaletteImage::ClearedRegion::write_datagram
00129 //       Access: Public
00130 //  Description: Extracts the contents of the ClearedRegion from the
00131 //               indicated datagram.
00132 ////////////////////////////////////////////////////////////////////
00133 void PaletteImage::ClearedRegion::
00134 fillin(DatagramIterator &scan) {
00135   _x = scan.get_int32();
00136   _y = scan.get_int32();
00137   _x_size = scan.get_int32();
00138   _y_size = scan.get_int32();
00139 }
00140 
00141 
00142 
00143 
00144 
00145 
00146 ////////////////////////////////////////////////////////////////////
00147 //     Function: PaletteImage::Default Constructor
00148 //       Access: Private
00149 //  Description: The default constructor is only for the convenience
00150 //               of the Bam reader.
00151 ////////////////////////////////////////////////////////////////////
00152 PaletteImage::
00153 PaletteImage() {
00154   _page = (PalettePage *)NULL;
00155   _index = 0;
00156   _new_image = false;
00157   _got_image = false;
00158 }
00159 
00160 ////////////////////////////////////////////////////////////////////
00161 //     Function: PaletteImage::Constructor
00162 //       Access: Public
00163 //  Description:
00164 ////////////////////////////////////////////////////////////////////
00165 PaletteImage::
00166 PaletteImage(PalettePage *page, int index) :
00167   _page(page),
00168   _index(index)
00169 {
00170   _properties = page->get_properties();
00171   _size_known = true;
00172   _x_size = pal->_pal_x_size;
00173   _y_size = pal->_pal_y_size;
00174   _new_image = true;
00175   _got_image = false;
00176 
00177   ostringstream name;
00178   // We must end the basename with a dot, so that it does not appear
00179   // to have a filename extension.  Otherwise, an embedded dot in the
00180   // group's name would make everything following appear to be an
00181   // extension, which would get lost in the set_filename() call.
00182   name << page->get_group()->get_name() << "_palette_"
00183        << page->get_name() << "_" << index + 1 << ".";
00184 
00185   _basename = name.str();
00186 
00187   set_filename(page->get_group(), _basename);
00188   _shadow_image.make_shadow_image(_basename);
00189 }
00190 
00191 ////////////////////////////////////////////////////////////////////
00192 //     Function: PaletteImage::get_page
00193 //       Access: Public
00194 //  Description: Returns the particular PalettePage this image is
00195 //               associated with.
00196 ////////////////////////////////////////////////////////////////////
00197 PalettePage *PaletteImage::
00198 get_page() const {
00199   return _page;
00200 }
00201 
00202 ////////////////////////////////////////////////////////////////////
00203 //     Function: PaletteImage::is_empty
00204 //       Access: Public
00205 //  Description: Returns true if there are no textures, or only one
00206 //               "solitary" texture, placed on the image.  In either
00207 //               case, the PaletteImage need not be generated.
00208 ////////////////////////////////////////////////////////////////////
00209 bool PaletteImage::
00210 is_empty() const {
00211   if (_placements.empty()) {
00212     // The image is genuinely empty.
00213     return true;
00214 
00215   } else if (_placements.size() == 1) {
00216     // If the image has exactly one texture, we consider the image
00217     // empty only if the texture is actually flagged as 'solitary'.
00218     return (_placements[0]->get_omit_reason() == OR_solitary);
00219 
00220   } else {
00221     // The image has more than one texture, so it's definitely not
00222     // empty.
00223     return false;
00224   }
00225 }
00226 
00227 ////////////////////////////////////////////////////////////////////
00228 //     Function: PaletteImage::count_utilization
00229 //       Access: Public
00230 //  Description: Returns the fraction of the PaletteImage that is
00231 //               actually used by any textures.  This is 1.0 if every
00232 //               pixel in the PaletteImage is used, or 0.0 if none
00233 //               are.  Normally it will be somewhere in between.
00234 ////////////////////////////////////////////////////////////////////
00235 double PaletteImage::
00236 count_utilization() const {
00237   int used_pixels = 0;
00238 
00239   Placements::const_iterator pi;
00240   for (pi = _placements.begin(); pi != _placements.end(); ++pi) {
00241     TexturePlacement *placement = (*pi);
00242 
00243     int texture_pixels =
00244       placement->get_placed_x_size() *
00245       placement->get_placed_y_size();
00246     used_pixels += texture_pixels;
00247   }
00248 
00249   int total_pixels = get_x_size() * get_y_size();
00250 
00251   return (double)used_pixels / (double)total_pixels;
00252 }
00253 
00254 ////////////////////////////////////////////////////////////////////
00255 //     Function: PaletteImage::count_coverage
00256 //       Access: Public
00257 //  Description: Returns the a weighted average of the fraction of
00258 //               coverage represented by all of the textures placed on
00259 //               the palette.  This number represents the fraction of
00260 //               wasted pixels in the palette image consumed by
00261 //               copying the same pixels multiple times into the
00262 //               palette, or if the number is negative, it represents
00263 //               the fraction of pixels saved by not having to copy
00264 //               the entire texture into the palette.
00265 ////////////////////////////////////////////////////////////////////
00266 double PaletteImage::
00267 count_coverage() const {
00268   int coverage_pixels = 0;
00269 
00270   Placements::const_iterator pi;
00271   for (pi = _placements.begin(); pi != _placements.end(); ++pi) {
00272     TexturePlacement *placement = (*pi);
00273     TextureImage *texture = placement->get_texture();
00274     nassertr(texture != (TextureImage *)NULL, 0.0);
00275 
00276     int orig_pixels =
00277       texture->get_x_size() *
00278       texture->get_y_size();
00279     int placed_pixels =
00280       placement->get_placed_x_size() *
00281       placement->get_placed_y_size();
00282 
00283     coverage_pixels += placed_pixels - orig_pixels;
00284   }
00285 
00286   int total_pixels = get_x_size() * get_y_size();
00287 
00288   return (double)coverage_pixels / (double)total_pixels;
00289 }
00290 
00291 ////////////////////////////////////////////////////////////////////
00292 //     Function: PaletteImage::place
00293 //       Access: Public
00294 //  Description: Attempts to place the indicated texture on the image.
00295 //               Returns true if successful, or false if there was no
00296 //               available space.
00297 ////////////////////////////////////////////////////////////////////
00298 bool PaletteImage::
00299 place(TexturePlacement *placement) {
00300   nassertr(placement->is_size_known(), true);
00301   nassertr(!placement->is_placed(), true);
00302 
00303   int x, y;
00304   if (find_hole(x, y, placement->get_x_size(), placement->get_y_size())) {
00305     placement->place_at(this, x, y);
00306     _placements.push_back(placement);
00307     return true;
00308   }
00309 
00310   return false;
00311 }
00312 
00313 ////////////////////////////////////////////////////////////////////
00314 //     Function: PaletteImage::unplace
00315 //       Access: Public
00316 //  Description: Removes the texture from the image.
00317 ////////////////////////////////////////////////////////////////////
00318 void PaletteImage::
00319 unplace(TexturePlacement *placement) {
00320   nassertv(placement->is_placed() && placement->get_image() == this);
00321 
00322   Placements::iterator pi;
00323   pi = find(_placements.begin(), _placements.end(), placement);
00324   while (pi != _placements.end()) {
00325     _placements.erase(pi);
00326     pi = find(_placements.begin(), _placements.end(), placement);
00327   }
00328 
00329   _cleared_regions.push_back(ClearedRegion(placement));
00330 }
00331 
00332 ////////////////////////////////////////////////////////////////////
00333 //     Function: PaletteImage::check_solitary
00334 //       Access: Public
00335 //  Description: To be called after all textures have been placed on
00336 //               the image, this checks to see if there is only one
00337 //               texture on the image.  If there is, it is flagged as
00338 //               'solitary' so that the egg files will not needlessly
00339 //               reference the palettized image.
00340 //
00341 //               However, if pal->_omit_solitary is false, we
00342 //               generally don't change textures to solitary state.
00343 ////////////////////////////////////////////////////////////////////
00344 void PaletteImage::
00345 check_solitary() {
00346   if (_placements.size() == 1) {
00347     // How sad, only one.
00348     TexturePlacement *placement = *_placements.begin();
00349     nassertv(placement->get_omit_reason() == OR_none ||
00350              placement->get_omit_reason() == OR_solitary);
00351 
00352     if (pal->_omit_solitary || placement->get_omit_reason() == OR_solitary) {
00353       // We only omit the solitary texture if (a) we have
00354       // omit_solitary in effect, or (b) we don't have omit_solitary
00355       // in effect now, but we did before, and the texture is still
00356       // flagged as solitary from that previous pass.
00357       placement->omit_solitary();
00358     }
00359 
00360   } else {
00361     // Zero or multiple.
00362     Placements::const_iterator pi;
00363     for (pi = _placements.begin(); pi != _placements.end(); ++pi) {
00364       TexturePlacement *placement = (*pi);
00365       /*
00366       if (!(placement->get_omit_reason() == OR_none ||
00367             placement->get_omit_reason() == OR_solitary)) {
00368         nout << "texture " << *placement->get_texture() << " is omitted for "
00369              << placement->get_omit_reason() << "\n";
00370       }
00371       */
00372       nassertv(placement->get_omit_reason() == OR_none ||
00373                placement->get_omit_reason() == OR_solitary);
00374       placement->not_solitary();
00375     }
00376   }
00377 }
00378 
00379 ////////////////////////////////////////////////////////////////////
00380 //     Function: PaletteImage::optimal_resize
00381 //       Access: Public
00382 //  Description: Attempts to resize the palette image to as small as
00383 //               it can go.
00384 ////////////////////////////////////////////////////////////////////
00385 void PaletteImage::
00386 optimal_resize() {
00387   if (is_empty()) {
00388     return;
00389   }
00390 
00391   bool resized_any = false;
00392   bool success;
00393   do {
00394     success = false;
00395     nassertv(_x_size > 0 && _y_size > 0);
00396 
00397     // Try to cut it in half in both dimensions, one at a time.
00398     if (resize_image(_x_size, _y_size / 2)) {
00399       success = true;
00400       resized_any = true;
00401     }
00402     if (resize_image(_x_size / 2, _y_size)) {
00403       success = true;
00404       resized_any = true;
00405     }
00406   } while (success);
00407 
00408   if (resized_any) {
00409     nout << "Resizing "
00410          << FilenameUnifier::make_user_filename(get_filename()) << " to "
00411          << _x_size << " " << _y_size << "\n";
00412   }
00413 }
00414 
00415 ////////////////////////////////////////////////////////////////////
00416 //     Function: PaletteImage::resize_image
00417 //       Access: Public
00418 //  Description: Attempts to resize the palette image, and repack all
00419 //               of the textures within the new size.  Returns true if
00420 //               successful, false otherwise.  If this fails, it will
00421 //               still result in repacking all the textures in the
00422 //               original size.
00423 ////////////////////////////////////////////////////////////////////
00424 bool PaletteImage::
00425 resize_image(int x_size, int y_size) {
00426   // We already know we're going to be generating a new image from
00427   // scratch after this.
00428   _cleared_regions.clear();
00429   remove_image();
00430 
00431   // First, Save the current placement list, while simultaneously
00432   // clearing it.
00433   Placements saved;
00434   saved.swap(_placements);
00435 
00436   // Also save our current size.
00437   int saved_x_size = _x_size;
00438   int saved_y_size = _y_size;
00439 
00440   // Then, sort the textures to in order from biggest to smallest, as
00441   // an aid to optimal packing.
00442   sort(saved.begin(), saved.end(), SortPlacementBySize());
00443 
00444   // And while we're at it, we need to officially unplace each of
00445   // these.
00446   Placements::iterator pi;
00447   for (pi = saved.begin(); pi != saved.end(); ++pi) {
00448     (*pi)->force_replace();
00449   }
00450 
00451   // Finally, apply the new size and try to fit all the textures.
00452   _x_size = x_size;
00453   _y_size = y_size;
00454 
00455   bool packed = true;
00456   for (pi = saved.begin(); pi != saved.end() && packed; ++pi) {
00457     if (!place(*pi)) {
00458       packed = false;
00459     }
00460   }
00461 
00462   if (!packed) {
00463     // If it didn't work, phooey.  Put 'em all back.
00464     _x_size = saved_x_size;
00465     _y_size = saved_y_size;
00466 
00467     Placements remove;
00468     remove.swap(_placements);
00469     for (pi = remove.begin(); pi != remove.end(); ++pi) {
00470       (*pi)->force_replace();
00471     }
00472 
00473     bool all_packed = true;
00474     for (pi = saved.begin(); pi != saved.end(); ++pi) {
00475       if (!place(*pi)) {
00476         all_packed = false;
00477       }
00478     }
00479     nassertr(all_packed, false);
00480   }
00481 
00482   return packed;
00483 }
00484 
00485 ////////////////////////////////////////////////////////////////////
00486 //     Function: PaletteImage::write_placements
00487 //       Access: Public
00488 //  Description: Writes a list of the textures that have been placed
00489 //               on this image to the indicated output stream, one per
00490 //               line.
00491 ////////////////////////////////////////////////////////////////////
00492 void PaletteImage::
00493 write_placements(ostream &out, int indent_level) const {
00494   Placements::const_iterator pi;
00495   for (pi = _placements.begin(); pi != _placements.end(); ++pi) {
00496     TexturePlacement *placement = (*pi);
00497     placement->write_placed(out, indent_level);
00498   }
00499 }
00500 
00501 ////////////////////////////////////////////////////////////////////
00502 //     Function: PaletteImage::reset_image
00503 //       Access: Public
00504 //  Description: Unpacks each texture that has been placed on this
00505 //               image, resetting the image to empty.
00506 ////////////////////////////////////////////////////////////////////
00507 void PaletteImage::
00508 reset_image() {
00509   // We need a copy so we can modify this list as we traverse it.
00510   Placements copy_placements = _placements;
00511   Placements::const_iterator pi;
00512   for (pi = copy_placements.begin(); pi != copy_placements.end(); ++pi) {
00513     TexturePlacement *placement = (*pi);
00514     placement->force_replace();
00515   }
00516 
00517   _placements.clear();
00518   _cleared_regions.clear();
00519   remove_image();
00520 }
00521 
00522 ////////////////////////////////////////////////////////////////////
00523 //     Function: PaletteImage::setup_shadow_image
00524 //       Access: Public
00525 //  Description: Ensures the _shadow_image has the correct filename
00526 //               and image types, based on what was supplied on the
00527 //               command line and in the .txa file.
00528 ////////////////////////////////////////////////////////////////////
00529 void PaletteImage::
00530 setup_shadow_image() {
00531   _shadow_image.make_shadow_image(_basename);
00532 }
00533 
00534 ////////////////////////////////////////////////////////////////////
00535 //     Function: PaletteImage::update_image
00536 //       Access: Public
00537 //  Description: If the palette has changed since it was last written
00538 //               out, updates the image and writes out a new one.  If
00539 //               redo_all is true, regenerates the image from scratch
00540 //               and writes it out again, whether it needed it or not.
00541 ////////////////////////////////////////////////////////////////////
00542 void PaletteImage::
00543 update_image(bool redo_all) {
00544   if (is_empty() && pal->_aggressively_clean_mapdir) {
00545     // If the palette image is 'empty', ensure that it doesn't exist.
00546     // No need to clutter up the map directory.
00547     remove_image();
00548     return;
00549   }
00550 
00551   if (redo_all) {
00552     // If we're redoing everything, throw out the old image anyway.
00553     remove_image();
00554   }
00555 
00556   // Do we need to update?
00557   bool needs_update =
00558     _new_image || !exists() ||
00559     !_cleared_regions.empty();
00560 
00561   Placements::iterator pi;
00562   // We must continue to walk through all of the textures on the
00563   // palette, even after we discover the palette requires an update,
00564   // so we can determine which source images need to be recopied.
00565   for (pi = _placements.begin(); pi != _placements.end(); ++pi) {
00566     TexturePlacement *placement = (*pi);
00567 
00568     if (!placement->is_filled()) {
00569       needs_update = true;
00570 
00571     } else {
00572       SourceTextureImage *source =
00573         placement->get_texture()->get_preferred_source();
00574 
00575       if (source != (SourceTextureImage *)NULL &&
00576           source->get_filename().compare_timestamps(get_filename()) > 0) {
00577         // The source image is newer than the palette image; we need to
00578         // regenerate.
00579         placement->mark_unfilled();
00580         needs_update = true;
00581       }
00582     }
00583   }
00584 
00585   if (!needs_update) {
00586     // No sweat; nothing has changed.
00587     return;
00588   }
00589 
00590   get_image();
00591 
00592   // Set to black any parts of the image that we recently unplaced.
00593   ClearedRegions::iterator ci;
00594   for (ci = _cleared_regions.begin(); ci != _cleared_regions.end(); ++ci) {
00595     ClearedRegion &region = (*ci);
00596     region.clear(_image);
00597   }
00598   _cleared_regions.clear();
00599 
00600   // Now add the recent additions to the image.
00601   for (pi = _placements.begin(); pi != _placements.end(); ++pi) {
00602     TexturePlacement *placement = (*pi);
00603     if (!placement->is_filled()) {
00604       placement->fill_image(_image);
00605     }
00606   }
00607 
00608   write(_image);
00609 
00610   if (pal->_shadow_color_type != (PNMFileType *)NULL) {
00611     _shadow_image.write(_image);
00612   }
00613 }
00614 
00615 
00616 ////////////////////////////////////////////////////////////////////
00617 //     Function: PaletteImage::find_hole
00618 //       Access: Private
00619 //  Description: Searches for a hole of at least x_size by y_size
00620 //               pixels somewhere within the PaletteImage.  If a
00621 //               suitable hole is found, sets x and y to the top left
00622 //               corner and returns true; otherwise, returns false.
00623 ////////////////////////////////////////////////////////////////////
00624 bool PaletteImage::
00625 find_hole(int &x, int &y, int x_size, int y_size) const {
00626   y = 0;
00627   while (y + y_size <= _y_size) {
00628     int next_y = _y_size;
00629     // Scan along the row at 'y'.
00630     x = 0;
00631     while (x + x_size <= _x_size) {
00632       int next_x = x;
00633 
00634       // Consider the spot at x, y.
00635       TexturePlacement *overlap = find_overlap(x, y, x_size, y_size);
00636 
00637       if (overlap == (TexturePlacement *)NULL) {
00638         // Hooray!
00639         return true;
00640       }
00641 
00642       next_x = overlap->get_placed_x() + overlap->get_placed_x_size();
00643       next_y = min(next_y, overlap->get_placed_y() + overlap->get_placed_y_size());
00644       nassertr(next_x > x, false);
00645       x = next_x;
00646     }
00647 
00648     nassertr(next_y > y, false);
00649     y = next_y;
00650   }
00651 
00652   // Nope, wouldn't fit anywhere.
00653   return false;
00654 }
00655 
00656 ////////////////////////////////////////////////////////////////////
00657 //     Function: PaletteImage::find_overlap
00658 //       Access: Private
00659 //  Description: If the rectangle whose top left corner is x, y and
00660 //               whose size is x_size, y_size describes an empty hole
00661 //               that does not overlap any placed images, returns
00662 //               NULL; otherwise, returns the first placed texture
00663 //               that the image does overlap.  It is assumed the
00664 //               rectangle lies completely within the boundaries of
00665 //               the image itself.
00666 ////////////////////////////////////////////////////////////////////
00667 TexturePlacement *PaletteImage::
00668 find_overlap(int x, int y, int x_size, int y_size) const {
00669   Placements::const_iterator pi;
00670   for (pi = _placements.begin(); pi != _placements.end(); ++pi) {
00671     TexturePlacement *placement = (*pi);
00672     if (placement->is_placed() &&
00673         placement->intersects(x, y, x_size, y_size)) {
00674       return placement;
00675     }
00676   }
00677 
00678   return (TexturePlacement *)NULL;
00679 }
00680 
00681 ////////////////////////////////////////////////////////////////////
00682 //     Function: PaletteImage::get_image
00683 //       Access: Public
00684 //  Description: Reads or generates the PNMImage that corresponds to
00685 //               the palette as it is known so far.
00686 ////////////////////////////////////////////////////////////////////
00687 void PaletteImage::
00688 get_image() {
00689   if (_got_image) {
00690     return;
00691   }
00692 
00693   if (!_new_image) {
00694     if (pal->_shadow_color_type != (PNMFileType *)NULL) {
00695       if (_shadow_image.read(_image)) {
00696         _got_image = true;
00697         return;
00698       }
00699     } else {
00700       if (read(_image)) {
00701         _got_image = true;
00702         return;
00703       }
00704     }
00705   }
00706 
00707   nout << "Generating new "
00708        << FilenameUnifier::make_user_filename(get_filename()) << "\n";
00709 
00710   // We won't be using this any more.
00711   _cleared_regions.clear();
00712 
00713   _image.clear(get_x_size(), get_y_size(), _properties.get_num_channels());
00714   _new_image = false;
00715   _got_image = true;
00716 
00717   // Now fill up the image.
00718   Placements::iterator pi;
00719   for (pi = _placements.begin(); pi != _placements.end(); ++pi) {
00720     TexturePlacement *placement = (*pi);
00721     placement->fill_image(_image);
00722   }
00723 }
00724 
00725 ////////////////////////////////////////////////////////////////////
00726 //     Function: PaletteImage::remove_image
00727 //       Access: Private
00728 //  Description: Deletes the image file.
00729 ////////////////////////////////////////////////////////////////////
00730 void PaletteImage::
00731 remove_image() {
00732   unlink();
00733   if (pal->_shadow_color_type != (PNMFileType *)NULL) {
00734     _shadow_image.unlink();
00735   }
00736   _new_image = true;
00737 }
00738 
00739 ////////////////////////////////////////////////////////////////////
00740 //     Function: PaletteImage::register_with_read_factory
00741 //       Access: Public, Static
00742 //  Description: Registers the current object as something that can be
00743 //               read from a Bam file.
00744 ////////////////////////////////////////////////////////////////////
00745 void PaletteImage::
00746 register_with_read_factory() {
00747   BamReader::get_factory()->
00748     register_factory(get_class_type(), make_PaletteImage);
00749 }
00750 
00751 ////////////////////////////////////////////////////////////////////
00752 //     Function: PaletteImage::write_datagram
00753 //       Access: Public, Virtual
00754 //  Description: Fills the indicated datagram up with a binary
00755 //               representation of the current object, in preparation
00756 //               for writing to a Bam file.
00757 ////////////////////////////////////////////////////////////////////
00758 void PaletteImage::
00759 write_datagram(BamWriter *writer, Datagram &datagram) {
00760   ImageFile::write_datagram(writer, datagram);
00761 
00762   datagram.add_uint32(_cleared_regions.size());
00763   ClearedRegions::const_iterator ci;
00764   for (ci = _cleared_regions.begin(); ci != _cleared_regions.end(); ++ci) {
00765     (*ci).write_datagram(datagram);
00766   }
00767 
00768   datagram.add_uint32(_placements.size());
00769   Placements::const_iterator pi;
00770   for (pi = _placements.begin(); pi != _placements.end(); ++pi) {
00771     writer->write_pointer(datagram, (*pi));
00772   }
00773 
00774   writer->write_pointer(datagram, _page);
00775   datagram.add_uint32(_index);
00776   datagram.add_string(_basename);
00777   datagram.add_bool(_new_image);
00778 
00779   // We don't write _got_image or _image.  These are loaded
00780   // per-session.
00781 
00782   // We don't write _shadow_image.  This is just a runtime convenience
00783   // for specifying the name of the shadow file, and we redefine this
00784   // per-session (which allows us to pick up a new
00785   // pal->_shadow_dirname if it changes).
00786 }
00787 
00788 ////////////////////////////////////////////////////////////////////
00789 //     Function: PaletteImage::complete_pointers
00790 //       Access: Public, Virtual
00791 //  Description: Called after the object is otherwise completely read
00792 //               from a Bam file, this function's job is to store the
00793 //               pointers that were retrieved from the Bam file for
00794 //               each pointer object written.  The return value is the
00795 //               number of pointers processed from the list.
00796 ////////////////////////////////////////////////////////////////////
00797 int PaletteImage::
00798 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00799   int index = ImageFile::complete_pointers(p_list, manager);
00800 
00801   int i;
00802   _placements.reserve(_num_placements);
00803   for (i = 0; i < _num_placements; i++) {
00804     TexturePlacement *placement;
00805     DCAST_INTO_R(placement, p_list[index], index);
00806     _placements.push_back(placement);
00807     index++;
00808   }
00809 
00810   if (p_list[index] != (TypedWritable *)NULL) {
00811     DCAST_INTO_R(_page, p_list[index], index);
00812   }
00813   index++;
00814 
00815   return index;
00816 }
00817 
00818 ////////////////////////////////////////////////////////////////////
00819 //     Function: PaletteImage::make_PaletteImage
00820 //       Access: Protected
00821 //  Description: This method is called by the BamReader when an object
00822 //               of this type is encountered in a Bam file; it should
00823 //               allocate and return a new object with all the data
00824 //               read.
00825 ////////////////////////////////////////////////////////////////////
00826 TypedWritable *PaletteImage::
00827 make_PaletteImage(const FactoryParams &params) {
00828   PaletteImage *me = new PaletteImage;
00829   DatagramIterator scan;
00830   BamReader *manager;
00831 
00832   parse_params(params, scan, manager);
00833   me->fillin(scan, manager);
00834   return me;
00835 }
00836 
00837 ////////////////////////////////////////////////////////////////////
00838 //     Function: PaletteImage::fillin
00839 //       Access: Protected
00840 //  Description: Reads the binary data from the given datagram
00841 //               iterator, which was written by a previous call to
00842 //               write_datagram().
00843 ////////////////////////////////////////////////////////////////////
00844 void PaletteImage::
00845 fillin(DatagramIterator &scan, BamReader *manager) {
00846   ImageFile::fillin(scan, manager);
00847 
00848   int num_cleared_regions = scan.get_uint32();
00849   _cleared_regions.reserve(num_cleared_regions);
00850   for (int i = 0; i < num_cleared_regions; i++) {
00851     _cleared_regions.push_back(ClearedRegion());
00852     _cleared_regions.back().fillin(scan);
00853   }
00854 
00855   _num_placements = scan.get_uint32();
00856   manager->read_pointers(scan, _num_placements);
00857 
00858   manager->read_pointer(scan);  // _page
00859 
00860   _index = scan.get_uint32();
00861   _basename = scan.get_string();
00862   _new_image = scan.get_bool();
00863 }

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