diff --git a/panda/src/gobj/pixelBuffer.I b/panda/src/gobj/pixelBuffer.I index f6a23d050d..57cb468916 100644 --- a/panda/src/gobj/pixelBuffer.I +++ b/panda/src/gobj/pixelBuffer.I @@ -311,39 +311,67 @@ set_uchar_rgb_texel(const uchar color[3], int x, int y, int width) } //////////////////////////////////////////////////////////////////// -// Function: PixelBuffer::store_unsigned_byte +// Function: PixelBuffer::store_unscaled_byte // Access: Private // Description: This is used by load() to store the next consecutive // component value into the indicated element of the // array, which is taken to be an array of unsigned -// bytes. +// bytes. The value is assumed to be in the range +// 0-255. //////////////////////////////////////////////////////////////////// INLINE void PixelBuffer:: -store_unsigned_byte(int &index, double value) { - nassertv(index >= 0 && index < (int)_image.size()); - _image[index++] = (uchar)(value * 255.0); +store_unscaled_byte(int &index, int value) { + _image[index++] = (uchar)value; } //////////////////////////////////////////////////////////////////// -// Function: PixelBuffer::store_unsigned_short +// Function: PixelBuffer::store_unscaled_short // Access: Private // Description: This is used by load() to store the next consecutive // component value into the indicated element of the // array, which is taken to be an array of unsigned -// shorts. +// shorts. The value is assumed to be in the range +// 0-65535. //////////////////////////////////////////////////////////////////// INLINE void PixelBuffer:: -store_unsigned_short(int &index, double value) { - nassertv(index >= 0 && index+1 < (int)_image.size()); +store_unscaled_short(int &index, int value) { union { ushort us; uchar uc[2]; } v; - v.us = (ushort)(value * 65535.0); + v.us = (ushort)value; _image[index++] = v.uc[0]; _image[index++] = v.uc[1]; } +//////////////////////////////////////////////////////////////////// +// Function: PixelBuffer::store_scaled_byte +// Access: Private +// Description: This is used by load() to store the next consecutive +// component value into the indicated element of the +// array, which is taken to be an array of unsigned +// bytes. The value will be scaled by the indicated +// factor before storing it. +//////////////////////////////////////////////////////////////////// +INLINE void PixelBuffer:: +store_scaled_byte(int &index, int value, double scale) { + store_unscaled_byte(index, (int)(value * scale)); +} + +//////////////////////////////////////////////////////////////////// +// Function: PixelBuffer::store_scaled_short +// Access: Private +// Description: This is used by load() to store the next consecutive +// component value into the indicated element of the +// array, which is taken to be an array of unsigned +// shorts. The value will be scaled by the indicated +// factor before storing it. +//////////////////////////////////////////////////////////////////// +INLINE void PixelBuffer:: +store_scaled_short(int &index, int value, double scale) { + store_unscaled_short(index, (int)(value * scale)); +} + //////////////////////////////////////////////////////////////////// // Function: PixelBuffer::get_unsigned_byte // Access: Private diff --git a/panda/src/gobj/pixelBuffer.cxx b/panda/src/gobj/pixelBuffer.cxx index 1d45420be9..dd77b13616 100644 --- a/panda/src/gobj/pixelBuffer.cxx +++ b/panda/src/gobj/pixelBuffer.cxx @@ -111,28 +111,9 @@ bool PixelBuffer::load(const PNMImage& pnmimage) bool has_alpha = pnmimage.has_alpha(); bool is_grayscale = pnmimage.is_grayscale(); - if (maxval > 255) { - // Wide pixels; we need to use a short for each component. - _type = T_unsigned_short; - _image = PTA_uchar(_xsize * _ysize * _components * 2); - int idx = 0; - - for (int j = _ysize-1; j >= 0; j--) { - for (int i = 0; i < _xsize; i++) { - if (is_grayscale) { - store_unsigned_short(idx, pnmimage.get_gray(i, j)); - } else { - store_unsigned_short(idx, pnmimage.get_red(i, j)); - store_unsigned_short(idx, pnmimage.get_green(i, j)); - store_unsigned_short(idx, pnmimage.get_blue(i, j)); - } - if (has_alpha) { - store_unsigned_short(idx, pnmimage.get_alpha(i, j)); - } - } - } - } else { - // Normal pixels: a byte per component will do. + if (maxval == 255) { + // Most common case: one byte per pixel, and the source image + // shows a maxval of 255. No scaling is necessary. _type = T_unsigned_byte; _image = PTA_uchar(_xsize * _ysize * _components); int idx = 0; @@ -140,14 +121,84 @@ bool PixelBuffer::load(const PNMImage& pnmimage) for (int j = _ysize-1; j >= 0; j--) { for (int i = 0; i < _xsize; i++) { if (is_grayscale) { - store_unsigned_byte(idx, pnmimage.get_gray(i, j)); + store_unscaled_byte(idx, pnmimage.get_gray_val(i, j)); } else { - store_unsigned_byte(idx, pnmimage.get_red(i, j)); - store_unsigned_byte(idx, pnmimage.get_green(i, j)); - store_unsigned_byte(idx, pnmimage.get_blue(i, j)); + store_unscaled_byte(idx, pnmimage.get_red_val(i, j)); + store_unscaled_byte(idx, pnmimage.get_green_val(i, j)); + store_unscaled_byte(idx, pnmimage.get_blue_val(i, j)); } if (has_alpha) { - store_unsigned_byte(idx, pnmimage.get_alpha(i, j)); + store_unscaled_byte(idx, pnmimage.get_alpha_val(i, j)); + } + } + } + + } else if (maxval == 65535) { + // Another possible case: two bytes per pixel, and the source + // image shows a maxval of 65535. Again, no scaling is necessary. + _type = T_unsigned_short; + _image = PTA_uchar(_xsize * _ysize * _components * 2); + int idx = 0; + + for (int j = _ysize-1; j >= 0; j--) { + for (int i = 0; i < _xsize; i++) { + if (is_grayscale) { + store_unscaled_short(idx, pnmimage.get_gray_val(i, j)); + } else { + store_unscaled_short(idx, pnmimage.get_red_val(i, j)); + store_unscaled_short(idx, pnmimage.get_green_val(i, j)); + store_unscaled_short(idx, pnmimage.get_blue_val(i, j)); + } + if (has_alpha) { + store_unscaled_short(idx, pnmimage.get_alpha_val(i, j)); + } + } + } + + } else if (maxval <= 255) { + // A less common case: one byte per pixel, but the maxval is + // something other than 255. In this case, we should scale the + // pixel values up to the appropriate amount. + _type = T_unsigned_byte; + _image = PTA_uchar(_xsize * _ysize * _components); + int idx = 0; + double scale = 255.0 / (double)maxval; + + for (int j = _ysize-1; j >= 0; j--) { + for (int i = 0; i < _xsize; i++) { + if (is_grayscale) { + store_scaled_byte(idx, pnmimage.get_gray_val(i, j), scale); + } else { + store_scaled_byte(idx, pnmimage.get_red_val(i, j), scale); + store_scaled_byte(idx, pnmimage.get_green_val(i, j), scale); + store_scaled_byte(idx, pnmimage.get_blue_val(i, j), scale); + } + if (has_alpha) { + store_scaled_byte(idx, pnmimage.get_alpha_val(i, j), scale); + } + } + } + + } else { + // Another uncommon case: two bytes per pixel, and the maxval is + // something other than 65535. Again, we must scale the pixel + // values. + _type = T_unsigned_short; + _image = PTA_uchar(_xsize * _ysize * _components * 2); + int idx = 0; + double scale = 65535.0 / (double)maxval; + + for (int j = _ysize-1; j >= 0; j--) { + for (int i = 0; i < _xsize; i++) { + if (is_grayscale) { + store_scaled_short(idx, pnmimage.get_gray_val(i, j), scale); + } else { + store_scaled_short(idx, pnmimage.get_red_val(i, j), scale); + store_scaled_short(idx, pnmimage.get_green_val(i, j), scale); + store_scaled_short(idx, pnmimage.get_blue_val(i, j), scale); + } + if (has_alpha) { + store_scaled_short(idx, pnmimage.get_alpha_val(i, j), scale); } } } diff --git a/panda/src/gobj/pixelBuffer.h b/panda/src/gobj/pixelBuffer.h index 13a24a2054..d17e78da35 100644 --- a/panda/src/gobj/pixelBuffer.h +++ b/panda/src/gobj/pixelBuffer.h @@ -112,8 +112,10 @@ public: int x, int y, int width); private: - INLINE void store_unsigned_byte(int &index, double value); - INLINE void store_unsigned_short(int &index, double value); + INLINE void store_unscaled_byte(int &index, int value); + INLINE void store_unscaled_short(int &index, int value); + INLINE void store_scaled_byte(int &index, int value, double scale); + INLINE void store_scaled_short(int &index, int value, double scale); INLINE double get_unsigned_byte(int &index) const; INLINE double get_unsigned_short(int &index) const;