Ver código fonte

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

David Rose 24 anos atrás
pai
commit
e71491040f

+ 5 - 0
panda/src/glgsg/config_glgsg.cxx

@@ -65,6 +65,11 @@ bool gl_save_mipmaps = config_glgsg.GetBool("gl-save-mipmaps", false);
 // variable.
 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;
 
 static GLDecalType

+ 2 - 1
panda/src/glgsg/config_glgsg.h

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

+ 80 - 9
panda/src/glgsg/glGraphicsStateGuardian.cxx

@@ -2223,9 +2223,15 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) {
   case GL_DEPTH_COMPONENT:
     glgsg_cat.debug(false) << "GL_DEPTH_COMPONENT, ";
     break;
+  case GL_BGR:
+    glgsg_cat.debug(false) << "GL_BGR, ";
+    break;
   case GL_RGB:
     glgsg_cat.debug(false) << "GL_RGB, ";
     break;
+  case GL_BGRA:
+    glgsg_cat.debug(false) << "GL_BGRA, ";
+    break;
   case GL_RGBA:
     glgsg_cat.debug(false) << "GL_RGBA, ";
     break;
@@ -2350,9 +2356,15 @@ draw_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,
   case GL_DEPTH_COMPONENT:
     glgsg_cat.debug(false) << "GL_DEPTH_COMPONENT, ";
     break;
+  case GL_BGR:
+    glgsg_cat.debug(false) << "GL_BGR, ";
+    break;
   case GL_RGB:
     glgsg_cat.debug(false) << "GL_RGB, ";
     break;
+  case GL_BGRA:
+    glgsg_cat.debug(false) << "GL_BGRA, ";
+    break;
   case GL_RGBA:
     glgsg_cat.debug(false) << "GL_RGBA, ";
     break;
@@ -3784,10 +3796,12 @@ compute_gl_image_size(int xsize, int ysize, int external_format, int type) {
     num_components = 2;
     break;
 
+  case GL_BGR:
   case GL_RGB:
     num_components = 3;
     break;
 
+  case GL_BGRA:
   case GL_RGBA:
     num_components = 4;
     break;
@@ -3819,6 +3833,40 @@ compute_gl_image_size(int xsize, int ysize, int external_format, int type) {
 }
 #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
@@ -3837,13 +3885,30 @@ apply_texture_immediate(Texture *tex) {
     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 external_format = get_external_image_format(pb->get_format());
   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
   int wanted_size = 
-    compute_gl_image_size(pb->get_xsize(), pb->get_ysize(),
+    compute_gl_image_size(xsize, ysize,
                           external_format, type);
   nassertr(wanted_size == (int)pb->_image.size(), false);
 #endif  // NDEBUG
@@ -3854,7 +3919,7 @@ apply_texture_immediate(Texture *tex) {
   glgsg_cat.debug()
     << "glTexImage2D(GL_TEXTURE_2D, "
     << (int)internal_format << ", "
-    << pb->get_xsize() << ", " << pb->get_ysize() << ", "
+    << xsize << ", " << ysize << ", "
     << pb->get_border() << ", " << (int)external_format << ", "
     << (int)type << ", " << tex->get_name() << ")\n";
 #endif
@@ -3868,8 +3933,8 @@ apply_texture_immediate(Texture *tex) {
       }
 #endif
       gluBuild2DMipmaps(GL_TEXTURE_2D, internal_format,
-                        pb->get_xsize(), pb->get_ysize(),
-                        external_format, type, pb->_image);
+                        xsize, ysize,
+                        external_format, type, image);
 #ifndef NDEBUG
       if (gl_save_mipmaps) {
         save_mipmap_images(tex);
@@ -3882,8 +3947,8 @@ apply_texture_immediate(Texture *tex) {
 
   nassertr(!pb->_image.empty(), false);
   glTexImage2D(GL_TEXTURE_2D, 0, internal_format,
-               pb->get_xsize(), pb->get_ysize(), pb->get_border(),
-               external_format, type, pb->_image);
+               xsize, ysize, pb->get_border(),
+               external_format, type, image);
   report_errors();
   return true;
 }
@@ -3901,6 +3966,8 @@ get_texture_wrap_mode(Texture::WrapMode wm) {
     return GL_CLAMP;
   case Texture::WM_repeat:
     return GL_REPEAT;
+  case Texture::WM_invalid:
+    break;
   }
   glgsg_cat.error() << "Invalid Texture::WrapMode value!\n";
   return GL_CLAMP;
@@ -3924,6 +3991,8 @@ get_texture_filter_type(Texture::FilterType ft) {
     case Texture::FT_nearest_mipmap_linear:
     case Texture::FT_linear_mipmap_linear:
       return GL_LINEAR;
+    case Texture::FT_invalid:
+      break;
     }
   } else {
     switch (ft) {
@@ -3939,6 +4008,8 @@ get_texture_filter_type(Texture::FilterType ft) {
       return GL_NEAREST_MIPMAP_LINEAR;
     case Texture::FT_linear_mipmap_linear:
       return GL_LINEAR_MIPMAP_LINEAR;
+    case Texture::FT_invalid:
+      break;
     }
   }
   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_rgb12:
   case PixelBuffer::F_rgb332:
-    return GL_RGB;
+    return gl_supports_bgr ? GL_BGR : GL_RGB;
   case PixelBuffer::F_rgba:
   case PixelBuffer::F_rgbm:
   case PixelBuffer::F_rgba4:
   case PixelBuffer::F_rgba5:
   case PixelBuffer::F_rgba8:
   case PixelBuffer::F_rgba12:
-    return GL_RGBA;
+    return gl_supports_bgr ? GL_BGRA : GL_RGBA;
   case PixelBuffer::F_luminance:
     return GL_LUMINANCE;
   case PixelBuffer::F_luminance_alphamask:
@@ -4016,7 +4087,7 @@ get_external_image_format(PixelBuffer::Format format) {
   glgsg_cat.error()
     << "Invalid PixelBuffer::Format value in get_external_image_format(): "
     << (int)format << "\n";
-  return GL_RGB;
+  return GL_BGR;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 18 - 15
panda/src/gobj/pixelBuffer.cxx

@@ -168,9 +168,12 @@ bool PixelBuffer::write( const string& name ) const
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: read
-//       Access:
-//  Description:
+//     Function: load
+//       Access: Public
+//  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)
 {
@@ -228,9 +231,9 @@ bool PixelBuffer::load(const PNMImage& pnmimage)
         if (is_grayscale) {
           store_unscaled_byte(idx, pnmimage.get_gray_val(i, j));
         } 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_green_val(i, j));
+          store_unscaled_byte(idx, pnmimage.get_red_val(i, j));
         }
         if (has_alpha) {
           store_unscaled_byte(idx, pnmimage.get_alpha_val(i, j));
@@ -250,9 +253,9 @@ bool PixelBuffer::load(const PNMImage& pnmimage)
         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));
+          store_unscaled_short(idx, pnmimage.get_green_val(i, j));
+          store_unscaled_short(idx, pnmimage.get_red_val(i, j));
         }
         if (has_alpha) {
           store_unscaled_short(idx, pnmimage.get_alpha_val(i, j));
@@ -274,9 +277,9 @@ bool PixelBuffer::load(const PNMImage& pnmimage)
         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);
+          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) {
           store_scaled_byte(idx, pnmimage.get_alpha_val(i, j), scale);
@@ -298,9 +301,9 @@ bool PixelBuffer::load(const PNMImage& pnmimage)
         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);
+          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) {
           store_scaled_short(idx, pnmimage.get_alpha_val(i, j), scale);
@@ -332,9 +335,9 @@ store(PNMImage &pnmimage) const {
         if (is_grayscale) {
           pnmimage.set_gray(i, j, get_unsigned_byte(idx));
         } 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_green(i, j, get_unsigned_byte(idx));
+          pnmimage.set_red(i, j, get_unsigned_byte(idx));
         }
         if (has_alpha)
           pnmimage.set_alpha(i, j, get_unsigned_byte(idx));
@@ -353,9 +356,9 @@ store(PNMImage &pnmimage) const {
         if (is_grayscale) {
           pnmimage.set_gray(i, j, get_unsigned_short(idx));
         } 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_green(i, j, get_unsigned_short(idx));
+          pnmimage.set_red(i, j, get_unsigned_short(idx));
         }
         if (has_alpha)
           pnmimage.set_alpha(i, j, get_unsigned_short(idx));

+ 12 - 0
panda/src/gobj/pixelBuffer.h

@@ -38,6 +38,18 @@ class RenderBuffer;
 ////////////////////////////////////////////////////////////////////
 //       Class : PixelBuffer
 // 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 {
 public: