/src/ogre/OgreMain/src/OgreDDSCodec.cpp
Line | Count | Source |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | |
29 | | #include "OgreStableHeaders.h" |
30 | | |
31 | | #include "OgreDDSCodec.h" |
32 | | #include "OgreImage.h" |
33 | | |
34 | | namespace Ogre { |
35 | | // Internal DDS structure definitions |
36 | | #if OGRE_COMPILER == OGRE_COMPILER_MSVC |
37 | | #pragma pack (push, 1) |
38 | | #else |
39 | | #pragma pack (1) |
40 | | #endif |
41 | | |
42 | | // Nested structure |
43 | | struct DDSPixelFormat |
44 | | { |
45 | | uint32 size; |
46 | | uint32 flags; |
47 | | uint32 fourCC; |
48 | | uint32 rgbBits; |
49 | | uint32 redMask; |
50 | | uint32 greenMask; |
51 | | uint32 blueMask; |
52 | | uint32 alphaMask; |
53 | | }; |
54 | | |
55 | | // Nested structure |
56 | | struct DDSCaps |
57 | | { |
58 | | uint32 caps1; |
59 | | uint32 caps2; |
60 | | uint32 caps3; |
61 | | uint32 caps4; |
62 | | }; |
63 | | // Main header, note preceded by 'DDS ' |
64 | | struct DDSHeader |
65 | | { |
66 | | uint32 size; |
67 | | uint32 flags; |
68 | | uint32 height; |
69 | | uint32 width; |
70 | | uint32 sizeOrPitch; |
71 | | uint32 depth; |
72 | | uint32 mipMapCount; |
73 | | uint32 reserved1[11]; |
74 | | DDSPixelFormat pixelFormat; |
75 | | DDSCaps caps; |
76 | | uint32 reserved2; |
77 | | }; |
78 | | |
79 | | // Extended header |
80 | | struct DDSExtendedHeader |
81 | | { |
82 | | uint32 dxgiFormat; |
83 | | uint32 resourceDimension; |
84 | | uint32 miscFlag; // see D3D11_RESOURCE_MISC_FLAG |
85 | | uint32 arraySize; |
86 | | uint32 reserved; |
87 | | }; |
88 | | |
89 | | |
90 | | // An 8-byte DXT colour block, represents a 4x4 texel area. Used by all DXT formats |
91 | | struct DXTColourBlock |
92 | | { |
93 | | // 2 colour ranges |
94 | | uint16 colour_0; |
95 | | uint16 colour_1; |
96 | | // 16 2-bit indexes, each byte here is one row |
97 | | uint8 indexRow[4]; |
98 | | }; |
99 | | // An 8-byte DXT explicit alpha block, represents a 4x4 texel area. Used by DXT2/3 |
100 | | struct DXTExplicitAlphaBlock |
101 | | { |
102 | | // 16 4-bit values, each 16-bit value is one row |
103 | | uint16 alphaRow[4]; |
104 | | }; |
105 | | // An 8-byte DXT interpolated alpha block, represents a 4x4 texel area. Used by DXT4/5 |
106 | | struct DXTInterpolatedAlphaBlock |
107 | | { |
108 | | // 2 alpha ranges |
109 | | uint8 alpha_0; |
110 | | uint8 alpha_1; |
111 | | // 16 3-bit indexes. Unfortunately 3 bits doesn't map too well to row bytes |
112 | | // so just stored raw |
113 | | uint8 indexes[6]; |
114 | | }; |
115 | | |
116 | | #if OGRE_COMPILER == OGRE_COMPILER_MSVC |
117 | | #pragma pack (pop) |
118 | | #else |
119 | | #pragma pack () |
120 | | #endif |
121 | | |
122 | | namespace { |
123 | | const uint32 DDS_MAGIC = FOURCC('D', 'D', 'S', ' '); |
124 | | const uint32 DDS_PIXELFORMAT_SIZE = 8 * sizeof(uint32); |
125 | | const uint32 DDS_CAPS_SIZE = 4 * sizeof(uint32); |
126 | | const uint32 DDS_HEADER_SIZE = 19 * sizeof(uint32) + DDS_PIXELFORMAT_SIZE + DDS_CAPS_SIZE; |
127 | | |
128 | | const uint32 DDSD_CAPS = 0x00000001; |
129 | | const uint32 DDSD_HEIGHT = 0x00000002; |
130 | | const uint32 DDSD_WIDTH = 0x00000004; |
131 | | const uint32 DDSD_PIXELFORMAT = 0x00001000; |
132 | | const uint32 DDSD_DEPTH = 0x00800000; |
133 | | const uint32 DDPF_ALPHAPIXELS = 0x00000001; |
134 | | const uint32 DDPF_FOURCC = 0x00000004; |
135 | | const uint32 DDPF_RGB = 0x00000040; |
136 | | const uint32 DDSCAPS_COMPLEX = 0x00000008; |
137 | | const uint32 DDSCAPS_TEXTURE = 0x00001000; |
138 | | const uint32 DDSCAPS_MIPMAP = 0x00400000; |
139 | | const uint32 DDSCAPS2_CUBEMAP = 0x00000200; |
140 | | const uint32 DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400; |
141 | | const uint32 DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800; |
142 | | const uint32 DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000; |
143 | | const uint32 DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000; |
144 | | const uint32 DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000; |
145 | | const uint32 DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000; |
146 | | const uint32 DDSCAPS2_VOLUME = 0x00200000; |
147 | | |
148 | | // Currently unused |
149 | | // const uint32 DDSD_PITCH = 0x00000008; |
150 | | // const uint32 DDSD_MIPMAPCOUNT = 0x00020000; |
151 | | // const uint32 DDSD_LINEARSIZE = 0x00080000; |
152 | | |
153 | | // Special FourCC codes |
154 | | const uint32 D3DFMT_R16F = 111; |
155 | | const uint32 D3DFMT_G16R16F = 112; |
156 | | const uint32 D3DFMT_A16B16G16R16F = 113; |
157 | | const uint32 D3DFMT_R32F = 114; |
158 | | const uint32 D3DFMT_G32R32F = 115; |
159 | | const uint32 D3DFMT_A32B32G32R32F = 116; |
160 | | } |
161 | | |
162 | | //--------------------------------------------------------------------- |
163 | | DDSCodec* DDSCodec::msInstance = 0; |
164 | | //--------------------------------------------------------------------- |
165 | | void DDSCodec::startup(void) |
166 | 0 | { |
167 | 0 | if (!msInstance) |
168 | 0 | { |
169 | |
|
170 | 0 | LogManager::getSingleton().logMessage( |
171 | 0 | LML_NORMAL, |
172 | 0 | "DDS codec registering"); |
173 | |
|
174 | 0 | msInstance = OGRE_NEW DDSCodec(); |
175 | 0 | Codec::registerCodec(msInstance); |
176 | 0 | } |
177 | |
|
178 | 0 | } |
179 | | //--------------------------------------------------------------------- |
180 | | void DDSCodec::shutdown(void) |
181 | 0 | { |
182 | 0 | if(msInstance) |
183 | 0 | { |
184 | 0 | Codec::unregisterCodec(msInstance); |
185 | 0 | OGRE_DELETE msInstance; |
186 | 0 | msInstance = 0; |
187 | 0 | } |
188 | |
|
189 | 0 | } |
190 | | //--------------------------------------------------------------------- |
191 | | DDSCodec::DDSCodec(): |
192 | 0 | mType("dds"), |
193 | 0 | mDecodeEnforce(false) |
194 | 0 | { |
195 | 0 | } |
196 | | //--------------------------------------------------------------------- |
197 | | DataStreamPtr DDSCodec::encode(const Any& input) const |
198 | 0 | { |
199 | 0 | Image* image = any_cast<Image*>(input); |
200 | |
|
201 | 0 | bool isCubeMap = image->hasFlag(IF_CUBEMAP); |
202 | | |
203 | | // Establish texture attributes |
204 | 0 | bool isVolume = (image->getDepth() > 1); |
205 | 0 | bool isFloat32r = (image->getFormat() == PF_FLOAT32_R); |
206 | 0 | bool isFloat16 = (image->getFormat() == PF_FLOAT16_RGBA); |
207 | 0 | bool isFloat16r = (image->getFormat() == PF_FLOAT16_R); |
208 | 0 | bool isFloat32 = (image->getFormat() == PF_FLOAT32_RGBA); |
209 | 0 | bool notImplemented = false; |
210 | 0 | String notImplementedString = ""; |
211 | | |
212 | | // Check for all the 'not implemented' conditions |
213 | 0 | if ((isVolume == true)&&(image->getWidth() != image->getHeight())) |
214 | 0 | { |
215 | | // Square textures only |
216 | 0 | notImplemented = true; |
217 | 0 | notImplementedString += "non square textures"; |
218 | 0 | } |
219 | |
|
220 | 0 | uint32 size = 1; |
221 | 0 | while (size < image->getWidth()) |
222 | 0 | { |
223 | 0 | size <<= 1; |
224 | 0 | } |
225 | 0 | if (size != image->getWidth()) |
226 | 0 | { |
227 | | // Power two textures only |
228 | 0 | notImplemented = true; |
229 | 0 | notImplementedString += "non power two textures"; |
230 | 0 | } |
231 | |
|
232 | 0 | switch(image->getFormat()) |
233 | 0 | { |
234 | 0 | case PF_A8R8G8B8: |
235 | 0 | case PF_X8R8G8B8: |
236 | 0 | case PF_R8G8B8: |
237 | 0 | case PF_A8B8G8R8: |
238 | 0 | case PF_X8B8G8R8: |
239 | 0 | case PF_B8G8R8: |
240 | 0 | case PF_FLOAT32_R: |
241 | 0 | case PF_FLOAT16_R: |
242 | 0 | case PF_FLOAT16_RGBA: |
243 | 0 | case PF_FLOAT32_RGBA: |
244 | 0 | break; |
245 | 0 | default: |
246 | | // No crazy FOURCC or 565 et al. file formats at this stage |
247 | 0 | notImplemented = true; |
248 | 0 | notImplementedString = PixelUtil::getFormatName(image->getFormat()); |
249 | 0 | break; |
250 | 0 | } |
251 | | |
252 | | |
253 | | |
254 | | // Except if any 'not implemented' conditions were met |
255 | 0 | if (notImplemented) |
256 | 0 | { |
257 | 0 | OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, |
258 | 0 | "DDS encoding for " + notImplementedString + " not supported"); |
259 | 0 | } |
260 | 0 | else |
261 | 0 | { |
262 | | // Build header and write to disk |
263 | | |
264 | | // Variables for some DDS header flags |
265 | 0 | bool hasAlpha = false; |
266 | 0 | uint32 ddsHeaderFlags = 0; |
267 | 0 | uint32 ddsHeaderRgbBits = 0; |
268 | 0 | uint32 ddsHeaderSizeOrPitch = 0; |
269 | 0 | uint32 ddsHeaderCaps1 = 0; |
270 | 0 | uint32 ddsHeaderCaps2 = 0; |
271 | 0 | uint32 ddsMagic = DDS_MAGIC; |
272 | | |
273 | | // Initalise the header flags |
274 | 0 | ddsHeaderFlags = (isVolume) ? DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_DEPTH|DDSD_PIXELFORMAT : |
275 | 0 | DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT; |
276 | |
|
277 | 0 | bool flipRgbMasks = false; |
278 | | |
279 | | // Initalise the rgbBits flags |
280 | 0 | switch(image->getFormat()) |
281 | 0 | { |
282 | 0 | case PF_A8B8G8R8: |
283 | 0 | flipRgbMasks = true; |
284 | 0 | OGRE_FALLTHROUGH; |
285 | 0 | case PF_A8R8G8B8: |
286 | 0 | ddsHeaderRgbBits = 8 * 4; |
287 | 0 | hasAlpha = true; |
288 | 0 | break; |
289 | 0 | case PF_X8B8G8R8: |
290 | 0 | flipRgbMasks = true; |
291 | 0 | OGRE_FALLTHROUGH; |
292 | 0 | case PF_X8R8G8B8: |
293 | 0 | ddsHeaderRgbBits = 8 * 4; |
294 | 0 | break; |
295 | 0 | case PF_B8G8R8: |
296 | 0 | case PF_R8G8B8: |
297 | 0 | ddsHeaderRgbBits = 8 * 3; |
298 | 0 | break; |
299 | 0 | case PF_FLOAT32_R: |
300 | 0 | ddsHeaderRgbBits = 32; |
301 | 0 | break; |
302 | 0 | case PF_FLOAT16_R: |
303 | 0 | ddsHeaderRgbBits = 16; |
304 | 0 | break; |
305 | 0 | case PF_FLOAT16_RGBA: |
306 | 0 | ddsHeaderRgbBits = 16 * 4; |
307 | 0 | hasAlpha = true; |
308 | 0 | break; |
309 | 0 | case PF_FLOAT32_RGBA: |
310 | 0 | ddsHeaderRgbBits = 32 * 4; |
311 | 0 | hasAlpha = true; |
312 | 0 | break; |
313 | 0 | default: |
314 | 0 | ddsHeaderRgbBits = 0; |
315 | 0 | break; |
316 | 0 | } |
317 | | |
318 | | // Initalise the SizeOrPitch flags (power two textures for now) |
319 | 0 | ddsHeaderSizeOrPitch = static_cast<uint32>(ddsHeaderRgbBits * image->getWidth()); |
320 | | |
321 | | // Initalise the caps flags |
322 | 0 | ddsHeaderCaps1 = (isVolume||isCubeMap) ? DDSCAPS_COMPLEX|DDSCAPS_TEXTURE : DDSCAPS_TEXTURE; |
323 | 0 | if (isVolume) |
324 | 0 | { |
325 | 0 | ddsHeaderCaps2 = DDSCAPS2_VOLUME; |
326 | 0 | } |
327 | 0 | else if (isCubeMap) |
328 | 0 | { |
329 | 0 | ddsHeaderCaps2 = DDSCAPS2_CUBEMAP| |
330 | 0 | DDSCAPS2_CUBEMAP_POSITIVEX|DDSCAPS2_CUBEMAP_NEGATIVEX| |
331 | 0 | DDSCAPS2_CUBEMAP_POSITIVEY|DDSCAPS2_CUBEMAP_NEGATIVEY| |
332 | 0 | DDSCAPS2_CUBEMAP_POSITIVEZ|DDSCAPS2_CUBEMAP_NEGATIVEZ; |
333 | 0 | } |
334 | |
|
335 | 0 | if( image->getNumMipmaps() > 0 ) |
336 | 0 | ddsHeaderCaps1 |= DDSCAPS_MIPMAP; |
337 | | |
338 | | // Populate the DDS header information |
339 | 0 | DDSHeader ddsHeader; |
340 | 0 | ddsHeader.size = DDS_HEADER_SIZE; |
341 | 0 | ddsHeader.flags = ddsHeaderFlags; |
342 | 0 | ddsHeader.width = image->getWidth(); |
343 | 0 | ddsHeader.height = image->getHeight(); |
344 | 0 | ddsHeader.depth = (uint32)(isVolume ? image->getDepth() : 0); |
345 | 0 | ddsHeader.depth = (uint32)(isCubeMap ? 6 : ddsHeader.depth); |
346 | 0 | ddsHeader.mipMapCount = image->getNumMipmaps() + 1; |
347 | 0 | ddsHeader.sizeOrPitch = ddsHeaderSizeOrPitch; |
348 | 0 | for (unsigned int & reserved1 : ddsHeader.reserved1) // XXX nasty constant 11 |
349 | 0 | { |
350 | 0 | reserved1 = 0; |
351 | 0 | } |
352 | 0 | ddsHeader.reserved2 = 0; |
353 | |
|
354 | 0 | ddsHeader.pixelFormat.size = DDS_PIXELFORMAT_SIZE; |
355 | 0 | ddsHeader.pixelFormat.flags = (hasAlpha) ? DDPF_RGB|DDPF_ALPHAPIXELS : DDPF_RGB; |
356 | 0 | ddsHeader.pixelFormat.flags = (isFloat32r || isFloat16r || isFloat16 || isFloat32) ? DDPF_FOURCC : ddsHeader.pixelFormat.flags; |
357 | 0 | if (isFloat32r) { |
358 | 0 | ddsHeader.pixelFormat.fourCC = D3DFMT_R32F; |
359 | 0 | } |
360 | 0 | else if (isFloat16r) { |
361 | 0 | ddsHeader.pixelFormat.fourCC = D3DFMT_R16F; |
362 | 0 | } |
363 | 0 | else if (isFloat16) { |
364 | 0 | ddsHeader.pixelFormat.fourCC = D3DFMT_A16B16G16R16F; |
365 | 0 | } |
366 | 0 | else if (isFloat32) { |
367 | 0 | ddsHeader.pixelFormat.fourCC = D3DFMT_A32B32G32R32F; |
368 | 0 | } |
369 | 0 | else { |
370 | 0 | ddsHeader.pixelFormat.fourCC = 0; |
371 | 0 | } |
372 | 0 | ddsHeader.pixelFormat.rgbBits = ddsHeaderRgbBits; |
373 | |
|
374 | 0 | ddsHeader.pixelFormat.alphaMask = (hasAlpha) ? 0xFF000000 : 0x00000000; |
375 | 0 | ddsHeader.pixelFormat.alphaMask = (isFloat32r || isFloat16r) ? 0x00000000 : ddsHeader.pixelFormat.alphaMask; |
376 | 0 | ddsHeader.pixelFormat.redMask = (isFloat32r || isFloat16r) ? 0xFFFFFFFF :0x00FF0000; |
377 | 0 | ddsHeader.pixelFormat.greenMask = (isFloat32r || isFloat16r) ? 0x00000000 :0x0000FF00; |
378 | 0 | ddsHeader.pixelFormat.blueMask = (isFloat32r || isFloat16r) ? 0x00000000 :0x000000FF; |
379 | |
|
380 | 0 | if( flipRgbMasks ) |
381 | 0 | std::swap( ddsHeader.pixelFormat.redMask, ddsHeader.pixelFormat.blueMask ); |
382 | |
|
383 | 0 | ddsHeader.caps.caps1 = ddsHeaderCaps1; |
384 | 0 | ddsHeader.caps.caps2 = ddsHeaderCaps2; |
385 | | // ddsHeader.caps.reserved[0] = 0; |
386 | | // ddsHeader.caps.reserved[1] = 0; |
387 | | |
388 | | // Swap endian |
389 | 0 | flipEndian(&ddsMagic, sizeof(uint32)); |
390 | 0 | flipEndian(&ddsHeader, 4, sizeof(DDSHeader) / 4); |
391 | |
|
392 | 0 | char *tmpData = 0; |
393 | 0 | char *dataPtr = (char*)image->getData(); |
394 | |
|
395 | 0 | if( image->getFormat() == PF_B8G8R8 ) |
396 | 0 | { |
397 | 0 | PixelBox src( image->getSize() / 3, 1, 1, PF_B8G8R8, image->getData() ); |
398 | 0 | tmpData = new char[image->getSize()]; |
399 | 0 | PixelBox dst( image->getSize() / 3, 1, 1, PF_R8G8B8, tmpData ); |
400 | |
|
401 | 0 | PixelUtil::bulkPixelConversion( src, dst ); |
402 | |
|
403 | 0 | dataPtr = tmpData; |
404 | 0 | } |
405 | |
|
406 | 0 | size_t totalSize = sizeof(uint32) + DDS_HEADER_SIZE + image->getSize(); |
407 | 0 | auto pMemStream = OGRE_NEW Ogre::MemoryDataStream(totalSize); |
408 | |
|
409 | 0 | pMemStream->write(&ddsMagic, sizeof(uint32)); |
410 | 0 | pMemStream->write(&ddsHeader, DDS_HEADER_SIZE); |
411 | 0 | pMemStream->write(dataPtr, image->getSize()); |
412 | 0 | pMemStream->seek(0); |
413 | |
|
414 | 0 | delete [] tmpData; |
415 | |
|
416 | 0 | return Ogre::DataStreamPtr(pMemStream); |
417 | 0 | } |
418 | 0 | } |
419 | | //--------------------------------------------------------------------- |
420 | | void DDSCodec::encodeToFile(const Any& input, const String& outFileName) const |
421 | 0 | { |
422 | 0 | DataStreamPtr strm = encode(input); |
423 | |
|
424 | 0 | try |
425 | 0 | { |
426 | | // Write the file |
427 | 0 | std::ofstream of; |
428 | 0 | of.open(outFileName.c_str(), std::ios_base::binary | std::ios_base::out); |
429 | |
|
430 | 0 | const size_t buffSize = 4096; |
431 | 0 | char buffer[buffSize]; |
432 | |
|
433 | 0 | while (!strm->eof()) { |
434 | 0 | size_t bytesRead = strm->read(buffer, buffSize); |
435 | 0 | of.write(buffer, bytesRead); |
436 | 0 | } |
437 | |
|
438 | 0 | of.close(); |
439 | 0 | } |
440 | 0 | catch(...) |
441 | 0 | { |
442 | 0 | } |
443 | 0 | } |
444 | | //--------------------------------------------------------------------- |
445 | | PixelFormat DDSCodec::convertDXToOgreFormat(uint32 dxfmt) const |
446 | 0 | { |
447 | 0 | switch (dxfmt) { |
448 | 0 | case 2: // DXGI_FORMAT_R32G32B32A32_FLOAT |
449 | 0 | return PF_FLOAT32_RGBA; |
450 | 0 | case 3: // DXGI_FORMAT_R32G32B32A32_UINT |
451 | 0 | return PF_R32G32B32A32_UINT; |
452 | 0 | case 4: //DXGI_FORMAT_R32G32B32A32_SINT |
453 | 0 | return PF_R32G32B32A32_SINT; |
454 | 0 | case 6: // DXGI_FORMAT_R32G32B32_FLOAT |
455 | 0 | return PF_FLOAT32_RGB; |
456 | 0 | case 7: // DXGI_FORMAT_R32G32B32_UINT |
457 | 0 | return PF_R32G32B32_UINT; |
458 | 0 | case 8: // DXGI_FORMAT_R32G32B32_SINT |
459 | 0 | return PF_R32G32B32_SINT; |
460 | 0 | case 10: // DXGI_FORMAT_R16G16B16A16_FLOAT |
461 | 0 | return PF_FLOAT16_RGBA; |
462 | 0 | case 12: // DXGI_FORMAT_R16G16B16A16_UINT |
463 | 0 | return PF_R16G16B16A16_UINT; |
464 | 0 | case 13: // DXGI_FORMAT_R16G16B16A16_SNORM |
465 | 0 | return PF_R16G16B16A16_SNORM; |
466 | 0 | case 14: // DXGI_FORMAT_R16G16B16A16_SINT |
467 | 0 | return PF_R16G16B16A16_SINT; |
468 | 0 | case 16: // DXGI_FORMAT_R32G32_FLOAT |
469 | 0 | return PF_FLOAT32_GR; |
470 | 0 | case 17: // DXGI_FORMAT_R32G32_UINT |
471 | 0 | return PF_R32G32_UINT; |
472 | 0 | case 18: // DXGI_FORMAT_R32G32_SINT |
473 | 0 | return PF_R32G32_SINT; |
474 | 0 | case 24: // DXGI_FORMAT_R10G10B10A2_UNORM |
475 | 0 | case 25: // DXGI_FORMAT_R10G10B10A2_UINT |
476 | 0 | return PF_A2B10G10R10; |
477 | 0 | case 26: // DXGI_FORMAT_R11G11B10_FLOAT |
478 | 0 | return PF_R11G11B10_FLOAT; |
479 | 0 | case 28: // DXGI_FORMAT_R8G8B8A8_UNORM |
480 | 0 | case 29: // DXGI_FORMAT_R8G8B8A8_UNORM_SRGB |
481 | 0 | return PF_A8B8G8R8; |
482 | 0 | case 30: // DXGI_FORMAT_R8G8B8A8_UINT |
483 | 0 | return PF_R8G8B8A8_UINT; |
484 | 0 | case 31: // DXGI_FORMAT_R8G8B8A8_SNORM |
485 | 0 | return PF_R8G8B8A8_SNORM; |
486 | 0 | case 32: // DXGI_FORMAT_R8G8B8A8_SINT |
487 | 0 | return PF_R8G8B8A8_SINT; |
488 | 0 | case 34: // DXGI_FORMAT_R16G16_FLOAT |
489 | 0 | return PF_FLOAT16_GR; |
490 | 0 | case 35: // DXGI_FORMAT_R16G16_UNORM |
491 | 0 | return PF_SHORT_GR; |
492 | 0 | case 36: // DXGI_FORMAT_R16G16_UINT |
493 | 0 | return PF_R16G16_UINT; |
494 | 0 | case 37: // DXGI_FORMAT_R16G16_SNORM |
495 | 0 | return PF_R16G16_SNORM; |
496 | 0 | case 38: // DXGI_FORMAT_R16G16_SINT |
497 | 0 | return PF_R16G16_SINT; |
498 | 0 | case 41: // DXGI_FORMAT_R32_FLOAT |
499 | 0 | return PF_FLOAT32_R; |
500 | 0 | case 42: // DXGI_FORMAT_R32_UINT |
501 | 0 | return PF_R32_UINT; |
502 | 0 | case 43: // DXGI_FORMAT_R32_SINT |
503 | 0 | return PF_R32_SINT; |
504 | 0 | case 49: // DXGI_FORMAT_R8G8_UNORM |
505 | 0 | case 50: // DXGI_FORMAT_R8G8_UINT |
506 | 0 | return PF_R8G8_UINT; |
507 | 0 | case 52: // DXGI_FORMAT_R8G8_SINT |
508 | 0 | return PF_R8G8_SINT; |
509 | 0 | case 54: // DXGI_FORMAT_R16_FLOAT |
510 | 0 | return PF_FLOAT16_R; |
511 | 0 | case 56: // DXGI_FORMAT_R16_UNORM |
512 | 0 | return PF_L16; |
513 | 0 | case 57: // DXGI_FORMAT_R16_UINT |
514 | 0 | return PF_R16_UINT; |
515 | 0 | case 58: // DXGI_FORMAT_R16_SNORM |
516 | 0 | return PF_R16_SNORM; |
517 | 0 | case 59: // DXGI_FORMAT_R16_SINT |
518 | 0 | return PF_R16_SINT; |
519 | 0 | case 61: // DXGI_FORMAT_R8_UNORM |
520 | 0 | return PF_R8; |
521 | 0 | case 62: // DXGI_FORMAT_R8_UINT |
522 | 0 | return PF_R8_UINT; |
523 | 0 | case 63: // DXGI_FORMAT_R8_SNORM |
524 | 0 | return PF_R8_SNORM; |
525 | 0 | case 64: // DXGI_FORMAT_R8_SINT |
526 | 0 | return PF_R8_SINT; |
527 | 0 | case 65: // DXGI_FORMAT_A8_UNORM |
528 | 0 | return PF_A8; |
529 | 0 | case 80: // DXGI_FORMAT_BC4_UNORM |
530 | 0 | return PF_BC4_UNORM; |
531 | 0 | case 81: // DXGI_FORMAT_BC4_SNORM |
532 | 0 | return PF_BC4_SNORM; |
533 | 0 | case 83: // DXGI_FORMAT_BC5_UNORM |
534 | 0 | return PF_BC5_UNORM; |
535 | 0 | case 84: // DXGI_FORMAT_BC5_SNORM |
536 | 0 | return PF_BC5_SNORM; |
537 | 0 | case 85: // DXGI_FORMAT_B5G6R5_UNORM |
538 | 0 | return PF_R5G6B5; |
539 | 0 | case 86: // DXGI_FORMAT_B5G5R5A1_UNORM |
540 | 0 | return PF_A1R5G5B5; |
541 | 0 | case 87: // DXGI_FORMAT_B8G8R8A8_UNORM |
542 | 0 | return PF_A8R8G8B8; |
543 | 0 | case 88: // DXGI_FORMAT_B8G8R8X8_UNORM |
544 | 0 | return PF_X8R8G8B8; |
545 | 0 | case 95: // DXGI_FORMAT_BC6H_UF16 |
546 | 0 | return PF_BC6H_UF16; |
547 | 0 | case 96: // DXGI_FORMAT_BC6H_SF16 |
548 | 0 | return PF_BC6H_SF16; |
549 | 0 | case 98: // DXGI_FORMAT_BC7_UNORM |
550 | 0 | case 99: // DXGI_FORMAT_BC7_UNORM_SRGB |
551 | 0 | return PF_BC7_UNORM; |
552 | 0 | case 20: // DXGI_FORMAT_D32_FLOAT_S8X24_UINT |
553 | 0 | case 22: // DXGI_FORMAT_X32_TYPELESS_G8X24_UINT |
554 | 0 | case 40: // DXGI_FORMAT_D32_FLOAT |
555 | 0 | case 45: // DXGI_FORMAT_D24_UNORM_S8_UINT |
556 | 0 | case 47: // DXGI_FORMAT_X24_TYPELESS_G8_UINT |
557 | 0 | case 55: // DXGI_FORMAT_D16_UNORM |
558 | 0 | default: |
559 | 0 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
560 | 0 | "Unsupported DirectX format found in DDS file", |
561 | 0 | "DDSCodec::convertDXToOgreFormat"); |
562 | 0 | } |
563 | 0 | } |
564 | | //--------------------------------------------------------------------- |
565 | | PixelFormat DDSCodec::convertFourCCFormat(uint32 fourcc) const |
566 | 0 | { |
567 | | // convert dxt pixel format |
568 | 0 | switch(fourcc) |
569 | 0 | { |
570 | 0 | case FOURCC('D','X','T','1'): |
571 | 0 | return PF_DXT1; |
572 | 0 | case FOURCC('D','X','T','2'): |
573 | 0 | return PF_DXT2; |
574 | 0 | case FOURCC('D','X','T','3'): |
575 | 0 | return PF_DXT3; |
576 | 0 | case FOURCC('D','X','T','4'): |
577 | 0 | return PF_DXT4; |
578 | 0 | case FOURCC('D','X','T','5'): |
579 | 0 | return PF_DXT5; |
580 | 0 | case FOURCC('A','T','I','1'): |
581 | 0 | case FOURCC('B','C','4','U'): |
582 | 0 | return PF_BC4_UNORM; |
583 | 0 | case FOURCC('B','C','4','S'): |
584 | 0 | return PF_BC4_SNORM; |
585 | 0 | case FOURCC('A','T','I','2'): |
586 | 0 | case FOURCC('B','C','5','U'): |
587 | 0 | return PF_BC5_UNORM; |
588 | 0 | case FOURCC('B','C','5','S'): |
589 | 0 | return PF_BC5_SNORM; |
590 | 0 | case D3DFMT_R16F: |
591 | 0 | return PF_FLOAT16_R; |
592 | 0 | case D3DFMT_G16R16F: |
593 | 0 | return PF_FLOAT16_GR; |
594 | 0 | case D3DFMT_A16B16G16R16F: |
595 | 0 | return PF_FLOAT16_RGBA; |
596 | 0 | case D3DFMT_R32F: |
597 | 0 | return PF_FLOAT32_R; |
598 | 0 | case D3DFMT_G32R32F: |
599 | 0 | return PF_FLOAT32_GR; |
600 | 0 | case D3DFMT_A32B32G32R32F: |
601 | 0 | return PF_FLOAT32_RGBA; |
602 | | // We could support 3Dc here, but only ATI cards support it, not nVidia |
603 | 0 | default: |
604 | 0 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
605 | 0 | "Unsupported FourCC format found in DDS file", |
606 | 0 | "DDSCodec::convertFourCCFormat"); |
607 | 0 | }; |
608 | |
|
609 | 0 | } |
610 | | //--------------------------------------------------------------------- |
611 | | PixelFormat DDSCodec::convertPixelFormat(uint32 rgbBits, uint32 rMask, |
612 | | uint32 gMask, uint32 bMask, uint32 aMask) const |
613 | 0 | { |
614 | | // General search through pixel formats |
615 | 0 | for (int i = PF_UNKNOWN + 1; i < PF_COUNT; ++i) |
616 | 0 | { |
617 | 0 | PixelFormat pf = static_cast<PixelFormat>(i); |
618 | 0 | if (PixelUtil::getNumElemBits(pf) == rgbBits) |
619 | 0 | { |
620 | 0 | uint64 testMasks[4]; |
621 | 0 | PixelUtil::getBitMasks(pf, testMasks); |
622 | 0 | int testBits[4]; |
623 | 0 | PixelUtil::getBitDepths(pf, testBits); |
624 | 0 | if (testMasks[0] == rMask && testMasks[1] == gMask && |
625 | 0 | testMasks[2] == bMask && |
626 | | // for alpha, deal with 'X8' formats by checking bit counts |
627 | 0 | (testMasks[3] == aMask || (aMask == 0 && testBits[3] == 0))) |
628 | 0 | { |
629 | 0 | return pf; |
630 | 0 | } |
631 | 0 | } |
632 | |
|
633 | 0 | } |
634 | | |
635 | 0 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Cannot determine pixel format", |
636 | 0 | "DDSCodec::convertPixelFormat"); |
637 | 0 | } |
638 | | //--------------------------------------------------------------------- |
639 | | void DDSCodec::unpackDXTColour(PixelFormat pf, const DXTColourBlock& block, |
640 | | ColourValue* pCol) const |
641 | 0 | { |
642 | | // Note - we assume all values have already been endian swapped |
643 | | |
644 | | // Colour lookup table |
645 | 0 | ColourValue derivedColours[4]; |
646 | |
|
647 | 0 | if (pf == PF_DXT1 && block.colour_0 <= block.colour_1) |
648 | 0 | { |
649 | | // 1-bit alpha |
650 | 0 | PixelUtil::unpackColour(&(derivedColours[0]), PF_R5G6B5, &(block.colour_0)); |
651 | 0 | PixelUtil::unpackColour(&(derivedColours[1]), PF_R5G6B5, &(block.colour_1)); |
652 | | // one intermediate colour, half way between the other two |
653 | 0 | derivedColours[2] = (derivedColours[0] + derivedColours[1]) / 2; |
654 | | // transparent colour |
655 | 0 | derivedColours[3] = ColourValue::ZERO; |
656 | 0 | } |
657 | 0 | else |
658 | 0 | { |
659 | 0 | PixelUtil::unpackColour(&(derivedColours[0]), PF_R5G6B5, &(block.colour_0)); |
660 | 0 | PixelUtil::unpackColour(&(derivedColours[1]), PF_R5G6B5, &(block.colour_1)); |
661 | | // first interpolated colour, 1/3 of the way along |
662 | 0 | derivedColours[2] = (2 * derivedColours[0] + derivedColours[1]) / 3; |
663 | | // second interpolated colour, 2/3 of the way along |
664 | 0 | derivedColours[3] = (derivedColours[0] + 2 * derivedColours[1]) / 3; |
665 | 0 | } |
666 | | |
667 | | // Process 4x4 block of texels |
668 | 0 | for (size_t row = 0; row < 4; ++row) |
669 | 0 | { |
670 | 0 | for (size_t x = 0; x < 4; ++x) |
671 | 0 | { |
672 | | // LSB come first |
673 | 0 | uint8 colIdx = static_cast<uint8>(block.indexRow[row] >> (x * 2) & 0x3); |
674 | 0 | if (pf == PF_DXT1) |
675 | 0 | { |
676 | | // Overwrite entire colour |
677 | 0 | pCol[(row * 4) + x] = derivedColours[colIdx]; |
678 | 0 | } |
679 | 0 | else |
680 | 0 | { |
681 | | // alpha has already been read (alpha precedes colour) |
682 | 0 | ColourValue& col = pCol[(row * 4) + x]; |
683 | 0 | col.r = derivedColours[colIdx].r; |
684 | 0 | col.g = derivedColours[colIdx].g; |
685 | 0 | col.b = derivedColours[colIdx].b; |
686 | 0 | } |
687 | 0 | } |
688 | |
|
689 | 0 | } |
690 | | |
691 | |
|
692 | 0 | } |
693 | | //--------------------------------------------------------------------- |
694 | | void DDSCodec::unpackDXTAlpha( |
695 | | const DXTExplicitAlphaBlock& block, ColourValue* pCol) const |
696 | 0 | { |
697 | | // Note - we assume all values have already been endian swapped |
698 | | |
699 | | // This is an explicit alpha block, 4 bits per pixel, LSB first |
700 | 0 | for (unsigned short row : block.alphaRow) |
701 | 0 | { |
702 | 0 | for (size_t x = 0; x < 4; ++x) |
703 | 0 | { |
704 | | // Shift and mask off to 4 bits |
705 | 0 | uint8 val = static_cast<uint8>(row >> (x * 4) & 0xF); |
706 | | // Convert to [0,1] |
707 | 0 | pCol->a = (Real)val / (Real)0xF; |
708 | 0 | pCol++; |
709 | | |
710 | 0 | } |
711 | | |
712 | 0 | } |
713 | |
|
714 | 0 | } |
715 | | //--------------------------------------------------------------------- |
716 | | void DDSCodec::unpackDXTAlpha( |
717 | | const DXTInterpolatedAlphaBlock& block, ColourValue* pCol) const |
718 | 0 | { |
719 | | // Adaptive 3-bit alpha part |
720 | 0 | float derivedAlphas[8]; |
721 | | |
722 | | // Explicit extremes |
723 | 0 | derivedAlphas[0] = ((float) block.alpha_0) * (1.0f / 255.0f); |
724 | 0 | derivedAlphas[1] = ((float) block.alpha_1) * (1.0f / 255.0f); |
725 | |
|
726 | 0 | if(block.alpha_0 > block.alpha_1) |
727 | 0 | { |
728 | | // 6 interpolated alpha values. |
729 | | // full range including extremes at [0] and [7] |
730 | | // we want to fill in [1] through [6] at weights ranging |
731 | | // from 1/7 to 6/7 |
732 | 0 | for(size_t i = 1; i < 7; ++i) |
733 | 0 | derivedAlphas[i + 1] = (derivedAlphas[0] * (7 - i) + derivedAlphas[1] * i) * (1.0f / 7.0f); |
734 | 0 | } |
735 | 0 | else |
736 | 0 | { |
737 | | // 4 interpolated alpha values. |
738 | | // full range including extremes at [0] and [5] |
739 | | // we want to fill in [1] through [4] at weights ranging |
740 | | // from 1/5 to 4/5 |
741 | 0 | for(size_t i = 1; i < 5; ++i) |
742 | 0 | derivedAlphas[i + 1] = (derivedAlphas[0] * (5 - i) + derivedAlphas[1] * i) * (1.0f / 5.0f); |
743 | |
|
744 | 0 | derivedAlphas[6] = 0.0f; |
745 | 0 | derivedAlphas[7] = 1.0f; |
746 | 0 | } |
747 | | |
748 | | // Ok, now we've built the reference values, process the indexes |
749 | 0 | uint32 dw = block.indexes[0] | (block.indexes[1] << 8) | (block.indexes[2] << 16); |
750 | |
|
751 | 0 | for(size_t i = 0; i < 8; ++i, dw >>= 3) |
752 | 0 | pCol[i].a = derivedAlphas[dw & 0x7]; |
753 | |
|
754 | 0 | dw = block.indexes[3] | (block.indexes[4] << 8) | (block.indexes[5] << 16); |
755 | |
|
756 | 0 | for(size_t i = 8; i < 16; ++i, dw >>= 3) |
757 | 0 | pCol[i].a = derivedAlphas[dw & 0x7]; |
758 | 0 | } |
759 | | //--------------------------------------------------------------------- |
760 | | void DDSCodec::decode(const DataStreamPtr& stream, const Any& output) const |
761 | 0 | { |
762 | 0 | Image* image = any_cast<Image*>(output); |
763 | | // Read 4 character code |
764 | 0 | uint32 fileType; |
765 | 0 | stream->read(&fileType, sizeof(uint32)); |
766 | 0 | flipEndian(&fileType, sizeof(uint32)); |
767 | | |
768 | 0 | if (FOURCC('D', 'D', 'S', ' ') != fileType) |
769 | 0 | { |
770 | 0 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, |
771 | 0 | "This is not a DDS file!", "DDSCodec::decode"); |
772 | 0 | } |
773 | | |
774 | | // Read header in full |
775 | 0 | DDSHeader header; |
776 | 0 | stream->read(&header, sizeof(DDSHeader)); |
777 | | |
778 | | // Endian flip if required, all 32-bit values |
779 | 0 | flipEndian(&header, 4, sizeof(DDSHeader) / 4); |
780 | | |
781 | | // Check some sizes |
782 | 0 | if (header.size != DDS_HEADER_SIZE) |
783 | 0 | { |
784 | 0 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, |
785 | 0 | "DDS header size mismatch!", "DDSCodec::decode"); |
786 | 0 | } |
787 | 0 | if (header.pixelFormat.size != DDS_PIXELFORMAT_SIZE) |
788 | 0 | { |
789 | 0 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, |
790 | 0 | "DDS header size mismatch!", "DDSCodec::decode"); |
791 | 0 | } |
792 | | |
793 | 0 | uint32 imgDepth = 1; // (deal with volume later) |
794 | 0 | uint32 numFaces = 1; // assume one face until we know otherwise |
795 | 0 | uint32 num_mipmaps = 0; |
796 | 0 | PixelFormat format = PF_UNKNOWN; |
797 | |
|
798 | 0 | if (header.caps.caps1 & DDSCAPS_MIPMAP) |
799 | 0 | { |
800 | 0 | num_mipmaps = static_cast<uint8>(header.mipMapCount - 1); |
801 | 0 | } |
802 | 0 | else |
803 | 0 | { |
804 | 0 | num_mipmaps = 0; |
805 | 0 | } |
806 | |
|
807 | 0 | bool decompressDXT = false; |
808 | | // Figure out basic image type |
809 | 0 | if (header.caps.caps2 & DDSCAPS2_CUBEMAP) |
810 | 0 | { |
811 | 0 | numFaces = 6; |
812 | 0 | } |
813 | 0 | else if (header.caps.caps2 & DDSCAPS2_VOLUME) |
814 | 0 | { |
815 | 0 | imgDepth = header.depth; |
816 | 0 | } |
817 | | // Pixel format |
818 | 0 | PixelFormat sourceFormat = PF_UNKNOWN; |
819 | |
|
820 | 0 | if (header.pixelFormat.flags & DDPF_FOURCC) |
821 | 0 | { |
822 | | // Check if we have an DX10 style extended header and read it. This is necessary for B6H and B7 formats |
823 | 0 | if(header.pixelFormat.fourCC == FOURCC('D', 'X', '1', '0')) |
824 | 0 | { |
825 | 0 | DDSExtendedHeader extHeader; |
826 | 0 | stream->read(&extHeader, sizeof(DDSExtendedHeader)); |
827 | | |
828 | | // Endian flip if required, all 32-bit values |
829 | 0 | flipEndian(&header, sizeof(DDSExtendedHeader)); |
830 | 0 | sourceFormat = convertDXToOgreFormat(extHeader.dxgiFormat); |
831 | 0 | } |
832 | 0 | else |
833 | 0 | { |
834 | 0 | sourceFormat = convertFourCCFormat(header.pixelFormat.fourCC); |
835 | 0 | } |
836 | 0 | } |
837 | 0 | else |
838 | 0 | { |
839 | 0 | sourceFormat = convertPixelFormat(header.pixelFormat.rgbBits, |
840 | 0 | header.pixelFormat.redMask, header.pixelFormat.greenMask, |
841 | 0 | header.pixelFormat.blueMask, |
842 | 0 | header.pixelFormat.flags & DDPF_ALPHAPIXELS ? |
843 | 0 | header.pixelFormat.alphaMask : 0); |
844 | 0 | } |
845 | |
|
846 | 0 | if (PixelUtil::isCompressed(sourceFormat)) |
847 | 0 | { |
848 | 0 | if (Root::getSingleton().getRenderSystem() == NULL || |
849 | 0 | !Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_TEXTURE_COMPRESSION_DXT) || |
850 | 0 | mDecodeEnforce) |
851 | 0 | { |
852 | | // We'll need to decompress |
853 | 0 | decompressDXT = true; |
854 | | // Convert format |
855 | 0 | switch (sourceFormat) |
856 | 0 | { |
857 | 0 | case PF_DXT1: |
858 | | // source can be either 565 or 5551 depending on whether alpha present |
859 | | // unfortunately you have to read a block to figure out which |
860 | | // Note that we upgrade to 32-bit pixel formats here, even |
861 | | // though the source is 16-bit; this is because the interpolated |
862 | | // values will benefit from the 32-bit results, and the source |
863 | | // from which the 16-bit samples are calculated may have been |
864 | | // 32-bit so can benefit from this. |
865 | 0 | DXTColourBlock block; |
866 | 0 | stream->read(&block, sizeof(DXTColourBlock)); |
867 | 0 | flipEndian(&(block.colour_0), sizeof(uint16)); |
868 | 0 | flipEndian(&(block.colour_1), sizeof(uint16)); |
869 | | // skip back since we'll need to read this again |
870 | 0 | stream->skip(0 - (long)sizeof(DXTColourBlock)); |
871 | | // colour_0 <= colour_1 means transparency in DXT1 |
872 | 0 | if (block.colour_0 <= block.colour_1) |
873 | 0 | { |
874 | 0 | format = PF_BYTE_RGBA; |
875 | 0 | } |
876 | 0 | else |
877 | 0 | { |
878 | 0 | format = PF_BYTE_RGB; |
879 | 0 | } |
880 | 0 | break; |
881 | 0 | case PF_DXT2: |
882 | 0 | case PF_DXT3: |
883 | 0 | case PF_DXT4: |
884 | 0 | case PF_DXT5: |
885 | | // full alpha present, formats vary only in encoding |
886 | 0 | format = PF_BYTE_RGBA; |
887 | 0 | break; |
888 | 0 | default: |
889 | | // all other cases need no special format handling |
890 | 0 | break; |
891 | 0 | } |
892 | 0 | } |
893 | 0 | else |
894 | 0 | { |
895 | | // Use original format |
896 | 0 | format = sourceFormat; |
897 | 0 | } |
898 | 0 | } |
899 | 0 | else // not compressed |
900 | 0 | { |
901 | | // Don't test against DDPF_RGB since greyscale DDS doesn't set this |
902 | | // just derive any other kind of format |
903 | 0 | format = sourceFormat; |
904 | 0 | } |
905 | | |
906 | | // Calculate total size from number of mipmaps, faces and size |
907 | 0 | image->create(format, header.width, header.height, imgDepth, numFaces, num_mipmaps); |
908 | | |
909 | | // Now deal with the data |
910 | 0 | void* destPtr = image->getData(); |
911 | | |
912 | | // all mips for a face, then each face |
913 | 0 | for(size_t i = 0; i < numFaces; ++i) |
914 | 0 | { |
915 | 0 | uint32 width = image->getWidth(); |
916 | 0 | uint32 height = image->getHeight(); |
917 | 0 | uint32 depth = image->getDepth(); |
918 | |
|
919 | 0 | for(size_t mip = 0; mip <= num_mipmaps; ++mip) |
920 | 0 | { |
921 | 0 | size_t dstPitch = width * PixelUtil::getNumElemBytes(format); |
922 | | |
923 | 0 | if (PixelUtil::isCompressed(sourceFormat)) |
924 | 0 | { |
925 | | // Compressed data |
926 | 0 | if (decompressDXT) |
927 | 0 | { |
928 | 0 | DXTColourBlock col; |
929 | 0 | DXTInterpolatedAlphaBlock iAlpha; |
930 | 0 | DXTExplicitAlphaBlock eAlpha; |
931 | | // 4x4 block of decompressed colour |
932 | 0 | ColourValue tempColours[16]; |
933 | 0 | size_t destBpp = PixelUtil::getNumElemBytes(format); |
934 | | |
935 | | // slices are done individually |
936 | 0 | for(size_t z = 0; z < depth; ++z) |
937 | 0 | { |
938 | 0 | size_t remainingHeight = height; |
939 | | |
940 | | // 4x4 blocks in x/y |
941 | 0 | for (size_t y = 0; y < height; y += 4) |
942 | 0 | { |
943 | 0 | size_t sy = std::min<size_t>( remainingHeight, 4u ); |
944 | 0 | remainingHeight -= sy; |
945 | |
|
946 | 0 | size_t remainingWidth = width; |
947 | |
|
948 | 0 | for (size_t x = 0; x < width; x += 4) |
949 | 0 | { |
950 | 0 | size_t sx = std::min<size_t>( remainingWidth, 4u ); |
951 | 0 | size_t destPitchMinus4 = dstPitch - destBpp * sx; |
952 | |
|
953 | 0 | remainingWidth -= sx; |
954 | |
|
955 | 0 | if (sourceFormat == PF_DXT2 || |
956 | 0 | sourceFormat == PF_DXT3) |
957 | 0 | { |
958 | | // explicit alpha |
959 | 0 | stream->read(&eAlpha, sizeof(DXTExplicitAlphaBlock)); |
960 | 0 | flipEndian(eAlpha.alphaRow, sizeof(uint16), 4); |
961 | 0 | unpackDXTAlpha(eAlpha, tempColours) ; |
962 | 0 | } |
963 | 0 | else if (sourceFormat == PF_DXT4 || |
964 | 0 | sourceFormat == PF_DXT5) |
965 | 0 | { |
966 | | // interpolated alpha |
967 | 0 | stream->read(&iAlpha, sizeof(DXTInterpolatedAlphaBlock)); |
968 | 0 | flipEndian(&(iAlpha.alpha_0), sizeof(uint16)); |
969 | 0 | flipEndian(&(iAlpha.alpha_1), sizeof(uint16)); |
970 | 0 | unpackDXTAlpha(iAlpha, tempColours) ; |
971 | 0 | } |
972 | | // always read colour |
973 | 0 | stream->read(&col, sizeof(DXTColourBlock)); |
974 | 0 | flipEndian(&(col.colour_0), sizeof(uint16)); |
975 | 0 | flipEndian(&(col.colour_1), sizeof(uint16)); |
976 | 0 | unpackDXTColour(sourceFormat, col, tempColours); |
977 | | |
978 | | // write 4x4 block to uncompressed version |
979 | 0 | for (size_t by = 0; by < sy; ++by) |
980 | 0 | { |
981 | 0 | for (size_t bx = 0; bx < sx; ++bx) |
982 | 0 | { |
983 | 0 | PixelUtil::packColour(tempColours[by*4+bx], |
984 | 0 | format, destPtr); |
985 | 0 | destPtr = static_cast<void*>( |
986 | 0 | static_cast<uchar*>(destPtr) + destBpp); |
987 | 0 | } |
988 | | // advance to next row |
989 | 0 | destPtr = static_cast<void*>( |
990 | 0 | static_cast<uchar*>(destPtr) + destPitchMinus4); |
991 | 0 | } |
992 | | // next block. Our dest pointer is 4 lines down |
993 | | // from where it started |
994 | 0 | if (x + 4 >= width) |
995 | 0 | { |
996 | | // Jump back to the start of the line |
997 | 0 | destPtr = static_cast<void*>( |
998 | 0 | static_cast<uchar*>(destPtr) - destPitchMinus4); |
999 | 0 | } |
1000 | 0 | else |
1001 | 0 | { |
1002 | | // Jump back up 4 rows and 4 pixels to the |
1003 | | // right to be at the next block to the right |
1004 | 0 | destPtr = static_cast<void*>( |
1005 | 0 | static_cast<uchar*>(destPtr) - dstPitch * sy + destBpp * sx); |
1006 | |
|
1007 | 0 | } |
1008 | |
|
1009 | 0 | } |
1010 | |
|
1011 | 0 | } |
1012 | 0 | } |
1013 | |
|
1014 | 0 | } |
1015 | 0 | else |
1016 | 0 | { |
1017 | | // load directly |
1018 | | // DDS format lies! sizeOrPitch is not always set for DXT!! |
1019 | 0 | size_t dxtSize = PixelUtil::getMemorySize(width, height, depth, format); |
1020 | 0 | stream->read(destPtr, dxtSize); |
1021 | 0 | destPtr = static_cast<void*>(static_cast<uchar*>(destPtr) + dxtSize); |
1022 | 0 | } |
1023 | |
|
1024 | 0 | } |
1025 | 0 | else |
1026 | 0 | { |
1027 | | // Note: We assume the source and destination have the same pitch |
1028 | 0 | for (size_t z = 0; z < depth; ++z) |
1029 | 0 | { |
1030 | 0 | for (size_t y = 0; y < height; ++y) |
1031 | 0 | { |
1032 | 0 | stream->read(destPtr, dstPitch); |
1033 | 0 | destPtr = static_cast<void*>(static_cast<uchar*>(destPtr) + dstPitch); |
1034 | 0 | } |
1035 | 0 | } |
1036 | 0 | } |
1037 | | |
1038 | | /// Next mip |
1039 | 0 | if(width!=1) width /= 2; |
1040 | 0 | if(height!=1) height /= 2; |
1041 | 0 | if(depth!=1) depth /= 2; |
1042 | 0 | } |
1043 | |
|
1044 | 0 | } |
1045 | 0 | } |
1046 | | //--------------------------------------------------------------------- |
1047 | | String DDSCodec::getType() const |
1048 | 0 | { |
1049 | 0 | return mType; |
1050 | 0 | } |
1051 | | //--------------------------------------------------------------------- |
1052 | | String DDSCodec::magicNumberToFileExt(const char *magicNumberPtr, size_t maxbytes) const |
1053 | 0 | { |
1054 | 0 | if (maxbytes >= sizeof(uint32)) |
1055 | 0 | { |
1056 | 0 | uint32 fileType; |
1057 | 0 | memcpy(&fileType, magicNumberPtr, sizeof(uint32)); |
1058 | 0 | flipEndian(&fileType, sizeof(uint32)); |
1059 | |
|
1060 | 0 | if (DDS_MAGIC == fileType) |
1061 | 0 | { |
1062 | 0 | return String("dds"); |
1063 | 0 | } |
1064 | 0 | } |
1065 | | |
1066 | 0 | return BLANKSTRING; |
1067 | |
|
1068 | 0 | } |
1069 | | //--------------------------------------------------------------------- |
1070 | | bool DDSCodec::setParameter(const String& name, const String& value) |
1071 | 0 | { |
1072 | 0 | if (name == "decode_enforce") |
1073 | 0 | return StringConverter::parse(value, mDecodeEnforce); |
1074 | | |
1075 | 0 | return false; |
1076 | 0 | } |
1077 | | |
1078 | | } |
1079 | | |