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