00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <iostream>
00011 #include <fstream>
00012 #include <algorithm>
00013 #include <celutil/debug.h>
00014 #include <celutil/bytes.h>
00015 #include <celengine/gl.h>
00016 #include <celengine/glext.h>
00017 #include <celengine/image.h>
00018
00019 using namespace std;
00020
00021
00022
00023 struct DDPixelFormat
00024 {
00025 uint32 size;
00026 uint32 flags;
00027 uint32 fourCC;
00028 uint32 bpp;
00029 uint32 redMask;
00030 uint32 greenMask;
00031 uint32 blueMask;
00032 uint32 alphaMask;
00033 };
00034
00035 struct DDSCaps
00036 {
00037 uint32 caps;
00038 uint32 caps2;
00039 uint32 caps3;
00040 uint32 caps4;
00041 };
00042
00043 struct DDColorKey
00044 {
00045 uint32 lowVal;
00046 uint32 highVal;
00047 };
00048
00049 struct DDSurfaceDesc
00050 {
00051 uint32 size;
00052 uint32 flags;
00053 uint32 height;
00054 uint32 width;
00055 uint32 pitch;
00056 uint32 depth;
00057 uint32 mipMapLevels;
00058 uint32 alphaBitDepth;
00059 uint32 reserved;
00060 uint32 surface;
00061
00062 DDColorKey ckDestOverlay;
00063 DDColorKey ckDestBlt;
00064 DDColorKey ckSrcOverlay;
00065 DDColorKey ckSrcBlt;
00066
00067 DDPixelFormat format;
00068 DDSCaps caps;
00069
00070 uint32 textureStage;
00071 };
00072
00073
00074 static uint32 FourCC(const char* s)
00075 {
00076 return (((uint32) s[3] << 24) |
00077 ((uint32) s[2] << 16) |
00078 ((uint32) s[1] << 8) |
00079 (uint32) s[0]);
00080 }
00081
00082
00083 #define DDPF_RGB 0x40
00084 #define DDPF_FOURCC 0x04
00085
00086
00087 Image* LoadDDSImage(const string& filename)
00088 {
00089 ifstream in(filename.c_str(), ios::in | ios::binary);
00090 if (!in.good())
00091 {
00092 DPRINTF(0, "Error opening DDS texture file %s.\n", filename.c_str());
00093 return NULL;
00094 }
00095
00096 char header[4];
00097 in.read(header, sizeof header);
00098 if (header[0] != 'D' || header[1] != 'D' ||
00099 header[2] != 'S' || header[3] != ' ')
00100 {
00101 DPRINTF(0, "DDS texture file %s has bad header.\n", filename.c_str());
00102 return NULL;
00103 }
00104
00105 DDSurfaceDesc ddsd;
00106 in.read(reinterpret_cast<char*>(&ddsd), sizeof ddsd);
00107 LE_TO_CPU_INT32(ddsd.size, ddsd.size);
00108 LE_TO_CPU_INT32(ddsd.pitch, ddsd.pitch);
00109 LE_TO_CPU_INT32(ddsd.width, ddsd.width);
00110 LE_TO_CPU_INT32(ddsd.height, ddsd.height);
00111 LE_TO_CPU_INT32(ddsd.mipMapLevels, ddsd.mipMapLevels);
00112 LE_TO_CPU_INT32(ddsd.format.flags, ddsd.format.flags);
00113 LE_TO_CPU_INT32(ddsd.format.redMask, ddsd.format.redMask);
00114 LE_TO_CPU_INT32(ddsd.format.greenMask, ddsd.format.greenMask);
00115 LE_TO_CPU_INT32(ddsd.format.blueMask, ddsd.format.blueMask);
00116 LE_TO_CPU_INT32(ddsd.format.alphaMask, ddsd.format.alphaMask);
00117 LE_TO_CPU_INT32(ddsd.format.bpp, ddsd.format.bpp);
00118 LE_TO_CPU_INT32(ddsd.format.fourCC, ddsd.format.fourCC);
00119
00120 int format = -1;
00121
00122 if (ddsd.format.fourCC != 0)
00123 {
00124 if (ddsd.format.fourCC == FourCC("DXT1"))
00125 {
00126 format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
00127 }
00128 else if (ddsd.format.fourCC == FourCC("DXT3"))
00129 {
00130 format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
00131 }
00132 else if (ddsd.format.fourCC == FourCC("DXT5"))
00133 {
00134 format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
00135 }
00136 else
00137 {
00138 cerr << "Unknown FourCC in DDS file: " << ddsd.format.fourCC;
00139 }
00140 }
00141 else
00142 {
00143 clog << "DDS Format: " << ddsd.format.fourCC << '\n';
00144 if (ddsd.format.bpp == 32)
00145 {
00146 if (ddsd.format.redMask == 0x00ff0000 &&
00147 ddsd.format.greenMask == 0x0000ff00 &&
00148 ddsd.format.blueMask == 0x000000ff &&
00149 ddsd.format.alphaMask == 0xff000000)
00150 {
00151 format = GL_BGRA_EXT;
00152 }
00153 else if (ddsd.format.redMask == 0x000000ff &&
00154 ddsd.format.greenMask == 0x0000ff00 &&
00155 ddsd.format.blueMask == 0x00ff0000 &&
00156 ddsd.format.alphaMask == 0xff000000)
00157 {
00158 format = GL_RGBA;
00159 }
00160 }
00161 else if (ddsd.format.bpp == 24)
00162 {
00163 if (ddsd.format.redMask == 0x00ff0000 &&
00164 ddsd.format.greenMask == 0x0000ff00 &&
00165 ddsd.format.blueMask == 0x000000ff)
00166 {
00167 format = GL_BGR_EXT;
00168 }
00169 else if (ddsd.format.redMask == 0x000000ff &&
00170 ddsd.format.greenMask == 0x0000ff00 &&
00171 ddsd.format.blueMask == 0x00ff0000)
00172 {
00173 format = GL_RGB;
00174 }
00175 }
00176 }
00177
00178 if (format == -1)
00179 {
00180 DPRINTF(0, "Unsupported format for DDS texture file %s.\n",
00181 filename.c_str());
00182 return NULL;
00183 }
00184
00185
00186
00187 if (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
00188 format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
00189 format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
00190 {
00191 if (!ExtensionSupported("GL_EXT_texture_compression_s3tc"))
00192 return NULL;
00193 }
00194
00195
00196
00197
00198 Image* img = new Image(format,
00199 (int) ddsd.width,
00200 (int) ddsd.height,
00201 max(ddsd.mipMapLevels, 1u));
00202 if (img == NULL)
00203 return NULL;
00204
00205 in.read(reinterpret_cast<char*>(img->getPixels()), img->getSize());
00206 if (!in.eof() && !in.good())
00207 {
00208 DPRINTF(0, "Failed reading data from DDS texture file %s.\n",
00209 filename.c_str());
00210 delete img;
00211 return NULL;
00212 }
00213
00214 #if 0
00215 cout << "sizeof(ddsd) = " << sizeof(ddsd) << '\n';
00216 cout << "dimensions: " << ddsd.width << 'x' << ddsd.height << '\n';
00217 cout << "mipmap levels: " << ddsd.mipMapLevels << '\n';
00218 cout << "fourCC: " << ddsd.format.fourCC << '\n';
00219 cout << "bpp: " << ddsd.format.bpp << '\n';
00220 #endif
00221
00222 return img;
00223 }