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
00282
00283 inline Int32 CDDSImage::clamp_size(Int32 size)
00284 {
00285 if (size <= 0)
00286 size = 1;
00287
00288 return size;
00289 }
00290
00291
00292
00293
00294
00295
00296
00300 DDSImageFileType& DDSImageFileType::the (void)
00301 {
00302 return _the;
00303 }
00304
00305
00306
00307
00308
00309 void DDSImageFileType::setFlipImage(bool s)
00310 {
00311 _flipImage = s;
00312 }
00313
00314 bool DDSImageFileType::getFlipImage(void)
00315 {
00316 return _flipImage;
00317 }
00318
00319 void DDSImageFileType::setFlipCubeMap(bool s)
00320 {
00321 _flipCubeMap = s;
00322 }
00323
00324 bool DDSImageFileType::getFlipCubeMap(void)
00325 {
00326 return _flipCubeMap;
00327 }
00328
00329 void DDSImageFileType::setSwapCubeMap(bool s)
00330 {
00331 _swapCubeMap = s;
00332 }
00333
00334 bool DDSImageFileType::getSwapCubeMap(void)
00335 {
00336 return _swapCubeMap;
00337 }
00338
00339
00340
00345 bool DDSImageFileType::read(ImagePtr &image, std::istream &is, const std::string &mimetype)
00346 {
00347 bool validImage = false;
00348 CDDSImage ddsImage;
00349 Int32 i,j,w,h,d, mm = 0, components, format,size;
00350 Int32 width = 0, height = 0, depth = 0, numMipMaps = 0;
00351 bool isCompressed, isCubeMap, isVolume;
00352 UInt8 *data;
00353 UInt32 dataSize = 0;
00354
00355 SINFO << "DDS File Info: ";
00356
00357 if (ddsImage.load(is, _flipImage, _swapCubeMap, _flipCubeMap) &&
00358 (validImage = ddsImage.is_valid()))
00359 {
00360 components = ddsImage.get_components();
00361 format = ddsImage.get_format();
00362 isCompressed = ddsImage.is_compressed();
00363 isCubeMap = ddsImage.is_cubemap();
00364 isVolume = ddsImage.is_volume();
00365
00366 SINFO << "cs: " << components
00367 << ", f: " << format
00368 << ", cd: " << isCompressed
00369 << ", cm: " << isCubeMap
00370 << ", vo: " << isVolume
00371 << endLog;
00372
00373 for (i = 0; i < ddsImage.get_num_images(); ++i) {
00374 w = ddsImage[i].get_width();
00375 h = ddsImage[i].get_height();
00376 d = ddsImage[i].get_depth();
00377 size = ddsImage[i].get_size();
00378 dataSize += size;
00379 mm = ddsImage[i].get_num_mipmaps();
00380 if (i) {
00381 if ( (w != width) || (h != height) || (d != depth) &&
00382 (mm != numMipMaps) )
00383 validImage = false;
00384 }
00385 else {
00386 width = w;
00387 height = h;
00388 depth = d;
00389 numMipMaps = mm;
00390 }
00391 SINFO << " " << i
00392 << ", " << w << "x" << h << "x" << d
00393 << ", size: " << size
00394 << ", mm: " << mm
00395 << endLog;
00396 for (j = 0; j < mm; ++j) {
00397 w = ddsImage[i].get_mipmap(j).get_width();
00398 h = ddsImage[i].get_mipmap(j).get_height();
00399 d = ddsImage[i].get_mipmap(j).get_depth();
00400 size = ddsImage[i].get_mipmap(j).get_size();
00401 dataSize += size;
00402 SINFO << " " << j
00403 << ", " << w << "x" << h << "x" << d
00404 << ", size: " << size
00405 << ", mm: " << mm
00406 << endLog;
00407
00408 }
00409 }
00410 if (validImage) {
00411 image->set( osg::Image::PixelFormat(format),
00412 width, height, depth,
00413 numMipMaps + 1,
00414 1, 0.0, 0, osg::Image::OSG_UINT8_IMAGEDATA,
00415 true,
00416 ddsImage.get_num_images() );
00417
00418 if (dataSize == image->getSize()) {
00419 data = image->editData();
00420
00421
00422 for (i = 0; i < ddsImage.get_num_images(); ++i) {
00423 size = ddsImage[i].get_size();
00424 memcpy (data, ddsImage[i].get_pixels(), size);
00425 data += size;
00426 for (j = 0; j < mm; ++j) {
00427 size = ddsImage[i].get_mipmap(j).get_size();
00428 memcpy (data, ddsImage[i].get_mipmap(j).get_pixels(), size);
00429 data += size;
00430 }
00431 }
00432 }
00433 else {
00434 SWARNING << "ERROR: Invalid data size; cannot cp dds data"
00435 << endLog;
00436
00437 }
00438 }
00439 }
00440 else
00441 SWARNING << "DDS Load Failed !" << endLog;
00442
00443 return validImage;;
00444 }
00445
00446
00452 std::string DDSImageFileType::determineMimetypeFromStream(std::istream &is)
00453 {
00454 char filecode[4];
00455 is.read(filecode, 4);
00456 is.seekg(-4, std::ios::cur);
00457 return strncmp(filecode, "DDS ", 4) == 0 ?
00458 std::string(getMimeType()) : std::string();
00459 }
00460
00461
00465 DDSImageFileType::DDSImageFileType(const Char8 *mimeType,
00466 const Char8 *suffixArray[],
00467 UInt16 suffixByteCount,
00468 UInt32 flags) :
00469 ImageFileType(mimeType, suffixArray, suffixByteCount, flags),
00470 _flipImage(true),
00471 _flipCubeMap(false),
00472 _swapCubeMap(false)
00473 {}
00474
00475
00479 DDSImageFileType::~DDSImageFileType(void) {}
00480
00481
00483
00484
00486
00487 CDDSImage::CDDSImage()
00488 : format(0),
00489 components(0),
00490 compressed(false),
00491 cubemap(false),
00492 volume(false),
00493 valid(false)
00494 {
00495 }
00496
00497 CDDSImage::~CDDSImage()
00498 {
00499 }
00500
00502
00503
00504
00505
00506 bool CDDSImage::load(std::istream &is, bool flipImage, bool swapCubeMap, bool flipCubeMap)
00507 {
00508 DDS_HEADER ddsh;
00509 char filecode[4];
00510 Int32 width, height, depth;
00511 Int32 (CDDSImage::*sizefunc)(Int32, Int32);
00512
00513
00514 clear();
00515
00516
00517 is.read(filecode, 4);
00518 if (strncmp(filecode, "DDS ", 4) != 0)
00519 return false;
00520
00521
00522 is.read(reinterpret_cast<char*>(&ddsh), sizeof(ddsh));
00523
00524 swap_endian(&ddsh.dwSize);
00525 swap_endian(&ddsh.dwFlags);
00526 swap_endian(&ddsh.dwHeight);
00527 swap_endian(&ddsh.dwWidth);
00528 swap_endian(&ddsh.dwPitchOrLinearSize);
00529 swap_endian(&ddsh.dwDepth);
00530 swap_endian(&ddsh.dwMipMapCount);
00531 swap_endian(&ddsh.ddspf.dwSize);
00532 swap_endian(&ddsh.ddspf.dwFlags);
00533 swap_endian(&ddsh.ddspf.dwFourCC);
00534 swap_endian(&ddsh.ddspf.dwRGBBitCount);
00535 swap_endian(&ddsh.dwCaps1);
00536 swap_endian(&ddsh.dwCaps2);
00537
00538
00539 if (ddsh.dwCaps2 & DDS_CUBEMAP)
00540 cubemap = true;
00541
00542
00543 if ((ddsh.dwCaps2 & DDS_VOLUME) && (ddsh.dwDepth > 0))
00544 volume = true;
00545
00546
00547 if (ddsh.ddspf.dwFlags & DDS_FOURCC)
00548 {
00549 switch(ddsh.ddspf.dwFourCC)
00550 {
00551 case FOURCC_DXT1:
00552 format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
00553 components = 3;
00554 compressed = true;
00555 break;
00556 case FOURCC_DXT3:
00557 format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
00558 components = 4;
00559 compressed = true;
00560 break;
00561 case FOURCC_DXT5:
00562 format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
00563 components = 4;
00564 compressed = true;
00565 break;
00566 default:
00567 SWARNING << "ERROR: unknown compressed format(" << ddsh.ddspf.dwFourCC
00568 << ")!" << endLog;
00569 return false;
00570 }
00571 }
00572 else if (ddsh.ddspf.dwFlags == DDS_RGBA && ddsh.ddspf.dwRGBBitCount == 32)
00573 {
00574 format = Image::OSG_BGRA_PF;
00575 compressed = false;
00576 components = 4;
00577 }
00578 else if (ddsh.ddspf.dwFlags == DDS_RGB && ddsh.ddspf.dwRGBBitCount == 32)
00579 {
00580 format = Image::OSG_BGRA_PF;
00581 compressed = false;
00582 components = 4;
00583 }
00584 else if (ddsh.ddspf.dwFlags == DDS_RGB && ddsh.ddspf.dwRGBBitCount == 24)
00585 {
00586 format = Image::OSG_BGR_PF;
00587 compressed = false;
00588 components = 3;
00589 }
00590 else if ( ddsh.ddspf.dwRGBBitCount == 8)
00591 {
00592 format = Image::OSG_L_PF;
00593 compressed = false;
00594 components = 1;
00595 }
00596 else
00597 {
00598 SWARNING << "ERROR: unknown image format!" << endLog;
00599 return false;
00600 }
00601
00602
00603 width = ddsh.dwWidth;
00604 height = ddsh.dwHeight;
00605 depth = clamp_size(ddsh.dwDepth);
00606
00607
00608
00609 sizefunc = (compressed ? &CDDSImage::size_dxtc : &CDDSImage::size_rgb);
00610
00611
00612 for (Int32 n = 0; n < (cubemap ? 6 : 1); n++)
00613 {
00614 Int32 size;
00615
00616
00617 size = (this->*sizefunc)(width, height)*depth;
00618
00619
00620 CTexture img(width, height, depth, size);
00621 is.read(img, img.size);
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634 align_memory(&img);
00635
00636 if ( (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) &&
00637 check_dxt1_alpha_data(img, img.size))
00638 format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
00639
00640 if ((flipImage && !cubemap) || (flipCubeMap && cubemap))
00641 flip(img, img.width, img.height, img.depth, img.size);
00642
00643 Int32 w = clamp_size(width >> 1);
00644 Int32 h = clamp_size(height >> 1);
00645 Int32 d = clamp_size(depth >> 1);
00646
00647
00648 Int32 numMipmaps = ddsh.dwMipMapCount;
00649
00650
00651
00652 if (numMipmaps != 0)
00653 numMipmaps--;
00654
00655
00656 for (Int32 i = 0; i < numMipmaps && (w || h); i++)
00657 {
00658
00659 size = (this->*sizefunc)(w, h)*d;
00660
00661 CSurface mipmap(w, h, d, size);
00662 is.read(mipmap, mipmap.size);
00663
00664 if ((flipImage && !cubemap) || (flipCubeMap && cubemap))
00665 {
00666 flip(mipmap, mipmap.width, mipmap.height, mipmap.depth,
00667 mipmap.size);
00668 }
00669
00670 img.mipmaps.push_back(mipmap);
00671
00672
00673 w = clamp_size(w >> 1);
00674 h = clamp_size(h >> 1);
00675 d = clamp_size(d >> 1);
00676 }
00677
00678 images.push_back(img);
00679
00680 }
00681
00682
00683 if (cubemap && swapCubeMap)
00684 {
00685 CTexture tmp;
00686 tmp = images[3];
00687 images[3] = images[2];
00688 images[2] = tmp;
00689 }
00690
00691 valid = true;
00692
00693 return true;
00694 }
00695
00697
00698 void CDDSImage::clear()
00699 {
00700 components = 0;
00701 format = 0;
00702 compressed = false;
00703 cubemap = false;
00704 volume = false;
00705 valid = false;
00706
00707 images.clear();
00708 }
00709
00711
00712
00713 CTexture &CDDSImage::operator[](Int32 index)
00714 {
00715
00716 assert(valid);
00717 assert(index < Int32(images.size()));
00718
00719 return images[index];
00720 }
00721
00723
00724 CDDSImage::operator char*()
00725 {
00726 assert(valid);
00727
00728 return images[0];
00729 }
00730
00731
00732
00734
00736
00738
00739 inline Int32 CDDSImage::get_line_width(Int32 width, Int32 bpp)
00740 {
00741 return ((width * bpp + 31) & -32) >> 3;
00742 }
00743
00745
00746 Int32 CDDSImage::size_dxtc(Int32 width, Int32 height)
00747 {
00748 Int32 comp( ( (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ||
00749 (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) ) ? 8 : 16 );
00750
00751 return ((width+3)/4)*((height+3)/4)*comp;
00752
00753
00754 }
00755
00757
00758 Int32 CDDSImage::size_rgb(Int32 width, Int32 height)
00759 {
00760 return width*height*components;
00761
00762 }
00763
00765
00766 inline void CDDSImage::swap_endian(void *val)
00767 {
00768 #if BYTE_ORDER == BIG_ENDIAN
00769 UInt32 *ival = (UInt32 *)val;
00770
00771 *ival = ((*ival >> 24) & 0x000000ff) |
00772 ((*ival >> 8) & 0x0000ff00) |
00773 ((*ival << 8) & 0x00ff0000) |
00774 ((*ival << 24) & 0xff000000);
00775 #endif
00776 }
00777
00779
00780 void CDDSImage::align_memory(CTexture *surface)
00781 {
00782
00783 if (compressed || volume || cubemap)
00784 return;
00785
00786
00787 Int32 linesize = get_line_width(surface->width, components*8);
00788 Int32 imagesize = linesize*surface->height;
00789
00790
00791 if (surface->size == imagesize)
00792 return;
00793
00794
00795 CTexture newSurface(surface->width, surface->height, surface->depth,
00796 imagesize);
00797
00798
00799 char *srcimage = static_cast<char*>(*surface);
00800 char *dstimage = static_cast<char*>(newSurface);
00801 for (Int32 n = 0; n < surface->depth; n++)
00802 {
00803 char *curline = srcimage;
00804 char *newline = dstimage;
00805
00806 Int32 imsize = surface->size / surface->depth;
00807 Int32 lnsize = imsize / surface->height;
00808
00809 for (Int32 i = 0; i < surface->height; i++)
00810 {
00811 memcpy(newline, curline, lnsize);
00812 newline += linesize;
00813 curline += lnsize;
00814 }
00815 }
00816
00817
00818 *surface = newSurface;
00819 }
00820
00822
00823 bool CDDSImage::check_dxt1_alpha_data (char *image, Int32 size)
00824 {
00825 bool hasAlpha(false);
00826 DXTColBlock *colBlock(reinterpret_cast<DXTColBlock*>(image));
00827
00828 for (unsigned i = 0, n = (size / 8); i < n; i++)
00829 if (colBlock[i].col0 <= colBlock[i].col1)
00830 {
00831 for (unsigned j = 0; j < 4; j++) {
00832 UInt8 byte = colBlock[i].row[j];
00833 for (unsigned p = 0; p < 4; p++, byte >> 2) {
00834 if ((byte & 3) == 3) {
00835 hasAlpha = true;
00836 break;
00837 }
00838 }
00839 }
00840
00841 if (hasAlpha)
00842 {
00843 FNOTICE (( "Found alpha in DXT1 %d/%d, col0:%d, col1:%d\n",
00844 i, n, colBlock[i].col0, colBlock[i].col1 ));
00845
00846 for (unsigned j = 0; j < 4; j++)
00847 FNOTICE (( " DXT Col Index: %d %d %d %d\n",
00848 ((colBlock[i].row[j] >> 0) & 3),
00849 ((colBlock[i].row[j] >> 2) & 3),
00850 ((colBlock[i].row[j] >> 4) & 3),
00851 ((colBlock[i].row[j] >> 6) & 3) ));
00852 }
00853
00854 if (hasAlpha)
00855 break;
00856 }
00857
00858 return hasAlpha;
00859 }
00860
00862
00863 void CDDSImage::flip(char *image, Int32 width, Int32 height, Int32 depth, Int32 size)
00864 {
00865 Int32 linesize;
00866 Int32 offset;
00867
00868 if (!compressed)
00869 {
00870 assert(depth > 0);
00871
00872 Int32 imagesize = size/depth;
00873 linesize = imagesize / height;
00874
00875 for (Int32 n = 0; n < depth; n++)
00876 {
00877 offset = imagesize*n;
00878 char *top = image + offset;
00879 char *bottom = top + (imagesize-linesize);
00880
00881 for (Int32 i = 0; i < (height >> 1); i++)
00882 {
00883 swap(bottom, top, linesize);
00884
00885 top += linesize;
00886 bottom -= linesize;
00887 }
00888 }
00889 }
00890 else
00891 {
00892 void (CDDSImage::*flipblocks)(DXTColBlock*, Int32);
00893 Int32 xblocks = width / 4;
00894 Int32 yblocks = height / 4;
00895 Int32 blocksize;
00896
00897 switch (format)
00898 {
00899 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
00900 blocksize = 8;
00901 flipblocks = &CDDSImage::flip_blocks_dxtc1;
00902 break;
00903 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
00904 blocksize = 8;
00905 flipblocks = &CDDSImage::flip_blocks_dxtc1;
00906 break;
00907 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
00908 blocksize = 16;
00909 flipblocks = &CDDSImage::flip_blocks_dxtc3;
00910 break;
00911 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
00912 blocksize = 16;
00913 flipblocks = &CDDSImage::flip_blocks_dxtc5;
00914 break;
00915 default:
00916 return;
00917 }
00918
00919 linesize = xblocks * blocksize;
00920
00921 DXTColBlock *top;
00922 DXTColBlock *bottom;
00923
00924 for (Int32 j = 0; j < (yblocks >> 1); j++)
00925 {
00926 top = reinterpret_cast<DXTColBlock*>(image + j * linesize);
00927 bottom = reinterpret_cast<DXTColBlock*>(image + (((yblocks-j)-1) * linesize));
00928
00929 (this->*flipblocks)(top, xblocks);
00930 (this->*flipblocks)(bottom, xblocks);
00931
00932 swap(bottom, top, linesize);
00933 }
00934 }
00935 }
00936
00938
00939 void CDDSImage::swap(void *byte1, void *byte2, Int32 size)
00940 {
00941 UInt8 *tmp = new UInt8[size];
00942
00943 memcpy(tmp, byte1, size);
00944 memcpy(byte1, byte2, size);
00945 memcpy(byte2, tmp, size);
00946
00947 delete [] tmp;
00948 }
00949
00951
00952 void CDDSImage::flip_blocks_dxtc1(DXTColBlock *line, Int32 numBlocks)
00953 {
00954 DXTColBlock *curblock = line;
00955
00956 for (Int32 i = 0; i < numBlocks; i++)
00957 {
00958 swap(&curblock->row[0], &curblock->row[3], sizeof(UInt8));
00959 swap(&curblock->row[1], &curblock->row[2], sizeof(UInt8));
00960
00961 curblock++;
00962 }
00963 }
00964
00966
00967 void CDDSImage::flip_blocks_dxtc3(DXTColBlock *line, Int32 numBlocks)
00968 {
00969 DXTColBlock *curblock = line;
00970 DXT3AlphaBlock *alphablock;
00971
00972 for (Int32 i = 0; i < numBlocks; i++)
00973 {
00974 alphablock = reinterpret_cast<DXT3AlphaBlock*>(curblock);
00975
00976 swap(&alphablock->row[0], &alphablock->row[3], sizeof(UInt16));
00977 swap(&alphablock->row[1], &alphablock->row[2], sizeof(UInt16));
00978
00979 curblock++;
00980
00981 swap(&curblock->row[0], &curblock->row[3], sizeof(UInt8));
00982 swap(&curblock->row[1], &curblock->row[2], sizeof(UInt8));
00983
00984 curblock++;
00985 }
00986 }
00987
00989
00990 void CDDSImage::flip_dxt5_alpha(DXT5AlphaBlock *block)
00991 {
00992 UInt8 gBits[4][4];
00993
00994 const UInt32 mask = 0x00000007;
00995 UInt32 bits = 0;
00996 memcpy(&bits, &block->row[0], sizeof(UInt8) * 3);
00997
00998 gBits[0][0] = UInt8(bits & mask);
00999 bits >>= 3;
01000 gBits[0][1] = UInt8(bits & mask);
01001 bits >>= 3;
01002 gBits[0][2] = UInt8(bits & mask);
01003 bits >>= 3;
01004 gBits[0][3] = UInt8(bits & mask);
01005 bits >>= 3;
01006 gBits[1][0] = UInt8(bits & mask);
01007 bits >>= 3;
01008 gBits[1][1] = UInt8(bits & mask);
01009 bits >>= 3;
01010 gBits[1][2] = UInt8(bits & mask);
01011 bits >>= 3;
01012 gBits[1][3] = UInt8(bits & mask);
01013
01014 bits = 0;
01015 memcpy(&bits, &block->row[3], sizeof(UInt8) * 3);
01016
01017 gBits[2][0] = UInt8(bits & mask);
01018 bits >>= 3;
01019 gBits[2][1] = UInt8(bits & mask);
01020 bits >>= 3;
01021 gBits[2][2] = UInt8(bits & mask);
01022 bits >>= 3;
01023 gBits[2][3] = UInt8(bits & mask);
01024 bits >>= 3;
01025 gBits[3][0] = UInt8(bits & mask);
01026 bits >>= 3;
01027 gBits[3][1] = UInt8(bits & mask);
01028 bits >>= 3;
01029 gBits[3][2] = UInt8(bits & mask);
01030 bits >>= 3;
01031 gBits[3][3] = UInt8(bits & mask);
01032
01033 UInt32 *pBits = (reinterpret_cast<UInt32*>(&(block->row[0])));
01034
01035 *pBits = *pBits | (gBits[3][0] << 0);
01036 *pBits = *pBits | (gBits[3][1] << 3);
01037 *pBits = *pBits | (gBits[3][2] << 6);
01038 *pBits = *pBits | (gBits[3][3] << 9);
01039
01040 *pBits = *pBits | (gBits[2][0] << 12);
01041 *pBits = *pBits | (gBits[2][1] << 15);
01042 *pBits = *pBits | (gBits[2][2] << 18);
01043 *pBits = *pBits | (gBits[2][3] << 21);
01044
01045 pBits = (reinterpret_cast<UInt32*>(&(block->row[3])));
01046
01047 #if BYTE_ORDER == BIG_ENDIAN
01048 *pBits &= 0x000000ff;
01049 #else
01050 *pBits &= 0xff000000;
01051 #endif
01052
01053 *pBits = *pBits | (gBits[1][0] << 0);
01054 *pBits = *pBits | (gBits[1][1] << 3);
01055 *pBits = *pBits | (gBits[1][2] << 6);
01056 *pBits = *pBits | (gBits[1][3] << 9);
01057
01058 *pBits = *pBits | (gBits[0][0] << 12);
01059 *pBits = *pBits | (gBits[0][1] << 15);
01060 *pBits = *pBits | (gBits[0][2] << 18);
01061 *pBits = *pBits | (gBits[0][3] << 21);
01062 }
01063
01065
01066 void CDDSImage::flip_blocks_dxtc5(DXTColBlock *line, Int32 numBlocks)
01067 {
01068 DXTColBlock *curblock = line;
01069 DXT5AlphaBlock *alphablock;
01070
01071 for (Int32 i = 0; i < numBlocks; i++)
01072 {
01073 alphablock = reinterpret_cast<DXT5AlphaBlock*>(curblock);
01074
01075 flip_dxt5_alpha(alphablock);
01076
01077 curblock++;
01078
01079 swap(&curblock->row[0], &curblock->row[3], sizeof(UInt8));
01080 swap(&curblock->row[1], &curblock->row[2], sizeof(UInt8));
01081
01082 curblock++;
01083 }
01084 }
01085
01087
01089
01091
01092 CTexture::CTexture()
01093 : CSurface()
01094 {
01095 }
01096
01098
01099 CTexture::CTexture(Int32 w, Int32 h, Int32 d, Int32 imgSize)
01100 : CSurface(w, h, d, imgSize)
01101 {
01102 }
01103
01105
01106 CTexture::CTexture(const CTexture ©)
01107 : CSurface(copy)
01108 {
01109 for (UInt32 i = 0; i < copy.mipmaps.size(); i++)
01110 mipmaps.push_back(copy.mipmaps[i]);
01111 }
01112
01114
01115 CTexture &CTexture::operator= (const CTexture &rhs)
01116 {
01117 if (this != &rhs)
01118 {
01119 CSurface::operator = (rhs);
01120
01121 mipmaps.clear();
01122 for (UInt32 i = 0; i < rhs.mipmaps.size(); i++)
01123 {
01124 mipmaps.push_back(rhs.mipmaps[i]);
01125 }
01126 }
01127
01128 return *this;
01129 }
01130
01132
01133 CTexture::~CTexture()
01134 {
01135 mipmaps.clear();
01136 }
01137
01139
01141
01143
01144 CSurface::CSurface()
01145 : width(0),
01146 height(0),
01147 depth(0),
01148 size(0),
01149 pixels(NULL)
01150 {
01151 }
01152
01154
01155 CSurface::CSurface(Int32 w, Int32 h, Int32 d, Int32 imgsize)
01156 {
01157 pixels = NULL;
01158 create(w, h, d, imgsize);
01159 }
01160
01162
01163 CSurface::CSurface(const CSurface ©)
01164 : width(0),
01165 height(0),
01166 depth(0),
01167 size(0),
01168 pixels(NULL)
01169 {
01170
01171 if (copy.pixels)
01172 {
01173 size = copy.size;
01174 width = copy.width;
01175 height = copy.height;
01176 depth = copy.depth;
01177 pixels = new char[size];
01178 memcpy(pixels, copy.pixels, copy.size);
01179 }
01180 }
01181
01183
01184 CSurface &CSurface::operator= (const CSurface &rhs)
01185 {
01186 if (this != &rhs)
01187 {
01188 clear();
01189
01190 if (rhs.pixels)
01191 {
01192 size = rhs.size;
01193 width = rhs.width;
01194 height = rhs.height;
01195 depth = rhs.depth;
01196
01197 pixels = new char[size];
01198 memcpy(pixels, rhs.pixels, size);
01199 }
01200 }
01201
01202 return *this;
01203 }
01204
01206
01207 CSurface::~CSurface()
01208 {
01209 clear();
01210 }
01211
01213
01214 CSurface::operator char*()
01215 {
01216 return pixels;
01217 }
01218
01220
01221 void CSurface::create(Int32 w, Int32 h, Int32 d, Int32 imgsize)
01222 {
01223 clear();
01224
01225 width = w;
01226 height = h;
01227 depth = d;
01228 size = imgsize;
01229 pixels = new char[imgsize];
01230 }
01231
01233
01234 void CSurface::clear()
01235 {
01236 delete [] pixels;
01237 pixels = NULL;
01238 }