Coverage Report

Created: 2026-02-26 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgrePixelFormat.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
#include "OgreStableHeaders.h"
29
#include "OgrePixelFormat.h"
30
#include "OgrePixelFormatDescriptions.h"
31
32
namespace {
33
#include "OgrePixelConversions.h"
34
}
35
36
namespace Ogre {
37
38
    //-----------------------------------------------------------------------
39
    size_t PixelBox::getConsecutiveSize() const
40
0
    {
41
0
        return PixelUtil::getMemorySize(getWidth(), getHeight(), getDepth(), format);
42
0
    }
43
    PixelBox PixelBox::getSubVolume(const Box &def, bool resetOrigin /* = true */) const
44
0
    {
45
0
        OgreAssert(contains(def), "");
46
47
0
        if(PixelUtil::isCompressed(format) && (def.left != left || def.top != top || def.right != right || def.bottom != bottom))
48
0
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot return subvolume of compressed PixelBuffer with less than slice granularity", "PixelBox::getSubVolume");
49
50
        // Calculate new pixelbox and optionally reset origin.
51
0
        PixelBox rval(def, format, data);
52
0
        rval.rowPitch = rowPitch;
53
0
        rval.slicePitch = slicePitch;
54
55
0
        if(resetOrigin)
56
0
        {
57
0
            if(PixelUtil::isCompressed(format))
58
0
            {
59
0
                if(rval.front > 0)
60
0
                {
61
0
                    rval.data = (uint8*)rval.data + rval.front * PixelUtil::getMemorySize(getWidth(), getHeight(), 1, format);
62
0
                    rval.back -= rval.front;
63
0
                    rval.front = 0;
64
0
                }
65
0
            }
66
0
            else
67
0
            {
68
0
                rval.data = rval.getTopLeftFrontPixelPtr();
69
0
                rval.right -= rval.left;
70
0
                rval.bottom -= rval.top;
71
0
                rval.back -= rval.front;
72
0
                rval.front = rval.top = rval.left = 0;
73
0
            }
74
0
        }
75
76
0
        return rval;
77
0
    }
78
    uchar* PixelBox::getTopLeftFrontPixelPtr() const
79
0
    {
80
0
        return data + (left + top * rowPitch + front * slicePitch) * PixelUtil::getNumElemBytes(format);
81
0
    }
82
    //-----------------------------------------------------------------------
83
    /**
84
    * Directly get the description record for provided pixel format. For debug builds,
85
    * this checks the bounds of fmt with an assertion.
86
    */
87
    static inline const PixelFormatDescription &getDescriptionFor(const PixelFormat fmt)
88
0
    {
89
0
        const int ord = (int)fmt;
90
0
        assert(ord>=0 && ord<PF_COUNT);
91
92
0
        return _pixelFormats[ord];
93
0
    }
94
    //-----------------------------------------------------------------------
95
    uint8 PixelUtil::getNumElemBytes( PixelFormat format )
96
0
    {
97
0
        return getDescriptionFor(format).elemBytes;
98
0
    }
99
    //-----------------------------------------------------------------------
100
    static size_t astc_slice_size(uint32 width, uint32 height, uint32 blockWidth, uint32 blockHeight)
101
0
    {
102
0
        return ((width + blockWidth - 1) / blockWidth) *
103
0
               ((height + blockHeight - 1) / blockHeight) * 16;
104
0
    }
105
    size_t PixelUtil::getMemorySize(uint32 width, uint32 height, uint32 depth, PixelFormat format)
106
0
    {
107
0
        if(isCompressed(format))
108
0
        {
109
0
            switch(format)
110
0
            {
111
                // DXT formats work by dividing the image into 4x4 blocks, then encoding each
112
                // 4x4 block with a certain number of bytes. 
113
0
                case PF_DXT1:
114
0
                    return ((width+3)/4)*((height+3)/4)*8 * depth;
115
0
                case PF_DXT2:
116
0
                case PF_DXT3:
117
0
                case PF_DXT4:
118
0
                case PF_DXT5:
119
0
                    return ((width+3)/4)*((height+3)/4)*16 * depth;
120
0
                case PF_BC4_SNORM:
121
0
                case PF_BC4_UNORM:
122
0
                    return ((width+3)/4)*((height+3)/4)*8 * depth;
123
0
                case PF_BC5_SNORM:
124
0
                case PF_BC5_UNORM:
125
0
                case PF_BC6H_SF16:
126
0
                case PF_BC6H_UF16:
127
0
                case PF_BC7_UNORM:
128
0
                    return ((width+3)/4)*((height+3)/4)*16 * depth;
129
130
                // Size calculations from the PVRTC OpenGL extension spec
131
                // http://www.khronos.org/registry/gles/extensions/IMG/IMG_texture_compression_pvrtc.txt
132
                // Basically, 32 bytes is the minimum texture size.  Smaller textures are padded up to 32 bytes
133
0
                case PF_PVRTC_RGB2:
134
0
                case PF_PVRTC_RGBA2:
135
0
                case PF_PVRTC2_2BPP:
136
0
                    return (std::max((int)width, 16) * std::max((int)height, 8) * 2 + 7) / 8;
137
0
                case PF_PVRTC_RGB4:
138
0
                case PF_PVRTC_RGBA4:
139
0
                case PF_PVRTC2_4BPP:
140
0
                    return (std::max((int)width, 8) * std::max((int)height, 8) * 4 + 7) / 8;
141
142
                // see https://registry.khronos.org/OpenGL-Refpages/es3/html/glCompressedTexImage2D.xhtml
143
0
                case PF_ETC1_RGB8:
144
0
                case PF_ETC2_RGB8:
145
0
                case PF_ETC2_RGB8A1:
146
0
                case PF_ATC_RGB:
147
0
                    return ((width + 3) / 4) * ((height + 3) / 4) * 8;
148
0
                case PF_ETC2_RGBA8:
149
0
                case PF_ATC_RGBA_EXPLICIT_ALPHA:
150
0
                case PF_ATC_RGBA_INTERPOLATED_ALPHA:
151
0
                    return ((width + 3) / 4) * ((height + 3) / 4) * 16;
152
153
0
                case PF_ASTC_RGBA_4X4_LDR:
154
0
                    return astc_slice_size(width, height, 4, 4) * depth;
155
0
                case PF_ASTC_RGBA_5X4_LDR:
156
0
                    return astc_slice_size(width, height, 5, 4) * depth;
157
0
                case PF_ASTC_RGBA_5X5_LDR:
158
0
                    return astc_slice_size(width, height, 5, 5) * depth;
159
0
                case PF_ASTC_RGBA_6X5_LDR:
160
0
                    return astc_slice_size(width, height, 6, 5) * depth;
161
0
                case PF_ASTC_RGBA_6X6_LDR:
162
0
                    return astc_slice_size(width, height, 6, 6) * depth;
163
0
                case PF_ASTC_RGBA_8X5_LDR:
164
0
                    return astc_slice_size(width, height, 8, 5) * depth;
165
0
                case PF_ASTC_RGBA_8X6_LDR:
166
0
                    return astc_slice_size(width, height, 8, 6) * depth;
167
0
                case PF_ASTC_RGBA_8X8_LDR:
168
0
                    return astc_slice_size(width, height, 8, 8) * depth;
169
0
                case PF_ASTC_RGBA_10X5_LDR:
170
0
                    return astc_slice_size(width, height, 10, 5) * depth;
171
0
                case PF_ASTC_RGBA_10X6_LDR:
172
0
                    return astc_slice_size(width, height, 10, 6) * depth;
173
0
                case PF_ASTC_RGBA_10X8_LDR:
174
0
                    return astc_slice_size(width, height, 10, 8) * depth;
175
0
                case PF_ASTC_RGBA_10X10_LDR:
176
0
                    return astc_slice_size(width, height, 10, 10) * depth;
177
0
                case PF_ASTC_RGBA_12X10_LDR:
178
0
                    return astc_slice_size(width, height, 12, 10) * depth;
179
0
                case PF_ASTC_RGBA_12X12_LDR:
180
0
                    return astc_slice_size(width, height, 12, 12) * depth;
181
0
                default:
182
0
                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid compressed pixel format",
183
0
                    "PixelUtil::getMemorySize");
184
0
            }
185
0
        }
186
0
        else
187
0
        {
188
0
            return width*height*depth*getNumElemBytes(format);
189
0
        }
190
0
    }
