Celestia

Форк
0
/
dds_decompress.cpp 
339 строк · 12.0 Кб
1
#include <array>
2

3
#include "dds_decompress.h"
4

5
/*
6
DXT1/DXT3/DXT5 texture decompression
7

8
The original code is from Benjamin Dobell, see below for details. Compared to
9
the original this one adds DXT3 decompression, is valid C89, and is x64
10
compatible as it uses fixed size integers everywhere. It also uses a different
11
PackRGBA order.
12

13
---
14

15
Copyright (c) 2012, Matthäus G. "Anteru" Chajdas (http://anteru.net)
16

17
Permission is hereby granted, free of charge, to any person obtaining a copy of
18
this software and associated documentation files (the "Software"), to deal in
19
the Software without restriction, including without limitation the rights to
20
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
21
of the Software, and to permit persons to whom the Software is furnished to do
22
so, subject to the following conditions:
23

24
The above copyright notice and this permission notice shall be included in all
25
copies or substantial portions of the Software.
26

27
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33
SOFTWARE.
34

35
---
36

37
Copyright (C) 2009 Benjamin Dobell, Glass Echidna
38

39
Permission is hereby granted, free of charge, to any person obtaining a copy of
40
this software and associated documentation files (the "Software"), to deal in
41
the Software without restriction, including without limitation the rights to
42
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
43
of the Software, and to permit persons to whom the Software is furnished to do
44
so, subject to the following conditions:
45

46
The above copyright notice and this permission notice shall be included in all
47
copies or substantial portions of the Software.
48

49
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
52
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
54
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
55
SOFTWARE.
56

57
---
58
*/
59

