浏览代码

tga optimizations

Sean Barrett 11 年之前
父节点
当前提交
f0976fd312
共有 1 个文件被更改,包括 109 次插入143 次删除
  1. 109 143
      stb_image.c

+ 109 - 143
stb_image.c

@@ -22,7 +22,7 @@
       - overridable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD)
       - overridable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD)
 
 
    Latest revisions:
    Latest revisions:
-      1.35 (2014-05-27) warnings, bugfixes, etc
+      1.35 (2014-05-27) warnings, bugfixes, TGA optimization, etc
       1.34 (unknown   ) warning fix
       1.34 (unknown   ) warning fix
       1.33 (2011-07-14) minor fixes suggested by Dave Moore
       1.33 (2011-07-14) minor fixes suggested by Dave Moore
       1.32 (2011-07-13) info support for all filetypes (SpartanJ)
       1.32 (2011-07-13) info support for all filetypes (SpartanJ)
@@ -57,7 +57,7 @@
                                                  John Bartholomew
                                                  John Bartholomew
  Optimizations & bugfixes                        Ken Hamada
  Optimizations & bugfixes                        Ken Hamada
     Fabian "ryg" Giesen                          Cort Stratton
     Fabian "ryg" Giesen                          Cort Stratton
-                                                 Blazej Dariusz Roszkowski
+    Arseny Kapoulkine                            Blazej Dariusz Roszkowski
                                                  Thibault Reuille
                                                  Thibault Reuille
  If your name should be here but                 Paul Du Bois
  If your name should be here but                 Paul Du Bois
  isn't let Sean know.                            Guillaume George
  isn't let Sean know.                            Guillaume George
@@ -3260,13 +3260,13 @@ static stbi_uc *tga_load(stbi *s, int *x, int *y, int *comp, int req_comp)
    int tga_width = get16le(s);
    int tga_width = get16le(s);
    int tga_height = get16le(s);
    int tga_height = get16le(s);
    int tga_bits_per_pixel = get8u(s);
    int tga_bits_per_pixel = get8u(s);
+   int tga_comp = tga_bits_per_pixel / 8;
    int tga_inverted = get8u(s);
    int tga_inverted = get8u(s);
    //   image data
    //   image data
    unsigned char *tga_data;
    unsigned char *tga_data;
    unsigned char *tga_palette = NULL;
    unsigned char *tga_palette = NULL;
    int i, j;
    int i, j;
    unsigned char raw_data[4];
    unsigned char raw_data[4];
-   unsigned char trans_data[4];
    int RLE_count = 0;
    int RLE_count = 0;
    int RLE_repeating = 0;
    int RLE_repeating = 0;
    int read_next_pixel = 1;
    int read_next_pixel = 1;
@@ -3294,178 +3294,143 @@ static stbi_uc *tga_load(stbi *s, int *x, int *y, int *comp, int req_comp)
    //   If I'm paletted, then I'll use the number of bits from the palette
    //   If I'm paletted, then I'll use the number of bits from the palette
    if ( tga_indexed )
    if ( tga_indexed )
    {
    {
-      tga_bits_per_pixel = tga_palette_bits;
+      tga_comp = tga_palette_bits / 8;
    }
    }
 
 
    //   tga info
    //   tga info
    *x = tga_width;
    *x = tga_width;
    *y = tga_height;
    *y = tga_height;
-   if ( (req_comp < 1) || (req_comp > 4) )
-   {
-      //   just use whatever the file was
-      req_comp = tga_bits_per_pixel / 8;
-      *comp = req_comp;
-   } else
-   {
-      //   force a new number of components
-      *comp = tga_bits_per_pixel/8;
-   }
+   if (comp) *comp = tga_comp;
+
    tga_data = (unsigned char*)malloc( tga_width * tga_height * req_comp );
    tga_data = (unsigned char*)malloc( tga_width * tga_height * req_comp );
    if (!tga_data) return epuc("outofmem", "Out of memory");
    if (!tga_data) return epuc("outofmem", "Out of memory");
 
 
    //   skip to the data's starting position (offset usually = 0)
    //   skip to the data's starting position (offset usually = 0)
    skip(s, tga_offset );
    skip(s, tga_offset );
-   //   do I need to load a palette?
-   if ( tga_indexed )
-   {
-      //   any data to skip? (offset usually = 0)
-      skip(s, tga_palette_start );
-      //   load the palette
-      tga_palette = (unsigned char*)malloc( tga_palette_len * tga_palette_bits / 8 );
-      if (!tga_palette) {
-         free(tga_data);
-         return epuc("outofmem", "Out of memory");
-      }
-      if (!getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) {
-         free(tga_data);
-         free(tga_palette);
-         return epuc("bad palette", "Corrupt TGA");
+
+   if ( !tga_indexed && !tga_is_RLE) {
+      for (i=0; i < tga_height; ++i) {
+         int y = tga_inverted ? tga_height -i - 1 : i;
+         stbi__uint8 *tga_row = tga_data + y*tga_width*tga_comp;
+         getn(s, tga_row, tga_width * tga_comp);
       }
       }
-   }
-   //   load the data
-   trans_data[0] = trans_data[1] = trans_data[2] = trans_data[3] = 0;
-   for (i=0; i < tga_width * tga_height; ++i)
-   {
-      //   if I'm in RLE mode, do I need to get a RLE chunk?
-      if ( tga_is_RLE )
+   } else  {
+      //   do I need to load a palette?
+      if ( tga_indexed)
       {
       {
-         if ( RLE_count == 0 )
-         {
-            //   yep, get the next byte as a RLE command
-            int RLE_cmd = get8u(s);
-            RLE_count = 1 + (RLE_cmd & 127);
-            RLE_repeating = RLE_cmd >> 7;
-            read_next_pixel = 1;
-         } else if ( !RLE_repeating )
-         {
-            read_next_pixel = 1;
+         //   any data to skip? (offset usually = 0)
+         skip(s, tga_palette_start );
+         //   load the palette
+         tga_palette = (unsigned char*)malloc( tga_palette_len * tga_palette_bits / 8 );
+         if (!tga_palette) {
+            free(tga_data);
+            return epuc("outofmem", "Out of memory");
+         }
+         if (!getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) {
+            free(tga_data);
+            free(tga_palette);
+            return epuc("bad palette", "Corrupt TGA");
          }
          }
-      } else
-      {
-         read_next_pixel = 1;
       }
       }
-      //   OK, if I need to read a pixel, do it now
-      if ( read_next_pixel )
+      //   load the data
+      for (i=0; i < tga_width * tga_height; ++i)
       {
       {
-         //   load however much data we did have
-         if ( tga_indexed )
+         //   if I'm in RLE mode, do I need to get a RLE chunk?
+         if ( tga_is_RLE )
          {
          {
-            //   read in 1 byte, then perform the lookup
-            int pal_idx = get8u(s);
-            if ( pal_idx >= tga_palette_len )
+            if ( RLE_count == 0 )
             {
             {
-               //   invalid index
-               pal_idx = 0;
-            }
-            pal_idx *= tga_bits_per_pixel / 8;
-            for (j = 0; j*8 < tga_bits_per_pixel; ++j)
+               //   yep, get the next byte as a RLE command
+               int RLE_cmd = get8u(s);
+               RLE_count = 1 + (RLE_cmd & 127);
+               RLE_repeating = RLE_cmd >> 7;
+               read_next_pixel = 1;
+            } else if ( !RLE_repeating )
             {
             {
-               raw_data[j] = tga_palette[pal_idx+j];
+               read_next_pixel = 1;
             }
             }
          } else
          } else
          {
          {
-            //   read in the data raw
-            for (j = 0; j*8 < tga_bits_per_pixel; ++j)
+            read_next_pixel = 1;
+         }
+         //   OK, if I need to read a pixel, do it now
+         if ( read_next_pixel )
+         {
+            //   load however much data we did have
+            if ( tga_indexed )
+            {
+               //   read in 1 byte, then perform the lookup
+               int pal_idx = get8u(s);
+               if ( pal_idx >= tga_palette_len )
+               {
+                  //   invalid index
+                  pal_idx = 0;
+               }
+               pal_idx *= tga_bits_per_pixel / 8;
+               for (j = 0; j*8 < tga_bits_per_pixel; ++j)
+               {
+                  raw_data[j] = tga_palette[pal_idx+j];
+               }
+            } else
             {
             {
-               raw_data[j] = get8u(s);
+               //   read in the data raw
+               for (j = 0; j*8 < tga_bits_per_pixel; ++j)
+               {
+                  raw_data[j] = get8u(s);
+               }
             }
             }
-         }
-         //   convert raw to the intermediate format
-         switch (tga_bits_per_pixel)
+            //   clear the reading flag for the next pixel
+            read_next_pixel = 0;
+         } // end of reading a pixel
+
+         // copy data
+         for (j = 0; j < tga_comp; ++j)
+           tga_data[i*tga_comp+j] = raw_data[j];
+
+         //   in case we're in RLE mode, keep counting down
+         --RLE_count;
+      }
+      //   do I need to invert the image?
+      if ( tga_inverted )
+      {
+         for (j = 0; j*2 < tga_height; ++j)
          {
          {
-         case 8:
-            //   Luminous => RGBA
-            trans_data[0] = raw_data[0];
-            trans_data[1] = raw_data[0];
-            trans_data[2] = raw_data[0];
-            trans_data[3] = 255;
-            break;
-         case 16:
-            //   Luminous,Alpha => RGBA
-            trans_data[0] = raw_data[0];
-            trans_data[1] = raw_data[0];
-            trans_data[2] = raw_data[0];
-            trans_data[3] = raw_data[1];
-            break;
-         case 24:
-            //   BGR => RGBA
-            trans_data[0] = raw_data[2];
-            trans_data[1] = raw_data[1];
-            trans_data[2] = raw_data[0];
-            trans_data[3] = 255;
-            break;
-         case 32:
-            //   BGRA => RGBA
-            trans_data[0] = raw_data[2];
-            trans_data[1] = raw_data[1];
-            trans_data[2] = raw_data[0];
-            trans_data[3] = raw_data[3];
-            break;
+            int index1 = j * tga_width * req_comp;
+            int index2 = (tga_height - 1 - j) * tga_width * req_comp;
+            for (i = tga_width * req_comp; i > 0; --i)
+            {
+               unsigned char temp = tga_data[index1];
+               tga_data[index1] = tga_data[index2];
+               tga_data[index2] = temp;
+               ++index1;
+               ++index2;
+            }
          }
          }
-         //   clear the reading flag for the next pixel
-         read_next_pixel = 0;
-      } // end of reading a pixel
-      //   convert to final format
-      switch (req_comp)
+      }
+      //   clear my palette, if I had one
+      if ( tga_palette != NULL )
       {
       {
-      case 1:
-         //   RGBA => Luminance
-         tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]);
-         break;
-      case 2:
-         //   RGBA => Luminance,Alpha
-         tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]);
-         tga_data[i*req_comp+1] = trans_data[3];
-         break;
-      case 3:
-         //   RGBA => RGB
-         tga_data[i*req_comp+0] = trans_data[0];
-         tga_data[i*req_comp+1] = trans_data[1];
-         tga_data[i*req_comp+2] = trans_data[2];
-         break;
-      case 4:
-         //   RGBA => RGBA
-         tga_data[i*req_comp+0] = trans_data[0];
-         tga_data[i*req_comp+1] = trans_data[1];
-         tga_data[i*req_comp+2] = trans_data[2];
-         tga_data[i*req_comp+3] = trans_data[3];
-         break;
+         free( tga_palette );
       }
       }
