00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <wx/wfstream.h>
00013 #include "flexilog.h"
00014 #include "imagedds.h"
00015 #include "glgetproc.h"
00016
00017
00018 using namespace VRUT;
00019
00020
00021 ImageDDS::ImageDDS() : Image()
00022 {
00023 }
00024
00025
00026 ImageDDS::~ImageDDS()
00027 {
00028 }
00029
00030
00031 bool ImageDDS::IsOk() const
00032 {
00033 return (image.data != (unsigned char *)NULL);
00034 }
00035
00036
00037 bool ImageDDS::Load(const wxString & fname)
00038 {
00039 if (Image::Load(fname))
00040 {
00041 SAFE_DELETE_ARR(image.data);
00042
00043 wxFileInputStream fin(fname);
00044
00045 fin.Read(&image.header, sizeof(image.header));
00046
00047 if ( image.header.dwMagic != DDS_MAGIC || image.header.dwSize != 124 ||
00048 !(image.header.dwFlags & DDSD_PIXELFORMAT) || !(image.header.dwFlags & DDSD_CAPS) )
00049 {
00050 LOGERROR(wxString::Format(wxT("<ImageDDS>File '%s' doesn't appear to be a valid .dds file"), fname.c_str()));
00051 return false;
00052 }
00053
00054 if ( PF_IS_DXT1( image.header.sPixelFormat ) )
00055 {
00056 image.compressed = true;
00057 image.swap = false;
00058 image.palette = false;
00059 image.divSize = 4;
00060 image.blockBytes = 8;
00061 image.internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
00062 }
00063 else if ( PF_IS_DXT3( image.header.sPixelFormat ) )
00064 {
00065 image.compressed = true;
00066 image.swap = false;
00067 image.palette = false;
00068 image.divSize = 4;
00069 image.blockBytes = 16;
00070 image.internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
00071 }
00072 else if ( PF_IS_DXT5( image.header.sPixelFormat ) )
00073 {
00074 image.compressed = true;
00075 image.swap = false;
00076 image.palette = false;
00077 image.divSize = 4;
00078 image.blockBytes = 16;
00079 image.internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
00080 }
00081 else if ( PF_IS_BGRA8( image.header.sPixelFormat ) )
00082 {
00083 image.compressed = false;
00084 image.swap = false;
00085 image.palette = false;
00086 image.divSize = 1;
00087 image.blockBytes = 4;
00088 image.internalFormat = GL_RGBA8;
00089 image.externalFormat = GL_BGRA;
00090 image.type = GL_UNSIGNED_BYTE;
00091 }
00092 else if ( PF_IS_BGR8( image.header.sPixelFormat ) )
00093 {
00094 image.compressed = false;
00095 image.swap = false;
00096 image.palette = false;
00097 image.divSize = 1;
00098 image.blockBytes = 3;
00099 image.internalFormat = GL_RGB8;
00100 image.externalFormat = GL_BGR;
00101 image.type = GL_UNSIGNED_BYTE;
00102 }
00103 else if ( PF_IS_BGR5A1( image.header.sPixelFormat ) )
00104 {
00105 image.compressed = false;
00106 image.swap = true;
00107 image.palette = false;
00108 image.divSize = 1;
00109 image.blockBytes = 2;
00110 image.internalFormat = GL_RGB5_A1;
00111 image.externalFormat = GL_BGRA;
00112 image.type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
00113 }
00114 else if ( PF_IS_BGR565( image.header.sPixelFormat ) )
00115 {
00116 image.compressed = false;
00117 image.swap = true;
00118 image.palette = false;
00119 image.divSize = 1;
00120 image.blockBytes = 2;
00121 image.internalFormat = GL_RGB5;
00122 image.externalFormat = GL_RGB;
00123 image.type = GL_UNSIGNED_SHORT_5_6_5;
00124 }
00125 else if ( PF_IS_INDEX8( image.header.sPixelFormat ) )
00126 {
00127 image.compressed = false;
00128 image.swap = false;
00129 image.palette = true;
00130 image.divSize = 1;
00131 image.blockBytes = 1;
00132 image.internalFormat = GL_RGB8;
00133 image.externalFormat = GL_BGRA;
00134 image.type = GL_UNSIGNED_BYTE;
00135 }
00136 else
00137 {
00138 LOGERROR(wxString::Format(wxT("<ImageDDS>Unknown pixel format in DDS file '%s'"), fname.c_str()));
00139 return false;
00140 }
00141
00142
00143 unsigned curr = fin.TellI();
00144 unsigned end = fin.SeekI(0, wxFromEnd);
00145 fin.SeekI(curr);
00146 unsigned bufferSize = end - curr;
00147
00148 image.data = new unsigned char[bufferSize];
00149 fin.Read(image.data, sizeof(unsigned char) * bufferSize);
00150
00151 return true;
00152 }
00153 return false;
00154 }
00155
00156
00157 GLuint ImageDDS::BuildOglTexture() const
00158 {
00159 GLuint texID = GL_ID_NONE;
00160 if (IsOk())
00161 {
00162 unsigned x = image.header.dwWidth;
00163 unsigned y = image.header.dwHeight;
00164 unsigned mipMapCount = (image.header.dwFlags & DDSD_MIPMAPCOUNT) ? image.header.dwMipMapCount : 1;
00165 glEnable(GL_TEXTURE_2D);
00166
00167 if (image.compressed)
00168 {
00169 unsigned size = __max( image.divSize, x )/image.divSize * __max( image.divSize, y )/image.divSize * image.blockBytes;
00170 if ( size != image.header.dwPitchOrLinearSize || !(image.header.dwFlags & DDSD_LINEARSIZE) )
00171 {
00172 LOGERROR(wxT("<ImageDDS>Texture size mismatch"));
00173 return texID;
00174 }
00175 PFNGLCOMPRESSEDTEXIMAGE2DPROC vrutCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) GLGETPROC("glCompressedTexImage2D");
00176 if ( vrutCompressedTexImage2D == NULL )
00177 {
00178 LOGERROR(wxT("<ImageDDS>Compressed textures not supported"));
00179 return texID;
00180 }
00181
00182 glGenTextures( 1, &texID );
00183 glBindTexture( GL_TEXTURE_2D, texID );
00184 glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE );
00185 unsigned offset = 0;
00186 for ( unsigned int ix = 0; ix < mipMapCount; ++ix )
00187 {
00188 vrutCompressedTexImage2D( GL_TEXTURE_2D, ix, image.internalFormat, x, y, 0, size, image.data + offset );
00189 GLCHECKERROR;
00190 x = (x+1)>>1;
00191 y = (y+1)>>1;
00192 offset += size;
00193 size = __max( image.divSize, x )/image.divSize * __max( image.divSize, y )/image.divSize * image.blockBytes;
00194 }
00195 }
00196 else if (image.palette)
00197 {
00198
00199
00200 unsigned size = image.header.dwPitchOrLinearSize * image.header.dwHeight;
00201
00202 if ( (image.header.dwFlags & DDSD_PITCH) == 0 ||
00203 image.header.sPixelFormat.dwRGBBitCount != 8 ||
00204 (size != x * y * image.blockBytes) )
00205 {
00206 LOGERROR(wxT("<ImageDDS>Size mismatch"));
00207 return texID;
00208 }
00209
00210 glGenTextures( 1, &texID );
00211 glBindTexture( GL_TEXTURE_2D, texID );
00212 glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE );
00213 unsigned char * data = image.data + 256 * 4;
00214 unsigned int * palette = (unsigned int *)image.data;
00215 unsigned int * unpacked = new unsigned[size * sizeof(unsigned)];
00216 unsigned offset = 0;
00217 for ( unsigned ix = 0; ix < mipMapCount; ++ix )
00218 {
00219 for ( unsigned zz = 0; zz < size; ++zz )
00220 {
00221 unpacked[ zz ] = palette[ data[ zz ] ];
00222 }
00223 glPixelStorei( GL_UNPACK_ROW_LENGTH, y );
00224 glTexImage2D( GL_TEXTURE_2D, ix, image.internalFormat, x, y, 0, image.externalFormat, image.type, unpacked );
00225 GLCHECKERROR;
00226 x = (x+1)>>1;
00227 y = (y+1)>>1;
00228 offset += size;
00229 size = x * y * image.blockBytes;
00230 }
00231 delete [] unpacked;
00232 }
00233 else
00234 {
00235 if (image.swap )
00236 glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_TRUE );
00237 glGenTextures( 1, &texID );
00238 glBindTexture( GL_TEXTURE_2D, texID );
00239 glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE );
00240 unsigned size = x * y * image.blockBytes;
00241 unsigned offset = 0;
00242
00243 for ( unsigned int ix = 0; ix < mipMapCount; ++ix )
00244 {
00245 glPixelStorei( GL_UNPACK_ROW_LENGTH, y );
00246 glTexImage2D( GL_TEXTURE_2D, ix, image.internalFormat, x, y, 0, image.externalFormat, image.type, image.data );
00247 GLCHECKERROR;
00248 x = (x+1)>>1;
00249 y = (y+1)>>1;
00250 offset += size;
00251 size = x * y * image.blockBytes;
00252 }
00253 glPixelStorei( GL_UNPACK_SWAP_BYTES, GL_FALSE );
00254 GLCHECKERROR;
00255 }
00256 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipMapCount-1 );
00257 GLCHECKERROR;
00258 }
00259
00260 return texID;
00261 }
00262
00263
00264 bool ImageDDS::HasTransparency() const
00265 {
00266 return IsOk() && ( image.header.dwFlags & DDPF_ALPHAPIXELS );
00267 }
00268
00269 int ImageDDS::GetWidth() const
00270 {
00271 return (IsOk()?image.header.dwWidth:0);
00272 }
00273
00274 int ImageDDS::GetHeight() const
00275 {
00276 return (IsOk()?image.header.dwHeight:0);
00277 }