change normal texture byte ordering from RGBA to BGRA (big-endian)

This commit is contained in:
David Rose 2002-02-21 00:24:33 +00:00
parent eb0f572b3b
commit e71491040f
5 changed files with 117 additions and 25 deletions

View File

@ -65,6 +65,11 @@ bool gl_save_mipmaps = config_glgsg.GetBool("gl-save-mipmaps", false);
// variable. // variable.
bool gl_auto_normalize_lighting = config_glgsg.GetBool("auto-normalize-lighting", false); bool gl_auto_normalize_lighting = config_glgsg.GetBool("auto-normalize-lighting", false);
// Configure this true to indicate the current version of GL fully
// supports textures with B, G, R ordering; false if it only supports
// R, G, B.
bool gl_supports_bgr = config_glgsg.GetBool("gl-supports-bgr", true);
GLDecalType gl_decal_type = GDT_offset; GLDecalType gl_decal_type = GDT_offset;
static GLDecalType static GLDecalType

View File

@ -30,8 +30,9 @@ extern bool gl_cull_traversal;
extern bool gl_ignore_mipmaps; extern bool gl_ignore_mipmaps;
extern bool gl_force_mipmaps; extern bool gl_force_mipmaps;
extern bool gl_show_mipmaps; extern bool gl_show_mipmaps;
extern bool gl_auto_normalize_lighting;
extern bool gl_save_mipmaps; extern bool gl_save_mipmaps;
extern bool gl_auto_normalize_lighting;
extern bool gl_supports_bgr;
// Ways to implement decals. // Ways to implement decals.
enum GLDecalType { enum GLDecalType {

View File

@ -2223,9 +2223,15 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT:
glgsg_cat.debug(false) << "GL_DEPTH_COMPONENT, "; glgsg_cat.debug(false) << "GL_DEPTH_COMPONENT, ";
break; break;
case GL_BGR:
glgsg_cat.debug(false) << "GL_BGR, ";
break;
case GL_RGB: case GL_RGB:
glgsg_cat.debug(false) << "GL_RGB, "; glgsg_cat.debug(false) << "GL_RGB, ";
break; break;
case GL_BGRA:
glgsg_cat.debug(false) << "GL_BGRA, ";
break;
case GL_RGBA: case GL_RGBA:
glgsg_cat.debug(false) << "GL_RGBA, "; glgsg_cat.debug(false) << "GL_RGBA, ";
break; break;
@ -2350,9 +2356,15 @@ draw_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT:
glgsg_cat.debug(false) << "GL_DEPTH_COMPONENT, "; glgsg_cat.debug(false) << "GL_DEPTH_COMPONENT, ";
break; break;
case GL_BGR:
glgsg_cat.debug(false) << "GL_BGR, ";
break;
case GL_RGB: case GL_RGB:
glgsg_cat.debug(false) << "GL_RGB, "; glgsg_cat.debug(false) << "GL_RGB, ";
break; break;
case GL_BGRA:
glgsg_cat.debug(false) << "GL_BGRA, ";
break;
case GL_RGBA: case GL_RGBA:
glgsg_cat.debug(false) << "GL_RGBA, "; glgsg_cat.debug(false) << "GL_RGBA, ";
break; break;
@ -3784,10 +3796,12 @@ compute_gl_image_size(int xsize, int ysize, int external_format, int type) {
num_components = 2; num_components = 2;
break; break;
case GL_BGR:
case GL_RGB: case GL_RGB:
num_components = 3; num_components = 3;
break; break;
case GL_BGRA:
case GL_RGBA: case GL_RGBA:
num_components = 4; num_components = 4;
break; break;
@ -3819,6 +3833,40 @@ compute_gl_image_size(int xsize, int ysize, int external_format, int type) {
} }
#endif // NDEBUG #endif // NDEBUG
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::uchar_bgr_to_rgb
// Description: Recopies the given array of pixels, converting from
// BGR to RGB arrangement.
////////////////////////////////////////////////////////////////////
static void
uchar_bgr_to_rgb(unsigned char *dest, const unsigned char *source,
int num_pixels) {
for (int i = 0; i < num_pixels; i++) {
dest[0] = source[2];
dest[1] = source[1];
dest[2] = source[0];
dest += 3;
source += 3;
}
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::uchar_bgra_to_rgba
// Description: Recopies the given array of pixels, converting from
// BGRA to RGBA arrangement.
////////////////////////////////////////////////////////////////////
static void
uchar_bgra_to_rgba(unsigned char *dest, const unsigned char *source,
int num_pixels) {
for (int i = 0; i < num_pixels; i++) {
dest[0] = source[2];
dest[1] = source[1];
dest[2] = source[0];
dest[3] = source[3];
dest += 4;
source += 4;
}
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::apply_texture_immediate // Function: GLGraphicsStateGuardian::apply_texture_immediate
@ -3837,13 +3885,30 @@ apply_texture_immediate(Texture *tex) {
return false; return false;
} }
int xsize = pb->get_xsize();
int ysize = pb->get_ysize();
int num_pixels = xsize * ysize;
GLenum internal_format = get_internal_image_format(pb->get_format()); GLenum internal_format = get_internal_image_format(pb->get_format());
GLenum external_format = get_external_image_format(pb->get_format()); GLenum external_format = get_external_image_format(pb->get_format());
GLenum type = get_image_type(pb->get_image_type()); GLenum type = get_image_type(pb->get_image_type());
uchar *image = pb->_image;
if (!gl_supports_bgr) {
// If the GL doesn't claim to support BGR, we may have to reverse
// the byte ordering of the image.
if (external_format == GL_RGB && pb->get_image_type() == PixelBuffer::T_unsigned_byte) {
image = (uchar *)alloca(num_pixels * 3);
uchar_bgr_to_rgb(image, pb->_image, num_pixels);
} else if (external_format == GL_RGBA && pb->get_image_type() == PixelBuffer::T_unsigned_byte) {
image = (uchar *)alloca(num_pixels * 4);
uchar_bgra_to_rgba(image, pb->_image, num_pixels);
}
}
#ifndef NDEBUG #ifndef NDEBUG
int wanted_size = int wanted_size =
compute_gl_image_size(pb->get_xsize(), pb->get_ysize(), compute_gl_image_size(xsize, ysize,
external_format, type); external_format, type);
nassertr(wanted_size == (int)pb->_image.size(), false); nassertr(wanted_size == (int)pb->_image.size(), false);
#endif // NDEBUG #endif // NDEBUG
@ -3854,7 +3919,7 @@ apply_texture_immediate(Texture *tex) {
glgsg_cat.debug() glgsg_cat.debug()
<< "glTexImage2D(GL_TEXTURE_2D, " << "glTexImage2D(GL_TEXTURE_2D, "
<< (int)internal_format << ", " << (int)internal_format << ", "
<< pb->get_xsize() << ", " << pb->get_ysize() << ", " << xsize << ", " << ysize << ", "
<< pb->get_border() << ", " << (int)external_format << ", " << pb->get_border() << ", " << (int)external_format << ", "
<< (int)type << ", " << tex->get_name() << ")\n"; << (int)type << ", " << tex->get_name() << ")\n";
#endif #endif
@ -3868,8 +3933,8 @@ apply_texture_immediate(Texture *tex) {
} }
#endif #endif
gluBuild2DMipmaps(GL_TEXTURE_2D, internal_format, gluBuild2DMipmaps(GL_TEXTURE_2D, internal_format,
pb->get_xsize(), pb->get_ysize(), xsize, ysize,
external_format, type, pb->_image); external_format, type, image);
#ifndef NDEBUG #ifndef NDEBUG
if (gl_save_mipmaps) { if (gl_save_mipmaps) {
save_mipmap_images(tex); save_mipmap_images(tex);
@ -3882,8 +3947,8 @@ apply_texture_immediate(Texture *tex) {
nassertr(!pb->_image.empty(), false); nassertr(!pb->_image.empty(), false);
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, glTexImage2D(GL_TEXTURE_2D, 0, internal_format,
pb->get_xsize(), pb->get_ysize(), pb->get_border(), xsize, ysize, pb->get_border(),
external_format, type, pb->_image); external_format, type, image);
report_errors(); report_errors();
return true; return true;
} }
@ -3901,6 +3966,8 @@ get_texture_wrap_mode(Texture::WrapMode wm) {
return GL_CLAMP; return GL_CLAMP;
case Texture::WM_repeat: case Texture::WM_repeat:
return GL_REPEAT; return GL_REPEAT;
case Texture::WM_invalid:
break;
} }
glgsg_cat.error() << "Invalid Texture::WrapMode value!\n"; glgsg_cat.error() << "Invalid Texture::WrapMode value!\n";
return GL_CLAMP; return GL_CLAMP;
@ -3924,6 +3991,8 @@ get_texture_filter_type(Texture::FilterType ft) {
case Texture::FT_nearest_mipmap_linear: case Texture::FT_nearest_mipmap_linear:
case Texture::FT_linear_mipmap_linear: case Texture::FT_linear_mipmap_linear:
return GL_LINEAR; return GL_LINEAR;
case Texture::FT_invalid:
break;
} }
} else { } else {
switch (ft) { switch (ft) {
@ -3939,6 +4008,8 @@ get_texture_filter_type(Texture::FilterType ft) {
return GL_NEAREST_MIPMAP_LINEAR; return GL_NEAREST_MIPMAP_LINEAR;
case Texture::FT_linear_mipmap_linear: case Texture::FT_linear_mipmap_linear:
return GL_LINEAR_MIPMAP_LINEAR; return GL_LINEAR_MIPMAP_LINEAR;
case Texture::FT_invalid:
break;
} }
} }
glgsg_cat.error() << "Invalid Texture::FilterType value!\n"; glgsg_cat.error() << "Invalid Texture::FilterType value!\n";
@ -3999,14 +4070,14 @@ get_external_image_format(PixelBuffer::Format format) {
case PixelBuffer::F_rgb8: case PixelBuffer::F_rgb8:
case PixelBuffer::F_rgb12: case PixelBuffer::F_rgb12:
case PixelBuffer::F_rgb332: case PixelBuffer::F_rgb332:
return GL_RGB; return gl_supports_bgr ? GL_BGR : GL_RGB;
case PixelBuffer::F_rgba: case PixelBuffer::F_rgba:
case PixelBuffer::F_rgbm: case PixelBuffer::F_rgbm:
case PixelBuffer::F_rgba4: case PixelBuffer::F_rgba4:
case PixelBuffer::F_rgba5: case PixelBuffer::F_rgba5:
case PixelBuffer::F_rgba8: case PixelBuffer::F_rgba8:
case PixelBuffer::F_rgba12: case PixelBuffer::F_rgba12:
return GL_RGBA; return gl_supports_bgr ? GL_BGRA : GL_RGBA;
case PixelBuffer::F_luminance: case PixelBuffer::F_luminance:
return GL_LUMINANCE; return GL_LUMINANCE;
case PixelBuffer::F_luminance_alphamask: case PixelBuffer::F_luminance_alphamask:
@ -4016,7 +4087,7 @@ get_external_image_format(PixelBuffer::Format format) {
glgsg_cat.error() glgsg_cat.error()
<< "Invalid PixelBuffer::Format value in get_external_image_format(): " << "Invalid PixelBuffer::Format value in get_external_image_format(): "
<< (int)format << "\n"; << (int)format << "\n";
return GL_RGB; return GL_BGR;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -168,9 +168,12 @@ bool PixelBuffer::write( const string& name ) const
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: read // Function: load
// Access: // Access: Public
// Description: // Description: Extracts the image data from the given PNMImage and
// stores it in the _image member, as an unadorned array
// of pixel values. Note that we now store pixel
// components in the order B, G, R, A.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool PixelBuffer::load(const PNMImage& pnmimage) bool PixelBuffer::load(const PNMImage& pnmimage)
{ {
@ -228,9 +231,9 @@ bool PixelBuffer::load(const PNMImage& pnmimage)
if (is_grayscale) { if (is_grayscale) {
store_unscaled_byte(idx, pnmimage.get_gray_val(i, j)); store_unscaled_byte(idx, pnmimage.get_gray_val(i, j));
} else { } else {
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)); store_unscaled_byte(idx, pnmimage.get_blue_val(i, j));
store_unscaled_byte(idx, pnmimage.get_green_val(i, j));
store_unscaled_byte(idx, pnmimage.get_red_val(i, j));
} }
if (has_alpha) { if (has_alpha) {
store_unscaled_byte(idx, pnmimage.get_alpha_val(i, j)); store_unscaled_byte(idx, pnmimage.get_alpha_val(i, j));
@ -250,9 +253,9 @@ bool PixelBuffer::load(const PNMImage& pnmimage)
if (is_grayscale) { if (is_grayscale) {
store_unscaled_short(idx, pnmimage.get_gray_val(i, j)); store_unscaled_short(idx, pnmimage.get_gray_val(i, j));
} else { } 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)); store_unscaled_short(idx, pnmimage.get_blue_val(i, j));
store_unscaled_short(idx, pnmimage.get_green_val(i, j));
store_unscaled_short(idx, pnmimage.get_red_val(i, j));
} }
if (has_alpha) { if (has_alpha) {
store_unscaled_short(idx, pnmimage.get_alpha_val(i, j)); store_unscaled_short(idx, pnmimage.get_alpha_val(i, j));
@ -274,9 +277,9 @@ bool PixelBuffer::load(const PNMImage& pnmimage)
if (is_grayscale) { if (is_grayscale) {
store_scaled_byte(idx, pnmimage.get_gray_val(i, j), scale); store_scaled_byte(idx, pnmimage.get_gray_val(i, j), scale);
} else { } 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); store_scaled_byte(idx, pnmimage.get_blue_val(i, j), scale);
store_scaled_byte(idx, pnmimage.get_green_val(i, j), scale);
store_scaled_byte(idx, pnmimage.get_red_val(i, j), scale);
} }
if (has_alpha) { if (has_alpha) {
store_scaled_byte(idx, pnmimage.get_alpha_val(i, j), scale); store_scaled_byte(idx, pnmimage.get_alpha_val(i, j), scale);
@ -298,9 +301,9 @@ bool PixelBuffer::load(const PNMImage& pnmimage)
if (is_grayscale) { if (is_grayscale) {
store_scaled_short(idx, pnmimage.get_gray_val(i, j), scale); store_scaled_short(idx, pnmimage.get_gray_val(i, j), scale);
} else { } 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); store_scaled_short(idx, pnmimage.get_blue_val(i, j), scale);
store_scaled_short(idx, pnmimage.get_green_val(i, j), scale);
store_scaled_short(idx, pnmimage.get_red_val(i, j), scale);
} }
if (has_alpha) { if (has_alpha) {
store_scaled_short(idx, pnmimage.get_alpha_val(i, j), scale); store_scaled_short(idx, pnmimage.get_alpha_val(i, j), scale);
@ -332,9 +335,9 @@ store(PNMImage &pnmimage) const {
if (is_grayscale) { if (is_grayscale) {
pnmimage.set_gray(i, j, get_unsigned_byte(idx)); pnmimage.set_gray(i, j, get_unsigned_byte(idx));
} else { } else {
pnmimage.set_red(i, j, get_unsigned_byte(idx));
pnmimage.set_green(i, j, get_unsigned_byte(idx));
pnmimage.set_blue(i, j, get_unsigned_byte(idx)); pnmimage.set_blue(i, j, get_unsigned_byte(idx));
pnmimage.set_green(i, j, get_unsigned_byte(idx));
pnmimage.set_red(i, j, get_unsigned_byte(idx));
} }
if (has_alpha) if (has_alpha)
pnmimage.set_alpha(i, j, get_unsigned_byte(idx)); pnmimage.set_alpha(i, j, get_unsigned_byte(idx));
@ -353,9 +356,9 @@ store(PNMImage &pnmimage) const {
if (is_grayscale) { if (is_grayscale) {
pnmimage.set_gray(i, j, get_unsigned_short(idx)); pnmimage.set_gray(i, j, get_unsigned_short(idx));
} else { } else {
pnmimage.set_red(i, j, get_unsigned_short(idx));
pnmimage.set_green(i, j, get_unsigned_short(idx));
pnmimage.set_blue(i, j, get_unsigned_short(idx)); pnmimage.set_blue(i, j, get_unsigned_short(idx));
pnmimage.set_green(i, j, get_unsigned_short(idx));
pnmimage.set_red(i, j, get_unsigned_short(idx));
} }
if (has_alpha) if (has_alpha)
pnmimage.set_alpha(i, j, get_unsigned_short(idx)); pnmimage.set_alpha(i, j, get_unsigned_short(idx));

View File

@ -38,6 +38,18 @@ class RenderBuffer;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Class : PixelBuffer // Class : PixelBuffer
// Description : // Description :
// Maintains an array of pixel data corresponding to an
// image, e.g. copied from the frame buffer, or as part
// of a Texture.
// Pixel data is stored in a generic, uncompressed
// format. Each row of pixels is laid out horizontally,
// from the top to the bottom, with no padding between
// rows. Each pixel consumes one or more bytes,
// according to get_component_width(). If the Format
// indicates multiple components are present, they are
// stored in the order B, G, R, A.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA PixelBuffer : public ImageBuffer { class EXPCL_PANDA PixelBuffer : public ImageBuffer {
public: public: