00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
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
00052 #include <OSGLog.h>
00053
00054 #include <OSGImage.h>
00055
00056 #include "OSGDDSImageFileType.h"
00057
00058 #ifdef OSG_SGI_STL
00059
00060
00061 #ifndef INT_MAX
00062 #define INT_MAX numeric_limits<Int32>::max()
00063 #endif
00064 #else
00065 #include <limits.h>
00066 #endif
00067 OSG_USING_NAMESPACE
00068
00069
00082
00083
00084
00085
00086 static const Char8 *suffixArray[] =
00087 {
00088 "dds"
00089 };
00090
00091
00092 DDSImageFileType DDSImageFileType::_the("image/x-dds",
00093 suffixArray, sizeof(suffixArray),
00094 OSG_READ_SUPPORTED |
00095 OSG_WRITE_SUPPORTED);
00096
00097
00098
00099
00100
00101
00102
00103
00104 #ifdef WIN32
00105 # include <windows.h>
00106 #endif
00107
00108 const UInt32 DDS_ALPHAPIXELS = 0x00000001;
00109 const UInt32 DDS_ALPHA = 0x00000002;
00110 const UInt32 DDS_FOURCC = 0x00000004;
00111 const UInt32 DDS_RGB = 0x00000040;
00112 const UInt32 DDS_RGBA = 0x00000041;
00113 const UInt32 DDS_DEPTH = 0x00800000;
00114 const UInt32 DDS_COMPRESSED = 0x00000080;
00115 const UInt32 DDS_LUMINANCE = 0x00020000;
00116
00117 const UInt32 DDS_COMPLEX = 0x00000008;
00118 const UInt32 DDS_CUBEMAP = 0x00000200;
00119 const UInt32 DDS_VOLUME = 0x00200000;
00120
00121 const UInt32 FOURCC_DXT1 = 0x31545844;
00122 const UInt32 FOURCC_DXT3 = 0x33545844;
00123 const UInt32 FOURCC_DXT5 = 0x35545844;
00124
00125 struct DDS_PIXELFORMAT {
00126 UInt32 dwSize;
00127 UInt32 dwFlags;
00128 UInt32 dwFourCC;
00129 UInt32 dwRGBBitCount;
00130 UInt32 dwRBitMask;
00131 UInt32 dwGBitMask;
00132 UInt32 dwBBitMask;
00133 UInt32 dwABitMask;
00134 };
00135
00136 struct DXTColBlock {
00137 UInt16 col0;
00138 UInt16 col1;
00139
00140 UInt8 row[4];
00141 };
00142
00143 struct DXT3AlphaBlock {
00144 UInt16 row[4];
00145 };
00146
00147 struct DXT5AlphaBlock
00148 {
00149 UInt8 alpha0;
00150 UInt8 alpha1;
00151
00152 UInt8 row[6];
00153 };
00154
00155 struct DDS_HEADER {
00156 UInt32 dwSize;
00157 UInt32 dwFlags;
00158 UInt32 dwHeight;
00159 UInt32 dwWidth;
00160 UInt32 dwPitchOrLinearSize;
00161 UInt32 dwDepth;
00162 UInt32 dwMipMapCount;
00163 UInt32 dwReserved1[11];
00164 DDS_PIXELFORMAT ddspf;
00165 UInt32 dwCaps1;
00166 UInt32 dwCaps2;
00167 UInt32 dwReserved2[3];
00168 };
00169
00170 class CSurface
00171 {
00172 friend class CTexture;
00173 friend class CDDSImage;
00174
00175 public:
00176 CSurface();
00177 CSurface(Int32 w, Int32 h, Int32 d, Int32 imgsize);
00178 CSurface(const CSurface ©);
00179 CSurface &operator= (const CSurface &rhs);
00180 virtual ~CSurface();
00181
00182 operator char*();
00183
00184 void create(Int32 w, Int32 h, Int32 d, Int32 imgsize);
00185 void clear();
00186
00187 inline Int32 get_width() { return width; }
00188 inline Int32 get_height() { return height; }
00189 inline Int32 get_depth() { return depth; }
00190 inline Int32 get_size() { return size; }
00191 inline char* get_pixels() { return pixels; }
00192
00193 protected:
00194 Int32 width;
00195 Int32 height;
00196 Int32 depth;
00197 Int32 size;
00198
00199 char *pixels;
00200 };
00201
00202 class CTexture : public CSurface
00203 {
00204 friend class CDDSImage;
00205
00206 public:
00207 CTexture();
00208 CTexture(Int32 w, Int32 h, Int32 d, Int32 imgSize);
00209 CTexture(const CTexture ©);
00210 CTexture &operator= (const CTexture &rhs);
00211 ~CTexture();
00212
00213 inline CSurface &get_mipmap(Int32 index)
00214 {
00215 assert(index < (Int32)mipmaps.size());
00216 return mipmaps[index];
00217 }
00218
00219 inline Int32 get_num_mipmaps() { return (Int32)mipmaps.size(); }
00220 protected:
00221 std::vector<CSurface> mipmaps;
00222 };
00223
00224 class CDDSImage
00225 {
00226 public:
00227 CDDSImage();
00228 ~CDDSImage();
00229
00230 bool load(std::istream &is, bool flipImage = true, bool swapCubeMap = true,
00231 bool flipCubeMap = false);
00232 void clear();
00233
00234 operator char*();
00235 CTexture &operator[](Int32 index);
00236
00237 inline Int32 get_num_images(void) { return (Int32)images.size(); }
00238 inline CTexture &get_image(Int32 index)
00239 {
00240 assert(index < (Int32)images.size());
00241 return images[index];
00242 }
00243
00244 inline Int32 get_components() { return components; }
00245 inline Int32 get_format() { return format; }
00246
00247 inline bool is_compressed() { return compressed; }
00248 inline bool is_cubemap() { return cubemap; }
00249 inline bool is_volume() { return volume; }
00250 inline bool is_valid() { return valid; }
00251
00252 private:
00253 Int32 clamp_size(Int32 size);
00254 Int32 get_line_width(Int32 width, Int32 bpp);
00255 Int32 size_dxtc(Int32 width, Int32 height);
00256 Int32 size_rgb(Int32 width, Int32 height);
00257 inline void swap_endian(void *val);
00258 void align_memory(CTexture *surface);
00259
00260 void flip (char *image, Int32 width, Int32 height, Int32 depth, Int32 size);
00261 bool check_dxt1_alpha_data (char *image, Int32 size);
00262
00263 void swap(void *byte1, void *byte2, Int32 size);
00264
00265 void flip_blocks_dxtc1(DXTColBlock *line, Int32 numBlocks);
00266 void flip_blocks_dxtc3(DXTColBlock *line, Int32 numBlocks);
00267 void flip_blocks_dxtc5(DXTColBlock *line, Int32 numBlocks);
00268 void flip_dxt5_alpha(DXT5AlphaBlock *block);
00269
00270 Int32 format;
00271 Int32 components;
00272 bool compressed;
00273 bool cubemap;
00274 bool volume;
00275 bool valid;
00276
00277 std::vector<CTexture> images;
00278
00279 };
00280
00281
00282
00283
00284
00285
00286
00290 DDSImageFileType& DDSImageFileType::the (void)
00291 {
00292 return _the;
00293 }
00294
00295
00296
00297
00298
00299 void DDSImageFileType::setFlipImage(bool s)
00300 {
00301 _flipImage = s;
00302 }
00303
00304 bool DDSImageFileType::getFlipImage(void)
00305 {
00306 return _flipImage;
00307 }
00308
00309 void DDSImageFileType::setFlipCubeMap(bool s)
00310 {
00311 _flipCubeMap = s;
00312 }
00313
00314 bool DDSImageFileType::getFlipCubeMap(void)
00315 {
00316 return _flipCubeMap;
00317 }
00318
00319 void DDSImageFileType::setSwapCubeMap(bool s)
00320 {
00321 _swapCubeMap = s;
00322 }
00323
00324 bool DDSImageFileType::getSwapCubeMap(void)
00325 {
00326 return _swapCubeMap;
00327 }
00328
00329
00330
00335 bool DDSImageFileType::read(ImagePtr &image, std::istream &is, const std::string &mimetype)
00336 {
00337 bool validImage = false;
00338 CDDSImage ddsImage;
00339 Int32 i,j,w,h,d, mm = 0, components, format,size;
00340 Int32 width = 0, height = 0, depth = 0, numMipMaps = 0;
00341 bool isCompressed, isCubeMap, isVolume;
00342 UInt8 *data;
00343 UInt32 dataSize = 0;
00344
00345 SINFO << "DDS File Info: ";
00346
00347 if (ddsImage.load(is, _flipImage, _swapCubeMap, _flipCubeMap) &&
00348 (validImage = ddsImage.is_valid()))
00349 {
00350 components = ddsImage.get_components();
00351 format = ddsImage.get_format();
00352 isCompressed = ddsImage.is_compressed();
00353 isCubeMap = ddsImage.is_cubemap();
00354 isVolume = ddsImage.is_volume();
00355
00356 SINFO << "cs: " << components
00357 << ", f: " << format
00358 << ", cd: " << isCompressed
00359 << ", cm: " << isCubeMap
00360 << ", vo: " << isVolume
00361 << endLog;
00362
00363 for (i = 0; i < ddsImage.get_num_images(); ++i) {
00364 w = ddsImage[i].get_width();
00365 h = ddsImage[i].get_height();
00366 d = ddsImage[i].get_depth();
00367 size = ddsImage[i].get_size();
00368 dataSize += size;
00369 mm = ddsImage[i].get_num_mipmaps();
00370 if (i) {
00371 if ( (w != width) || (h != height) || (d != depth) &&
00372 (mm != numMipMaps) )
00373 validImage = false;
00374 }
00375 else {
00376 width = w;
00377 height = h;
00378 depth = d;
00379 numMipMaps = mm;
00380 }
00381 SINFO << " " << i
00382 << ", " << w << "x" << h << "x" << d
00383 << ", size: " << size
00384 << ", mm: " << mm
00385 << endLog;
00386 for (j = 0; j < mm; ++j) {
00387 w = ddsImage[i].get_mipmap(j).get_width();
00388 h = ddsImage[i].get_mipmap(j).get_height();
00389 d = ddsImage[i].get_mipmap(j).get_depth();
00390 size = ddsImage[i].get_mipmap(j).get_size();
00391 dataSize += size;
00392 SINFO << " " << j
00393 << ", " << w << "x" << h << "x" << d
00394 << ", size: " << size
00395 << ", mm: " << mm
00396 << endLog;
00397
00398 }
00399 }
00400 if (validImage) {
00401 image->set( osg::Image::PixelFormat(format),
00402 width, height, depth,
00403 numMipMaps + 1,
00404 1, 0.0, 0, osg::Image::OSG_UINT8_IMAGEDATA,
00405 true,
00406 ddsImage.get_num_images() );
00407
00408 if (dataSize == image->getSize()) {
00409 data = image->getData();
00410
00411
00412 for (i = 0; i < ddsImage.get_num_images(); ++i) {
00413 size = ddsImage[i].get_size();
00414 memcpy (data, ddsImage[i].get_pixels(), size);
00415 data += size;
00416 for (j = 0; j < mm; ++j) {
00417 size = ddsImage[i].get_mipmap(j).get_size();
00418 memcpy (data, ddsImage[i].get_mipmap(j).get_pixels(), size);
00419 data += size;
00420 }
00421 }
00422 }
00423 else {
00424 SWARNING << "ERROR: Invalid data size; cannot cp dds data"
00425 << endLog;
00426
00427 }
00428 }
00429 }
00430 else
00431 SWARNING << "DDS Load Failed !" << endLog;
00432
00433 return validImage;;
00434 }
00435
00436
00442 std::string DDSImageFileType::determineMimetypeFromStream(std::istream &is)
00443 {
00444 char filecode[4];
00445 is.read(filecode, 4);
00446 is.seekg(-4, std::ios::cur);
00447 return strncmp(filecode, "DDS ", 4) == 0 ?
00448 std::string(getMimeType()) : std::string();
00449 }
00450
00451
00455 DDSImageFileType::DDSImageFileType(const Char8 *mimeType,
00456 const Char8 *suffixArray[],
00457 UInt16 suffixByteCount,
00458 UInt32 flags) :
00459 ImageFileType(mimeType, suffixArray, suffixByteCount, flags),
00460 _flipImage(true),
00461 _flipCubeMap(false),
00462 _swapCubeMap(false)
00463 {}
00464
00465
00469 DDSImageFileType::~DDSImageFileType(void) {}
00470
00471
00473
00474
00476
00477 CDDSImage::CDDSImage()
00478 : format(0),
00479 components(0),
00480 compressed(false),
00481 cubemap(false),
00482 volume(false),
00483 valid(false)
00484 {
00485 }
00486
00487 CDDSImage::~CDDSImage()
00488 {
00489 }
00490
00492
00493
00494
00495
00496 bool CDDSImage::load(std::istream &is, bool flipImage, bool swapCubeMap, bool flipCubeMap)
00497 {
00498 DDS_HEADER ddsh;
00499 char filecode[4];
00500 Int32 width, height, depth;
00501 Int32 (CDDSImage::*sizefunc)(Int32, Int32);
00502
00503
00504 clear();
00505
00506
00507 is.read(filecode, 4);
00508 if (strncmp(filecode, "DDS ", 4) != 0)
00509 return false;
00510
00511
00512 is.read(reinterpret_cast<char*>(&ddsh), sizeof(ddsh));
00513
00514 swap_endian(&ddsh.dwSize);
00515 swap_endian(&ddsh.dwFlags);
00516 swap_endian(&ddsh.dwHeight);
00517 swap_endian(&ddsh.dwWidth);
00518 swap_endian(&ddsh.dwPitchOrLinearSize);
00519 swap_endian(&ddsh.dwDepth);
00520 swap_endian(&ddsh.dwMipMapCount);
00521 swap_endian(&ddsh.ddspf.dwSize);
00522 swap_endian(&ddsh.ddspf.dwFlags);
00523 swap_endian(&ddsh.ddspf.dwFourCC);
00524 swap_endian(&ddsh.ddspf.dwRGBBitCount);
00525 swap_endian(&ddsh.dwCaps1);
00526 swap_endian(&ddsh.dwCaps2);
00527
00528
00529 if (ddsh.dwCaps2 & DDS_CUBEMAP)
00530 cubemap = true;
00531
00532
00533 if ((ddsh.dwCaps2 & DDS_VOLUME) && (ddsh.dwDepth > 0))
00534 volume = true;
00535
00536
00537 if (ddsh.ddspf.dwFlags & DDS_FOURCC)
00538 {
00539 switch(ddsh.ddspf.dwFourCC)
00540 {
00541 case FOURCC_DXT1:
00542 format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
00543 components = 3;
00544 compressed = true;
00545 break;
00546 case FOURCC_DXT3:
00547 format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
00548 components = 4;
00549 compressed = true;
00550 break;
00551 case FOURCC_DXT5:
00552 format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
00553 components = 4;
00554 compressed = true;
00555 break;
00556 default:
00557 SWARNING << "ERROR: unknown compressed format(" << ddsh.ddspf.dwFourCC
00558 << ")!" << endLog;
00559 return false;
00560 }
00561 }
00562 else if (ddsh.ddspf.dwFlags == DDS_RGBA && ddsh.ddspf.dwRGBBitCount == 32)
00563 {
00564 format = Image::OSG_BGRA_PF;
00565 compressed = false;
00566 components = 4;
00567 }
00568 else if (ddsh.ddspf.dwFlags == DDS_RGB && ddsh.ddspf.dwRGBBitCount == 32)
00569 {
00570 format = Image::OSG_BGRA_PF;
00571 compressed = false;
00572 components = 4;
00573 }
00574 else if (ddsh.ddspf.dwFlags == DDS_RGB && ddsh.ddspf.dwRGBBitCount == 24)
00575 {
00576 format = Image::OSG_BGR_PF;
00577 compressed = false;
00578 components = 3;
00579 }
00580 else if ( ddsh.ddspf.dwRGBBitCount == 8)
00581 {
00582 format = Image::OSG_L_PF;
00583 compressed = false;
00584 components = 1;
00585 }
00586 else
00587 {
00588 SWARNING << "ERROR: unknown image format!" << endLog;
00589 return false;
00590 }
00591
00592
00593 width = ddsh.dwWidth;
00594 height = ddsh.dwHeight;
00595 depth = clamp_size(ddsh.dwDepth);
00596
00597
00598
00599 sizefunc = (compressed ? &CDDSImage::size_dxtc : &CDDSImage::size_rgb);
00600
00601
00602 for (Int32 n = 0; n < (cubemap ? 6 : 1); n++)
00603 {
00604 Int32 size;
00605
00606
00607 size = (this->*sizefunc)(width, height)*depth;
00608
00609
00610 CTexture img(width, height, depth, size);
00611 is.read(img, img.size);
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624 align_memory(&img);
00625
00626 if ( (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) &&
00627 check_dxt1_alpha_data(img, img.size))
00628 format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
00629
00630 if ((flipImage && !cubemap) || (flipCubeMap && cubemap))
00631 flip(img, img.width, img.height, img.depth, img.size);
00632
00633 Int32 w = clamp_size(width >> 1);
00634 Int32 h = clamp_size(height >> 1);
00635 Int32 d = clamp_size(depth >> 1);
00636
00637
00638 Int32 numMipmaps = ddsh.dwMipMapCount;
00639
00640
00641
00642 if (numMipmaps != 0)
00643 numMipmaps--;
00644
00645
00646 for (Int32 i = 0; i < numMipmaps && (w || h); i++)
00647 {
00648
00649 size = (this->*sizefunc)(w, h)*d;
00650
00651 CSurface mipmap(w, h, d, size);
00652 is.read(mipmap, mipmap.size);
00653
00654 if ((flipImage && !cubemap) || (flipCubeMap && cubemap))
00655 {
00656 flip(mipmap, mipmap.width, mipmap.height, mipmap.depth,
00657 mipmap.size);
00658 }
00659
00660 img.mipmaps.push_back(mipmap);
00661
00662
00663 w = clamp_size(w >> 1);
00664 h = clamp_size(h >> 1);
00665 d = clamp_size(d >> 1);
00666 }
00667
00668 images.push_back(img);
00669
00670 }
00671
00672
00673 if (cubemap && swapCubeMap)
00674 {
00675 CTexture tmp;
00676 tmp = images[3];
00677 images[3] = images[2];
00678 images[2] = tmp;
00679 }
00680
00681 valid = true;
00682
00683 return true;
00684 }
00685
00687
00688 void CDDSImage::clear()
00689 {
00690 components = 0;
00691 format = 0;
00692 compressed = false;
00693 cubemap = false;
00694 volume = false;
00695 valid = false;
00696
00697 images.clear();
00698 }
00699
00701
00702
00703 CTexture &CDDSImage::operator[](Int32 index)
00704 {
00705
00706 assert(valid);
00707 assert(index < (Int32)images.size());
00708
00709 return images[index];
00710 }
00711
00713
00714 CDDSImage::operator char*()
00715 {
00716 assert(valid);
00717
00718 return images[0];
00719 }
00720
00721
00723
00724 inline Int32 CDDSImage::clamp_size(Int32 size)
00725 {
00726 if (size <= 0)
00727 size = 1;
00728
00729 return size;
00730 }
00731
00733
00735
00737
00738 inline Int32 CDDSImage::get_line_width(Int32 width, Int32 bpp)
00739 {
00740 return ((width * bpp + 31) & -32) >> 3;
00741 }
00742
00744
00745 Int32 CDDSImage::size_dxtc(Int32 width, Int32 height)
00746 {
00747 Int32 comp( ( (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ||
00748 (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) ) ? 8 : 16 );
00749
00750 return ((width+3)/4)*((height+3)/4)*comp;
00751
00752
00753 }
00754
00756
00757 Int32 CDDSImage::size_rgb(Int32 width, Int32 height)
00758 {
00759 return width*height*components;
00760
00761 }
00762
00764
00765 inline void CDDSImage::swap_endian(void *val)
00766 {
00767 #if BYTE_ORDER == BIG_ENDIAN
00768 UInt32 *ival = (UInt32 *)val;
00769
00770 *ival = ((*ival >> 24) & 0x000000ff) |
00771 ((*ival >> 8) & 0x0000ff00) |
00772 ((*ival << 8) & 0x00ff0000) |
00773 ((*ival << 24) & 0xff000000);
00774 #endif
00775 }
00776
00778
00779 void CDDSImage::align_memory(CTexture *surface)
00780 {
00781
00782 if (compressed || volume || cubemap)
00783 return;
00784
00785
00786 Int32 linesize = get_line_width(surface->width, components*8);
00787 Int32 imagesize = linesize*surface->height;
00788
00789
00790 if (surface->size == imagesize)
00791 return;
00792
00793
00794 CTexture newSurface(surface->width, surface->height, surface->depth,
00795 imagesize);
00796
00797
00798 char *srcimage = (char*)*surface;
00799 char *dstimage = (char*)newSurface;
00800 for (Int32 n = 0; n < surface->depth; n++)
00801 {
00802 char *curline = srcimage;
00803 char *newline = dstimage;
00804
00805 Int32 imsize = surface->size / surface->depth;
00806 Int32 lnsize = imsize / surface->height;
00807
00808 for (Int32 i = 0; i < surface->height; i++)
00809 {
00810 memcpy(newline, curline, lnsize);
00811 newline += linesize;
00812 curline += lnsize;
00813 }
00814 }
00815
00816
00817 *surface = newSurface;
00818 }
00819
00821
00822 bool CDDSImage::check_dxt1_alpha_data (char *image, Int32 size)
00823 {
00824 bool hasAlpha(false);
00825 DXTColBlock *colBlock((DXTColBlock*)(image));
00826
00827 for (unsigned i = 0, n = (size / 8); i < n; i++)
00828 if (colBlock[i].col0 <= colBlock[i].col1)
00829 {
00830 for (unsigned j = 0; j < 4; j++) {
00831 UInt8 byte = colBlock[i].row[j];
00832 for (unsigned p = 0; p < 4; p++, byte >> 2) {
00833 if ((byte & 3) == 3) {
00834 hasAlpha = true;
00835 break;
00836 }
00837 }
00838 }
00839
00840 if (hasAlpha)
00841 {
00842 FNOTICE (( "Found alpha in DXT1 %d/%d, col0:%d, col1:%d\n",
00843 i, n, colBlock[i].col0, colBlock[i].col1 ));
00844
00845 for (unsigned j = 0; j < 4; j++)
00846 FNOTICE (( " DXT Col Index: %d %d %d %d\n",
00847 ((colBlock[i].row[j] >> 0) & 3),
00848 ((colBlock[i].row[j] >> 2) & 3),
00849 ((colBlock[i].row[j] >> 4) & 3),
00850 ((colBlock[i].row[j] >> 6) & 3) ));
00851 }
00852
00853 if (hasAlpha)
00854 break;
00855 }
00856
00857 return hasAlpha;
00858 }
00859
00861
00862 void CDDSImage::flip(char *image, Int32 width, Int32 height, Int32 depth, Int32 size)
00863 {
00864 Int32 linesize;
00865 Int32 offset;
00866
00867 if (!compressed)
00868 {
00869 assert(depth > 0);
00870
00871 Int32 imagesize = size/depth;
00872 linesize = imagesize / height;
00873
00874 for (Int32 n = 0; n < depth; n++)
00875 {
00876 offset = imagesize*n;
00877 char *top = image + offset;
00878 char *bottom = top + (imagesize-linesize);
00879
00880 for (Int32 i = 0; i < (height >> 1); i++)
00881 {
00882 swap(bottom, top, linesize);
00883
00884 top += linesize;
00885 bottom -= linesize;
00886 }
00887 }
00888 }
00889 else
00890 {
00891 void (CDDSImage::*flipblocks)(DXTColBlock*, Int32);
00892 Int32 xblocks = width / 4;
00893 Int32 yblocks = height / 4;
00894 Int32 blocksize;
00895
00896 switch (format)
00897 {
00898 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
00899 blocksize = 8;
00900 flipblocks = &CDDSImage::flip_blocks_dxtc1;
00901 break;
00902 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
00903 blocksize = 8;
00904 flipblocks = &CDDSImage::flip_blocks_dxtc1;
00905 break;
00906 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
00907 blocksize = 16;
00908 flipblocks = &CDDSImage::flip_blocks_dxtc3;
00909 break;
00910 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
00911 blocksize = 16;
00912 flipblocks = &CDDSImage::flip_blocks_dxtc5;
00913 break;
00914 default:
00915 return;
00916 }
00917
00918 linesize = xblocks * blocksize;
00919
00920 DXTColBlock *top;
00921 DXTColBlock *bottom;
00922
00923 for (Int32 j = 0; j < (yblocks >> 1); j++)
00924 {
00925 top = (DXTColBlock*)(image + j * linesize);
00926 bottom = (DXTColBlock*)(image + (((yblocks-j)-1) * linesize));
00927
00928 (this->*flipblocks)(top, xblocks);
00929 (this->*flipblocks)(bottom, xblocks);
00930
00931 swap(bottom, top, linesize);
00932 }
00933 }
00934 }
00935
00937
00938 void CDDSImage::swap(void *byte1, void *byte2, Int32 size)
00939 {
00940 UInt8 *tmp = new UInt8[size];
00941
00942 memcpy(tmp, byte1, size);
00943 memcpy(byte1, byte2, size);
00944 memcpy(byte2, tmp, size);
00945
00946 delete [] tmp;
00947 }
00948
00950
00951 void CDDSImage::flip_blocks_dxtc1(DXTColBlock *line, Int32 numBlocks)
00952 {
00953 DXTColBlock *curblock = line;
00954
00955 for (Int32 i = 0; i < numBlocks; i++)
00956 {
00957 swap(&curblock->row[0], &curblock->row[3], sizeof(UInt8));
00958 swap(&curblock->row[1], &curblock->row[2], sizeof(UInt8));
00959
00960 curblock++;
00961 }
00962 }
00963
00965
00966 void CDDSImage::flip_blocks_dxtc3(DXTColBlock *line, Int32 numBlocks)
00967 {
00968 DXTColBlock *curblock = line;
00969 DXT3AlphaBlock *alphablock;
00970
00971 for (Int32 i = 0; i < numBlocks; i++)
00972 {
00973 alphablock = (DXT3AlphaBlock*)curblock;
00974
00975 swap(&alphablock->row[0], &alphablock->row[3], sizeof(UInt16));
00976 swap(&alphablock->row[1], &alphablock->row[2], sizeof(UInt16));
00977
00978 curblock++;
00979
00980 swap(&curblock->row[0], &curblock->row[3], sizeof(UInt8));
00981 swap(&curblock->row[1], &curblock->row[2], sizeof(UInt8));
00982
00983 curblock++;
00984 }
00985 }
00986
00988
00989 void CDDSImage::flip_dxt5_alpha(DXT5AlphaBlock *block)
00990 {
00991 UInt8 gBits[4][4];
00992
00993 const UInt32 mask = 0x00000007;
00994 UInt32 bits = 0;
00995 memcpy(&bits, &block->row[0], sizeof(UInt8) * 3);
00996
00997 gBits[0][0] = (UInt8)(bits & mask);
00998 bits >>= 3;
00999 gBits[0][1] = (UInt8)(bits & mask);
01000 bits >>= 3;
01001 gBits[0][2] = (UInt8)(bits & mask);
01002 bits >>= 3;
01003 gBits[0][3] = (UInt8)(bits & mask);
01004 bits >>= 3;
01005 gBits[1][0] = (UInt8)(bits & mask);
01006 bits >>= 3;
01007 gBits[1][1] = (UInt8)(bits & mask);
01008 bits >>= 3;
01009 gBits[1][2] = (UInt8)(bits & mask);
01010 bits >>= 3;
01011 gBits[1][3] = (UInt8)(bits & mask);
01012
01013 bits = 0;
01014 memcpy(&bits, &block->row[3], sizeof(UInt8) * 3);
01015
01016 gBits[2][0] = (UInt8)(bits & mask);
01017 bits >>= 3;
01018 gBits[2][1] = (UInt8)(bits & mask);
01019 bits >>= 3;
01020 gBits[2][2] = (UInt8)(bits & mask);
01021 bits >>= 3;
01022 gBits[2][3] = (UInt8)(bits & mask);
01023 bits >>= 3;
01024 gBits[3][0] = (UInt8)(bits & mask);
01025 bits >>= 3;
01026 gBits[3][1] = (UInt8)(bits & mask);
01027 bits >>= 3;
01028 gBits[3][2] = (UInt8)(bits & mask);
01029 bits >>= 3;
01030 gBits[3][3] = (UInt8)(bits & mask);
01031
01032 UInt32 *pBits = ((UInt32*) &(block->row[0]));
01033
01034 *pBits = *pBits | (gBits[3][0] << 0);
01035 *pBits = *pBits | (gBits[3][1] << 3);
01036 *pBits = *pBits | (gBits[3][2] << 6);
01037 *pBits = *pBits | (gBits[3][3] << 9);
01038
01039 *pBits = *pBits | (gBits[2][0] << 12);
01040 *pBits = *pBits | (gBits[2][1] << 15);
01041 *pBits = *pBits | (gBits[2][2] << 18);
01042 *pBits = *pBits | (gBits[2][3] << 21);
01043
01044 pBits = ((UInt32*) &(block->row[3]));
01045
01046 #if BYTE_ORDER == BIG_ENDIAN
01047 *pBits &= 0x000000ff;
01048 #else
01049 *pBits &= 0xff000000;
01050 #endif
01051
01052 *pBits = *pBits | (gBits[1][0] << 0);
01053 *pBits = *pBits | (gBits[1][1] << 3);
01054 *pBits = *pBits | (gBits[1][2] << 6);
01055 *pBits = *pBits | (gBits[1][3] << 9);
01056
01057 *pBits = *pBits | (gBits[0][0] << 12);
01058 *pBits = *pBits | (gBits[0][1] << 15);
01059 *pBits = *pBits | (gBits[0][2] << 18);
01060 *pBits = *pBits | (gBits[0][3] << 21);
01061 }
01062
01064
01065 void CDDSImage::flip_blocks_dxtc5(DXTColBlock *line, Int32 numBlocks)
01066 {
01067 DXTColBlock *curblock = line;
01068 DXT5AlphaBlock *alphablock;
01069
01070 for (Int32 i = 0; i < numBlocks; i++)
01071 {
01072 alphablock = (DXT5AlphaBlock*)curblock;
01073
01074 flip_dxt5_alpha(alphablock);
01075
01076 curblock++;
01077
01078 swap(&curblock->row[0], &curblock->row[3], sizeof(UInt8));
01079 swap(&curblock->row[1], &curblock->row[2], sizeof(UInt8));
01080
01081 curblock++;
01082 }
01083 }
01084
01086
01088
01090
01091 CTexture::CTexture()
01092 : CSurface()
01093 {
01094 }
01095
01097
01098 CTexture::CTexture(Int32 w, Int32 h, Int32 d, Int32 imgSize)
01099 : CSurface(w, h, d, imgSize)
01100 {
01101 }
01102
01104
01105 CTexture::CTexture(const CTexture ©)
01106 : CSurface(copy)
01107 {
01108 for (UInt32 i = 0; i < copy.mipmaps.size(); i++)
01109 mipmaps.push_back(copy.mipmaps[i]);
01110 }
01111
01113
01114 CTexture &CTexture::operator= (const CTexture &rhs)
01115 {
01116 if (this != &rhs)
01117 {
01118 CSurface::operator = (rhs);
01119
01120 mipmaps.clear();
01121 for (UInt32 i = 0; i < rhs.mipmaps.size(); i++)
01122 {
01123 mipmaps.push_back(rhs.mipmaps[i]);
01124 }
01125 }
01126
01127 return *this;
01128 }
01129
01131
01132 CTexture::~CTexture()
01133 {
01134 mipmaps.clear();
01135 }
01136
01138
01140
01142
01143 CSurface::CSurface()
01144 : width(0),
01145 height(0),
01146 depth(0),
01147 size(0),
01148 pixels(NULL)
01149 {
01150 }
01151
01153
01154 CSurface::CSurface(Int32 w, Int32 h, Int32 d, Int32 imgsize)
01155 {
01156 pixels = NULL;
01157 create(w, h, d, imgsize);
01158 }
01159
01161
01162 CSurface::CSurface(const CSurface ©)
01163 : width(0),
01164 height(0),
01165 depth(0),
01166 size(0),
01167 pixels(NULL)
01168 {
01169
01170 if (copy.pixels)
01171 {
01172 size = copy.size;
01173 width = copy.width;
01174 height = copy.height;
01175 depth = copy.depth;
01176 pixels = new char[size];
01177 memcpy(pixels, copy.pixels, copy.size);
01178 }
01179 }
01180
01182
01183 CSurface &CSurface::operator= (const CSurface &rhs)
01184 {
01185 if (this != &rhs)
01186 {
01187 clear();
01188
01189 if (rhs.pixels)
01190 {
01191 size = rhs.size;
01192 width = rhs.width;
01193 height = rhs.height;
01194 depth = rhs.depth;
01195
01196 pixels = new char[size];
01197 memcpy(pixels, rhs.pixels, size);
01198 }
01199 }
01200
01201 return *this;
01202 }
01203
01205
01206 CSurface::~CSurface()
01207 {
01208 clear();
01209 }
01210
01212
01213 CSurface::operator char*()
01214 {
01215 return pixels;
01216 }
01217
01219
01220 void CSurface::create(Int32 w, Int32 h, Int32 d, Int32 imgsize)
01221 {
01222 clear();
01223
01224 width = w;
01225 height = h;
01226 depth = d;
01227 size = imgsize;
01228 pixels = new char[imgsize];
01229 }
01230
01232
01233 void CSurface::clear()
01234 {
01235 delete [] pixels;
01236 pixels = NULL;
01237 }