191
    //-----------------------------------------------------------------------
192
    uint8 PixelUtil::getNumElemBits( PixelFormat format )
193
0
    {
194
0
        return getDescriptionFor(format).elemBytes * 8;
195
0
    }
196
    //-----------------------------------------------------------------------
197
    unsigned int PixelUtil::getFlags( PixelFormat format )
198
0
    {
199
0
        return getDescriptionFor(format).flags;
200
0
    }
201
    //-----------------------------------------------------------------------
202
    bool PixelUtil::hasAlpha(PixelFormat format)
203
0
    {
204
0
        return (PixelUtil::getFlags(format) & PFF_HASALPHA) > 0;
205
0
    }
206
    //-----------------------------------------------------------------------
207
    bool PixelUtil::isFloatingPoint(PixelFormat format)
208
0
    {
209
0
        return (PixelUtil::getFlags(format) & PFF_FLOAT) > 0;
210
0
    }
211
    //-----------------------------------------------------------------------
212
    bool PixelUtil::isInteger(PixelFormat format)
213
0
    {
214
0
        return (PixelUtil::getFlags(format) & PFF_INTEGER) > 0;
215
0
    }
216
    //-----------------------------------------------------------------------
217
    bool PixelUtil::isCompressed(PixelFormat format)
218
0
    {
219
0
        return (PixelUtil::getFlags(format) & PFF_COMPRESSED) > 0;
220
0
    }
221
    //-----------------------------------------------------------------------
222
    bool PixelUtil::isDepth(PixelFormat format)
