Panda3D

pnmImage.cxx

00001 // Filename: pnmImage.cxx
00002 // Created by:  drose (14Jun00)
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 "pnmImage.h"
00016 #include "pnmReader.h"
00017 #include "pnmWriter.h"
00018 #include "pnmBrush.h"
00019 #include "config_pnmimage.h"
00020 #include "perlinNoise2.h"
00021 #include "stackedPerlinNoise2.h"
00022 #include <algorithm>
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: PNMImage::Constructor
00026 //       Access: Published
00027 //  Description:
00028 ////////////////////////////////////////////////////////////////////
00029 PNMImage::
00030 PNMImage(const Filename &filename, PNMFileType *type) {
00031   _array = NULL;
00032   _alpha = NULL;
00033   _has_read_size = false;
00034 
00035   bool result = read(filename, type);
00036   if (!result) {
00037     pnmimage_cat.error()
00038       << "Could not read image " << filename << "\n";
00039   }
00040 }
00041 
00042 ////////////////////////////////////////////////////////////////////
00043 //     Function: PNMImage::clear
00044 //       Access: Published
00045 //  Description: Frees all memory allocated for the image, and clears
00046 //               all its parameters (size, color, type, etc).
00047 ////////////////////////////////////////////////////////////////////
00048 void PNMImage::
00049 clear() {
00050   if (_array != (xel *)NULL) {
00051     PANDA_FREE_ARRAY(_array);
00052     _array = (xel *)NULL;
00053   }
00054   if (_alpha != (xelval *)NULL) {
00055     PANDA_FREE_ARRAY(_alpha);
00056     _alpha = (xelval *)NULL;
00057   }
00058   _x_size = 0;
00059   _y_size = 0;
00060   _num_channels = 0;
00061   _maxval = 255;
00062   _comment.clear();
00063   _type = (PNMFileType *)NULL;
00064   _has_read_size = false;
00065 }
00066 
00067 ////////////////////////////////////////////////////////////////////
00068 //     Function: PNMImage::clear
00069 //       Access: Published
00070 //  Description: This flavor of clear() reinitializes the image to an
00071 //               empty (black) image with the given dimensions.
00072 ////////////////////////////////////////////////////////////////////
00073 void PNMImage::
00074 clear(int x_size, int y_size, int num_channels,
00075       xelval maxval, PNMFileType *type) {
00076   clear();
00077   nassertv(num_channels >= 1 && num_channels <= 4);
00078 
00079   _x_size = x_size;
00080   _y_size = y_size;
00081   _num_channels = num_channels;
00082   _maxval = maxval;
00083   _comment.clear();
00084   _type = type;
00085   _has_read_size = false;
00086 
00087   if (has_alpha()) {
00088     allocate_alpha();
00089     memset(_alpha, 0, sizeof(xelval) * _y_size * _x_size);
00090   }
00091 
00092   allocate_array();
00093   memset(_array, 0, sizeof(xel) * _y_size * _x_size);
00094 
00095   setup_rc();
00096 }
00097 
00098 ////////////////////////////////////////////////////////////////////
00099 //     Function: PNMImage::copy_from
00100 //       Access: Published
00101 //  Description: Makes this image become a copy of the other image.
00102 ////////////////////////////////////////////////////////////////////
00103 void PNMImage::
00104 copy_from(const PNMImage &copy) {
00105   clear();
00106   copy_header_from(copy);
00107 
00108   if (copy.is_valid()) {
00109     if (has_alpha()) {
00110       memcpy(_alpha, copy._alpha, sizeof(xelval) * _y_size * _x_size);
00111     }
00112     memcpy(_array, copy._array, sizeof(xel) * _y_size * _x_size);
00113   }
00114 }
00115 
00116 ////////////////////////////////////////////////////////////////////
00117 //     Function: PNMImage::copy_channel
00118 //       Access: Published
00119 //  Description: Copies a channel from one image into another.
00120 //               Images must be the same size
00121 ////////////////////////////////////////////////////////////////////
00122 void PNMImage::
00123 copy_channel(const PNMImage &copy, int src_channel, int dest_channel) {
00124   // Make sure the channels are in range
00125   nassertv(src_channel >= 0 && src_channel <= 3);
00126   nassertv(dest_channel >= 0 && dest_channel <= 3);
00127   // Make sure that images are valid
00128   if (!copy.is_valid() || !is_valid()) {
00129     pnmimage_cat.error() << "One of the images is invalid!\n";
00130     return;
00131   }
00132   // Make sure the images are the same size
00133   if (_x_size != copy.get_x_size() || _y_size != copy.get_y_size()){
00134     pnmimage_cat.error() << "Image size doesn't match!\n";
00135     return;
00136   }
00137   // Do the actual copying
00138   for (int x = 0; x < _x_size; x++) {
00139     for (int y = 0; y < _y_size; y++) {
00140       LVecBase4d t = get_xel_a(x, y);
00141       LVecBase4d o = copy.get_xel_a(x, y);
00142       t.set_cell(dest_channel,o.get_cell(src_channel));
00143       set_xel_a(x, y, t);
00144     }
00145   }
00146 }
00147 
00148 
00149 ////////////////////////////////////////////////////////////////////
00150 //     Function: PNMImage::copy_header_from
00151 //       Access: Published
00152 //  Description: Copies just the header information into this image.
00153 //               This will blow away any image data stored in the
00154 //               image.  The new image data will be allocated, but
00155 //               left unitialized.
00156 ////////////////////////////////////////////////////////////////////
00157 void PNMImage::
00158 copy_header_from(const PNMImageHeader &header) {
00159   clear();
00160   PNMImageHeader::operator = (header);
00161 
00162   if (has_alpha()) {
00163     allocate_alpha();
00164   }
00165 
00166   allocate_array();
00167   setup_rc();
00168 }
00169 
00170 ////////////////////////////////////////////////////////////////////
00171 //     Function: PNMImage::take_from
00172 //       Access: Published
00173 //  Description: Move the contents of the other image into this one,
00174 //               and empty the other image.
00175 ////////////////////////////////////////////////////////////////////
00176 void PNMImage::
00177 take_from(PNMImage &orig) {
00178   clear();
00179   PNMImageHeader::operator = (orig);
00180   setup_rc();
00181 
00182   if (has_alpha()) {
00183     _alpha = orig._alpha;
00184     orig._alpha = NULL;
00185   }
00186   _array = orig._array;
00187   orig._array = NULL;
00188 
00189   orig.clear();
00190 }
00191 
00192 ////////////////////////////////////////////////////////////////////
00193 //     Function: PNMImage::fill_val
00194 //       Access: Published
00195 //  Description: Sets the entire image (except the alpha channel) to
00196 //               the given color.
00197 ////////////////////////////////////////////////////////////////////
00198 void PNMImage::
00199 fill_val(xelval red, xelval green, xelval blue) {
00200   if (is_valid()) {
00201     for (int y = 0; y < get_y_size(); y++) {
00202       for (int x = 0; x < get_x_size(); x++) {
00203         set_xel_val(x, y, red, green, blue);
00204       }
00205     }
00206   }
00207 }
00208 
00209 ////////////////////////////////////////////////////////////////////
00210 //     Function: PNMImage::alpha_fill_val
00211 //       Access: Published
00212 //  Description: Sets the entire alpha channel to the given level.
00213 ////////////////////////////////////////////////////////////////////
00214 void PNMImage::
00215 alpha_fill_val(xelval alpha) {
00216   if (is_valid()) {
00217     if (!has_alpha()) {
00218       add_alpha();
00219     }
00220 
00221     for (int y = 0; y < get_y_size(); y++) {
00222       for (int x = 0; x < get_x_size(); x++) {
00223         set_alpha_val(x, y, alpha);
00224       }
00225     }
00226   }
00227 }
00228 
00229 ////////////////////////////////////////////////////////////////////
00230 //     Function: PNMImage::remix_channels
00231 //       Access: Published
00232 //  Description: Transforms every pixel using the operation
00233 //               (Ro,Go,Bo) = conv.xform_point(Ri,Gi,Bi);
00234 //               Input must be a color image.
00235 ////////////////////////////////////////////////////////////////////
00236 void PNMImage::
00237 remix_channels(const LMatrix4f &conv) {
00238   int nchannels = get_num_channels();
00239   nassertv((nchannels >= 3) && (nchannels <= 4));
00240   for (int y = 0; y < get_y_size(); y++) {
00241     for (int x = 0; x < get_x_size(); x++) {
00242       LVector3f inv(get_red(x,y),get_green(x,y),get_blue(x,y));
00243       LVector3f outv(conv.xform_point(inv));
00244       set_xel(x,y,outv[0],outv[1],outv[2]);
00245     }
00246   }
00247 }
00248 
00249 ////////////////////////////////////////////////////////////////////
00250 //     Function: PNMImage::read
00251 //       Access: Published
00252 //  Description: Reads the indicated image filename.  If type is
00253 //               non-NULL, it is a suggestion for the type of file it
00254 //               is.  Returns true if successful, false on error.
00255 ////////////////////////////////////////////////////////////////////
00256 bool PNMImage::
00257 read(const Filename &filename, PNMFileType *type, bool report_unknown_type) {
00258   PNMReader *reader = make_reader(filename, type, report_unknown_type);
00259   if (reader == (PNMReader *)NULL) {
00260     clear();
00261     return false;
00262   }
00263 
00264   return read(reader);
00265 }
00266 
00267 ////////////////////////////////////////////////////////////////////
00268 //     Function: PNMImage::read
00269 //       Access: Published
00270 //  Description: Reads the image data from the indicated stream.
00271 //
00272 //               The filename is advisory only, and may be used
00273 //               to suggest a type if it has a known extension.
00274 //
00275 //               If type is non-NULL, it is a suggestion for the type
00276 //               of file it is (and a non-NULL type will override any
00277 //               magic number test or filename extension lookup).
00278 //
00279 //               Returns true if successful, false on error.
00280 ////////////////////////////////////////////////////////////////////
00281 bool PNMImage::
00282 read(istream &data, const string &filename, PNMFileType *type,
00283      bool report_unknown_type) {
00284   PNMReader *reader = PNMImageHeader::make_reader
00285     (&data, false, filename, string(), type, report_unknown_type);
00286   if (reader == (PNMReader *)NULL) {
00287     clear();
00288     return false;
00289   }
00290   return read(reader);
00291 }
00292 
00293 ////////////////////////////////////////////////////////////////////
00294 //     Function: PNMImage::read
00295 //       Access: Published
00296 //  Description: This flavor of read() uses an already-existing
00297 //               PNMReader to read the image file.  You can get a
00298 //               reader via the PNMImageHeader::make_reader() methods.
00299 //               This is a good way to examine the header of a file
00300 //               (for instance, to determine its size) before actually
00301 //               reading the entire image.
00302 //
00303 //               The PNMReader is always deleted upon completion,
00304 //               whether succesful or not.
00305 ////////////////////////////////////////////////////////////////////
00306 bool PNMImage::
00307 read(PNMReader *reader) {
00308   bool has_read_size = _has_read_size;
00309   int read_x_size = _read_x_size;
00310   int read_y_size = _read_y_size;
00311 
00312   clear();
00313 
00314   if (reader == NULL) {
00315     return false;
00316   }
00317 
00318   if (!reader->is_valid()) {
00319     delete reader;
00320     return false;
00321   }
00322 
00323   if (has_read_size) {
00324     reader->set_read_size(read_x_size, read_y_size);
00325   }
00326   reader->prepare_read();
00327 
00328   copy_header_from(*reader);
00329 
00330   // We reassign y_size after reading because we might have read a
00331   // truncated file.
00332   _y_size = reader->read_data(_array, _alpha);
00333   delete reader;
00334 
00335   if (_y_size == 0) {
00336     clear();
00337     return false;
00338   }
00339 
00340   setup_rc();
00341 
00342   if (has_read_size && (_x_size != read_x_size || _y_size != read_y_size)) {
00343     // The Reader didn't comply with our size request.  Do the sizing
00344     // explicitly, then.
00345     PNMImage new_image(read_x_size, read_y_size, get_num_channels(),
00346                        get_maxval(), get_type());
00347     new_image.quick_filter_from(*this);
00348     take_from(new_image);
00349   }
00350 
00351   return true;
00352 }
00353 
00354 ////////////////////////////////////////////////////////////////////
00355 //     Function: PNMImage::write
00356 //       Access: Published
00357 //  Description: Writes the image to the indicated filename.  If type
00358 //               is non-NULL, it is a suggestion for the type of image
00359 //               file to write.
00360 ////////////////////////////////////////////////////////////////////
00361 bool PNMImage::
00362 write(const Filename &filename, PNMFileType *type) const {
00363   if (!is_valid()) {
00364     return false;
00365   }
00366 
00367   PNMWriter *writer = PNMImageHeader::make_writer(filename, type);
00368   if (writer == (PNMWriter *)NULL) {
00369     return false;
00370   }
00371 
00372   return write(writer);
00373 }
00374 
00375 ////////////////////////////////////////////////////////////////////
00376 //     Function: PNMImage::write
00377 //       Access: Published
00378 //  Description: Writes the image to the indicated ostream.
00379 //
00380 //               The filename is advisory only, and may be used
00381 //               suggest a type if it has a known extension.
00382 //
00383 //               If type is non-NULL, it is a suggestion for the type
00384 //               of image file to write.
00385 ////////////////////////////////////////////////////////////////////
00386 bool PNMImage::
00387 write(ostream &data, const string &filename, PNMFileType *type) const {
00388   if (!is_valid()) {
00389     return false;
00390   }
00391 
00392   PNMWriter *writer = PNMImageHeader::make_writer
00393     (&data, false, filename, type);
00394   if (writer == (PNMWriter *)NULL) {
00395     return false;
00396   }
00397 
00398   return write(writer);
00399 }
00400 
00401 ////////////////////////////////////////////////////////////////////
00402 //     Function: PNMImage::write
00403 //       Access: Published
00404 //  Description: This flavor of write() uses an already-existing
00405 //               PNMWriter to write the image file.  You can get a
00406 //               writer via the PNMImageHeader::make_writer() methods.
00407 //
00408 //               The PNMWriter is always deleted upon completion,
00409 //               whether succesful or not.
00410 ////////////////////////////////////////////////////////////////////
00411 bool PNMImage::
00412 write(PNMWriter *writer) const {
00413   if (writer == NULL) {
00414     return false;
00415   }
00416 
00417   if (!is_valid()) {
00418     delete writer;
00419     return false;
00420   }
00421 
00422   writer->copy_header_from(*this);
00423   int result = writer->write_data(_array, _alpha);
00424   delete writer;
00425 
00426   return (result == _y_size);
00427 }
00428 
00429 
00430 
00431 ////////////////////////////////////////////////////////////////////
00432 //     Function: PNMImage::set_color_type
00433 //       Access: Published
00434 //  Description: Translates the image to or from grayscale, color, or
00435 //               four-color mode.  Grayscale images are converted to
00436 //               full-color images with R, G, B set to the original
00437 //               gray level; color images are converted to grayscale
00438 //               according to the value of Bright().  The alpha
00439 //               channel, if added, is initialized to zero.
00440 ////////////////////////////////////////////////////////////////////
00441 void PNMImage::
00442 set_color_type(PNMImage::ColorType color_type) {
00443   nassertv((int)color_type >= 1 && (int)color_type <= 4);
00444   if (color_type == get_color_type()) {
00445     return;
00446   }
00447 
00448   if (!is_grayscale() && is_grayscale(color_type)) {
00449     // convert to grayscale from color
00450     for (int y = 0; y < get_y_size(); y++) {
00451       for (int x = 0; x < get_x_size(); x++) {
00452         set_gray(x, y, get_bright(x, y));
00453       }
00454     }
00455 
00456   } else if (is_grayscale() && !is_grayscale(color_type)) {
00457     // convert to color from grayscale
00458     for (int y = 0; y < get_y_size(); y++) {
00459       for (int x = 0; x<get_x_size(); x++) {
00460         set_xel_val(x, y, get_gray_val(x, y));
00461       }
00462     }
00463   }
00464 
00465   if (has_alpha() && !has_alpha(color_type)) {
00466     // discard the alpha channel
00467     if (_alpha!=NULL) {
00468       PANDA_FREE_ARRAY(_alpha);
00469       _alpha = NULL;
00470     }
00471 
00472   } else if (!has_alpha() && has_alpha(color_type)) {
00473     // create a new alpha channel
00474     allocate_alpha();
00475     memset(_alpha, 0, sizeof(xelval) * (_x_size * _y_size));
00476   }
00477 
00478   _num_channels = (int)color_type;
00479   setup_rc();
00480 }
00481 
00482 ////////////////////////////////////////////////////////////////////
00483 //     Function: PNMImage::make_grayscale
00484 //       Access: Published
00485 //  Description: Converts the image from RGB to grayscale.  Any alpha
00486 //               channel, if present, is left undisturbed.  The
00487 //               optional rc, gc, bc values represent the relative
00488 //               weights to apply to each channel to convert it to
00489 //               grayscale.
00490 ////////////////////////////////////////////////////////////////////
00491 void PNMImage::
00492 make_grayscale(double rc, double gc, double bc) {
00493   if (is_grayscale()) {
00494     return;
00495   }
00496 
00497   for (int y = 0; y < get_y_size(); y++) {
00498     for (int x = 0; x < get_x_size(); x++) {
00499       set_gray(x, y, min(get_bright(x, y, rc, gc, bc), 1.0));
00500     }
00501   }
00502 
00503   _num_channels = has_alpha() ? 2 : 1;
00504   setup_rc();
00505 }
00506 
00507 ////////////////////////////////////////////////////////////////////
00508 //     Function: PNMImage::set_maxval
00509 //       Access: Published
00510 //  Description: Rescales the image to the indicated maxval.
00511 ////////////////////////////////////////////////////////////////////
00512 void PNMImage::
00513 set_maxval(xelval maxval) {
00514   nassertv(maxval > 0);
00515 
00516   if (maxval != _maxval) {
00517     double ratio = (double)maxval / (double)_maxval;
00518 
00519     if (is_grayscale()) {
00520       for (int y = 0; y < get_y_size(); y++) {
00521         for (int x = 0; x < get_x_size(); x++) {
00522           set_gray_val(x, y, (xelval)((long)get_gray_val(x, y) * ratio));
00523         }
00524       }
00525     } else {
00526       for (int y = 0; y < get_y_size(); y++) {
00527         for (int x = 0; x < get_x_size(); x++) {
00528           set_red_val(x, y, (xelval)((long)get_red_val(x, y) * ratio));
00529           set_green_val(x, y, (xelval)((long)get_green_val(x, y) * ratio));
00530           set_blue_val(x, y, (xelval)((long)get_blue_val(x, y) * ratio));
00531         }
00532       }
00533     }
00534 
00535     if (has_alpha()) {
00536       for (int y = 0; y < get_y_size(); y++) {
00537         for (int x = 0; x < get_x_size(); x++) {
00538           set_alpha_val(x, y,
00539                         (xelval)((long)get_alpha_val(x, y) * ratio));
00540         }
00541       }
00542     }
00543     _maxval = maxval;
00544   }
00545 }
00546 
00547 ////////////////////////////////////////////////////////////////////
00548 //     Function: PNMImage::get_channel_val
00549 //       Access: Published
00550 //  Description: Returns the nth component color at the indicated
00551 //               pixel.  The channel index should be in the range
00552 //               0..(get_num_channels()-1).  The channels are ordered B,
00553 //               G, R, A.  This is slightly less optimal than
00554 //               accessing the component values directly by named
00555 //               methods.  The value returned is in the range
00556 //               0..maxval.
00557 ////////////////////////////////////////////////////////////////////
00558 xelval PNMImage::
00559 get_channel_val(int x, int y, int channel) const {
00560   switch (channel) {
00561   case 0:
00562     return get_blue_val(x, y);
00563 
00564   case 1:
00565     return (_num_channels == 2) ? get_alpha_val(x, y) : get_green_val(x, y);
00566 
00567   case 2:
00568     return get_red_val(x, y);
00569 
00570   case 3:
00571     return get_alpha_val(x, y);
00572 
00573   default:
00574     pnmimage_cat.error()
00575       << "Invalid request for channel " << channel << " in "
00576       << get_num_channels() << "-channel image.\n";
00577     nassertr(false, 0);
00578     return 0;
00579   }
00580 }
00581 
00582 ////////////////////////////////////////////////////////////////////
00583 //     Function: PNMImage::set_channel_val
00584 //       Access: Published
00585 //  Description: Sets the nth component color at the indicated
00586 //               pixel.  The channel index should be in the range
00587 //               0..(get_num_channels()-1).  The channels are ordered B,
00588 //               G, R, A.  This is slightly less optimal than
00589 //               setting the component values directly by named
00590 //               methods.  The value given should be in the range
00591 //               0..maxval.
00592 ////////////////////////////////////////////////////////////////////
00593 void PNMImage::
00594 set_channel_val(int x, int y, int channel, xelval value) {
00595   switch (channel) {
00596   case 0:
00597     set_blue_val(x, y, value);
00598     break;
00599 
00600   case 1:
00601     if (_num_channels == 2) {
00602       set_alpha_val(x, y, value);
00603     } else {
00604       set_green_val(x, y, value);
00605     }
00606     break;
00607 
00608   case 2:
00609     set_red_val(x, y, value);
00610     break;
00611 
00612   case 3:
00613     set_alpha_val(x, y, value);
00614     break;
00615 
00616   default:
00617     nassertv(false);
00618   }
00619 }
00620 
00621 ////////////////////////////////////////////////////////////////////
00622 //     Function: PNMImage::get_pixel
00623 //       Access: Published
00624 //  Description: Returns the (r, g, b, a) pixel value at the indicated
00625 //               pixel, using a PixelSpec object.
00626 ////////////////////////////////////////////////////////////////////
00627 PNMImage::PixelSpec PNMImage::
00628 get_pixel(int x, int y) const {
00629   switch (_num_channels) {
00630   case 1:
00631     return PixelSpec(get_gray_val(x, y));
00632   case 2:
00633     return PixelSpec(get_gray_val(x, y), get_alpha_val(x, y));
00634   case 3:
00635     return PixelSpec(get_xel_val(x, y));
00636   case 4:
00637     return PixelSpec(get_xel_val(x, y), get_alpha_val(x, y));
00638   }
00639 
00640   return PixelSpec(0);
00641 }
00642 
00643 ////////////////////////////////////////////////////////////////////
00644 //     Function: PNMImage::set_pixel
00645 //       Access: Published
00646 //  Description: Sets the (r, g, b, a) pixel value at the indicated
00647 //               pixel, using a PixelSpec object.
00648 ////////////////////////////////////////////////////////////////////
00649 void PNMImage::
00650 set_pixel(int x, int y, const PixelSpec &pixel) {
00651   xel p;
00652   PPM_ASSIGN(p, pixel._red, pixel._green, pixel._blue);
00653   set_xel_val(x, y, p);
00654   if (_alpha != NULL) {
00655     set_alpha_val(x, y, pixel._alpha);
00656   }
00657 }
00658 
00659 ////////////////////////////////////////////////////////////////////
00660 //     Function: PNMImage::blend
00661 //       Access: Published
00662 //  Description: Smoothly blends the indicated pixel value in with
00663 //               whatever was already in the image, based on the given
00664 //               alpha value.  An alpha of 1.0 is fully opaque and
00665 //               completely replaces whatever was there previously;
00666 //               alpha of 0.0 is fully transparent and does nothing.
00667 ////////////////////////////////////////////////////////////////////
00668 void PNMImage::
00669 blend(int x, int y, double r, double g, double b, double alpha) {
00670   if (alpha >= 1.0) {
00671     // Completely replace the previous color.
00672     if (has_alpha()) {
00673       set_alpha(x, y, 1.0);
00674     }
00675     set_xel(x, y, r, g, b);
00676 
00677   } else if (alpha > 0.0) {
00678     // Blend with the previous color.
00679     double prev_alpha = has_alpha() ? get_alpha(x, y) : 1.0;
00680 
00681     if (prev_alpha == 0.0) {
00682       // Nothing there previously; replace with this new color.
00683       set_alpha(x, y, alpha);
00684       set_xel(x, y, r, g, b);
00685 
00686     } else {
00687       // Blend the color with the previous color.
00688       RGBColord prev_rgb = get_xel(x, y);
00689       r = r + (1.0 - alpha) * (get_red(x, y) - r);
00690       g = g + (1.0 - alpha) * (get_green(x, y) - g);
00691       b = b + (1.0 - alpha) * (get_blue(x, y) - b);
00692       alpha = prev_alpha + alpha * (1.0 - prev_alpha);
00693 
00694       if (has_alpha()) {
00695         set_alpha(x, y, alpha);
00696       }
00697       set_xel(x, y, r, g, b);
00698     }
00699   }
00700 }
00701 
00702 ////////////////////////////////////////////////////////////////////
00703 //     Function: PNMImage::copy_sub_image
00704 //       Access: Published
00705 //  Description: Copies a rectangular area of another image into a
00706 //               rectangular area of this image.  Both images must
00707 //               already have been initialized.  The upper-left corner
00708 //               of the region in both images is specified, and the
00709 //               size of the area; if the size is omitted, it defaults
00710 //               to the entire other image, or the largest piece that
00711 //               will fit.
00712 ////////////////////////////////////////////////////////////////////
00713 void PNMImage::
00714 copy_sub_image(const PNMImage &copy, int xto, int yto,
00715                int xfrom, int yfrom, int x_size, int y_size) {
00716   int xmin, ymin, xmax, ymax;
00717   setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
00718                   xmin, ymin, xmax, ymax);
00719 
00720   if (get_maxval() == copy.get_maxval()) {
00721     // The simple case: no pixel value rescaling is required.
00722     int x, y;
00723     for (y = ymin; y < ymax; y++) {
00724       for (x = xmin; x < xmax; x++) {
00725         set_xel_val(x, y, copy.get_xel_val(x - xmin + xfrom, y - ymin + yfrom));
00726       }
00727     }
00728 
00729     if (has_alpha() && copy.has_alpha()) {
00730       for (y = ymin; y < ymax; y++) {
00731         for (x = xmin; x < xmax; x++) {
00732           set_alpha_val(x, y, copy.get_alpha_val(x - xmin + xfrom, y - ymin + yfrom));
00733         }
00734       }
00735     }
00736 
00737   } else {
00738     // The harder case: rescale pixel values according to maxval.
00739     int x, y;
00740     for (y = ymin; y < ymax; y++) {
00741       for (x = xmin; x < xmax; x++) {
00742         set_xel(x, y, copy.get_xel(x - xmin + xfrom, y - ymin + yfrom));
00743       }
00744     }
00745 
00746     if (has_alpha() && copy.has_alpha()) {
00747       for (y = ymin; y < ymax; y++) {
00748         for (x = xmin; x < xmax; x++) {
00749           set_alpha(x, y, copy.get_alpha(x - xmin + xfrom, y - ymin + yfrom));
00750         }
00751       }
00752     }
00753   }
00754 }
00755 
00756 ////////////////////////////////////////////////////////////////////
00757 //     Function: PNMImage::blend_sub_image
00758 //       Access: Published
00759 //  Description: Behaves like copy_sub_image(), except the alpha
00760 //               channel of the copy is used to blend the copy into
00761 //               the destination image, instead of overwriting pixels
00762 //               unconditionally.
00763 //
00764 //               If pixel_scale is not 1.0, it specifies an amount to
00765 //               scale each *alpha* value of the source image before
00766 //               applying it to the target image.
00767 //
00768 //               If pixel_scale is 1.0 and the copy has no alpha
00769 //               channel, this degenerates into copy_sub_image().
00770 ////////////////////////////////////////////////////////////////////
00771 void PNMImage::
00772 blend_sub_image(const PNMImage &copy, int xto, int yto,
00773                 int xfrom, int yfrom, int x_size, int y_size,
00774                 double pixel_scale) {
00775   if (!copy.has_alpha() && pixel_scale == 1.0) {
00776     copy_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size);
00777     return;
00778   }
00779 
00780   int xmin, ymin, xmax, ymax;
00781   setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
00782                   xmin, ymin, xmax, ymax);
00783 
00784   int x, y;
00785   if (copy.has_alpha()) {
00786     for (y = ymin; y < ymax; y++) {
00787       for (x = xmin; x < xmax; x++) {
00788         blend(x, y, copy.get_xel(x - xmin + xfrom, y - ymin + yfrom),
00789               copy.get_alpha(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale);
00790       }
00791     }
00792   } else {
00793     for (y = ymin; y < ymax; y++) {
00794       for (x = xmin; x < xmax; x++) {
00795         blend(x, y, copy.get_xel(x - xmin + xfrom, y - ymin + yfrom),
00796               pixel_scale);
00797       }
00798     }
00799   }
00800 }
00801 
00802 ////////////////////////////////////////////////////////////////////
00803 //     Function: PNMImage::darken_sub_image
00804 //       Access: Published
00805 //  Description: Behaves like copy_sub_image(), but the resulting
00806 //               color will be the darker of the source and
00807 //               destination colors at each pixel (and at each R, G,
00808 //               B, A component value).
00809 //
00810 //               If pixel_scale is not 1.0, it specifies an amount to
00811 //               scale each pixel value of the source image before
00812 //               applying it to the target image.  The scale is
00813 //               applied with the center at 1.0: scaling the pixel
00814 //               value smaller brings it closer to 1.0.
00815 ////////////////////////////////////////////////////////////////////
00816 void PNMImage::
00817 darken_sub_image(const PNMImage &copy, int xto, int yto,
00818                  int xfrom, int yfrom, int x_size, int y_size,
00819                  double pixel_scale) {
00820   int xmin, ymin, xmax, ymax;
00821   setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
00822                   xmin, ymin, xmax, ymax);
00823 
00824   if (get_maxval() == copy.get_maxval() && pixel_scale == 1.0) {
00825     // The simple case: no pixel value rescaling is required.
00826     int x, y;
00827     for (y = ymin; y < ymax; y++) {
00828       for (x = xmin; x < xmax; x++) {
00829         xel c = copy.get_xel_val(x - xmin + xfrom, y - ymin + yfrom);
00830         xel o = get_xel_val(x, y);
00831         xel p;
00832         PPM_ASSIGN(p, min(c.r, o.r), min(c.g, o.g), min(c.b, o.b));
00833         set_xel_val(x, y, p);
00834       }
00835     }
00836 
00837     if (has_alpha() && copy.has_alpha()) {
00838       for (y = ymin; y < ymax; y++) {
00839         for (x = xmin; x < xmax; x++) {
00840           xelval c = copy.get_alpha_val(x - xmin + xfrom, y - ymin + yfrom);
00841           xelval o = get_alpha_val(x, y);
00842           set_alpha_val(x, y, min(c, o));
00843         }
00844       }
00845     }
00846 
00847   } else {
00848     // The harder case: rescale pixel values according to maxval.
00849     int x, y;
00850     for (y = ymin; y < ymax; y++) {
00851       for (x = xmin; x < xmax; x++) {
00852         RGBColord c = copy.get_xel(x - xmin + xfrom, y - ymin + yfrom);
00853         RGBColord o = get_xel(x, y);
00854         RGBColord p;
00855         p.set(min(1.0 - ((1.0 - c[0]) * pixel_scale), o[0]),
00856               min(1.0 - ((1.0 - c[1]) * pixel_scale), o[1]),
00857               min(1.0 - ((1.0 - c[2]) * pixel_scale), o[2]));
00858         set_xel(x, y, p);
00859       }
00860     }
00861 
00862     if (has_alpha() && copy.has_alpha()) {
00863       for (y = ymin; y < ymax; y++) {
00864         for (x = xmin; x < xmax; x++) {
00865           double c = copy.get_alpha(x - xmin + xfrom, y - ymin + yfrom);
00866           double o = get_alpha(x, y);
00867           set_alpha(x, y, min(1.0 - ((1.0 - c) * pixel_scale), o));
00868         }
00869       }
00870     }
00871   }
00872 }
00873 
00874 ////////////////////////////////////////////////////////////////////
00875 //     Function: PNMImage::lighten_sub_image
00876 //       Access: Published
00877 //  Description: Behaves like copy_sub_image(), but the resulting
00878 //               color will be the lighter of the source and
00879 //               destination colors at each pixel (and at each R, G,
00880 //               B, A component value).
00881 //
00882 //               If pixel_scale is not 1.0, it specifies an amount to
00883 //               scale each pixel value of the source image before
00884 //               applying it to the target image.
00885 ////////////////////////////////////////////////////////////////////
00886 void PNMImage::
00887 lighten_sub_image(const PNMImage &copy, int xto, int yto,
00888                   int xfrom, int yfrom, int x_size, int y_size,
00889                   double pixel_scale) {
00890   int xmin, ymin, xmax, ymax;
00891   setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
00892                   xmin, ymin, xmax, ymax);
00893 
00894   if (get_maxval() == copy.get_maxval() && pixel_scale == 1.0) {
00895     // The simple case: no pixel value rescaling is required.
00896     int x, y;
00897     for (y = ymin; y < ymax; y++) {
00898       for (x = xmin; x < xmax; x++) {
00899         xel c = copy.get_xel_val(x - xmin + xfrom, y - ymin + yfrom);
00900         xel o = get_xel_val(x, y);
00901         xel p;
00902         PPM_ASSIGN(p, max(c.r, o.r), max(c.g, o.g), max(c.b, o.b));
00903         set_xel_val(x, y, p);
00904       }
00905     }
00906 
00907     if (has_alpha() && copy.has_alpha()) {
00908       for (y = ymin; y < ymax; y++) {
00909         for (x = xmin; x < xmax; x++) {
00910           xelval c = copy.get_alpha_val(x - xmin + xfrom, y - ymin + yfrom);
00911           xelval o = get_alpha_val(x, y);
00912           set_alpha_val(x, y, max(c, o));
00913         }
00914       }
00915     }
00916 
00917   } else {
00918     // The harder case: rescale pixel values according to maxval.
00919     int x, y;
00920     for (y = ymin; y < ymax; y++) {
00921       for (x = xmin; x < xmax; x++) {
00922         RGBColord c = copy.get_xel(x - xmin + xfrom, y - ymin + yfrom);
00923         RGBColord o = get_xel(x, y);
00924         RGBColord p;
00925         p.set(max(c[0] * pixel_scale, o[0]),
00926               max(c[1] * pixel_scale, o[1]),
00927               max(c[2] * pixel_scale, o[2]));
00928         set_xel(x, y, p);
00929       }
00930     }
00931 
00932     if (has_alpha() && copy.has_alpha()) {
00933       for (y = ymin; y < ymax; y++) {
00934         for (x = xmin; x < xmax; x++) {
00935           double c = copy.get_alpha(x - xmin + xfrom, y - ymin + yfrom);
00936           double o = get_alpha(x, y);
00937           set_alpha(x, y, max(c * pixel_scale, o));
00938         }
00939       }
00940     }
00941   }
00942 }
00943 
00944 ////////////////////////////////////////////////////////////////////
00945 //     Function: PNMImage::threshold
00946 //       Access: Published
00947 //  Description: Selectively copies each pixel from either one source
00948 //               or another source, depending on the pixel value of
00949 //               the indicated channel of select_image.
00950 //
00951 //               For each pixel (x, y):
00952 //
00953 //               s = select_image.get_channel(x, y). Set this image's
00954 //               (x, y) to:
00955 //
00956 //               lt.get_xel(x, y) if s <= threshold, or
00957 //
00958 //               ge.get_xel(x, y) if s > threshold
00959 //
00960 //               Any of select_image, lt, or ge may be the same
00961 //               PNMImge object as this image, or the same as each
00962 //               other; or they may all be different. All images must
00963 //               be the same size.
00964 ////////////////////////////////////////////////////////////////////
00965 void PNMImage::
00966 threshold(const PNMImage &select_image, int channel, double threshold,
00967           const PNMImage &lt, const PNMImage &ge) {
00968   nassertv(get_x_size() <= select_image.get_x_size() && get_y_size() <= select_image.get_y_size());
00969   nassertv(get_x_size() <= lt.get_x_size() && get_y_size() <= lt.get_y_size());
00970   nassertv(get_x_size() <= ge.get_x_size() && get_y_size() <= ge.get_y_size());
00971   nassertv(channel >= 0 && channel < select_image.get_num_channels());
00972 
00973   xelval threshold_val = (xelval)(select_image.get_maxval() * threshold + 0.5);
00974 
00975   if (get_maxval() == lt.get_maxval() && get_maxval() == ge.get_maxval()) {
00976     // Simple case: the maxvals are all equal.  Copy by integer value.
00977     int x, y;
00978 
00979     if (channel == 3) {
00980       // Further special case: the alpha channel.
00981       if (has_alpha() && lt.has_alpha() && ge.has_alpha()) {
00982         // Copy alpha channel too.
00983         for (y = 0; y < get_y_size(); y++) {
00984           for (x = 0; x < get_x_size(); x++) {
00985             if (select_image.get_alpha_val(x, y) < threshold_val) {
00986               set_xel_val(x, y, lt.get_xel_val(x, y));
00987               set_alpha_val(x, y, lt.get_alpha_val(x, y));
00988             } else {
00989               set_xel_val(x, y, ge.get_xel_val(x, y));
00990               set_alpha_val(x, y, ge.get_alpha_val(x, y));
00991             }
00992           }
00993         }
00994 
00995       } else {
00996         // Don't copy alpha channel.
00997         for (y = 0; y < get_y_size(); y++) {
00998           for (x = 0; x < get_x_size(); x++) {
00999             if (select_image.get_alpha_val(x, y) < threshold_val) {
01000               set_xel_val(x, y, lt.get_xel_val(x, y));
01001             } else {
01002               set_xel_val(x, y, ge.get_xel_val(x, y));
01003             }
01004           }
01005         }
01006       }
01007     } else {
01008       // Any generic channel.
01009       if (has_alpha() && lt.has_alpha() && ge.has_alpha()) {
01010         // Copy alpha channel too.
01011         for (y = 0; y < get_y_size(); y++) {
01012           for (x = 0; x < get_x_size(); x++) {
01013             if (select_image.get_channel_val(x, y, channel) < threshold_val) {
01014               set_xel_val(x, y, lt.get_xel_val(x, y));
01015               set_alpha_val(x, y, lt.get_alpha_val(x, y));
01016             } else {
01017               set_xel_val(x, y, ge.get_xel_val(x, y));
01018               set_alpha_val(x, y, ge.get_alpha_val(x, y));
01019             }
01020           }
01021         }
01022 
01023       } else {
01024         // Don't copy alpha channel.
01025         for (y = 0; y < get_y_size(); y++) {
01026           for (x = 0; x < get_x_size(); x++) {
01027             if (select_image.get_channel_val(x, y, channel) < threshold_val) {
01028               set_xel_val(x, y, lt.get_xel_val(x, y));
01029             } else {
01030               set_xel_val(x, y, ge.get_xel_val(x, y));
01031             }
01032           }
01033         }
01034       }
01035     }
01036 
01037   } else {
01038     // General case: the maxvals are different.  Copy by floating-point value.
01039     int x, y;
01040 
01041     if (has_alpha() && lt.has_alpha() && ge.has_alpha()) {
01042       for (y = 0; y < get_y_size(); y++) {
01043         for (x = 0; x < get_x_size(); x++) {
01044           if (select_image.get_channel_val(x, y, channel) < threshold_val) {
01045             set_xel(x, y, lt.get_xel(x, y));
01046             set_alpha(x, y, lt.get_alpha(x, y));
01047           } else {
01048             set_xel(x, y, ge.get_xel(x, y));
01049             set_alpha(x, y, ge.get_alpha(x, y));
01050           }
01051         }
01052       }
01053     } else {
01054       for (y = 0; y < get_y_size(); y++) {
01055         for (x = 0; x < get_x_size(); x++) {
01056           if (select_image.get_channel_val(x, y, channel) < threshold_val) {
01057             set_xel(x, y, lt.get_xel(x, y));
01058           } else {
01059             set_xel(x, y, ge.get_xel(x, y));
01060           }
01061         }
01062       }
01063     }
01064   }
01065 }
01066 
01067 ////////////////////////////////////////////////////////////////////
01068 //     Function: PNMImage::copy_channel
01069 //       Access: Published
01070 //  Description: Copies just a single channel from the source image
01071 //               into a single channel of this image, leaving the
01072 //               remaining channels alone.
01073 ////////////////////////////////////////////////////////////////////
01074 void PNMImage::
01075 copy_channel(const PNMImage &copy, int xto, int yto, int cto,
01076              int xfrom, int yfrom, int cfrom,
01077              int x_size, int y_size) {
01078   int xmin, ymin, xmax, ymax;
01079   setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
01080                   xmin, ymin, xmax, ymax);
01081 
01082   if (get_maxval() == copy.get_maxval()) {
01083     // The simple case: no pixel value rescaling is required.
01084     int x, y;
01085     for (y = ymin; y < ymax; y++) {
01086       if (cto == 3 && cfrom == 3) {
01087         // To alpha channel, from alpha channel.
01088         for (x = xmin; x < xmax; x++) {
01089           set_alpha_val(x, y, copy.get_alpha_val(x - xmin + xfrom, y - ymin + yfrom));
01090         }
01091       } else if (cto == 3 && cfrom == 0) {
01092         // To alpha channel, from blue (or gray) channel.
01093         for (x = xmin; x < xmax; x++) {
01094           set_alpha_val(x, y, copy.get_blue_val(x - xmin + xfrom, y - ymin + yfrom));
01095         }
01096       } else if (cto == 0 && cfrom == 3) {
01097         // To blue (or gray) channel, from alpha channel.
01098         for (x = xmin; x < xmax; x++) {
01099           set_blue_val(x, y, copy.get_alpha_val(x - xmin + xfrom, y - ymin + yfrom));
01100         }
01101       } else {
01102         // Generic channels.
01103         for (x = xmin; x < xmax; x++) {
01104           set_channel_val(x, y, cto, copy.get_channel_val(x - xmin + xfrom, y - ymin + yfrom, cfrom));
01105         }
01106       }
01107     }
01108 
01109   } else {
01110     // The harder case: rescale pixel values according to maxval.
01111     int x, y;
01112     for (y = ymin; y < ymax; y++) {
01113       for (x = xmin; x < xmax; x++) {
01114         set_channel(x, y, cto, copy.get_channel(x - xmin + xfrom, y - ymin + yfrom, cfrom));
01115       }
01116     }
01117   }
01118 }
01119 
01120 ////////////////////////////////////////////////////////////////////
01121 //     Function: PNMImage::render_spot
01122 //       Access: Published
01123 //  Description: Renders a solid-color circle, with a fuzzy edge, into
01124 //               the center of the PNMImage.  If the PNMImage is
01125 //               non-square, this actually renders an ellipse.
01126 //
01127 //               The min_radius and max_radius are in the scale 0..1,
01128 //               where 1.0 means the full width of the image.  If
01129 //               min_radius == max_radius, the edge is sharp (but
01130 //               still antialiased); otherwise, the pixels between
01131 //               min_radius and max_radius are smoothly blended
01132 //               between fg and bg colors.
01133 ////////////////////////////////////////////////////////////////////
01134 void PNMImage::
01135 render_spot(const Colord &fg, const Colord &bg,
01136             double min_radius, double max_radius) {
01137   if (_x_size == 0 || _y_size == 0) {
01138     return;
01139   }
01140 
01141   double x_scale = 2.0 / _x_size;
01142   double y_scale = 2.0 / _y_size;
01143 
01144   // If the width is even, x_center1 == x_center0.  If the width is
01145   // odd, x_center1 == x_center0 + 1.
01146   int x_center0 = _x_size / 2;
01147   int y_center0 = _y_size / 2;
01148   int x_center1 = (_x_size + 1) / 2;
01149   int y_center1 = (_y_size + 1) / 2;
01150 
01151   double min_r2 = min_radius * min_radius;
01152   double max_r2 = max_radius * max_radius;
01153 
01154   for (int yi = 0; yi < y_center1; ++yi) {
01155     double y = yi * y_scale;
01156     double y2_inner = y * y;
01157     double y2_outer = (y + y_scale) * (y + y_scale);
01158     for (int xi = 0; xi < x_center1; ++xi) {
01159       double x = xi * x_scale;
01160       double d2_inner = (x * x + y2_inner);
01161       double d2_outer = ((x + x_scale) * (x + x_scale) + y2_outer);
01162       double d2_a = ((x + x_scale) * (x + x_scale) + y2_inner);
01163       double d2_b = (x * x + y2_outer);
01164 
01165       if ((d2_inner <= min_r2) &&
01166           (d2_outer <= min_r2) &&
01167           (d2_a <= min_r2) &&
01168           (d2_b <= min_r2)) {
01169         // This pixel is solidly in the center of the spot.
01170         set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, fg);
01171         set_xel_a(x_center0 + xi, y_center1 - 1 - yi, fg);
01172         set_xel_a(x_center1 - 1 - xi, y_center0 + yi, fg);
01173         set_xel_a(x_center0 + xi, y_center0 + yi, fg);
01174 
01175       } else if ((d2_inner > max_r2) &&
01176                  (d2_outer > max_r2) &&
01177                  (d2_a > max_r2) &&
01178                  (d2_b > max_r2)) {
01179         // This pixel is solidly outside the spot.
01180         set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, bg);
01181         set_xel_a(x_center0 + xi, y_center1 - 1 - yi, bg);
01182         set_xel_a(x_center1 - 1 - xi, y_center0 + yi, bg);
01183         set_xel_a(x_center0 + xi, y_center0 + yi, bg);
01184 
01185       } else {
01186         // This pixel is in a feathered area or along the antialiased edge.
01187         Colord c_outer, c_inner, c_a, c_b;
01188         compute_spot_pixel(c_outer, d2_outer, min_radius, max_radius, fg, bg);
01189         compute_spot_pixel(c_inner, d2_inner, min_radius, max_radius, fg, bg);
01190         compute_spot_pixel(c_a, d2_a, min_radius, max_radius, fg, bg);
01191         compute_spot_pixel(c_b, d2_b, min_radius, max_radius, fg, bg);
01192 
01193         // Now average all four pixels for the antialiased result.
01194         Colord c;
01195         c = (c_outer + c_inner + c_a + c_b) * 0.25;
01196 
01197         set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, c);
01198         set_xel_a(x_center0 + xi, y_center1 - 1 - yi, c);
01199         set_xel_a(x_center1 - 1 - xi, y_center0 + yi, c);
01200         set_xel_a(x_center0 + xi, y_center0 + yi, c);
01201       }
01202     }
01203   }
01204 }
01205 
01206 ////////////////////////////////////////////////////////////////////
01207 //     Function: PNMImage::expand_border
01208 //       Access: Published
01209 //  Description: Expands the image by the indicated number of pixels
01210 //               on each edge.  The new pixels are set to the
01211 //               indicated color.
01212 //
01213 //               If any of the values is negative, this actually crops
01214 //               the image.
01215 ////////////////////////////////////////////////////////////////////
01216 void PNMImage::
01217 expand_border(int left, int right, int bottom, int top,
01218               const Colord &color) {
01219   PNMImage new_image(get_x_size() + left + right,
01220                      get_y_size() + bottom + top,
01221                      get_num_channels(), get_maxval(), get_type());
01222   new_image.fill(color[0], color[1], color[2]);
01223   if (has_alpha()) {
01224     new_image.alpha_fill(color[3]);
01225   }
01226   new_image.copy_sub_image(*this, left, top);
01227 
01228   take_from(new_image);
01229 }
01230 
01231 ////////////////////////////////////////////////////////////////////
01232 //     Function: PNMImage::make_histogram
01233 //       Access: Published
01234 //  Description: Computes a histogram of the colors used in the
01235 //               image.
01236 ////////////////////////////////////////////////////////////////////
01237 void PNMImage::
01238 make_histogram(PNMImage::Histogram &histogram) {
01239   HistMap hist_map;
01240   PixelCount pixels;
01241 
01242   int num_pixels = _x_size * _y_size;
01243 
01244   compute_histogram(hist_map, _array, _alpha);
01245 
01246   pixels.reserve(hist_map.size());
01247   HistMap::const_iterator hi;
01248   for (hi = hist_map.begin(); hi != hist_map.end(); ++hi) {
01249     if ((*hi).second <= num_pixels) {
01250       pixels.push_back(PixelSpecCount((*hi).first, (*hi).second));
01251     }
01252   }
01253   ::sort(pixels.begin(), pixels.end());
01254 
01255   histogram.swap(pixels, hist_map);
01256 }
01257 
01258 ////////////////////////////////////////////////////////////////////
01259 //     Function: PNMImage::perlin_noise_fill
01260 //       Access: Published
01261 //  Description: Fills the image with a grayscale perlin noise
01262 //               pattern based on the indicated parameters.
01263 //               Uses set_xel to set the grayscale values.
01264 //               The sx and sy parameters are in multiples
01265 //               of the size of this image.
01266 //               See also the PerlinNoise2 class in mathutil.
01267 ////////////////////////////////////////////////////////////////////
01268 void PNMImage::
01269 perlin_noise_fill(double sx, double sy, int table_size, unsigned long seed) {
01270   double x, y;
01271   double noise;
01272   PerlinNoise2 perlin (sx * _x_size, sy * _y_size, table_size, seed);
01273   for (x = 0; x < _x_size; ++x) {
01274     for (y = 0; y < _y_size; ++y) {
01275       noise = perlin.noise(x, y);
01276       set_xel(x, y, 0.5 * (noise + 1.0));
01277     }
01278   }
01279 }
01280 
01281 ////////////////////////////////////////////////////////////////////
01282 //     Function: PNMImage::perlin_noise_fill
01283 //       Access: Published
01284 //  Description: Variant of perlin_noise_fill that uses an
01285 //               existing StackedPerlinNoise2 object.
01286 ////////////////////////////////////////////////////////////////////
01287 void PNMImage::
01288 perlin_noise_fill(StackedPerlinNoise2 &perlin) {
01289   double x, y;
01290   double noise;
01291   for (x = 0; x < _x_size; ++x) {
01292     for (y = 0; y < _y_size; ++y) {
01293       noise = perlin.noise(x / (double) _x_size, y / (double) _y_size);
01294       set_xel(x, y, 0.5 * (noise + 1.0));
01295     }
01296   }
01297 }
01298 
01299 ////////////////////////////////////////////////////////////////////
01300 //     Function: PNMImage::setup_rc
01301 //       Access: Private
01302 //  Description: Sets the _default_rc,bc,gc values appropriately
01303 //               according to the color type of the image, so that
01304 //               get_bright() will return a meaningful value for both
01305 //               color and grayscale images.
01306 ////////////////////////////////////////////////////////////////////
01307 void PNMImage::
01308 setup_rc() {
01309   if (is_grayscale()) {
01310     _default_rc = 0.0;
01311     _default_gc = 0.0;
01312     _default_bc = 1.0;
01313   } else {
01314     _default_rc = lumin_red;
01315     _default_gc = lumin_grn;
01316     _default_bc = lumin_blu;
01317   }
01318 }
01319 
01320 ////////////////////////////////////////////////////////////////////
01321 //     Function: PNMImage::get_average_xel
01322 //       Access: Published
01323 //  Description: Returns the average color of all of the pixels
01324 //               in the image.
01325 ////////////////////////////////////////////////////////////////////
01326 RGBColord PNMImage::
01327 get_average_xel() const {
01328   RGBColord color (RGBColord::zero());
01329   if (_x_size == 0 || _y_size == 0) {
01330     return color;
01331   }
01332 
01333   int x, y;
01334   for (x = 0; x < _x_size; ++x) {
01335     for (y = 0; y < _y_size; ++y) {
01336       color += get_xel(x, y);
01337     }
01338   }
01339 
01340   color *= 1.0 / (_x_size * _y_size);
01341   return color;
01342 }
01343 
01344 ////////////////////////////////////////////////////////////////////
01345 //     Function: PNMImage::get_average_xel_a
01346 //       Access: Published
01347 //  Description: Returns the average color of all of the pixels
01348 //               in the image, including the alpha channel.
01349 ////////////////////////////////////////////////////////////////////
01350 Colord PNMImage::
01351 get_average_xel_a() const {
01352   Colord color (Colord::zero());
01353   if (_x_size == 0 || _y_size == 0) {
01354     return color;
01355   }
01356 
01357   int x, y;
01358   for (x = 0; x < _x_size; ++x) {
01359     for (y = 0; y < _y_size; ++y) {
01360       color += get_xel_a(x, y);
01361     }
01362   }
01363 
01364   color *= 1.0 / (_x_size * _y_size);
01365   return color;
01366 }
01367 
01368 ////////////////////////////////////////////////////////////////////
01369 //     Function: PNMImage::get_average_gray
01370 //       Access: Published
01371 //  Description: Returns the average grayscale component of all of
01372 //               the pixels in the image.
01373 ////////////////////////////////////////////////////////////////////
01374 double PNMImage::
01375 get_average_gray() const {
01376   double color = 0.0;
01377   if (_x_size == 0 || _y_size == 0) {
01378     return color;
01379   }
01380 
01381   int x, y;
01382   for (x = 0; x < _x_size; ++x) {
01383     for (y = 0; y < _y_size; ++y) {
01384       color += get_gray(x, y);
01385     }
01386   }
01387 
01388   color *= 1.0 / (_x_size * _y_size);
01389   return color;
01390 }
01391 
01392 ////////////////////////////////////////////////////////////////////
01393 //     Function: PNMImage::operator ~
01394 //       Access: Published
01395 //  Description: Returns a new PNMImage that is the
01396 //               complement of the current PNMImage.
01397 ////////////////////////////////////////////////////////////////////
01398 PNMImage PNMImage::
01399 operator ~ () const {
01400   PNMImage target (*this);
01401   size_t array_size = _x_size * _y_size;
01402 
01403   if (_array != NULL && _alpha != NULL) {
01404     for (size_t i = 0; i < array_size; ++i) {
01405       target._array[i].r = _maxval - _array[i].r;
01406       target._array[i].g = _maxval - _array[i].g;
01407       target._array[i].b = _maxval - _array[i].b;
01408       target._alpha[i] = _maxval - _alpha[i];
01409     }
01410   } else if (_array != NULL) {
01411     for (size_t i = 0; i < array_size; ++i) {
01412       target._array[i].r = _maxval - _array[i].r;
01413       target._array[i].g = _maxval - _array[i].g;
01414       target._array[i].b = _maxval - _array[i].b;
01415     }
01416   } else if (_alpha != NULL) {
01417     for (size_t i = 0; i < array_size; ++i) {
01418       target._alpha[i] = _maxval - _alpha[i];
01419     }
01420   }
01421   return target;
01422 }
01423 
01424 ////////////////////////////////////////////////////////////////////
01425 //     Function: PNMImage::operator +=
01426 //       Access: Published
01427 //  Description: Returns a new PNMImage in which each pixel value
01428 //               is the sum of the corresponding pixel values
01429 //               in the two given images.
01430 //               Only valid when both images have the same size.
01431 ////////////////////////////////////////////////////////////////////
01432 void PNMImage::
01433 operator += (const PNMImage &other) {
01434   nassertv(_x_size == other._x_size && _y_size == other._y_size);
01435   nassertv(_maxval == other._maxval && _maxval == other._maxval);
01436   size_t array_size = _x_size * _y_size;
01437 
01438   if (_array != NULL && _alpha != NULL) {
01439     for (size_t i = 0; i < array_size; ++i) {
01440       _array[i].r = clamp_val(_array[i].r + other._array[i].r);
01441       _array[i].g = clamp_val(_array[i].g + other._array[i].g);
01442       _array[i].b = clamp_val(_array[i].b + other._array[i].b);
01443       _alpha[i] = clamp_val(_alpha[i] + other._alpha[i]);
01444     }
01445   } else if (_array != NULL) {
01446     for (size_t i = 0; i < array_size; ++i) {
01447       _array[i].r = clamp_val(_array[i].r + other._array[i].r);
01448       _array[i].g = clamp_val(_array[i].g + other._array[i].g);
01449       _array[i].b = clamp_val(_array[i].b + other._array[i].b);
01450     }
01451   } else if (_alpha != NULL) {
01452     for (size_t i = 0; i < array_size; ++i) {
01453       _alpha[i] = clamp_val(_alpha[i] + other._alpha[i]);
01454     }
01455   }
01456 }
01457 
01458 ////////////////////////////////////////////////////////////////////
01459 //     Function: PNMImage::operator +=
01460 //       Access: Published
01461 //  Description: Returns a new PNMImage in which the provided color
01462 //               is added to each pixel in the provided image.
01463 ////////////////////////////////////////////////////////////////////
01464 void PNMImage::
01465 operator += (const Colord &other) {
01466   size_t array_size = _x_size * _y_size;
01467   // Note: don't use to_val here because it clamps values below 0
01468   int add_r = (int)(other.get_x() * get_maxval() + 0.5);
01469   int add_g = (int)(other.get_y() * get_maxval() + 0.5);
01470   int add_b = (int)(other.get_z() * get_maxval() + 0.5);
01471   int add_a = (int)(other.get_w() * get_maxval() + 0.5);
01472 
01473   if (_array != NULL && _alpha != NULL) {
01474     for (size_t i = 0; i < array_size; ++i) {
01475       _array[i].r = clamp_val(_array[i].r + add_r);
01476       _array[i].g = clamp_val(_array[i].g + add_g);
01477       _array[i].b = clamp_val(_array[i].b + add_b);
01478       _alpha[i] = clamp_val(_alpha[i] + add_a);
01479     }
01480   } else if (_array != NULL) {
01481     for (size_t i = 0; i < array_size; ++i) {
01482       _array[i].r = clamp_val(_array[i].r + add_r);
01483       _array[i].g = clamp_val(_array[i].g + add_g);
01484       _array[i].b = clamp_val(_array[i].b + add_b);
01485     }
01486   } else if (_alpha != NULL) {
01487     for (size_t i = 0; i < array_size; ++i) {
01488       _alpha[i] = clamp_val(_alpha[i] + add_a);
01489     }
01490   }
01491 }
01492 
01493 ////////////////////////////////////////////////////////////////////
01494 //     Function: PNMImage::operator -=
01495 //       Access: Published
01496 //  Description: Returns a new PNMImage in which each pixel value
01497 //               from the right image is subtracted from each
01498 //               pixel value from the left image.
01499 //               Only valid when both images have the same size.
01500 ////////////////////////////////////////////////////////////////////
01501 void PNMImage::
01502 operator -= (const PNMImage &other) {
01503   nassertv(_x_size == other._x_size && _y_size == other._y_size);
01504   nassertv(_maxval == other._maxval && _maxval == other._maxval);
01505   size_t array_size = _x_size * _y_size;
01506 
01507   if (_array != NULL && _alpha != NULL) {
01508     for (size_t i = 0; i < array_size; ++i) {
01509       _array[i].r = clamp_val(_array[i].r - other._array[i].r);
01510       _array[i].g = clamp_val(_array[i].g - other._array[i].g);
01511       _array[i].b = clamp_val(_array[i].b - other._array[i].b);
01512       _alpha[i] = clamp_val(_alpha[i] - other._alpha[i]);
01513     }
01514   } else if (_array != NULL) {
01515     for (size_t i = 0; i < array_size; ++i) {
01516       _array[i].r = clamp_val(_array[i].r - other._array[i].r);
01517       _array[i].g = clamp_val(_array[i].g - other._array[i].g);
01518       _array[i].b = clamp_val(_array[i].b - other._array[i].b);
01519     }
01520   } else if (_alpha != NULL) {
01521     for (size_t i = 0; i < array_size; ++i) {
01522       _alpha[i] = clamp_val(_alpha[i] - other._alpha[i]);
01523     }
01524   }
01525 }
01526 
01527 ////////////////////////////////////////////////////////////////////
01528 //     Function: PNMImage::operator -=
01529 //       Access: Published
01530 //  Description: Returns a new PNMImage in which the provided color
01531 //               is subtracted from each pixel in the provided image.
01532 ////////////////////////////////////////////////////////////////////
01533 void PNMImage::
01534 operator -= (const Colord &other) {
01535   (*this) += (-other);
01536 }
01537 
01538 ////////////////////////////////////////////////////////////////////
01539 //     Function: PNMImage::operator *=
01540 //       Access: Published
01541 //  Description: Returns a new PNMImage in which each pixel value
01542 //               from the left image is multiplied by each
01543 //               pixel value from the right image. Note that the
01544 //               floating-point values in the 0..1 range are
01545 //               multiplied, not in the 0..maxval range.
01546 //               Only valid when both images have the same size.
01547 ////////////////////////////////////////////////////////////////////
01548 void PNMImage::
01549 operator *= (const PNMImage &other) {
01550   nassertv(_x_size == other._x_size && _y_size == other._y_size);
01551   size_t array_size = _x_size * _y_size;
01552 
01553   if (_array != NULL && _alpha != NULL) {
01554     for (size_t i = 0; i < array_size; ++i) {
01555       _array[i].r = to_val(from_val(_array[i].r) * other.from_val(other._array[i].r));
01556       _array[i].g = to_val(from_val(_array[i].g) * other.from_val(other._array[i].g));
01557       _array[i].b = to_val(from_val(_array[i].b) * other.from_val(other._array[i].b));
01558       _alpha[i] = to_val(from_val(_alpha[i]) * other.from_val(other._alpha[i]));
01559     }
01560   } else if (_array != NULL) {
01561     for (size_t i = 0; i < array_size; ++i) {
01562       _array[i].r = to_val(from_val(_array[i].r) * other.from_val(other._array[i].r));
01563       _array[i].g = to_val(from_val(_array[i].g) * other.from_val(other._array[i].g));
01564       _array[i].b = to_val(from_val(_array[i].b) * other.from_val(other._array[i].b));
01565     }
01566   } else if (_alpha != NULL) {
01567     for (size_t i = 0; i < array_size; ++i) {
01568       _alpha[i] = to_val(from_val(_alpha[i]) * other.from_val(other._alpha[i]));
01569     }
01570   }
01571 }
01572 
01573 ////////////////////////////////////////////////////////////////////
01574 //     Function: PNMImage::operator *=
01575 //       Access: Published
01576 //  Description: Multiplies every pixel value in the image by
01577 //               a constant floating-point multiplier value.
01578 ////////////////////////////////////////////////////////////////////
01579 void PNMImage::
01580 operator *= (double multiplier) {
01581   size_t array_size = _x_size * _y_size;
01582 
01583   if (_array != NULL && _alpha != NULL) {
01584     for (size_t i = 0; i < array_size; ++i) {
01585       _array[i].r = clamp_val(_array[i].r * multiplier);
01586       _array[i].g = clamp_val(_array[i].g * multiplier);
01587       _array[i].b = clamp_val(_array[i].b * multiplier);
01588       _alpha[i] = clamp_val(_alpha[i] * multiplier);
01589     }
01590   } else if (_array != NULL) {
01591     for (size_t i = 0; i < array_size; ++i) {
01592       _array[i].r = clamp_val(_array[i].r * multiplier);
01593       _array[i].g = clamp_val(_array[i].g * multiplier);
01594       _array[i].b = clamp_val(_array[i].b * multiplier);
01595     }
01596   } else if (_alpha != NULL) {
01597     for (size_t i = 0; i < array_size; ++i) {
01598       _alpha[i] = clamp_val(_alpha[i] * multiplier);
01599     }
01600   }
01601 }
01602 
 All Classes Functions Variables Enumerations