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::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 ©, 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 ©, 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 ©, 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 ©, 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 <, 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 ©, 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