-      //   in case we're in RLE mode, keep counting down
-      --RLE_count;
    }
    }
-   //   do I need to invert the image?
-   if ( tga_inverted )
+
+   // swap RGB
+   if (tga_comp >= 3)
    {
    {
-      for (j = 0; j*2 < tga_height; ++j)
+      unsigned char* tga_pixel = tga_data;
+      for (i=0; i < tga_width * tga_height; ++i)
       {
       {
-         int index1 = j * tga_width * req_comp;
-         int index2 = (tga_height - 1 - j) * tga_width * req_comp;
-         for (i = tga_width * req_comp; i > 0; --i)
-         {
-            unsigned char temp = tga_data[index1];
-            tga_data[index1] = tga_data[index2];
-            tga_data[index2] = temp;
-            ++index1;
-            ++index2;
-         }
+         unsigned char temp = tga_pixel[0];
+         tga_pixel[0] = tga_pixel[2];
+         tga_pixel[2] = temp;
+         tga_pixel += tga_comp;
       }
       }
    }
    }
-   //   clear my palette, if I had one
-   if ( tga_palette != NULL )
-   {
-      free( tga_palette );
-   }
+
+   // convert to target component count
+   if (req_comp && req_comp != tga_comp)
+      tga_data = convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);
+
    //   the things I do to get rid of an error message, and yet keep
    //   the things I do to get rid of an error message, and yet keep
    //   Microsoft's C compilers happy... [8^(
    //   Microsoft's C compilers happy... [8^(
    tga_palette_start = tga_palette_len = tga_palette_bits =
    tga_palette_start = tga_palette_len = tga_palette_bits =
@@ -4624,6 +4589,7 @@ int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int
              fix broken STBI_SIMD path
              fix broken STBI_SIMD path
              fix bug where stbi_load_from_file no longer left file pointer in correct place
              fix bug where stbi_load_from_file no longer left file pointer in correct place
              fix broken non-easy path for 32-bit BMP (possibly never used)
              fix broken non-easy path for 32-bit BMP (possibly never used)
+             TGA optimization by Arseny Kapoulkine
       1.34 (unknown)
       1.34 (unknown)
              use STBI_NOTUSED in resample_row_generic(), fix one more leak in tga failure case
              use STBI_NOTUSED in resample_row_generic(), fix one more leak in tga failure case
       1.33 (2011-07-14)
       1.33 (2011-07-14)