223
0
    {
224
0
        return (PixelUtil::getFlags(format) & PFF_DEPTH) > 0;
225
0
    }
226
    //-----------------------------------------------------------------------
227
    bool PixelUtil::isNativeEndian(PixelFormat format)
228
0
    {
229
0
        return (PixelUtil::getFlags(format) & PFF_NATIVEENDIAN) > 0;
230
0
    }
231
    //-----------------------------------------------------------------------
232
    bool PixelUtil::isLuminance(PixelFormat format)
233
0
    {
234
0
        return (PixelUtil::getFlags(format) & PFF_LUMINANCE) > 0;
235
0
    }
236
    //-----------------------------------------------------------------------
237
    void PixelUtil::getBitDepths(PixelFormat format, int rgba[4])
238
0
    {
239
0
        const PixelFormatDescription &des = getDescriptionFor(format);
240
0
        rgba[0] = des.rbits;
241
0
        rgba[1] = des.gbits;
242
0
        rgba[2] = des.bbits;
243
0
        rgba[3] = des.abits;
244
0
    }
245
    //-----------------------------------------------------------------------
246
    void PixelUtil::getBitMasks(PixelFormat format, uint64 rgba[4])
247
0
    {
248
0
        const PixelFormatDescription &des = getDescriptionFor(format);
249
0
        rgba[0] = des.rmask;
250
0
        rgba[1] = des.gmask;
251
0
        rgba[2] = des.bmask;
252
0
        rgba[3] = des.amask;
253
0
    }
254
    //---------------------------------------------------------------------
255
    void PixelUtil::getBitShifts(PixelFormat format, unsigned char rgba[4])
256
0
    {
257
0
        const PixelFormatDescription &des = getDescriptionFor(format);
258
0
        rgba[0] = des.rshift;
259
0
        rgba[1] = des.gshift;
260
0
        rgba[2] = des.bshift;
261
0
        rgba[3] = des.ashift;
262
0
    }
263
    //-----------------------------------------------------------------------
264
    const String& PixelUtil::getFormatName(PixelFormat srcformat)
265
0
    {
266
0
        return getDescriptionFor(srcformat).name;
267
0
    }
268
    //-----------------------------------------------------------------------
269
    bool PixelUtil::isAccessible(PixelFormat srcformat)
270
0
    {
271
0
        return (srcformat != PF_UNKNOWN) && !isCompressed(srcformat);
272
0
    }
273
    //-----------------------------------------------------------------------
274
    PixelComponentType PixelUtil::getComponentType(PixelFormat fmt)
275
0
    {
276
0
        const PixelFormatDescription &des = getDescriptionFor(fmt);
277
0
        return des.componentType;
278
0
    }
279
    //-----------------------------------------------------------------------
280
    uint8 PixelUtil::getComponentCount(PixelFormat fmt)
281
0
    {
282
0
        const PixelFormatDescription &des = getDescriptionFor(fmt);
283
0
        return des.componentCount;
284
0
    }
285
    //-----------------------------------------------------------------------
286
    PixelFormat PixelUtil::getFormatFromName(const String& name, bool accessibleOnly, bool caseSensitive)
287
0
    {
288
0
        String tmp = name;
289
0
        if (!caseSensitive)
290
0
        {
291
            // We are stored upper-case format names.
292
0
            StringUtil::toUpperCase(tmp);
293
0
        }
294
295
0
        for (int i = 0; i < PF_COUNT; ++i)
296
0
        {
297
0
            PixelFormat pf = static_cast<PixelFormat>(i);
298
0
            if (!accessibleOnly || isAccessible(pf))
299
0
            {
300
0
                if (tmp == getFormatName(pf))
301
0
                    return pf;
302
0
            }
303
0
        }
304
305
        // allow look-up by alias name
306
0
        if(tmp == "PF_BYTE_RGB")
307
0
            return PF_BYTE_RGB;
308
0
        if(tmp == "PF_BYTE_RGBA")
309
0
            return PF_BYTE_RGBA;
310
0
        if(tmp == "PF_BYTE_BGR")
311
0
            return PF_BYTE_BGR;
312
0
        if(tmp == "PF_BYTE_BGRA")
313
0
            return PF_BYTE_BGRA;
314
315
0
        return PF_UNKNOWN;
316
0
    }
317
    //-----------------------------------------------------------------------
318
    PixelFormat PixelUtil::getFormatForBitDepths(PixelFormat fmt, ushort integerBits, ushort floatBits)
