Coverage Report

Created: 2025-11-25 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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