fixed: auto_ptr -> unique_ptr
[opensg.git] / Source / System / Image / FileIO / OSGDDSImageFileType.cpp
blobca5ec49774b7433e7d6fde54552a2c5293cf1b0f
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2000-2002 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
29 /*---------------------------------------------------------------------------*\
30 * Changes *
31 * *
32 * *
33 * *
34 * *
35 * *
36 * *
37 \*---------------------------------------------------------------------------*/
38 //-------------------------------
39 // Includes
40 //-------------------------------
42 #include <cstdlib>
43 #include <cstdio>
44 #include <cassert>
46 #include "OSGConfig.h"
48 #include <string>
49 #include <vector>
51 #include <iostream>
52 #include <fstream>
54 #include "OSGLog.h"
56 #include "OSGImage.h"
58 #include "OSGDDSImageFileType.h"
60 #ifdef OSG_SGI_STL
62 //#include <limits>
63 #ifndef INT_MAX
64 #define INT_MAX numeric_limits<Int32>::max()
65 #endif
66 #else
67 #include <climits>
68 #endif
70 // Static Class Varible implementations:
71 static const OSG::Char8 *suffixArray[] =
73 "dds"
76 OSG_BEGIN_NAMESPACE
78 /*! \class DDSImageFileType
80 Image File Type to read/write and store/restore Image objects as
81 DDS data. Should work with binary and ascii dds/pbm/pgm/ppm data.
83 All the type specific code is included in the class. Does
84 not depend on external libs.
88 DDSImageFileType DDSImageFileType::_the("image/x-dds",
89 suffixArray,
90 sizeof(suffixArray),
91 (OSG_READ_SUPPORTED |
92 OSG_WRITE_SUPPORTED));
94 #ifdef WIN32
95 # include <windows.h>
96 #endif
98 const UInt32 DDS_DDPF_ALPHAPIXELS = 0x00000001;
99 const UInt32 DDS_DDPF_ALPHA = 0x00000002;
100 const UInt32 DDS_DDPF_FOURCC = 0x00000004;
101 const UInt32 DDS_DDPF_RGB = 0x00000040;
102 const UInt32 DDS_DDPF_YUV = 0x00000200;
103 const UInt32 DDS_DDPF_LUMINANCE = 0x00020000;
104 const UInt32 DDS_DDPF_OPENGL = 0x00200000;
105 const UInt32 DDS_DDPF_OPENGL_NV = 0x00600000;
106 const UInt32 DDS_DDPF_OPENGL_STD = 0x00A00000;
107 const UInt32 DDS_DDPF_RGBA = 0x00000041;
109 const UInt32 DDS_CAPS_COMPLEX = 0x00000008;
111 const UInt32 DDS_CAPS2_CUBEMAP = 0x00000200;
112 const UInt32 DDS_CAPS2_VOLUME = 0x00200000;
115 const UInt32 FOURCC_DXT1 = 0x31545844;
116 const UInt32 FOURCC_DXT3 = 0x33545844;
117 const UInt32 FOURCC_DXT5 = 0x35545844;
119 //const UInt32 DDS_DEPTH = 0x00800000;
120 //const UInt32 DDS_COMPRESSED = 0x00000080;
122 /*! \nohierarchy
125 struct DDS_PIXELFORMAT
127 UInt32 dwSize;
128 UInt32 dwFlags;
129 UInt32 dwFourCC;
130 UInt32 dwRGBBitCount;
131 UInt32 dwRBitMask;
132 UInt32 dwGBitMask;
133 UInt32 dwBBitMask;
134 UInt32 dwABitMask;
137 /*! \nohierarchy
140 struct DXTColBlock
142 UInt16 col0;
143 UInt16 col1;
145 UInt8 row[4];
148 /*! \nohierarchy
151 struct DXT3AlphaBlock
153 UInt16 row[4];
156 /*! \nohierarchy
159 struct DXT5AlphaBlock
161 UInt8 alpha0;
162 UInt8 alpha1;
164 UInt8 row[6];
167 /*! \nohierarchy
170 struct DDS_HEADER
172 UInt32 dwSize;
173 UInt32 dwFlags;
174 UInt32 dwHeight;
175 UInt32 dwWidth;
176 UInt32 dwPitchOrLinearSize;
177 UInt32 dwDepth;
178 UInt32 dwMipMapCount;
179 UInt32 dwReserved1[11];
180 DDS_PIXELFORMAT ddspf;
181 UInt32 dwCaps1;
182 UInt32 dwCaps2;
183 UInt32 dwReserved2[3];
186 /*! \nohierarchy
189 class CSurface
191 friend class CTexture;
192 friend class CDDSImage;
194 public:
196 CSurface();
197 CSurface(Int32 w, Int32 h, Int32 d, Int32 imgsize);
198 CSurface(const CSurface &copy);
199 CSurface &operator= (const CSurface &rhs);
200 virtual ~CSurface();
202 // operator char *();
204 void create(Int32 w, Int32 h, Int32 d, Int32 imgsize);
205 void clear();
207 Int32 get_width () { return width; }
208 Int32 get_height() { return height; }
209 Int32 get_depth () { return depth; }
210 Int32 get_size () { return size; }
211 char* get_pixels() { return pixels; }
213 void swapPixels(CSurface &other);
215 protected:
217 Int32 width;
218 Int32 height;
219 Int32 depth;
220 Int32 size;
222 char *pixels;
225 /*! \nohierarchy
228 class CTexture : public CSurface
230 friend class CDDSImage;
232 public:
234 CTexture();
235 CTexture(Int32 w, Int32 h, Int32 d, Int32 imgSize);
236 CTexture(const CTexture &copy);
237 CTexture &operator= (const CTexture &rhs);
238 ~CTexture();
240 CSurface &get_mipmap(Int32 index)
242 assert(index < Int32(mipmaps.size()));
243 return mipmaps[index];
246 int get_num_mipmaps() { return Int32(mipmaps.size()); }
248 protected:
249 std::vector<CSurface> mipmaps;
252 /*! \nohierarchy
255 class CDDSImage
257 public:
258 CDDSImage();
259 ~CDDSImage();
261 bool load(std::istream &is,
262 bool flipImage = true,
263 bool swapCubeMap = true,
264 bool flipCubeMap = false);
265 void clear();
267 // operator char*();
268 CTexture &operator[](Int32 index);
270 Int32 get_num_images(void) { return Int32(images.size()); }
271 CTexture &get_image(Int32 index)
273 assert(index < Int32(images.size()));
274 return images[index];
277 Int32 get_components() { return components; }
278 Int32 get_format () { return format; }
280 bool is_compressed() { return compressed; }
281 bool is_cubemap() { return cubemap; }
282 bool is_volume() { return volume; }
283 bool is_valid() { return valid; }
285 private:
287 Int32 clamp_size(Int32 size);
288 Int32 get_line_width(Int32 width, Int32 bpp);
289 Int32 size_dxtc(Int32 width, Int32 height);
290 Int32 size_rgb(Int32 width, Int32 height);
291 void swap_endian(void *val);
292 void align_memory(CTexture *surface);
294 void flip (CSurface &image,
295 Int32 width, Int32 height, Int32 depth,
296 Int32 size, UInt32 ddpfFlags);
297 bool check_dxt1_alpha_data (char *image, Int32 size);
299 void swap(void *byte1, void *byte2, Int32 size);
301 void flip_blocks_dxtc1(DXTColBlock *line, Int32 numBlocks);
302 void flip_blocks_dxtc3(DXTColBlock *line, Int32 numBlocks);
303 void flip_blocks_dxtc5(DXTColBlock *line, Int32 numBlocks);
304 void flip_dxt5_alpha(DXT5AlphaBlock *block);
306 void flipDXT (CSurface &image,
307 Int32 width, Int32 height, Int32 depth,
308 Int32 size);
310 void flipDXTStdToNV(CSurface &image,
311 Int32 width, Int32 height, Int32 depth,
312 Int32 size);
314 void changeLayout (CSurface &image,
315 Int32 width, Int32 height, Int32 depth,
316 Int32 size, bool bNVToStd);
318 Int32 format;
319 Int32 components;
320 bool compressed;
321 bool cubemap;
322 bool volume;
323 bool valid;
325 std::vector<CTexture> images;
329 void DDSImageFileType::setFlipImage(bool s)
331 _flipImage = s;
334 bool DDSImageFileType::getFlipImage(void)
336 return _flipImage;
339 void DDSImageFileType::setFlipCubeMap(bool s)
341 _flipCubeMap = s;
344 bool DDSImageFileType::getFlipCubeMap(void)
346 return _flipCubeMap;
349 void DDSImageFileType::setSwapCubeMap(bool s)
351 _swapCubeMap = s;
354 bool DDSImageFileType::getSwapCubeMap(void)
356 return _swapCubeMap;
360 //-------------------------------------------------------------------------
361 /*! Tries to fill the image object with the data read from
362 the given stream. Returns true on success.
365 bool DDSImageFileType::read( Image *pImage,
366 std::istream &is,
367 const std::string &mimetype)
369 bool validImage = false;
371 CDDSImage ddsImage;
373 Int32 i,j,w,h,d, mm = 0, components, format,size;
374 Int32 width = 0, height = 0, depth = 0, numMipMaps = 0;
375 bool isCompressed, isCubeMap, isVolume;
376 UInt8 *data;
377 UInt32 dataSize = 0;
379 SINFO << "DDS File Info: " << ": ";
381 if(ddsImage.load(is, _flipImage, _swapCubeMap, _flipCubeMap) &&
382 (validImage = ddsImage.is_valid()))
384 components = ddsImage.get_components();
385 format = ddsImage.get_format();
386 isCompressed = ddsImage.is_compressed();
387 isCubeMap = ddsImage.is_cubemap();
388 isVolume = ddsImage.is_volume();
390 SINFO << "cs: " << components
391 << ", f: " << format
392 << ", cd: " << isCompressed
393 << ", cm: " << isCubeMap
394 << ", vo: " << isVolume
395 << endLog;
397 for (i = 0; i < ddsImage.get_num_images(); ++i)
399 w = ddsImage[i].get_width();
400 h = ddsImage[i].get_height();
401 d = ddsImage[i].get_depth();
402 size = ddsImage[i].get_size();
404 dataSize += size;
406 mm = ddsImage[i].get_num_mipmaps();
408 if(i)
410 if((w != width) || (h != height) || (d != depth) ||
411 (mm != numMipMaps) )
413 validImage = false;
416 else
418 width = w;
419 height = h;
420 depth = d;
421 numMipMaps = mm;
424 SINFO << " " << i
425 << ", " << w << "x" << h << "x" << d
426 << ", size: " << size
427 << ", mm: " << mm
428 << endLog;
430 for (j = 0; j < mm; ++j)
432 w = ddsImage[i].get_mipmap(j).get_width();
433 h = ddsImage[i].get_mipmap(j).get_height();
434 d = ddsImage[i].get_mipmap(j).get_depth();
435 size = ddsImage[i].get_mipmap(j).get_size();
436 dataSize += size;
438 SINFO << " " << j
439 << ", " << w << "x" << h << "x" << d
440 << ", size: " << size
441 << ", mm: " << mm
442 << endLog;
447 if(validImage)
449 pImage->set( OSG::Image::PixelFormat(format),
450 width, height, depth,
451 numMipMaps + 1,
452 1, 0.0, 0, OSG::Image::OSG_UINT8_IMAGEDATA,
453 true,
454 ddsImage.get_num_images() );
456 if(dataSize == pImage->getSize())
458 data = pImage->editData();
460 // copy data;
461 for (i = 0; i < ddsImage.get_num_images(); ++i)
463 size = ddsImage[i].get_size();
464 memcpy (data, ddsImage[i].get_pixels(), size);
465 data += size;
466 for(j = 0; j < mm; ++j)
468 size = ddsImage[i].get_mipmap(j).get_size();
470 memcpy (data,
471 ddsImage[i].get_mipmap(j).get_pixels(),
472 size);
473 data += size;
477 else
479 SWARNING << "ERROR: Invalid data size; cannot cp dds data"
480 << endLog;
485 else
487 SWARNING << "DDS Load Failed !" << endLog;
490 return validImage;;
493 //-------------------------------------------------------------------------
494 /*! Tries to write the image object to the given fileName.
495 Returns true on success.
498 bool DDSImageFileType::write(const Image *,
499 std::ostream &,
500 const std::string &)
502 SWARNING << getMimeType()
503 << " write is not implemented "
504 << endLog;
506 return false;
510 //-------------------------------------------------------------------------
512 Tries to determine the mime type of the data provided by an input stream
513 by searching for magic bytes. Returns the mime type or an empty string
514 when the function could not determine the mime type.
517 std::string DDSImageFileType::determineMimetypeFromStream(std::istream &is)
519 char filecode[4];
521 is.read(filecode, 4);
522 is.seekg(-4, std::ios::cur);
524 return strncmp(filecode, "DDS ", 4) == 0 ?
525 std::string(getMimeType()) : std::string();
528 /**constructors & destructors**/
530 //-------------------------------------------------------------------------
531 /*! Constructor used for the singleton object
534 DDSImageFileType::DDSImageFileType(const Char8 *mimeType,
535 const Char8 *suffixArray[],
536 UInt16 suffixByteCount,
537 UInt32 flags ) :
539 Inherited (mimeType,suffixArray, suffixByteCount, flags),
540 _flipImage (true ),
541 _flipCubeMap(false),
542 _swapCubeMap(false)
546 //-------------------------------------------------------------------------
547 /*! Destructor
550 DDSImageFileType::~DDSImageFileType(void)
555 ///////////////////////////////////////////////////////////////////////////////
556 // CDDSImage public functions
558 ///////////////////////////////////////////////////////////////////////////////
559 // default constructor
561 CDDSImage::CDDSImage() :
562 format(0),
563 components(0),
564 compressed(false),
565 cubemap(false),
566 volume(false),
567 valid(false),
568 images()
572 CDDSImage::~CDDSImage()
576 ///////////////////////////////////////////////////////////////////////////////
577 // Swap the bytes in a 32 bit value
578 inline void CDDSImage::swap_endian(void *val)
580 #if BYTE_ORDER == BIG_ENDIAN
581 UInt32 *ival = (UInt32 *)val;
583 *ival = ((*ival >> 24) & 0x000000ff) |
584 ((*ival >> 8) & 0x0000ff00) |
585 ((*ival << 8) & 0x00ff0000) |
586 ((*ival << 24) & 0xff000000);
587 #endif
590 ///////////////////////////////////////////////////////////////////////////////
591 // clamps input size to [1-size]
592 inline int CDDSImage::clamp_size(Int32 size)
594 if (size <= 0)
595 size = 1;
597 return size;
601 ///////////////////////////////////////////////////////////////////////////////
602 // loads DDS image
604 // filename - fully qualified name of DDS image
605 // flipImage - specifies whether image is flipped on load, default is true
607 bool CDDSImage::load(std::istream &is,
608 bool flipImage,
609 bool swapCubeMap,
610 bool flipCubeMap)
612 DDS_HEADER ddsh;
613 char filecode[4];
614 Int32 width, height, depth;
615 Int32 (CDDSImage::*sizefunc)(Int32, Int32);
617 // clear any previously loaded images
618 clear();
620 // read in file marker, make sure its a DDS file
621 is.read(filecode, 4);
622 if (strncmp(filecode, "DDS ", 4) != 0)
623 return false;
625 // read in DDS header
626 is.read(reinterpret_cast<char*>(&ddsh), sizeof(ddsh));
628 swap_endian(&ddsh.dwSize);
629 swap_endian(&ddsh.dwFlags);
630 swap_endian(&ddsh.dwHeight);
631 swap_endian(&ddsh.dwWidth);
632 swap_endian(&ddsh.dwPitchOrLinearSize);
633 swap_endian(&ddsh.dwDepth);
634 swap_endian(&ddsh.dwMipMapCount);
635 swap_endian(&ddsh.ddspf.dwSize);
636 swap_endian(&ddsh.ddspf.dwFlags);
637 swap_endian(&ddsh.ddspf.dwFourCC);
638 swap_endian(&ddsh.ddspf.dwRGBBitCount);
639 swap_endian(&ddsh.dwCaps1);
640 swap_endian(&ddsh.dwCaps2);
642 // check if image is a cubempa
643 if (ddsh.dwCaps2 & DDS_CAPS2_CUBEMAP)
644 cubemap = true;
646 // check if image is a volume texture
647 if ((ddsh.dwCaps2 & DDS_CAPS2_VOLUME) && (ddsh.dwDepth > 0))
648 volume = true;
650 // figure out what the image format is
651 if (ddsh.ddspf.dwFlags & DDS_DDPF_FOURCC)
653 switch(ddsh.ddspf.dwFourCC)
655 case FOURCC_DXT1:
656 format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
657 components = 3;
658 compressed = true;
659 break;
660 case FOURCC_DXT3:
661 format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
662 components = 4;
663 compressed = true;
664 break;
665 case FOURCC_DXT5:
666 format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
667 components = 4;
668 compressed = true;
669 break;
670 default:
671 SWARNING << "ERROR: unknown compressed format("
672 << ddsh.ddspf.dwFourCC
673 << ")!"
674 << endLog;
675 return false;
678 else if((ddsh.ddspf.dwFlags & DDS_DDPF_RGBA) == DDS_DDPF_RGBA && ddsh.ddspf.dwRGBBitCount == 32)
680 format = Image::OSG_BGRA_PF;
681 compressed = false;
682 components = 4;
684 else if((ddsh.ddspf.dwFlags & DDS_DDPF_RGB ) == DDS_DDPF_RGB && ddsh.ddspf.dwRGBBitCount == 32)
686 format = Image::OSG_BGRA_PF;
687 compressed = false;
688 components = 4;
690 else if((ddsh.ddspf.dwFlags & DDS_DDPF_RGB ) == DDS_DDPF_RGB && ddsh.ddspf.dwRGBBitCount == 24)
692 format = Image::OSG_BGR_PF;
693 compressed = false;
694 components = 3;
696 else if ((ddsh.ddspf.dwFlags & DDS_DDPF_LUMINANCE) == DDS_DDPF_LUMINANCE && ddsh.ddspf.dwRGBBitCount == 8)
698 format = Image::OSG_L_PF;
699 compressed = false;
700 components = 1;
702 else
704 SWARNING << "ERROR: unknown image format!" << endLog;
705 return false;
708 // store primary surface width/height/depth
709 width = ddsh.dwWidth;
710 height = ddsh.dwHeight;
711 depth = clamp_size(ddsh.dwDepth); // set to 1 if 0
713 // use correct size calculation function depending on whether image is
714 // compressed
715 sizefunc = (compressed ? &CDDSImage::size_dxtc : &CDDSImage::size_rgb);
717 bool doFlipImage = false;
719 if((flipImage && !cubemap) || (flipCubeMap && cubemap))
720 doFlipImage = true;
722 if((ddsh.ddspf.dwFlags & DDS_DDPF_OPENGL) != 0x00000000 && volume == false)
723 doFlipImage = false;
725 #ifdef OSG_DEBUG
726 fprintf(stderr,
727 "dds status : opengl 0x%x | layout nv 0x%x "
728 "| layout std 0x%x | flip %d\n",
729 UInt32(ddsh.ddspf.dwFlags & DDS_DDPF_OPENGL),
730 UInt32((ddsh.ddspf.dwFlags & DDS_DDPF_OPENGL_NV ) == DDS_DDPF_OPENGL_NV ),
731 UInt32((ddsh.ddspf.dwFlags & DDS_DDPF_OPENGL_STD) == DDS_DDPF_OPENGL_STD),
732 UInt32(doFlipImage));
733 #endif
735 // load all surfaces for the image (6 surfaces for cubemaps)
736 for(Int32 n = 0; n < (cubemap ? 6 : 1); n++)
738 Int32 size;
740 // calculate surface size
741 size = (this->*sizefunc)(width, height)*depth;
743 // load surface
744 CTexture img(width, height, depth, size);
745 is.read(img.get_pixels(), img.size);
747 align_memory(&img);
749 if((format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) &&
750 check_dxt1_alpha_data(img.get_pixels(), img.size))
752 format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
756 if(doFlipImage == true)
758 flip(img, img.width, img.height, img.depth, img.size, ddsh.ddspf.dwFlags);
761 Int32 w = clamp_size(width >> 1);
762 Int32 h = clamp_size(height >> 1);
763 Int32 d = clamp_size(depth >> 1);
765 // store number of mipmaps
766 Int32 numMipmaps = ddsh.dwMipMapCount;
768 // number of mipmaps in file includes main surface so decrease count
769 // by one
770 if (numMipmaps != 0)
771 numMipmaps--;
773 // load all mipmaps for current surface
774 for (Int32 i = 0; i < numMipmaps && (w || h); i++)
776 // calculate mipmap size
777 size = (this->*sizefunc)(w, h)*d;
779 CSurface mipmap(w, h, d, size);
780 is.read(mipmap.get_pixels(), mipmap.size);
782 if(doFlipImage == true)
784 flip(mipmap, mipmap.width, mipmap.height, mipmap.depth,
785 mipmap.size, ddsh.ddspf.dwFlags);
788 img.mipmaps.push_back(mipmap);
790 // shrink to next power of 2
791 w = clamp_size(w >> 1);
792 h = clamp_size(h >> 1);
793 d = clamp_size(d >> 1);
796 images.push_back(img);
799 // swap cubemaps on y axis (since image is flipped in OGL)
800 if (cubemap && swapCubeMap)
802 CTexture tmp;
803 tmp = images[3];
804 images[3] = images[2];
805 images[2] = tmp;
808 valid = true;
810 return true;
813 ///////////////////////////////////////////////////////////////////////////////
814 // free image memory
816 void CDDSImage::clear()
818 components = 0;
819 format = 0;
820 compressed = false;
821 cubemap = false;
822 volume = false;
823 valid = false;
825 images.clear();
829 ///////////////////////////////////////////////////////////////////////////////
830 // returns individual texture when multiple textures are loaded (as is the case
831 // with volume textures and cubemaps)
833 CTexture &CDDSImage::operator[](Int32 index)
835 // make sure an image has been loaded
836 assert(valid);
837 assert(index < Int32(images.size()));
839 return images[index];
842 ///////////////////////////////////////////////////////////////////////////////
843 // returns pointer to main image
844 #if 0
845 CDDSImage::operator char*()
847 assert(valid);
849 return images[0];
851 #endif
854 ///////////////////////////////////////////////////////////////////////////////
855 // CDDSImage private functions
856 ///////////////////////////////////////////////////////////////////////////////
858 ///////////////////////////////////////////////////////////////////////////////
859 // calculates 4-byte aligned width of image
860 inline int CDDSImage::get_line_width(Int32 width, Int32 bpp)
862 return ((width * bpp + 31) & -32) >> 3;
865 ///////////////////////////////////////////////////////////////////////////////
866 // calculates size of DXTC texture in bytes
867 int CDDSImage::size_dxtc(Int32 width, Int32 height)
869 Int32 comp( ( (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ||
870 (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT) ) ? 8 : 16 );
872 return ((width+3)/4)*((height+3)/4)*comp;
875 ///////////////////////////////////////////////////////////////////////////////
876 // calculates size of uncompressed RGB texture in bytes
877 int CDDSImage::size_rgb(Int32 width, Int32 height)
879 return width*height*components;
882 ///////////////////////////////////////////////////////////////////////////////
883 // align to 4 byte boundary (add pad bytes to end of each line in the image)
884 void CDDSImage::align_memory(CTexture *surface)
886 // don't bother with compressed images, volume textures, or cubemaps
887 if (compressed || volume || cubemap)
888 return;
890 // calculate new image size
891 Int32 linesize = get_line_width(surface->width, components*8);
892 Int32 imagesize = linesize*surface->height;
894 // exit if already aligned
895 if (surface->size == imagesize)
896 return;
898 // create new image of new size
899 CTexture newSurface(surface->width, surface->height, surface->depth,
900 imagesize);
902 // add pad bytes to end of each line
903 char *srcimage = static_cast<char*>(surface->get_pixels());
904 char *dstimage = static_cast<char*>(newSurface.get_pixels());
905 for (Int32 n = 0; n < surface->depth; n++)
907 char *curline = srcimage;
908 char *newline = dstimage;
910 Int32 imsize = surface->size / surface->depth;
911 Int32 lnsize = imsize / surface->height;
913 for (Int32 i = 0; i < surface->height; i++)
915 memcpy(newline, curline, lnsize);
916 newline += linesize;
917 curline += lnsize;
921 // save padded image
922 *surface = newSurface;
925 ///////////////////////////////////////////////////////////////////////////////
926 // flip image around X axis
927 bool CDDSImage::check_dxt1_alpha_data (char *image, Int32 size)
929 bool hasAlpha(false);
930 DXTColBlock *colBlock(reinterpret_cast<DXTColBlock*>(image));
932 for (unsigned i = 0, n = (size / 8); i < n; i++)
933 if (colBlock[i].col0 <= colBlock[i].col1)
935 for (unsigned j = 0; j < 4; j++) {
936 UInt8 byte = colBlock[i].row[j];
937 for (unsigned p = 0; p < 4; p++/*, byte >> 2*/) {
938 if ((byte & 3) == 3) {
939 hasAlpha = true;
940 break;
945 if (hasAlpha)
947 FNOTICE (( "Found alpha in DXT1 %d/%d, col0:%d, col1:%d\n",
948 i, n, colBlock[i].col0, colBlock[i].col1 ));
950 for (unsigned j = 0; j < 4; j++)
951 FNOTICE (( " DXT Col Index: %d %d %d %d\n",
952 ((colBlock[i].row[j] >> 0) & 3),
953 ((colBlock[i].row[j] >> 2) & 3),
954 ((colBlock[i].row[j] >> 4) & 3),
955 ((colBlock[i].row[j] >> 6) & 3) ));
958 if (hasAlpha)
959 break;
962 return hasAlpha;
965 ///////////////////////////////////////////////////////////////////////////////
966 // flip image around X axis
967 void CDDSImage::flip(CSurface &image,
968 Int32 width,
969 Int32 height,
970 Int32 depth,
971 Int32 size,
972 UInt32 ddpfFlags )
974 Int32 linesize;
975 Int32 offset;
977 if(!compressed)
979 if((ddpfFlags & DDS_DDPF_OPENGL) != 0x00)
981 #ifdef OSG_DEBUG
982 fprintf(stderr, "already OpenGL data\n");
983 #endif
984 return;
987 assert(depth > 0);
989 Int32 imagesize = size/depth;
990 linesize = imagesize / height;
992 for (Int32 n = 0; n < depth; n++)
994 offset = imagesize * n;
995 char *top = image.get_pixels() + offset;
996 char *bottom = top + (imagesize-linesize);
998 for (Int32 i = 0; i < (height >> 1); i++)
1000 swap(bottom, top, linesize);
1002 top += linesize;
1003 bottom -= linesize;
1007 else
1009 if(depth == 1)
1011 void (CDDSImage::*flipblocks)(DXTColBlock*, Int32);
1013 Int32 xblocks = width / 4;
1014 Int32 yblocks = height / 4;
1015 Int32 blocksize;
1017 switch (format)
1019 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1020 blocksize = 8;
1021 flipblocks = &CDDSImage::flip_blocks_dxtc1;
1022 break;
1023 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1024 blocksize = 8;
1025 flipblocks = &CDDSImage::flip_blocks_dxtc1;
1026 break;
1027 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
1028 blocksize = 16;
1029 flipblocks = &CDDSImage::flip_blocks_dxtc3;
1030 break;
1031 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
1032 blocksize = 16;
1033 flipblocks = &CDDSImage::flip_blocks_dxtc5;
1034 break;
1035 default:
1036 return;
1039 linesize = xblocks * blocksize;
1041 DXTColBlock *top;
1042 DXTColBlock *bottom;
1044 Int32 j = 0;
1045 for(; j < (yblocks >> 1); j++)
1047 top = reinterpret_cast<DXTColBlock*>(image.get_pixels() + j * linesize);
1048 bottom = reinterpret_cast<DXTColBlock*>(image.get_pixels() + (((yblocks - j) - 1) * linesize));
1050 (this->*flipblocks)(top, xblocks);
1051 (this->*flipblocks)(bottom, xblocks);
1053 swap(bottom, top, linesize);
1056 if((yblocks & 0x01) == 0x01)
1058 top = reinterpret_cast<DXTColBlock*>(image.get_pixels() + j * linesize);
1060 (this->*flipblocks)(top, xblocks);
1063 else
1065 #ifdef OSG_DEBUG
1066 fprintf(stderr, "compressed volume\n");
1067 #endif
1069 if(format != GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
1071 #ifdef OSG_DEBUG
1072 fprintf(stderr, "sorry, only dxt1 rgb volumes supported yet\n");
1073 #endif
1075 return;
1078 #ifdef OSG_DEBUG
1079 fprintf(stderr,
1080 "dds status : opengl 0x%x | layout nv 0x%x "
1081 "| layout std 0x%x\n",
1082 UInt32(ddpfFlags & DDS_DDPF_OPENGL),
1083 UInt32((ddpfFlags & DDS_DDPF_OPENGL_NV ) == DDS_DDPF_OPENGL_NV ),
1084 UInt32((ddpfFlags & DDS_DDPF_OPENGL_STD) == DDS_DDPF_OPENGL_STD));
1085 #endif
1087 char *szEnvGPU = getenv("OSG_GPU_NVIDIA");
1089 #ifdef OSG_DEBUG
1090 fprintf(stderr, "env nv : %p\n", szEnvGPU);
1091 #endif
1093 if((ddpfFlags & DDS_DDPF_OPENGL) == 0x00)
1095 if(szEnvGPU == NULL)
1097 #ifdef OSG_DEBUG
1098 fprintf(stderr, "flip\n");
1099 #endif
1101 this->flipDXT(image,
1102 width,
1103 height,
1104 depth,
1105 size );
1107 else
1109 #ifdef OSG_DEBUG
1110 fprintf(stderr, "flip + adjust layout std->nv\n");
1111 #endif
1113 this->flipDXTStdToNV(image,
1114 width,
1115 height,
1116 depth,
1117 size );
1120 else
1122 if((ddpfFlags & DDS_DDPF_OPENGL_NV) == DDS_DDPF_OPENGL_NV)
1124 if(szEnvGPU == NULL)
1126 #ifdef OSG_DEBUG
1127 fprintf(stderr, "adjust layout nv->std\n");
1128 #endif
1130 this->changeLayout(image,
1131 width,
1132 height,
1133 depth,
1134 size,
1135 true);
1137 else
1139 #ifdef OSG_DEBUG
1140 fprintf(stderr, "do nothing (nv)\n");
1141 #endif
1144 else
1146 if(szEnvGPU == NULL)
1148 #ifdef OSG_DEBUG
1149 fprintf(stderr, "do nothing (std)\n");
1150 #endif
1152 else
1154 #ifdef OSG_DEBUG
1155 fprintf(stderr, "adjust layout std->nv\n");
1156 #endif
1158 this->changeLayout(image,
1159 width,
1160 height,
1161 depth,
1162 size,
1163 false );
1171 void CDDSImage::flipDXT(CSurface &image,
1172 Int32 width, Int32 height, Int32 depth,
1173 Int32 size)
1175 void (CDDSImage::*flipblocks)(DXTColBlock*, Int32);
1177 Int32 xblocks = width / 4;
1178 Int32 yblocks = height / 4;
1179 Int32 blocksize;
1181 switch (format)
1183 case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1184 blocksize = 8;
1185 flipblocks = &CDDSImage::flip_blocks_dxtc1;
1186 break;
1187 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1188 blocksize = 8;
1189 flipblocks = &CDDSImage::flip_blocks_dxtc1;
1190 break;
1191 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
1192 blocksize = 16;
1193 flipblocks = &CDDSImage::flip_blocks_dxtc3;
1194 break;
1195 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
1196 blocksize = 16;
1197 flipblocks = &CDDSImage::flip_blocks_dxtc5;
1198 break;
1199 default:
1200 return;
1203 Int32 linesize = xblocks * blocksize;
1205 DXTColBlock *top;
1206 DXTColBlock *bottom;
1208 Int32 SliceSize = xblocks * yblocks * blocksize;
1210 for(Int32 d = 0; d < depth; ++d)
1212 Int32 j = 0;
1213 for(; j < (yblocks >> 1); j++)
1215 top = reinterpret_cast<DXTColBlock*>(image.get_pixels() + d * SliceSize + j * linesize);
1216 bottom = reinterpret_cast<DXTColBlock*>(image.get_pixels() + d * SliceSize + (((yblocks - j) - 1) * linesize));
1218 (this->*flipblocks)(top, xblocks);
1219 (this->*flipblocks)(bottom, xblocks);
1221 swap(bottom, top, linesize);
1224 if((yblocks & 0x01) == 0x01)
1226 top = reinterpret_cast<DXTColBlock*>(image.get_pixels() + d * SliceSize + j * linesize);
1228 (this->*flipblocks)(top, xblocks);
1233 void CDDSImage::flipDXTStdToNV(CSurface &image,
1234 Int32 width, Int32 height, Int32 depth,
1235 Int32 size)
1237 CSurface tmp(image.get_width (),
1238 image.get_height(),
1239 image.get_depth (),
1240 image.get_size ());
1242 DXTColBlock *src = reinterpret_cast<DXTColBlock*>(image.get_pixels());
1243 DXTColBlock *dst = reinterpret_cast<DXTColBlock*>(tmp .get_pixels());
1245 Int32 xblocks = width / 4;
1246 Int32 yblocks = height / 4;
1248 Int32 dstD = 0;
1249 Int32 dstX = 0;
1250 Int32 dstY = 0;
1252 Int32 iSliceSize = xblocks * yblocks;
1253 Int32 dOffset = 0;
1255 Int32 dBlock = 4;
1256 Int32 iLastD = depth % 4;
1257 Int32 iLastDStart = Int32(floor(Real32(depth) / 4.f)) * 4;
1259 for(Int32 srcD = 0; srcD < depth; ++srcD)
1261 if(srcD == iLastDStart)
1262 dBlock = iLastD;
1264 for(Int32 srcY = 0; srcY < yblocks; ++srcY)
1266 for(Int32 srcX = 0; srcX < xblocks; ++srcX)
1268 Int32 srcIndex = srcD * iSliceSize + srcY * xblocks + srcX;
1269 Int32 dstIndex = (dstD + dOffset) * iSliceSize + (yblocks - 1 - dstY) * xblocks + dstX;
1271 ++dstD;
1273 if(dstD >= dBlock)
1275 dstD = 0;
1277 ++dstX;
1279 if(dstX >= xblocks)
1281 dstX = 0;
1283 ++dstY;
1285 if(dstY >= yblocks)
1287 dOffset += dBlock;
1288 dstY = 0;
1294 flip_blocks_dxtc1(&(src[dstIndex]), 1);
1296 dst[srcIndex] = src[dstIndex];
1301 image.swapPixels(tmp);
1304 void CDDSImage:: changeLayout(CSurface &image,
1305 Int32 width, Int32 height, Int32 depth,
1306 Int32 size, bool bNVToStd)
1308 CSurface tmp(image.get_width (),
1309 image.get_height(),
1310 image.get_depth (),
1311 image.get_size ());
1313 DXTColBlock *src = reinterpret_cast<DXTColBlock*>(image.get_pixels());
1314 DXTColBlock *dst = reinterpret_cast<DXTColBlock*>(tmp .get_pixels());
1316 Int32 xblocks = width / 4;
1317 Int32 yblocks = height / 4;
1319 Int32 dstD = 0;
1320 Int32 dstX = 0;
1321 Int32 dstY = 0;
1323 Int32 iSliceSize = xblocks * yblocks;
1324 Int32 dOffset = 0;
1326 Int32 dBlock = 4;
1327 Int32 iLastD = depth % 4;
1328 Int32 iLastDStart = Int32(floor(Real32(depth) / 4.f)) * 4;
1330 for(Int32 srcD = 0; srcD < depth; ++srcD)
1332 if(srcD == iLastDStart)
1333 dBlock = iLastD;
1335 for(Int32 srcY = 0; srcY < yblocks; ++srcY)
1337 for(Int32 srcX = 0; srcX < xblocks; ++srcX)
1339 Int32 srcIndex = srcD * iSliceSize + srcY * xblocks + srcX;
1340 Int32 dstIndex = (dstD + dOffset) * iSliceSize + dstY * xblocks + dstX;
1342 ++dstD;
1344 if(dstD >= dBlock)
1346 dstD = 0;
1348 ++dstX;
1350 if(dstX >= xblocks)
1352 dstX = 0;
1354 ++dstY;
1356 if(dstY >= yblocks)
1358 dOffset += dBlock;
1359 dstY = 0;
1364 if(bNVToStd == true)
1366 dst[dstIndex] = src[srcIndex];
1368 else
1370 dst[srcIndex] = src[dstIndex];
1376 image.swapPixels(tmp);
1379 ///////////////////////////////////////////////////////////////////////////////
1380 // swap to sections of memory
1381 void CDDSImage::swap(void *byte1, void *byte2, Int32 size)
1383 UInt8 *tmp = new UInt8[size];
1385 memcpy(tmp, byte1, size);
1386 memcpy(byte1, byte2, size);
1387 memcpy(byte2, tmp, size);
1389 delete [] tmp;
1392 ///////////////////////////////////////////////////////////////////////////////
1393 // flip a DXT1 color block
1394 void CDDSImage::flip_blocks_dxtc1(DXTColBlock *line, Int32 numBlocks)
1396 DXTColBlock *curblock = line;
1398 for (Int32 i = 0; i < numBlocks; i++)
1400 swap(&(curblock->row[0]), &(curblock->row[3]), sizeof(UInt8));
1401 swap(&(curblock->row[1]), &(curblock->row[2]), sizeof(UInt8));
1403 curblock++;
1407 ///////////////////////////////////////////////////////////////////////////////
1408 // flip a DXT3 color block
1409 void CDDSImage::flip_blocks_dxtc3(DXTColBlock *line, Int32 numBlocks)
1411 DXTColBlock *curblock = line;
1412 DXT3AlphaBlock *alphablock;
1414 for (Int32 i = 0; i < numBlocks; i++)
1416 alphablock = reinterpret_cast<DXT3AlphaBlock*>(curblock);
1418 swap(&alphablock->row[0], &alphablock->row[3], sizeof(UInt16));
1419 swap(&alphablock->row[1], &alphablock->row[2], sizeof(UInt16));
1421 curblock++;
1423 swap(&curblock->row[0], &curblock->row[3], sizeof(UInt8));
1424 swap(&curblock->row[1], &curblock->row[2], sizeof(UInt8));
1426 curblock++;
1430 ///////////////////////////////////////////////////////////////////////////////
1431 // flip a DXT5 alpha block
1432 void CDDSImage::flip_dxt5_alpha(DXT5AlphaBlock *block)
1434 UInt8 gBits[4][4];
1436 const UInt32 mask = 0x00000007; // bits = 00 00 01 11
1437 UInt32 bits = 0;
1438 memcpy(&bits, &block->row[0], sizeof(UInt8) * 3);
1440 gBits[0][0] = UInt8(bits & mask);
1441 bits >>= 3;
1442 gBits[0][1] = UInt8(bits & mask);
1443 bits >>= 3;
1444 gBits[0][2] = UInt8(bits & mask);
1445 bits >>= 3;
1446 gBits[0][3] = UInt8(bits & mask);
1447 bits >>= 3;
1448 gBits[1][0] = UInt8(bits & mask);
1449 bits >>= 3;
1450 gBits[1][1] = UInt8(bits & mask);
1451 bits >>= 3;
1452 gBits[1][2] = UInt8(bits & mask);
1453 bits >>= 3;
1454 gBits[1][3] = UInt8(bits & mask);
1456 bits = 0;
1457 memcpy(&bits, &block->row[3], sizeof(UInt8) * 3);
1459 gBits[2][0] = UInt8(bits & mask);
1460 bits >>= 3;
1461 gBits[2][1] = UInt8(bits & mask);
1462 bits >>= 3;
1463 gBits[2][2] = UInt8(bits & mask);
1464 bits >>= 3;
1465 gBits[2][3] = UInt8(bits & mask);
1466 bits >>= 3;
1467 gBits[3][0] = UInt8(bits & mask);
1468 bits >>= 3;
1469 gBits[3][1] = UInt8(bits & mask);
1470 bits >>= 3;
1471 gBits[3][2] = UInt8(bits & mask);
1472 bits >>= 3;
1473 gBits[3][3] = UInt8(bits & mask);
1475 UInt32 *pBits = (reinterpret_cast<UInt32 *>(&(block->row[0])));
1477 *pBits = *pBits | (gBits[3][0] << 0);
1478 *pBits = *pBits | (gBits[3][1] << 3);
1479 *pBits = *pBits | (gBits[3][2] << 6);
1480 *pBits = *pBits | (gBits[3][3] << 9);
1482 *pBits = *pBits | (gBits[2][0] << 12);
1483 *pBits = *pBits | (gBits[2][1] << 15);
1484 *pBits = *pBits | (gBits[2][2] << 18);
1485 *pBits = *pBits | (gBits[2][3] << 21);
1487 pBits = (reinterpret_cast<UInt32 *>(&(block->row[3])));
1489 #if BYTE_ORDER == BIG_ENDIAN
1490 *pBits &= 0x000000ff;
1491 #else
1492 *pBits &= 0xff000000;
1493 #endif
1495 *pBits = *pBits | (gBits[1][0] << 0);
1496 *pBits = *pBits | (gBits[1][1] << 3);
1497 *pBits = *pBits | (gBits[1][2] << 6);
1498 *pBits = *pBits | (gBits[1][3] << 9);
1500 *pBits = *pBits | (gBits[0][0] << 12);
1501 *pBits = *pBits | (gBits[0][1] << 15);
1502 *pBits = *pBits | (gBits[0][2] << 18);
1503 *pBits = *pBits | (gBits[0][3] << 21);
1506 ///////////////////////////////////////////////////////////////////////////////
1507 // flip a DXT5 color block
1508 void CDDSImage::flip_blocks_dxtc5(DXTColBlock *line, Int32 numBlocks)
1510 DXTColBlock *curblock = line;
1511 DXT5AlphaBlock *alphablock;
1513 for (Int32 i = 0; i < numBlocks; i++)
1515 alphablock = reinterpret_cast<DXT5AlphaBlock*>(curblock);
1517 flip_dxt5_alpha(alphablock);
1519 curblock++;
1521 swap(&curblock->row[0], &curblock->row[3], sizeof(UInt8));
1522 swap(&curblock->row[1], &curblock->row[2], sizeof(UInt8));
1524 curblock++;
1528 ///////////////////////////////////////////////////////////////////////////////
1529 // CTexture implementation
1530 ///////////////////////////////////////////////////////////////////////////////
1532 ///////////////////////////////////////////////////////////////////////////////
1533 // default constructor
1534 CTexture::CTexture()
1535 : CSurface(), // initialize base class part
1536 mipmaps()
1540 ///////////////////////////////////////////////////////////////////////////////
1541 // creates an empty texture
1542 CTexture::CTexture(Int32 w, Int32 h, Int32 d, Int32 imgSize)
1543 : CSurface(w, h, d, imgSize), // initialize base class part
1544 mipmaps()
1548 ///////////////////////////////////////////////////////////////////////////////
1549 // copy constructor
1550 CTexture::CTexture(const CTexture &copy)
1551 : CSurface(copy),
1552 mipmaps()
1554 for (UInt32 i = 0; i < copy.mipmaps.size(); i++)
1555 mipmaps.push_back(copy.mipmaps[i]);
1558 ///////////////////////////////////////////////////////////////////////////////
1559 // assignment operator
1560 CTexture &CTexture::operator= (const CTexture &rhs)
1562 if (this != &rhs)
1564 CSurface::operator = (rhs);
1566 mipmaps.clear();
1567 for (UInt32 i = 0; i < rhs.mipmaps.size(); i++)
1569 mipmaps.push_back(rhs.mipmaps[i]);
1573 return *this;
1576 ///////////////////////////////////////////////////////////////////////////////
1577 // clean up texture memory
1578 CTexture::~CTexture()
1580 mipmaps.clear();
1583 ///////////////////////////////////////////////////////////////////////////////
1584 // CSurface implementation
1585 ///////////////////////////////////////////////////////////////////////////////
1587 ///////////////////////////////////////////////////////////////////////////////
1588 // default constructor
1589 CSurface::CSurface()
1590 : width(0),
1591 height(0),
1592 depth(0),
1593 size(0),
1594 pixels(NULL)
1598 ///////////////////////////////////////////////////////////////////////////////
1599 // creates an empty image
1600 CSurface::CSurface(Int32 w, Int32 h, Int32 d, Int32 imgsize):
1601 width(0),
1602 height(0),
1603 depth(0),
1604 size(0),
1605 pixels(NULL)
1607 create(w, h, d, imgsize);
1610 ///////////////////////////////////////////////////////////////////////////////
1611 // copy constructor
1612 CSurface::CSurface(const CSurface &copy)
1613 : width(0),
1614 height(0),
1615 depth(0),
1616 size(0),
1617 pixels(NULL)
1620 if (copy.pixels)
1622 size = copy.size;
1623 width = copy.width;
1624 height = copy.height;
1625 depth = copy.depth;
1626 pixels = new char[size];
1627 memcpy(pixels, copy.pixels, copy.size);
1631 ///////////////////////////////////////////////////////////////////////////////
1632 // assignment operator
1633 CSurface &CSurface::operator= (const CSurface &rhs)
1635 if (this != &rhs)
1637 clear();
1639 if (rhs.pixels)
1641 size = rhs.size;
1642 width = rhs.width;
1643 height = rhs.height;
1644 depth = rhs.depth;
1646 pixels = new char[size];
1647 memcpy(pixels, rhs.pixels, size);
1651 return *this;
1654 ///////////////////////////////////////////////////////////////////////////////
1655 // clean up image memory
1657 CSurface::~CSurface()
1659 clear();
1662 ///////////////////////////////////////////////////////////////////////////////
1663 // returns a pointer to image
1665 #if 0
1666 CSurface::operator char*()
1668 return pixels;
1670 #endif
1672 ///////////////////////////////////////////////////////////////////////////////
1673 // creates an empty image
1675 void CSurface::create(Int32 w, Int32 h, Int32 d, Int32 imgsize)
1677 clear();
1679 width = w;
1680 height = h;
1681 depth = d;
1682 size = imgsize;
1683 pixels = new char[imgsize];
1686 ///////////////////////////////////////////////////////////////////////////////
1687 // free surface memory
1689 void CSurface::clear()
1691 delete [] pixels;
1692 pixels = NULL;
1695 void CSurface::swapPixels(CSurface &other)
1697 char *tmp = pixels;
1699 pixels = other.pixels;
1701 other.pixels = tmp;
1704 OSG_END_NAMESPACE