319
0
    {
320
0
        switch (integerBits)
321
0
        {
322
0
        case 16:
323
0
            switch (fmt)
324
0
            {
325
0
            case PF_R8G8B8:
326
0
            case PF_X8R8G8B8:
327
0
                return PF_R5G6B5;
328
329
0
            case PF_B8G8R8:
330
0
            case PF_X8B8G8R8:
331
0
                return PF_B5G6R5;
332
333
0
            case PF_A8R8G8B8:
334
0
            case PF_R8G8B8A8:
335
0
            case PF_A8B8G8R8:
336
0
            case PF_B8G8R8A8:
337
0
                return PF_A4R4G4B4;
338
339
0
            case PF_A2R10G10B10:
340
0
            case PF_A2B10G10R10:
341
0
                return PF_A1R5G5B5;
342
343
0
            default:
344
                // use original image format
345
0
                break;
346
0
            }
347
0
            break;
348
349
0
        case 32:
350
0
            switch (fmt)
351
0
            {
352
0
            case PF_R5G6B5:
353
0
                return PF_X8R8G8B8;
354
355
0
            case PF_B5G6R5:
356
0
                return PF_X8B8G8R8;
357
358
0
            case PF_A4R4G4B4:
359
0
                return PF_A8R8G8B8;
360
361
0
            case PF_A1R5G5B5:
362
0
                return PF_A2R10G10B10;
363
364
0
            default:
365
                // use original image format
366
0
                break;
367
0
            }
368
0
            break;
369
370
0
        default:
371
            // use original image format
372
0
            break;
373
0
        }
374
375
0
        switch (floatBits)
376
0
        {
377
0
        case 16:
378
0
            switch (fmt)
379
0
            {
380
0
            case PF_FLOAT32_R:
381
0
                return PF_FLOAT16_R;
382
383
0
            case PF_FLOAT32_RGB:
384
0
                return PF_FLOAT16_RGB;
385
386
0
            case PF_FLOAT32_RGBA:
387
0
                return PF_FLOAT16_RGBA;
388
389
0
            default:
390
                // use original image format
391
0
                break;
392
0
            }
393
0
            break;
394
395
0
        case 32:
396
0
            switch (fmt)
397
0
            {
398
0
            case PF_FLOAT16_R:
399
0
                return PF_FLOAT32_R;
400
401
0
            case PF_FLOAT16_RGB:
402
0
                return PF_FLOAT32_RGB;
403
404
0
            case PF_FLOAT16_RGBA:
405
0
                return PF_FLOAT32_RGBA;
406
407
0
            default:
408
                // use original image format
409
0
                break;
410
0
            }
411
0
            break;
412
413
0
        default:
414
            // use original image format
415
0
            break;
416
0
        }
417
418
0
        return fmt;
419
0
    }
420
    //-----------------------------------------------------------------------
421
    /*************************************************************************
422
    * Pixel packing/unpacking utilities
423
    */
424
    void PixelUtil::packColour(const uint8 r, const uint8 g, const uint8 b, const uint8 a, const PixelFormat pf,  void* dest)
425
0
    {
426
0
        const PixelFormatDescription &des = getDescriptionFor(pf);
427
0
        if(des.flags & PFF_NATIVEENDIAN) {
428
            // Shortcut for integer formats packing
429
0
            unsigned int value = ((Bitwise::fixedToFixed(r, 8, des.rbits)<<des.rshift) & des.rmask) |
430
0
                ((Bitwise::fixedToFixed(g, 8, des.gbits)<<des.gshift) & des.gmask) |
431
0
                ((Bitwise::fixedToFixed(b, 8, des.bbits)<<des.bshift) & des.bmask) |
432
0
                ((Bitwise::fixedToFixed(a, 8, des.abits)<<des.ashift) & des.amask);
433
            // And write to memory
434
0
            Bitwise::intWrite(dest, des.elemBytes, value);
435
0
        } else {
436
            // Convert to float
437
0
            packColour((float)r/255.0f,(float)g/255.0f,(float)b/255.0f,(float)a/255.0f, pf, dest);
438
0
        }
439
0
    }
440
    //-----------------------------------------------------------------------
441
    void PixelUtil::packColour(const float r, const float g, const float b, const float a, const PixelFormat pf,  void* dest)