60
namespace celestia::engine
61
{
62
namespace
63
{
64

65
constexpr std::uint32_t PackRGBA(std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint8_t a)
66
{
67
    return static_cast<std::uint32_t>(r) |
68
           static_cast<std::uint32_t>(g) << 8 |
69
           static_cast<std::uint32_t>(b) << 16 |
70
           static_cast<std::uint32_t>(a) << 24;
71
}
72

73
constexpr std::uint16_t PackRG(std::uint8_t r, std::uint8_t g)
74
{
75
    return static_cast<std::uint16_t>(r) | static_cast<std::uint16_t>(g) << 8;
76
}
77

78
void DecompressBlockDXT1Internal(const std::uint8_t* block,
79
                                 std::uint32_t* output,
80
                                 std::uint32_t outputStride,
81
                                 bool transparent0,
82
                                 const std::uint8_t* alphaValues)
83
{
84
    std::uint16_t color0 = *reinterpret_cast<const std::uint16_t*>(block);
85
    std::uint16_t color1 = *reinterpret_cast<const std::uint16_t*>(block + 2);
86

87
    std::uint32_t temp = (color0 >> 11) * 255 + 16;
88
    std::uint8_t r0 = static_cast<std::uint8_t>((temp / 32 + temp) / 32);
89
    temp = ((color0 & 0x07E0) >> 5) * 255 + 32;
90
    std::uint8_t g0 = static_cast<std::uint8_t>((temp / 64 + temp) / 64);
91
    temp = (color0 & 0x001F) * 255 + 16;
92
    std::uint8_t b0 = static_cast<std::uint8_t>((temp / 32 + temp) / 32);
93

94
    temp = (color1 >> 11) * 255 + 16;
95
    std::uint8_t r1 = static_cast<std::uint8_t>((temp / 32 + temp) / 32);
96
    temp = ((color1 & 0x07E0) >> 5) * 255 + 32;
97
    std::uint8_t g1 = static_cast<std::uint8_t>((temp / 64 + temp) / 64);
98
    temp = (color1 & 0x001F) * 255 + 16;
99
    std::uint8_t b1 = static_cast<std::uint8_t>((temp / 32 + temp) / 32);
100

101
    std::uint32_t code = *reinterpret_cast<const std::uint32_t*>(block + 4);
102

103
    if (color0 > color1)
104
    {
105
        for (int j = 0; j < 4; ++j)
106
        {
107
            for (int i = 0; i < 4; ++i)
108
            {
109
                std::uint8_t alpha = alphaValues[j * 4 + i];
110
                std::uint32_t finalColor = 0u;
111

112
                switch (std::uint32_t positionCode = (code >> 2 * (4 * j + i)) & 0x03; positionCode)
113
                {
114
                case 0:
115
                    finalColor = PackRGBA(r0, g0, b0, alpha);
116
                    break;
117
                case 1:
118
                    finalColor = PackRGBA(r1, g1, b1, alpha);
119
                    break;
120
                case 2:
121
                    finalColor = PackRGBA((2 * r0 + r1) / 3, (2 * g0 + g1) / 3,
122
                                          (2 * b0 + b1) / 3, alpha);
123
                    break;
124
                case 3:
125
                    finalColor = PackRGBA((r0 + 2 * r1) / 3, (g0 + 2 * g1) / 3,
126
                                          (b0 + 2 * b1) / 3, alpha);
127
                    break;
128
                }
129
                if (transparent0 && (finalColor == PackRGBA(0, 0, 0, 0xff)))
130
                {
131
                    alpha = 0;
132
                    finalColor = 0u;
133
                }
134
                output[j * outputStride + i] = finalColor;
135
            }
136
        }
137
    }
138
    else
139
    {
140
        for (int j = 0; j < 4; ++j)
141
        {
142
            for (int i = 0; i < 4; ++i)
143
            {
144
                std::uint8_t alpha = alphaValues[j * 4 + i];
145

146
                std::uint32_t finalColor = 0u;
147
                std::uint32_t positionCode = (code >> 2 * (4 * j + i)) & 0x03;
148

149
                switch (positionCode)
150
                {
151
                case 0:
152
                    finalColor = PackRGBA(r0, g0, b0, alpha);
153
                    break;
154
                case 1:
155
                    finalColor = PackRGBA(r1, g1, b1, alpha);
156
                    break;
157
                case 2:
158
                    finalColor = PackRGBA((r0 + r1) / 2, (g0 + g1) / 2, (b0 + b1) / 2, alpha);
159
                    break;
160
                case 3:
161
                    finalColor = PackRGBA(0, 0, 0, alpha);
162
                    break;
163
                }
164

165
                if (transparent0 && (finalColor == PackRGBA(0, 0, 0, 0xff)))
166
                {
167
                    alpha = 0;
168
                    finalColor = 0;
169
                }
170

171
                output[j * outputStride + i] = finalColor;
172
            }
173
        }
174
    }
175
}
176

177
} // namespace
178

179
void DecompressBlockDXT1(std::uint32_t x,
180
                         std::uint32_t y,
181
                         std::uint32_t width,
182
                         const std::uint8_t* blockStorage,
183
                         bool transparent0,
184
                         std::uint32_t* image)
185
{
186
    static std::array<const std::uint8_t, 16> constAlpha = {
187
        255, 255, 255, 255,
188
        255, 255, 255, 255,
189
        255, 255, 255, 255,
190
        255, 255, 255, 255
191
    };
192

193
    DecompressBlockDXT1Internal(blockStorage, 
194
                                image + x + (y * width),
195
                                width,
196
                                transparent0,
197
                                constAlpha.data());
198
}
199

200
void DecompressBlockDXT5(std::uint32_t x,
201
                         std::uint32_t y,
202
                         std::uint32_t width,
203
                         const std::uint8_t* blockStorage,
204
                         bool transparent0,
205
                         std::uint32_t* image)
206
{
207
    std::uint8_t alpha0 = *(blockStorage);
208
    std::uint8_t alpha1 = *(blockStorage + 1);
209

210
    const std::uint8_t* bits = blockStorage + 2;
211
    std::uint32_t alphaCode1 = PackRGBA(bits[2], bits[3], bits[4], bits[5]);
212
    std::uint16_t alphaCode2 = PackRG(bits[0], bits[1]);
213

214
    std::uint16_t color0 = *reinterpret_cast<const std::uint16_t*>(blockStorage + 8);
215
    std::uint16_t color1 = *reinterpret_cast<const std::uint16_t*>(blockStorage + 10);
216

217
    std::uint32_t temp = (color0 >> 11) * 255 + 16;
218
    std::uint8_t r0 = (uint8_t)((temp / 32 + temp) / 32);
219
    temp = ((color0 & 0x07E0) >> 5) * 255 + 32;
220
    std::uint8_t g0 = (uint8_t)((temp / 64 + temp) / 64);
221
    temp = (color0 & 0x001F) * 255 + 16;
222
    std::uint8_t b0 = (uint8_t)((temp / 32 + temp) / 32);
223

224
    temp = (color1 >> 11) * 255 + 16;
225
    std::uint8_t r1 = (uint8_t)((temp / 32 + temp) / 32);
226
    temp = ((color1 & 0x07E0) >> 5) * 255 + 32;
227
    std::uint8_t g1 = (uint8_t)((temp / 64 + temp) / 64);
228
    temp = (color1 & 0x001F) * 255 + 16;
229
    std::uint8_t b1 = (uint8_t)((temp / 32 + temp) / 32);
230

231
    std::uint32_t code = *reinterpret_cast<const std::uint32_t*>(blockStorage + 12);
232

233
    for (int j = 0; j < 4; j++)
234
    {
235
        for (int i = 0; i < 4; i++)
236
        {
237
            std::uint8_t finalAlpha;
238
            int alphaCode;
239
            int alphaCodeIndex = 3 * (4 * j + i);
240

241
            if (alphaCodeIndex <= 12)
242
            {
243
                alphaCode = (alphaCode2 >> alphaCodeIndex) & 0x07;
244
            }
245
            else if (alphaCodeIndex == 15)
246
            {
247
                alphaCode = (alphaCode2 >> 15) | ((alphaCode1 << 1) & 0x06);
248
            }
249
            else /* alphaCodeIndex >= 18 && alphaCodeIndex <= 45 */
250
            {
251
                alphaCode = (alphaCode1 >> (alphaCodeIndex - 16)) & 0x07;
252
            }
253

254
            if (alphaCode == 0)
255
            {
256
                finalAlpha = alpha0;
257
            }
258
            else if (alphaCode == 1)
259
            {
260
                finalAlpha = alpha1;
261
            }
262
            else
263
            {
264
                if (alpha0 > alpha1)
265
                {
266
                    finalAlpha = static_cast<std::uint8_t>(((8 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 7);
267
                }
268
                else
269
                {
270
                    if (alphaCode == 6)
271
                    {
272
                        finalAlpha = 0;
273
                    }
274
                    else if (alphaCode == 7)
275
                    {
276
                        finalAlpha = 255;
277
                    }
278
                    else
279
                    {
280
                        finalAlpha = static_cast<std::uint8_t>(((6 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 5);
281
                    }
282
                }
283
            }
284

285
            std::uint8_t colorCode = (code >> 2 * (4 * j + i)) & 0x03;
286
            std::uint32_t finalColor = 0;
287

288
            switch (colorCode)
289
            {
290
            case 0:
291
                finalColor = PackRGBA(r0, g0, b0, finalAlpha);
292
                break;
293
            case 1:
294
                finalColor = PackRGBA(r1, g1, b1, finalAlpha);
295
                break;
296
            case 2:
297
                finalColor = PackRGBA((2 * r0 + r1) / 3, (2 * g0 + g1) / 3,
298
                                      (2 * b0 + b1) / 3, finalAlpha);
299
                break;
300
            case 3:
301
                finalColor = PackRGBA((r0 + 2 * r1) / 3, (g0 + 2 * g1) / 3,
302
                                      (b0 + 2 * b1) / 3, finalAlpha);
303
                break;
304
            }
305

306
            image[i + x + (width * (y + j))] = finalColor;
307
        }
308
    }
309
}
310

311
void DecompressBlockDXT3(std::uint32_t x,
312
                         std::uint32_t y,
313
                         std::uint32_t width,
314
                         const std::uint8_t* blockStorage,
315
                         bool transparent0,
316
                         std::uint32_t* image)
317
{
318
    std::array<std::uint8_t, 16> alphaValues = { 0 };
319

320
    for (int i = 0; i < 4; ++i)
321
    {
322
        const std::uint16_t* alphaData = reinterpret_cast<const std::uint16_t*>(blockStorage);
323

324
        alphaValues[i * 4 + 0] = (((*alphaData) >> 0) & 0xF) * 17;
325
        alphaValues[i * 4 + 1] = (((*alphaData) >> 4) & 0xF) * 17;
326
        alphaValues[i * 4 + 2] = (((*alphaData) >> 8) & 0xF) * 17;
327
        alphaValues[i * 4 + 3] = (((*alphaData) >> 12) & 0xF) * 17;
328

329
        blockStorage += 2;
330
    }
331

332
    DecompressBlockDXT1Internal(blockStorage,
333
                                image + x + (y * width),
334
                                width,
335
                                transparent0,
336
                                alphaValues.data());
337
}
338

339
} // namespace celestia::engine
340

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.