Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

OSGDDSImageFileType.cpp

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002  *                                OpenSG                                     *
00003  *                                                                           *
00004  *                                                                           *
00005  *             Copyright (C) 2000-2002 by the OpenSG Forum                   *
00006  *                                                                           *
00007  *                            www.opensg.org                                 *
00008  *                                                                           *
00009  *   contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de          *
00010  *                                                                           *
00011 \*---------------------------------------------------------------------------*/
00012 /*---------------------------------------------------------------------------*\
00013  *                                License                                    *
00014  *                                                                           *
00015  * This library is free software; you can redistribute it and/or modify it   *
00016  * under the terms of the GNU Library General Public License as published    *
00017  * by the Free Software Foundation, version 2.                               *
00018  *                                                                           *
00019  * This library is distributed in the hope that it will be useful, but       *
00020  * WITHOUT ANY WARRANTY; without even the implied warranty of                *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU         *
00022  * Library General Public License for more details.                          *
00023  *                                                                           *
00024  * You should have received a copy of the GNU Library General Public         *
00025  * License along with this library; if not, write to the Free Software       *
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                 *
00027  *                                                                           *
00028 \*---------------------------------------------------------------------------*/
00029 /*---------------------------------------------------------------------------*\
00030  *                                Changes                                    *
00031  *                                                                           *
00032  *                                                                           *
00033  *                                                                           *
00034  *                                                                           *
00035  *                                                                           *
00036  *                                                                           *
00037 \*---------------------------------------------------------------------------*/
00038 //-------------------------------
00039 //  Includes
00040 //-------------------------------
00041 #include <stdlib.h>
00042 #include <stdio.h>
00043 #include <assert.h>
00044 
00045 #include "OSGConfig.h"
00046 
00047 #include <string>
00048 #include <vector>
00049 
00050 #include <iostream>
00051 #include <fstream>
00052 
00053 #include <OSGLog.h>
00054 
00055 #include <OSGImage.h>
00056 
00057 #include "OSGDDSImageFileType.h"
00058 
00059 #ifdef OSG_SGI_STL
00060 
00061 //#include <limits>
00062 #ifndef INT_MAX
00063 #define INT_MAX numeric_limits<int>::max()
00064 #endif
00065 #else
00066 #include <limits.h>
00067 #endif
00068 OSG_USING_NAMESPACE
00069 
00070 
00083 /*****************************
00084  *   Types
00085  *****************************/
00086 // Static Class Varible implementations:
00087 static const Char8 *suffixArray[] =
00088 {
00089     "dds"
00090 };
00091 
00092 
00093 DDSImageFileType DDSImageFileType::_the("dds",
00094                                         suffixArray, sizeof(suffixArray),
00095                                         OSG_READ_SUPPORTED | 
00096                                         OSG_WRITE_SUPPORTED);
00097 
00098 /*****************************
00099  *    Classvariables
00100  *****************************/
00101 
00102 /********************************
00103  *    Class helper
00104  *******************************/
00105 #ifdef WIN32
00106 #  include <windows.h>
00107 #endif
00108 
00109 const unsigned long DDS_FOURCC = 0x00000004;
00110 const unsigned long DDS_RGB    = 0x00000040;
00111 const unsigned long DDS_RGBA   = 0x00000041;
00112 const unsigned long DDS_DEPTH  = 0x00800000;
00113 
00114 const unsigned long DDS_COMPLEX = 0x00000008;
00115 const unsigned long DDS_CUBEMAP = 0x00000200;
00116 const unsigned long DDS_VOLUME  = 0x00200000;
00117 
00118 const unsigned long FOURCC_DXT1 = 0x31545844;
00119 const unsigned long FOURCC_DXT3 = 0x33545844;
00120 const unsigned long FOURCC_DXT5 = 0x35545844;
00121 
00122 struct DDS_PIXELFORMAT {
00123   unsigned long dwSize;
00124   unsigned long dwFlags;
00125   unsigned long dwFourCC;
00126   unsigned long dwRGBBitCount;
00127   unsigned long dwRBitMask;
00128   unsigned long dwGBitMask;
00129   unsigned long dwBBitMask;
00130   unsigned long dwABitMask;
00131 };
00132 
00133 struct DXTColBlock {
00134   unsigned short col0;
00135   unsigned short col1;
00136   
00137   unsigned char row[4];
00138 };
00139 
00140 struct DXT3AlphaBlock {
00141   unsigned short row[4];
00142 };
00143 
00144 struct DXT5AlphaBlock
00145 {
00146   unsigned char alpha0;
00147   unsigned char alpha1;
00148   
00149   unsigned char row[6];
00150 };
00151 
00152 struct DDS_HEADER {
00153   unsigned long dwSize;
00154   unsigned long dwFlags;
00155   unsigned long dwHeight;
00156   unsigned long dwWidth;
00157   unsigned long dwPitchOrLinearSize;
00158   unsigned long dwDepth;
00159   unsigned long dwMipMapCount;
00160   unsigned long dwReserved1[11];
00161   DDS_PIXELFORMAT ddspf;
00162   unsigned long dwCaps1;
00163   unsigned long dwCaps2;
00164   unsigned long dwReserved2[3];
00165 };
00166 
00167 class CSurface
00168 {
00169   friend class CTexture;
00170   friend class CDDSImage;    
00171   
00172 public:
00173   CSurface();
00174   CSurface(int w, int h, int d, int imgsize);
00175   CSurface(const CSurface &copy);
00176   CSurface &operator= (const CSurface &rhs);
00177   virtual ~CSurface();
00178   
00179   operator char*();
00180   
00181   void create(int w, int h, int d, int imgsize);
00182   void clear();
00183   
00184   inline int   get_width() { return width; }
00185   inline int   get_height() { return height; }
00186   inline int   get_depth() { return depth; }
00187   inline int   get_size() { return size; }
00188   inline char* get_pixels() { return pixels; }
00189 
00190 protected:
00191   int width;
00192   int height;
00193   int depth;
00194   int size;
00195   
00196   char *pixels;       
00197 };
00198 
00199 class CTexture : public CSurface
00200 {
00201   friend class CDDSImage;
00202   
00203 public:
00204   CTexture();
00205   CTexture(int w, int h, int d, int imgSize);
00206   CTexture(const CTexture &copy);
00207   CTexture &operator= (const CTexture &rhs);
00208   ~CTexture();
00209   
00210   inline CSurface &get_mipmap(int index) 
00211   { 
00212     assert(index < (int)mipmaps.size());
00213     return mipmaps[index]; 
00214   }
00215   
00216   inline int get_num_mipmaps() { return (int)mipmaps.size(); }
00217 protected:
00218   std::vector<CSurface> mipmaps;
00219 };
00220 
00221 class CDDSImage
00222 {
00223 public:
00224   CDDSImage();
00225   ~CDDSImage();
00226   
00227   bool load(std::string filename, bool flipImage = true);
00228   void clear();
00229   
00230   operator char*();
00231   CTexture &operator[](int index);
00232     
00233   inline int get_num_images(void) { return (int)images.size(); }
00234   inline CTexture &get_image(int index) 
00235   {
00236     assert(index < (int)images.size());
00237     return images[index];
00238   }
00239   
00240   inline int get_components() { return components; }
00241   inline int get_format() { return format; }
00242   
00243   inline bool is_compressed() { return compressed; }
00244   inline bool is_cubemap() { return cubemap; }
00245   inline bool is_volume() { return volume; }
00246   inline bool is_valid() { return valid; }
00247   
00248 private:
00249   int clamp_size(int size);
00250   int get_line_width(int width, int bpp);
00251   int size_dxtc(int width, int height);
00252   int size_rgb(int width, int height);
00253   inline void swap_endian(void *val);
00254   void align_memory(CTexture *surface);
00255   
00256   void flip(char *image, int width, int height, int depth, int size);
00257   
00258   void swap(void *byte1, void *byte2, int size);
00259   void flip_blocks_dxtc1(DXTColBlock *line, int numBlocks);
00260   void flip_blocks_dxtc3(DXTColBlock *line, int numBlocks);
00261   void flip_blocks_dxtc5(DXTColBlock *line, int numBlocks);
00262   void flip_dxt5_alpha(DXT5AlphaBlock *block);
00263   
00264   int format;
00265   int components;
00266   bool compressed;
00267   bool cubemap;
00268   bool volume;
00269   bool valid;
00270   
00271   std::vector<CTexture> images;
00272   
00273 };
00274 
00275 
00276 /********************************
00277  *    Class methodes
00278  *******************************/
00279 
00280 //-------------------------------------------------------------------------
00284 DDSImageFileType& DDSImageFileType::the (void)
00285 {
00286   return _the;
00287 }
00288 
00289 /*******************************
00290 *public
00291 *******************************/
00292 
00293 //-------------------------------------------------------------------------
00298 bool DDSImageFileType::read(ImagePtr &image, const Char8 *fileName)
00299 {
00300   bool validImage = false;
00301   CDDSImage ddsImage;
00302   int i,j,w,h,d, mm = 0, components, format,size;
00303   int width = 0, height = 0, depth = 0, numMipMaps = 0;
00304   bool isCompressed, isCubeMap, isVolume;
00305   unsigned char *data;
00306   unsigned dataSize = 0;
00307 
00308   SINFO << "DDS File Info: " << fileName << ": ";
00309   
00310   if (ddsImage.load(fileName) && (validImage = ddsImage.is_valid())) {
00311     components = ddsImage.get_components();
00312     format = ddsImage.get_format();
00313     isCompressed = ddsImage.is_compressed();
00314     isCubeMap = ddsImage.is_cubemap();
00315     isVolume = ddsImage.is_volume();
00316     SINFO << "cs: " << components 
00317           << ", f: " << format
00318           << ", cd: " << isCompressed 
00319           << ", cm: " << isCubeMap
00320           << ", vo: " << isVolume
00321           << endLog;
00322     for (i = 0; i < ddsImage.get_num_images(); ++i) {
00323       w = ddsImage[i].get_width();
00324       h = ddsImage[i].get_height();
00325       d = ddsImage[i].get_depth();
00326       size = ddsImage[i].get_size();
00327       dataSize += size;
00328       mm = ddsImage[i].get_num_mipmaps();    
00329       if (i) {
00330         if ( (w != width) || (h != height) || (d != depth) &&
00331              (mm != numMipMaps) )
00332           validImage = false;
00333       }
00334       else {
00335         width = w;
00336         height = h;
00337         depth = d;
00338         numMipMaps = mm;
00339       }
00340       SINFO << "  " << i 
00341             << ", " << w << "x" << h << "x" << d 
00342             << ", size: " << size 
00343             << ", mm: " << mm
00344             << endLog;
00345       for (j = 0; j < mm; ++j) {
00346         w = ddsImage[i].get_mipmap(j).get_width();
00347         h = ddsImage[i].get_mipmap(j).get_height();
00348         d = ddsImage[i].get_mipmap(j).get_depth();
00349         size = ddsImage[i].get_mipmap(j).get_size();
00350         dataSize += size;
00351         SINFO << "    " << j 
00352               << ", " << w << "x" << h << "x" << d 
00353               << ", size: " << size 
00354               << ", mm: " << mm
00355               << endLog;
00356         
00357       }
00358     }
00359     if (validImage) {
00360       image->set( osg::Image::PixelFormat(format), 
00361                   width, height, depth,
00362                   numMipMaps + 1,
00363                   1, 0.0, 0, osg::Image::OSG_UINT8_IMAGEDATA,
00364                   true, 
00365                   ddsImage.get_num_images() );
00366       
00367       if (dataSize == image->getSize()) {
00368         data = image->getData();
00369 
00370         // copy data;
00371         for (i = 0; i < ddsImage.get_num_images(); ++i) {
00372           size = ddsImage[i].get_size();
00373           memcpy (data, ddsImage[i].get_pixels(), size);
00374           data += size;
00375           for (j = 0; j < mm; ++j) {
00376             size = ddsImage[i].get_mipmap(j).get_size();
00377             memcpy (data, ddsImage[i].get_mipmap(j).get_pixels(), size);
00378             data += size;
00379           }
00380         }
00381       }
00382       else {
00383         SWARNING << "ERROR: Invalid data size; cannot cp dds data"
00384                  << endLog;
00385 
00386       }
00387     }
00388   }
00389   else
00390     SWARNING << "DDS Load Failed !" << endLog;
00391 
00392   return validImage;;
00393 }
00394 
00395 //-------------------------------------------------------------------------
00400 bool DDSImageFileType::write(const ImagePtr &image, const Char8 *fileName)
00401 {
00402   SWARNING << getMimeType()
00403            << " write is not implemented "
00404            << endLog;
00405   
00406   return false;
00407 }
00408 
00409 /******************************
00410 *protected
00411 ******************************/
00412 
00413 /******************************
00414 *private
00415 ******************************/
00416 
00417 /***************************
00418 *instance methodes
00419 ***************************/
00420 
00421 /***************************
00422 *public
00423 ***************************/
00424 
00427 //-------------------------------------------------------------------------
00431 DDSImageFileType::DDSImageFileType(const Char8 *mimeType,
00432                                    const Char8 *suffixArray[],
00433                                    UInt16 suffixByteCount,
00434                                    UInt32 flags) :
00435     ImageFileType(mimeType,suffixArray, suffixByteCount, flags)
00436 {
00437     return;
00438 }
00439 
00440 //-------------------------------------------------------------------------
00444 DDSImageFileType::DDSImageFileType(const DDSImageFileType &obj) :
00445     ImageFileType(obj)
00446 {
00447     return;
00448 }
00449 
00450 //-------------------------------------------------------------------------
00454 DDSImageFileType::~DDSImageFileType(void)
00455 {
00456     return;
00457 }
00458 
00459 
00461 // CDDSImage public functions
00462 
00464 // default constructor
00465 CDDSImage::CDDSImage()
00466   : format(0),
00467     components(0),
00468     compressed(false),
00469     cubemap(false),
00470     volume(false),
00471     valid(false)
00472 {
00473 }
00474 
00475 CDDSImage::~CDDSImage()
00476 {
00477 }
00478 
00480 // loads DDS image
00481 //
00482 // filename - fully qualified name of DDS image
00483 // flipImage - specifies whether image is flipped on load, default is true
00484 bool CDDSImage::load(std::string filename, bool flipImage)
00485 {
00486     DDS_HEADER ddsh;
00487     char filecode[4];
00488     FILE *fp;
00489     int width, height, depth;
00490     int (CDDSImage::*sizefunc)(int, int);
00491 
00492     // clear any previously loaded images
00493     clear();
00494     
00495     // open file
00496     fp = fopen(filename.data(), "rb");
00497     if (fp == NULL)
00498         return false;
00499 
00500     // read in file marker, make sure its a DDS file
00501     fread(filecode, 1, 4, fp);
00502     if (strncmp(filecode, "DDS ", 4) != 0)
00503     {
00504         fclose(fp);
00505         return false;
00506     }
00507 
00508     // read in DDS header
00509     fread(&ddsh, sizeof(ddsh), 1, fp);
00510 
00511     swap_endian(&ddsh.dwSize);
00512     swap_endian(&ddsh.dwFlags);
00513     swap_endian(&ddsh.dwHeight);
00514     swap_endian(&ddsh.dwWidth);
00515     swap_endian(&ddsh.dwPitchOrLinearSize);
00516     swap_endian(&ddsh.dwMipMapCount);
00517     swap_endian(&ddsh.ddspf.dwSize);
00518     swap_endian(&ddsh.ddspf.dwFlags);
00519     swap_endian(&ddsh.ddspf.dwFourCC);
00520     swap_endian(&ddsh.ddspf.dwRGBBitCount);
00521     swap_endian(&ddsh.dwCaps1);
00522     swap_endian(&ddsh.dwCaps2);
00523 
00524     // check if image is a cubempa
00525     if (ddsh.dwCaps2 & DDS_CUBEMAP)
00526         cubemap = true;
00527 
00528     // check if image is a volume texture
00529     if ((ddsh.dwCaps2 & DDS_VOLUME) && (ddsh.dwDepth > 0))
00530         volume = true;
00531 
00532     // figure out what the image format is
00533     if (ddsh.ddspf.dwFlags & DDS_FOURCC) 
00534     {
00535         switch(ddsh.ddspf.dwFourCC)
00536         {
00537             case FOURCC_DXT1:
00538                 format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
00539                 components = 3;
00540                 compressed = true;
00541                 break;
00542             case FOURCC_DXT3:
00543                 format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
00544                 components = 4;
00545                 compressed = true;
00546                 break;
00547             case FOURCC_DXT5:
00548                 format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
00549                 components = 4;
00550                 compressed = true;
00551                 break;
00552             default:
00553                 fclose(fp);
00554                 return false;
00555         }
00556     }
00557     else if (ddsh.ddspf.dwFlags == DDS_RGBA && ddsh.ddspf.dwRGBBitCount == 32)
00558     {
00559         format = Image::OSG_BGRA_PF; 
00560         compressed = false;
00561         components = 4;
00562     }
00563     else if (ddsh.ddspf.dwFlags == DDS_RGB  && ddsh.ddspf.dwRGBBitCount == 32)
00564     {
00565         format = Image::OSG_BGRA_PF; 
00566         compressed = false;
00567         components = 4;
00568     }
00569     else if (ddsh.ddspf.dwFlags == DDS_RGB  && ddsh.ddspf.dwRGBBitCount == 24)
00570     {
00571         format = Image::OSG_BGR_PF; 
00572         compressed = false;
00573         components = 3;
00574     }
00575     else if (/*ddsh.ddspf.dwFlags == 0x20000  &&*/ ddsh.ddspf.dwRGBBitCount == 8)
00576     {
00577         format = Image::OSG_L_PF; 
00578         compressed = false;
00579         components = 1;
00580     }
00581     else 
00582     {
00583         SWARNING << "ERROR: unknown image format!" << endLog;
00584         fclose(fp);
00585         return false;
00586     }
00587     
00588     // store primary surface width/height/depth
00589     width = ddsh.dwWidth;
00590     height = ddsh.dwHeight;
00591     depth = clamp_size(ddsh.dwDepth);   // set to 1 if 0
00592     
00593     // use correct size calculation function depending on whether image is 
00594     // compressed
00595     sizefunc = (compressed ? &CDDSImage::size_dxtc : &CDDSImage::size_rgb);
00596 
00597     // load all surfaces for the image (6 surfaces for cubemaps)
00598     for (int n = 0; n < (cubemap ? 6 : 1); n++)
00599     {
00600         int size; 
00601 
00602         // calculate surface size
00603         size = (this->*sizefunc)(width, height)*depth;
00604 
00605         // load surface
00606         CTexture img(width, height, depth, size);
00607         fread(img, 1, img.size, fp);
00608 
00609         align_memory(&img);
00610         
00611         if (flipImage && !cubemap)
00612             flip(img, img.width, img.height, img.depth, img.size);
00613         
00614         int w = clamp_size(width >> 1);
00615         int h = clamp_size(height >> 1);
00616         int d = clamp_size(depth >> 1); 
00617 
00618         // store number of mipmaps
00619         int numMipmaps = ddsh.dwMipMapCount;
00620 
00621         // number of mipmaps in file includes main surface so decrease count 
00622         // by one
00623         if (numMipmaps != 0)
00624             numMipmaps--;
00625 
00626         // load all mipmaps for current surface
00627         for (int i = 0; i < numMipmaps && (w || h); i++)
00628         {
00629             // calculate mipmap size
00630             size = (this->*sizefunc)(w, h)*d;
00631 
00632             CSurface mipmap(w, h, d, size);
00633             fread(mipmap, 1, mipmap.size, fp);
00634             
00635             if (flipImage && !cubemap)
00636             {
00637                 flip(mipmap, mipmap.width, mipmap.height, mipmap.depth, 
00638                     mipmap.size);
00639             }
00640 
00641             img.mipmaps.push_back(mipmap);
00642 
00643             // shrink to next power of 2
00644             w = clamp_size(w >> 1);
00645             h = clamp_size(h >> 1);
00646             d = clamp_size(d >> 1); 
00647         }
00648 
00649         images.push_back(img);
00650     }
00651 
00652 #if 0
00653     // swap cubemaps on y axis (since image is flipped in OGL)
00654     if (cubemap && flipImage)
00655     {
00656         CTexture tmp;
00657         tmp = images[3];
00658         images[3] = images[2];
00659         images[2] = tmp;
00660     }
00661 #endif
00662 
00663     fclose(fp);
00664 
00665     valid = true;
00666 
00667     return true;
00668 }
00669 
00671 // free image memory
00672 void CDDSImage::clear()
00673 {
00674     components = 0;
00675     format = 0;
00676     compressed = false;
00677     cubemap = false;
00678     volume = false;
00679     valid = false;
00680 
00681     images.clear();
00682 }
00683 
00685 // returns individual texture when multiple textures are loaded (as is the case
00686 // with volume textures and cubemaps)
00687 CTexture &CDDSImage::operator[](int index)
00688 { 
00689     // make sure an image has been loaded
00690     assert(valid);
00691     assert(index < (int)images.size());
00692 
00693     return images[index]; 
00694 }
00695 
00697 // returns pointer to main image
00698 CDDSImage::operator char*()
00699 { 
00700     assert(valid);
00701 
00702     return images[0]; 
00703 }
00704 
00705 
00707 // clamps input size to [1-size]
00708 inline int CDDSImage::clamp_size(int size)
00709 {
00710     if (size <= 0)
00711         size = 1;
00712 
00713     return size;
00714 }
00715 
00717 // CDDSImage private functions
00719 
00721 // calculates 4-byte aligned width of image
00722 inline int CDDSImage::get_line_width(int width, int bpp)
00723 {
00724     return ((width * bpp + 31) & -32) >> 3;
00725 }
00726 
00728 // calculates size of DXTC texture in bytes
00729 inline int CDDSImage::size_dxtc(int width, int height)
00730 {
00731     return ((width+3)/4)*((height+3)/4)*
00732         (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ? 8 : 16);   
00733 }
00734 
00736 // calculates size of uncompressed RGB texture in bytes
00737 inline int CDDSImage::size_rgb(int width, int height)
00738 {
00739     return width*height*components;
00740 }
00741 
00743 // Swap the bytes in a 32 bit value
00744 inline void CDDSImage::swap_endian(void *val)
00745 {
00746 #ifdef MACOS
00747     unsigned int *ival = (unsigned int *)val;
00748 
00749     *ival = ((*ival >> 24) & 0x000000ff) |
00750             ((*ival >>  8) & 0x0000ff00) |
00751             ((*ival <<  8) & 0x00ff0000) |
00752             ((*ival << 24) & 0xff000000);
00753 #endif
00754 }
00755 
00757 // align to 4 byte boundary (add pad bytes to end of each line in the image)
00758 void CDDSImage::align_memory(CTexture *surface)
00759 {
00760     // don't bother with compressed images, volume textures, or cubemaps
00761     if (compressed || volume || cubemap)
00762         return;
00763 
00764     // calculate new image size
00765     int linesize = get_line_width(surface->width, components*8);
00766     int imagesize = linesize*surface->height;
00767 
00768     // exit if already aligned
00769     if (surface->size == imagesize)
00770         return;
00771 
00772     // create new image of new size
00773     CTexture newSurface(surface->width, surface->height, surface->depth, 
00774         imagesize);
00775 
00776     // add pad bytes to end of each line
00777     char *srcimage = (char*)*surface;
00778     char *dstimage = (char*)newSurface;
00779     for (int n = 0; n < surface->depth; n++)
00780     {
00781         char *curline = srcimage;
00782         char *newline = dstimage;
00783 
00784         int imsize = surface->size / surface->depth;
00785         int lnsize = imsize / surface->height;
00786         
00787         for (int i = 0; i < surface->height; i++)
00788         {
00789             memcpy(newline, curline, lnsize);
00790             newline += linesize;
00791             curline += lnsize;
00792         }
00793     }
00794 
00795     // save padded image
00796     *surface = newSurface;
00797 }
00798 
00800 // flip image around X axis
00801 void CDDSImage::flip(char *image, int width, int height, int depth, int size)
00802 {
00803     int linesize;
00804     int offset;
00805 
00806     if (!compressed)
00807     {
00808         assert(depth > 0);
00809 
00810         int imagesize = size/depth;
00811         linesize = imagesize / height;
00812 
00813         for (int n = 0; n < depth; n++)
00814         {
00815             offset = imagesize*n;
00816             char *top = image + offset;
00817             char *bottom = top + (imagesize-linesize);
00818     
00819             for (int i = 0; i < (height >> 1); i++)
00820             {
00821                 swap(bottom, top, linesize);
00822 
00823                 top += linesize;
00824                 bottom -= linesize;
00825             }
00826         }
00827     }
00828     else
00829     {
00830         void (CDDSImage::*flipblocks)(DXTColBlock*, int);
00831         int xblocks = width / 4;
00832         int yblocks = height / 4;
00833         int blocksize;
00834 
00835         switch (format)
00836         {
00837             case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: 
00838                 blocksize = 8;
00839                 flipblocks = &CDDSImage::flip_blocks_dxtc1; 
00840                 break;
00841             case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: 
00842                 blocksize = 16;
00843                 flipblocks = &CDDSImage::flip_blocks_dxtc3; 
00844                 break;
00845             case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: 
00846                 blocksize = 16;
00847                 flipblocks = &CDDSImage::flip_blocks_dxtc5; 
00848                 break;
00849             default:
00850                 return;
00851         }
00852 
00853         linesize = xblocks * blocksize;
00854 
00855         DXTColBlock *top;
00856         DXTColBlock *bottom;
00857     
00858         for (int j = 0; j < (yblocks >> 1); j++)
00859         {
00860             top = (DXTColBlock*)(image + j * linesize);
00861             bottom = (DXTColBlock*)(image + (((yblocks-j)-1) * linesize));
00862 
00863             (this->*flipblocks)(top, xblocks);
00864             (this->*flipblocks)(bottom, xblocks);
00865 
00866             swap(bottom, top, linesize);
00867         }
00868     }
00869 }    
00870 
00872 // swap to sections of memory
00873 void CDDSImage::swap(void *byte1, void *byte2, int size)
00874 {
00875     unsigned char *tmp = new unsigned char[size];
00876 
00877     memcpy(tmp, byte1, size);
00878     memcpy(byte1, byte2, size);
00879     memcpy(byte2, tmp, size);
00880 
00881     delete [] tmp;
00882 }
00883 
00885 // flip a DXT1 color block
00886 void CDDSImage::flip_blocks_dxtc1(DXTColBlock *line, int numBlocks)
00887 {
00888     DXTColBlock *curblock = line;
00889 
00890     for (int i = 0; i < numBlocks; i++)
00891     {
00892         swap(&curblock->row[0], &curblock->row[3], sizeof(unsigned char));
00893         swap(&curblock->row[1], &curblock->row[2], sizeof(unsigned char));
00894 
00895         curblock++;
00896     }
00897 }
00898 
00900 // flip a DXT3 color block
00901 void CDDSImage::flip_blocks_dxtc3(DXTColBlock *line, int numBlocks)
00902 {
00903     DXTColBlock *curblock = line;
00904     DXT3AlphaBlock *alphablock;
00905 
00906     for (int i = 0; i < numBlocks; i++)
00907     {
00908         alphablock = (DXT3AlphaBlock*)curblock;
00909 
00910         swap(&alphablock->row[0], &alphablock->row[3], sizeof(unsigned short));
00911         swap(&alphablock->row[1], &alphablock->row[2], sizeof(unsigned short));
00912 
00913         curblock++;
00914 
00915         swap(&curblock->row[0], &curblock->row[3], sizeof(unsigned char));
00916         swap(&curblock->row[1], &curblock->row[2], sizeof(unsigned char));
00917 
00918         curblock++;
00919     }
00920 }
00921 
00923 // flip a DXT5 alpha block
00924 void CDDSImage::flip_dxt5_alpha(DXT5AlphaBlock *block)
00925 {
00926     unsigned char gBits[4][4];
00927     
00928     const unsigned long mask = 0x00000007;          // bits = 00 00 01 11
00929     unsigned long bits = 0;
00930     memcpy(&bits, &block->row[0], sizeof(unsigned char) * 3);
00931 
00932     gBits[0][0] = (unsigned char)(bits & mask);
00933     bits >>= 3;
00934     gBits[0][1] = (unsigned char)(bits & mask);
00935     bits >>= 3;
00936     gBits[0][2] = (unsigned char)(bits & mask);
00937     bits >>= 3;
00938     gBits[0][3] = (unsigned char)(bits & mask);
00939     bits >>= 3;
00940     gBits[1][0] = (unsigned char)(bits & mask);
00941     bits >>= 3;
00942     gBits[1][1] = (unsigned char)(bits & mask);
00943     bits >>= 3;
00944     gBits[1][2] = (unsigned char)(bits & mask);
00945     bits >>= 3;
00946     gBits[1][3] = (unsigned char)(bits & mask);
00947 
00948     bits = 0;
00949     memcpy(&bits, &block->row[3], sizeof(unsigned char) * 3);
00950 
00951     gBits[2][0] = (unsigned char)(bits & mask);
00952     bits >>= 3;
00953     gBits[2][1] = (unsigned char)(bits & mask);
00954     bits >>= 3;
00955     gBits[2][2] = (unsigned char)(bits & mask);
00956     bits >>= 3;
00957     gBits[2][3] = (unsigned char)(bits & mask);
00958     bits >>= 3;
00959     gBits[3][0] = (unsigned char)(bits & mask);
00960     bits >>= 3;
00961     gBits[3][1] = (unsigned char)(bits & mask);
00962     bits >>= 3;
00963     gBits[3][2] = (unsigned char)(bits & mask);
00964     bits >>= 3;
00965     gBits[3][3] = (unsigned char)(bits & mask);
00966 
00967     unsigned long *pBits = ((unsigned long*) &(block->row[0]));
00968 
00969     *pBits = *pBits | (gBits[3][0] << 0);
00970     *pBits = *pBits | (gBits[3][1] << 3);
00971     *pBits = *pBits | (gBits[3][2] << 6);
00972     *pBits = *pBits | (gBits[3][3] << 9);
00973 
00974     *pBits = *pBits | (gBits[2][0] << 12);
00975     *pBits = *pBits | (gBits[2][1] << 15);
00976     *pBits = *pBits | (gBits[2][2] << 18);
00977     *pBits = *pBits | (gBits[2][3] << 21);
00978 
00979     pBits = ((unsigned long*) &(block->row[3]));
00980 
00981 #ifdef MACOS
00982     *pBits &= 0x000000ff;
00983 #else
00984     *pBits &= 0xff000000;
00985 #endif
00986 
00987     *pBits = *pBits | (gBits[1][0] << 0);
00988     *pBits = *pBits | (gBits[1][1] << 3);
00989     *pBits = *pBits | (gBits[1][2] << 6);
00990     *pBits = *pBits | (gBits[1][3] << 9);
00991 
00992     *pBits = *pBits | (gBits[0][0] << 12);
00993     *pBits = *pBits | (gBits[0][1] << 15);
00994     *pBits = *pBits | (gBits[0][2] << 18);
00995     *pBits = *pBits | (gBits[0][3] << 21);
00996 }
00997 
00999 // flip a DXT5 color block
01000 void CDDSImage::flip_blocks_dxtc5(DXTColBlock *line, int numBlocks)
01001 {
01002     DXTColBlock *curblock = line;
01003     DXT5AlphaBlock *alphablock;
01004     
01005     for (int i = 0; i < numBlocks; i++)
01006     {
01007         alphablock = (DXT5AlphaBlock*)curblock;
01008         
01009         flip_dxt5_alpha(alphablock);
01010 
01011         curblock++;
01012 
01013         swap(&curblock->row[0], &curblock->row[3], sizeof(unsigned char));
01014         swap(&curblock->row[1], &curblock->row[2], sizeof(unsigned char));
01015 
01016         curblock++;
01017     }
01018 }
01019 
01021 // CTexture implementation
01023 
01025 // default constructor
01026 CTexture::CTexture()
01027   : CSurface()  // initialize base class part
01028 {
01029 }
01030 
01032 // creates an empty texture
01033 CTexture::CTexture(int w, int h, int d, int imgSize)
01034   : CSurface(w, h, d, imgSize)  // initialize base class part
01035 {
01036 }
01037 
01039 // copy constructor
01040 CTexture::CTexture(const CTexture &copy)
01041   : CSurface(copy)
01042 {
01043     for (unsigned int i = 0; i < copy.mipmaps.size(); i++)
01044         mipmaps.push_back(copy.mipmaps[i]);
01045 }
01046 
01048 // assignment operator
01049 CTexture &CTexture::operator= (const CTexture &rhs)
01050 {
01051     if (this != &rhs)
01052     {
01053         CSurface::operator = (rhs);
01054 
01055         mipmaps.clear();
01056         for (unsigned int i = 0; i < rhs.mipmaps.size(); i++)
01057         {
01058             mipmaps.push_back(rhs.mipmaps[i]);
01059         }
01060     }
01061 
01062     return *this;
01063 }
01064 
01066 // clean up texture memory
01067 CTexture::~CTexture()
01068 {
01069     mipmaps.clear();
01070 }
01071 
01073 // CSurface implementation
01075 
01077 // default constructor
01078 CSurface::CSurface()
01079   : width(0),
01080     height(0),
01081     depth(0),
01082     size(0),
01083     pixels(NULL)
01084 {
01085 }
01086 
01088 // creates an empty image
01089 CSurface::CSurface(int w, int h, int d, int imgsize)
01090 {
01091     pixels = NULL;
01092     create(w, h, d, imgsize);
01093 }
01094 
01096 // copy constructor
01097 CSurface::CSurface(const CSurface &copy)
01098   : width(0),
01099     height(0),
01100     depth(0),
01101     size(0),
01102     pixels(NULL)
01103 {
01104 
01105     if (copy.pixels)
01106     {
01107         size = copy.size;
01108         width = copy.width;
01109         height = copy.height;
01110         depth = copy.depth;
01111         pixels = new char[size];
01112         memcpy(pixels, copy.pixels, copy.size);
01113     }
01114 }
01115 
01117 // assignment operator
01118 CSurface &CSurface::operator= (const CSurface &rhs)
01119 {
01120     if (this != &rhs)
01121     {
01122         clear();
01123 
01124         if (rhs.pixels)
01125         {
01126             size = rhs.size;
01127             width = rhs.width;
01128             height = rhs.height;
01129             depth = rhs.depth;
01130 
01131             pixels = new char[size];
01132             memcpy(pixels, rhs.pixels, size);
01133         }
01134     }
01135 
01136     return *this;
01137 }
01138 
01140 // clean up image memory
01141 CSurface::~CSurface()
01142 {
01143     clear();
01144 }
01145 
01147 // returns a pointer to image
01148 CSurface::operator char*()
01149 { 
01150     return pixels; 
01151 }
01152 
01154 // creates an empty image
01155 void CSurface::create(int w, int h, int d, int imgsize)
01156 {
01157     clear();
01158 
01159     width = w;
01160     height = h;
01161     depth = d;
01162     size = imgsize;
01163     pixels = new char[imgsize];
01164 }
01165 
01167 // free surface memory
01168 void CSurface::clear()
01169 {
01170     delete [] pixels;
01171     pixels = NULL;
01172 }

Generated on Thu Aug 25 04:02:32 2005 for OpenSG by  doxygen 1.4.3