442
0
    {
443
        // Catch-it-all here
444
0
        const PixelFormatDescription &des = getDescriptionFor(pf);
445
0
        if(des.flags & PFF_NATIVEENDIAN) {
446
            // Do the packing
447
            //std::cerr << dest << " " << r << " " << g <<  " " << b << " " << a << std::endl;
448
0
            const unsigned int value = ((Bitwise::floatToFixed(r, des.rbits)<<des.rshift) & des.rmask) |
449
0
                ((Bitwise::floatToFixed(g, des.gbits)<<des.gshift) & des.gmask) |
450
0
                ((Bitwise::floatToFixed(b, des.bbits)<<des.bshift) & des.bmask) |
451
0
                ((Bitwise::floatToFixed(a, des.abits)<<des.ashift) & des.amask);
452
            // And write to memory
453
0
            Bitwise::intWrite(dest, des.elemBytes, value);
454
0
        } else {
455
0
            switch(pf)
456
0
            {
457
0
            case PF_FLOAT32_R:
458
0
                ((float*)dest)[0] = r;
459
0
                break;
460
0
            case PF_FLOAT32_GR:
461
0
                ((float*)dest)[0] = g;
462
0
                ((float*)dest)[1] = r;
463
0
                break;
464
0
            case PF_FLOAT32_RGB:
465
0
                ((float*)dest)[0] = r;
466
0
                ((float*)dest)[1] = g;
467
0
                ((float*)dest)[2] = b;
468
0
                break;
469
0
            case PF_FLOAT32_RGBA:
470
0
                ((float*)dest)[0] = r;
471
0
                ((float*)dest)[1] = g;
472
0
                ((float*)dest)[2] = b;
473
0
                ((float*)dest)[3] = a;
474
0
                break;
475
0
            case PF_DEPTH16:
476
0
            case PF_FLOAT16_R:
477
0
                ((uint16*)dest)[0] = Bitwise::floatToHalf(r);
478
0
                break;
479
0
            case PF_FLOAT16_GR:
480
0
                ((uint16*)dest)[0] = Bitwise::floatToHalf(g);
481
0
                ((uint16*)dest)[1] = Bitwise::floatToHalf(r);
482
0
                break;
483
0
            case PF_FLOAT16_RGB:
484
0
                ((uint16*)dest)[0] = Bitwise::floatToHalf(r);
485
0
                ((uint16*)dest)[1] = Bitwise::floatToHalf(g);
486
0
                ((uint16*)dest)[2] = Bitwise::floatToHalf(b);
487
0
                break;
488
0
            case PF_FLOAT16_RGBA:
489
0
                ((uint16*)dest)[0] = Bitwise::floatToHalf(r);
490
0
                ((uint16*)dest)[1] = Bitwise::floatToHalf(g);
491
0
                ((uint16*)dest)[2] = Bitwise::floatToHalf(b);
492
0
                ((uint16*)dest)[3] = Bitwise::floatToHalf(a);
493
0
                break;
494
0
            case PF_SHORT_RGB:
495
0
                ((uint16*)dest)[0] = (uint16)Bitwise::floatToFixed(r, 16);
496
0
                ((uint16*)dest)[1] = (uint16)Bitwise::floatToFixed(g, 16);
497
0
                ((uint16*)dest)[2] = (uint16)Bitwise::floatToFixed(b, 16);
498
0
                break;
499
0
            case PF_SHORT_RGBA:
500
0
                ((uint16*)dest)[0] = (uint16)Bitwise::floatToFixed(r, 16);
501
0
                ((uint16*)dest)[1] = (uint16)Bitwise::floatToFixed(g, 16);
502
0
                ((uint16*)dest)[2] = (uint16)Bitwise::floatToFixed(b, 16);
503
0
                ((uint16*)dest)[3] = (uint16)Bitwise::floatToFixed(a, 16);
504
0
                break;
505
0
            case PF_BYTE_LA:
506
0
                ((uint8*)dest)[0] = (uint8)Bitwise::floatToFixed(r, 8);
507
0
                ((uint8*)dest)[1] = (uint8)Bitwise::floatToFixed(a, 8);
508
0
                break;
509
0
            case PF_A8:
510
0
                ((uint8*)dest)[0] = (uint8)Bitwise::floatToFixed(r, 8);
511
0
                break;
512
0
            default:
513
                // Not yet supported
514
0
                OGRE_EXCEPT(
515
0
                    Exception::ERR_NOT_IMPLEMENTED,
516
0
                    "pack to "+getFormatName(pf)+" not implemented",
517
0
                    "PixelUtil::packColour");
518
0
                break;
519
0
            }
520
0
        }
521
0
    }
522
    //-----------------------------------------------------------------------
523
    void PixelUtil::unpackColour(uint8 *r, uint8 *g, uint8 *b, uint8 *a, PixelFormat pf,  const void* src)
524
0
    {
525
0
        const PixelFormatDescription &des = getDescriptionFor(pf);
526
0
        if(des.flags & PFF_NATIVEENDIAN) {
527
            // Shortcut for integer formats unpacking
528
0
            const unsigned int value = Bitwise::intRead(src, des.elemBytes);
529
0
            if(des.flags & PFF_LUMINANCE)
530
0
            {
531
                // Luminance format -- only rbits used
532
0
                *r = *g = *b = (uint8)Bitwise::fixedToFixed(
533
0
                    (value & des.rmask)>>des.rshift, des.rbits, 8);
534
0
            }
535
0
            else
536
0
            {
537
0
                *r = (uint8)Bitwise::fixedToFixed((value & des.rmask)>>des.rshift, des.rbits, 8);
538
0
                *g = (uint8)Bitwise::fixedToFixed((value & des.gmask)>>des.gshift, des.gbits, 8);
539
0
                *b = (uint8)Bitwise::fixedToFixed((value & des.bmask)>>des.bshift, des.bbits, 8);
540
0
            }
541
0
            if(des.flags & PFF_HASALPHA)
542
0
            {
543
0
                *a = (uint8)Bitwise::fixedToFixed((value & des.amask)>>des.ashift, des.abits, 8);
544
0
            }
545
0
            else
546
0
            {
547
0
                *a = 255; // No alpha, default a component to full
548
0
            }
549
0
        } else {
550
            // Do the operation with the more generic floating point
551
0
            float rr = 0, gg = 0, bb = 0, aa = 0;
552
0
            unpackColour(&rr,&gg,&bb,&aa, pf, src);
553
0
            *r = (uint8)Bitwise::floatToFixed(rr, 8);
554
0
            *g = (uint8)Bitwise::floatToFixed(gg, 8);
555
0
            *b = (uint8)Bitwise::floatToFixed(bb, 8);
556
0
            *a = (uint8)Bitwise::floatToFixed(aa, 8);
557
0
        }
558
0
    }
559
    //-----------------------------------------------------------------------
560
    void PixelUtil::unpackColour(float *r, float *g, float *b, float *a,
561
        PixelFormat pf,  const void* src)
562
0
    {
563
0
        const PixelFormatDescription &des = getDescriptionFor(pf);
564
0
        if(des.flags & PFF_NATIVEENDIAN) {
565
            // Shortcut for integer formats unpacking
566
0
            const unsigned int value = Bitwise::intRead(src, des.elemBytes);
567
0
            if(des.flags & PFF_LUMINANCE)
568
0
            {
569
                // Luminance format -- only rbits used
570
0
                *r = *g = *b = Bitwise::fixedToFloat(
571
0
                    (value & des.rmask)>>des.rshift, des.rbits);
572
0
            }
573
0
            else
574
0
            {
575
0
                *r = Bitwise::fixedToFloat((value & des.rmask)>>des.rshift, des.rbits);
576
0
                *g = Bitwise::fixedToFloat((value & des.gmask)>>des.gshift, des.gbits);
577
0
                *b = Bitwise::fixedToFloat((value & des.bmask)>>des.bshift, des.bbits);
578
0
            }
579
0
            if(des.flags & PFF_HASALPHA)
580
0
            {
581
0
                *a = Bitwise::fixedToFloat((value & des.amask)>>des.ashift, des.abits);
582
0
            }
583
0
            else
584
0
            {
585
0
                *a = 1.0f; // No alpha, default a component to full
586
0
            }
587
0
        } else {
588
0
            switch(pf)
589
0
            {
590
0
            case PF_FLOAT32_R:
591
0
                *r = *g = *b = ((const float*)src)[0];
592
0
                *a = 1.0f;
593
0
                break;
594
0
            case PF_FLOAT32_GR:
595
0
                *g = ((const float*)src)[0];
596
0
                *r = *b = ((const float*)src)[1];
597
0
                *a = 1.0f;
598
0
                break;
599
0
            case PF_FLOAT32_RGB:
600
0
                *r = ((const float*)src)[0];
601
0
                *g = ((const float*)src)[1];
602
0
                *b = ((const float*)src)[2];
603
0
                *a = 1.0f;
604
0
                break;
605
0
            case PF_FLOAT32_RGBA:
606
0
                *r = ((const float*)src)[0];
607
0
                *g = ((const float*)src)[1];
608
0
                *b = ((const float*)src)[2];
609
0
                *a = ((const float*)src)[3];
610
0
                break;
611
0
            case PF_FLOAT16_R:
612
0
                *r = *g = *b = Bitwise::halfToFloat(((const uint16*)src)[0]);
613
0
                *a = 1.0f;
614
0
                break;
615
0
            case PF_FLOAT16_GR:
616
0
                *g = Bitwise::halfToFloat(((const uint16*)src)[0]);
617
0
                *r = *b = Bitwise::halfToFloat(((const uint16*)src)[1]);
618
0
                *a = 1.0f;
619
0
                break;
620
0
            case PF_FLOAT16_RGB:
621
0
                *r = Bitwise::halfToFloat(((const uint16*)src)[0]);
622
0
                *g = Bitwise::halfToFloat(((const uint16*)src)[1]);
623
0
                *b = Bitwise::halfToFloat(((const uint16*)src)[2]);
624
0
                *a = 1.0f;
625
0
                break;
626
0
            case PF_FLOAT16_RGBA:
627
0
                *r = Bitwise::halfToFloat(((const uint16*)src)[0]);
628
0
                *g = Bitwise::halfToFloat(((const uint16*)src)[1]);
629
0
                *b = Bitwise::halfToFloat(((const uint16*)src)[2]);
630
0
                *a = Bitwise::halfToFloat(((const uint16*)src)[3]);
631
0
                break;
632
0
            case PF_SHORT_RGB:
633
0
                *r = Bitwise::fixedToFloat(((const uint16*)src)[0], 16);
634
0
                *g = Bitwise::fixedToFloat(((const uint16*)src)[1], 16);
635
0
                *b = Bitwise::fixedToFloat(((const uint16*)src)[2], 16);
636
0
                *a = 1.0f;
637
0
                break;
638
0
            case PF_SHORT_RGBA:
639
0
                *r = Bitwise::fixedToFloat(((const uint16*)src)[0], 16);
640
0
                *g = Bitwise::fixedToFloat(((const uint16*)src)[1], 16);
641
0
                *b = Bitwise::fixedToFloat(((const uint16*)src)[2], 16);
642
0
                *a = Bitwise::fixedToFloat(((const uint16*)src)[3], 16);
643
0
                break;
644
0
            case PF_BYTE_LA:
645
0
                *r = *g = *b = Bitwise::fixedToFloat(((const uint8*)src)[0], 8);
646
0
                *a = Bitwise::fixedToFloat(((const uint8*)src)[1], 8);
647
0
                break;
648
0
            default:
649
                // Not yet supported
650
0
                OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED,
651
0
                    "unpack from "+getFormatName(pf)+" not implemented",
652
0
                    "PixelUtil::unpackColour");
653
0
                break;
654
0
            }
655
0
        }
656
0
    }
657
    //-----------------------------------------------------------------------
658
    /* Convert pixels from one format to another */
659
    void PixelUtil::bulkPixelConversion(const PixelBox &src, const PixelBox &dst)
660
0
    {
661
0
        OgreAssert(src.getSize() == dst.getSize(), "");
662
663
        // Check for compressed formats, we don't support decompression, compression or recoding
664
0
        if(PixelUtil::isCompressed(src.format) || PixelUtil::isCompressed(dst.format))
665
0
        {
666
0
            OgreAssert(src.format == dst.format && src.isConsecutive() && dst.isConsecutive(),
667
0
                       "This method can not be used to compress or decompress images");
668
            // we can copy with slice granularity, useful for Tex2DArray handling
669
0
            size_t bytesPerSlice = getMemorySize(src.getWidth(), src.getHeight(), 1, src.format);
670
0
            memcpy(dst.data + bytesPerSlice * dst.front, src.data + bytesPerSlice * src.front,
671
0
                   bytesPerSlice * src.getDepth());
672
0
            return;
673
0
        }
674
675
        // The easy case
676
0
        if(src.format == dst.format) {
677
0
            uint8 *srcptr = src.getTopLeftFrontPixelPtr();
678
0
            uint8 *dstptr = dst.getTopLeftFrontPixelPtr();
679
680
            // Everything consecutive?
681
0
            if(src.isConsecutive() && dst.isConsecutive())
682
0
            {
683
0
                memcpy(dstptr, srcptr, src.getConsecutiveSize());
684
0
                return;
685
0
            }
686
687
0
            const size_t srcPixelSize = PixelUtil::getNumElemBytes(src.format);
688
0
            const size_t dstPixelSize = PixelUtil::getNumElemBytes(dst.format);
689
690
            // Calculate pitches+skips in bytes
691
0
            const size_t srcRowPitchBytes = src.rowPitch*srcPixelSize;
692
            //const size_t srcRowSkipBytes = src.getRowSkip()*srcPixelSize;
693
0
            const size_t srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
694
695
0
            const size_t dstRowPitchBytes = dst.rowPitch*dstPixelSize;
696
            //const size_t dstRowSkipBytes = dst.getRowSkip()*dstPixelSize;
697
0
            const size_t dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
698
699
            // Otherwise, copy per row
700
0
            const size_t rowSize = src.getWidth()*srcPixelSize;
701
0
            for(size_t z=src.front; z<src.back; z++)
702
0
            {
703
0
                for(size_t y=src.top; y<src.bottom; y++)
704
0
                {
705
0
                    memcpy(dstptr, srcptr, rowSize);
706
0
                    srcptr += srcRowPitchBytes;
707
0
                    dstptr += dstRowPitchBytes;
708
0
                }
709
0
                srcptr += srcSliceSkipBytes;
710
0
                dstptr += dstSliceSkipBytes;
711
0
            }
712
0
            return;
713
0
        }
714
        // Converting to PF_X8R8G8B8 is exactly the same as converting to
715
        // PF_A8R8G8B8. (same with PF_X8B8G8R8 and PF_A8B8G8R8)
716
0
        if(dst.format == PF_X8R8G8B8 || dst.format == PF_X8B8G8R8)
717
0
        {
718
            // Do the same conversion, with PF_A8R8G8B8, which has a lot of
719
            // optimized conversions
720
0
            PixelBox tempdst = dst;
721
0
            tempdst.format = dst.format==PF_X8R8G8B8?PF_A8R8G8B8:PF_A8B8G8R8;
722
0
            bulkPixelConversion(src, tempdst);
723
0
            return;
724
0
        }
725
        // Converting from PF_X8R8G8B8 is exactly the same as converting from
726
        // PF_A8R8G8B8, given that the destination format does not have alpha.
727
0
        if((src.format == PF_X8R8G8B8||src.format == PF_X8B8G8R8) && !hasAlpha(dst.format))
728
0
        {
729
            // Do the same conversion, with PF_A8R8G8B8, which has a lot of
730
            // optimized conversions
731
0
            PixelBox tempsrc = src;
732
0
            tempsrc.format = src.format==PF_X8R8G8B8?PF_A8R8G8B8:PF_A8B8G8R8;
733
0
            bulkPixelConversion(tempsrc, dst);
734
0
            return;
735
0
        }
736
737
// NB VC6 can't handle the templates required for optimised conversion, tough
738
0
#if OGRE_COMPILER != OGRE_COMPILER_MSVC || OGRE_COMP_VER >= 1300
739
        // Is there a specialized, inlined, conversion?
740
0
        if(doOptimizedConversion(src, dst))
741
0
        {
742
            // If so, good
743
0
            return;
744
0
        }
745
0
#endif
746
747
0
        const size_t srcPixelSize = PixelUtil::getNumElemBytes(src.format);
748
0
        const size_t dstPixelSize = PixelUtil::getNumElemBytes(dst.format);
749
0
        uint8* srcptr = src.getTopLeftFrontPixelPtr();
750
0
        uint8* dstptr = dst.getTopLeftFrontPixelPtr();
751
752
        // Old way, not taking into account box dimensions
753
        //uint8 *srcptr = static_cast<uint8*>(src.data), *dstptr = static_cast<uint8*>(dst.data);
754
755
        // Calculate pitches+skips in bytes
756
0
        const size_t srcRowSkipBytes = src.getRowSkip()*srcPixelSize;
757
0
        const size_t srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
758
0
        const size_t dstRowSkipBytes = dst.getRowSkip()*dstPixelSize;
759
0
        const size_t dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
760
761
        // The brute force fallback
762
0
        float r = 0, g = 0, b = 0, a = 1;
763
0
        for(size_t z=src.front; z<src.back; z++)
764
0
        {
765
0
            for(size_t y=src.top; y<src.bottom; y++)
766
0
            {
767
0
                for(size_t x=src.left; x<src.right; x++)
768
0
                {
769
0
                    unpackColour(&r, &g, &b, &a, src.format, srcptr);
770
0
                    packColour(r, g, b, a, dst.format, dstptr);
771
0
                    srcptr += srcPixelSize;
772
0
                    dstptr += dstPixelSize;
773
0
                }
774
0
                srcptr += srcRowSkipBytes;
775
0
                dstptr += dstRowSkipBytes;
776
0
            }
777
0
            srcptr += srcSliceSkipBytes;
778
0
            dstptr += dstSliceSkipBytes;
779
0
        }
780
0
    }
781
    //-----------------------------------------------------------------------
782
    void PixelUtil::bulkPixelVerticalFlip(const PixelBox &box)
783
0
    {
784
        // Check for compressed formats, we don't support decompression, compression or recoding
785
0
        OgreAssert(!PixelUtil::isCompressed(box.format), "This method can not be used for compressed formats");
786
        
787
0
        const size_t pixelSize = PixelUtil::getNumElemBytes(box.format);
788
0
        const size_t copySize = box.getWidth() * pixelSize;
789
790
        // Calculate pitches in bytes
791
0
        const size_t rowPitchBytes = box.rowPitch * pixelSize;
792
0
        const size_t slicePitchBytes = box.slicePitch * pixelSize;
793
794
0
        uint8 *basesrcptr = box.getTopLeftFrontPixelPtr();
795
0
        uint8 *basedstptr = basesrcptr + (box.bottom - box.top - 1) * rowPitchBytes;
796
0
        uint8* tmpptr = (uint8*)OGRE_MALLOC_SIMD(copySize, MEMCATEGORY_GENERAL);
797
        
798
        // swap rows
799
0
        const size_t halfRowCount = (box.bottom - box.top) >> 1;
800
0
        for(size_t z = box.front; z < box.back; z++)
801
0
        {
802
0
            uint8* srcptr = basesrcptr;
803
0
            uint8* dstptr = basedstptr;
804
0
            for(size_t y = 0; y < halfRowCount; y++)
805
0
            {
806
                // swap rows
807
0
                memcpy(tmpptr, dstptr, copySize);
808
0
                memcpy(dstptr, srcptr, copySize);
809
0
                memcpy(srcptr, tmpptr, copySize);
810
0
                srcptr += rowPitchBytes;
811
0
                dstptr -= rowPitchBytes;
812
0
            }
813
0
            basesrcptr += slicePitchBytes;
814
0
            basedstptr += slicePitchBytes;
815
0
        }
816
        
817
0
        OGRE_FREE_SIMD(tmpptr, MEMCATEGORY_GENERAL);
818
0
    }
819
820
    ColourValue PixelBox::getColourAt(size_t x, size_t y, size_t z) const
821
0
    {
822
0
        ColourValue cv;
823
824
0
        size_t pixelSize = PixelUtil::getNumElemBytes(format);
825
0
        size_t pixelOffset = pixelSize * (z * slicePitch + y * rowPitch + x);
826
0
        PixelUtil::unpackColour(&cv, format, (unsigned char *)data + pixelOffset);
827
828
0
        return cv;
829
0
    }
830
831
    void PixelBox::setColourAt(ColourValue const &cv, size_t x, size_t y, size_t z)
832
0
    {
833
0
        size_t pixelSize = PixelUtil::getNumElemBytes(format);
834
0
        size_t pixelOffset = pixelSize * (z * slicePitch + y * rowPitch + x);
835
0
        PixelUtil::packColour(cv, format, (unsigned char *)data + pixelOffset);
836
0
    }
837
838
}