]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_dxt.h
Initial vogl checkin
[vogl] / src / voglcore / vogl_dxt.h
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  *
25  **************************************************************************/
26
27 // File: vogl_dxt.h
28 #pragma once
29
30 #include "vogl_core.h"
31 #include "vogl.h"
32 #include "vogl_color.h"
33 #include "vogl_vec.h"
34 #include "vogl_rand.h"
35 #include "vogl_sparse_bit_array.h"
36 #include "vogl_hash_map.h"
37 #include <map>
38
39 #define VOGL_DXT_ALT_ROUNDING 1
40
41 namespace vogl
42 {
43     enum dxt_constants
44     {
45         cDXT1BytesPerBlock = 8U,
46         cDXT5NBytesPerBlock = 16U,
47         cDXT5SelectorBits = 3U,
48         cDXT5SelectorValues = 1U << cDXT5SelectorBits,
49         cDXT5SelectorMask = cDXT5SelectorValues - 1U,
50         cDXT1SelectorBits = 2U,
51         cDXT1SelectorValues = 1U << cDXT1SelectorBits,
52         cDXT1SelectorMask = cDXT1SelectorValues - 1U,
53         cDXTBlockShift = 2U,
54         cDXTBlockSize = 1U << cDXTBlockShift
55     };
56
57     enum dxt_format
58     {
59         cDXTInvalid = -1,
60
61         // cDXT1/1A must appear first!
62         cDXT1,
63         cDXT1A,
64         cDXT3,
65         cDXT5,
66         cDXT5A,
67         cDXN_XY, // inverted relative to standard ATI2, 360's DXN
68         cDXN_YX, // standard ATI2,
69         cETC1    // Ericsson texture compression (color only, 4x4 blocks, 4bpp, 64-bits/block)
70     };
71
72     const float cDXT1MaxLinearValue = 3.0f;
73     const float cDXT1InvMaxLinearValue = 1.0f / 3.0f;
74
75     const float cDXT5MaxLinearValue = 7.0f;
76     const float cDXT5InvMaxLinearValue = 1.0f / 7.0f;
77
78     // Converts DXT1 raw color selector index to a linear value.
79     extern const uint8 g_dxt1_to_linear[cDXT1SelectorValues];
80
81     // Converts DXT5 raw alpha selector index to a linear value.
82     extern const uint8 g_dxt5_to_linear[cDXT5SelectorValues];
83
84     // Converts DXT1 linear color selector index to a raw value (inverse of g_dxt1_to_linear).
85     extern const uint8 g_dxt1_from_linear[cDXT1SelectorValues];
86
87     // Converts DXT5 linear alpha selector index to a raw value (inverse of g_dxt5_to_linear).
88     extern const uint8 g_dxt5_from_linear[cDXT5SelectorValues];
89
90     extern const uint8 g_dxt5_alpha6_to_linear[cDXT5SelectorValues];
91
92     extern const uint8 g_six_alpha_invert_table[cDXT5SelectorValues];
93     extern const uint8 g_eight_alpha_invert_table[cDXT5SelectorValues];
94
95     const char *get_dxt_format_string(dxt_format fmt);
96     uint get_dxt_format_bits_per_pixel(dxt_format fmt);
97     bool get_dxt_format_has_alpha(dxt_format fmt);
98
99     const char *get_dxt_quality_string(vogl_dxt_quality q);
100
101     const char *get_dxt_compressor_name(vogl_dxt_compressor_type c);
102
103     struct dxt1_block
104     {
105         uint8 m_low_color[2];
106         uint8 m_high_color[2];
107
108         enum
109         {
110             cNumSelectorBytes = 4
111         };
112         uint8 m_selectors[cNumSelectorBytes];
113
114         inline void clear()
115         {
116             utils::zero_this(this);
117         }
118
119         // These methods assume the in-memory rep is in LE byte order.
120         inline uint get_low_color() const
121         {
122             return m_low_color[0] | (m_low_color[1] << 8U);
123         }
124
125         inline uint get_high_color() const
126         {
127             return m_high_color[0] | (m_high_color[1] << 8U);
128         }
129
130         inline void set_low_color(uint16 c)
131         {
132             m_low_color[0] = static_cast<uint8>(c & 0xFF);
133             m_low_color[1] = static_cast<uint8>((c >> 8) & 0xFF);
134         }
135
136         inline void set_high_color(uint16 c)
137         {
138             m_high_color[0] = static_cast<uint8>(c & 0xFF);
139             m_high_color[1] = static_cast<uint8>((c >> 8) & 0xFF);
140         }
141
142         inline bool is_constant_color_block() const
143         {
144             return get_low_color() == get_high_color();
145         }
146         inline bool is_alpha_block() const
147         {
148             return get_low_color() <= get_high_color();
149         }
150         inline bool is_non_alpha_block() const
151         {
152             return !is_alpha_block();
153         }
154
155         inline uint get_selector(uint x, uint y) const
156         {
157             VOGL_ASSERT((x < 4U) && (y < 4U));
158             return (m_selectors[y] >> (x * cDXT1SelectorBits)) & cDXT1SelectorMask;
159         }
160
161         inline void set_selector(uint x, uint y, uint val)
162         {
163             VOGL_ASSERT((x < 4U) && (y < 4U) && (val < 4U));
164
165             m_selectors[y] &= (~(cDXT1SelectorMask << (x * cDXT1SelectorBits)));
166             m_selectors[y] |= (val << (x * cDXT1SelectorBits));
167         }
168
169         inline void flip_x(uint w = 4, uint h = 4)
170         {
171             for (uint x = 0; x < (w / 2); x++)
172             {
173                 for (uint y = 0; y < h; y++)
174                 {
175                     const uint c = get_selector(x, y);
176                     set_selector(x, y, get_selector((w - 1) - x, y));
177                     set_selector((w - 1) - x, y, c);
178                 }
179             }
180         }
181
182         inline void flip_y(uint w = 4, uint h = 4)
183         {
184             for (uint y = 0; y < (h / 2); y++)
185             {
186                 for (uint x = 0; x < w; x++)
187                 {
188                     const uint c = get_selector(x, y);
189                     set_selector(x, y, get_selector(x, (h - 1) - y));
190                     set_selector(x, (h - 1) - y, c);
191                 }
192             }
193         }
194
195         static uint16 pack_color(const color_quad_u8 &color, bool scaled, uint bias = 127U);
196         static uint16 pack_color(uint r, uint g, uint b, bool scaled, uint bias = 127U);
197
198         static color_quad_u8 unpack_color(uint16 packed_color, bool scaled, uint alpha = 255U);
199         static void unpack_color(uint &r, uint &g, uint &b, uint16 packed_color, bool scaled);
200
201         static uint get_block_colors3(color_quad_u8 *pDst, uint16 color0, uint16 color1);
202         static uint get_block_colors3_round(color_quad_u8 *pDst, uint16 color0, uint16 color1);
203
204         static uint get_block_colors4(color_quad_u8 *pDst, uint16 color0, uint16 color1);
205         static uint get_block_colors4_round(color_quad_u8 *pDst, uint16 color0, uint16 color1);
206
207         // pDst must point to an array at least cDXT1SelectorValues long.
208         static uint get_block_colors(color_quad_u8 *pDst, uint16 color0, uint16 color1);
209
210         static uint get_block_colors_round(color_quad_u8 *pDst, uint16 color0, uint16 color1);
211
212         static color_quad_u8 unpack_endpoint(uint32 endpoints, uint index, bool scaled, uint alpha = 255U);
213         static uint pack_endpoints(uint lo, uint hi);
214
215         static void get_block_colors_NV5x(color_quad_u8 *pDst, uint16 packed_col0, uint16 packed_col1, bool color4);
216     };
217
218     VOGL_DEFINE_BITWISE_COPYABLE(dxt1_block);
219
220     struct dxt3_block
221     {
222         enum
223         {
224             cNumAlphaBytes = 8
225         };
226         uint8 m_alpha[cNumAlphaBytes];
227
228         void set_alpha(uint x, uint y, uint value, bool scaled);
229         uint get_alpha(uint x, uint y, bool scaled) const;
230
231         inline void flip_x(uint w = 4, uint h = 4)
232         {
233             for (uint x = 0; x < (w / 2); x++)
234             {
235                 for (uint y = 0; y < h; y++)
236                 {
237                     const uint c = get_alpha(x, y, false);
238                     set_alpha(x, y, get_alpha((w - 1) - x, y, false), false);
239                     set_alpha((w - 1) - x, y, c, false);
240                 }
241             }
242         }
243
244         inline void flip_y(uint w = 4, uint h = 4)
245         {
246             for (uint y = 0; y < (h / 2); y++)
247             {
248                 for (uint x = 0; x < w; x++)
249                 {
250                     const uint c = get_alpha(x, y, false);
251                     set_alpha(x, y, get_alpha(x, (h - 1) - y, false), false);
252                     set_alpha(x, (h - 1) - y, c, false);
253                 }
254             }
255         }
256     };
257
258     VOGL_DEFINE_BITWISE_COPYABLE(dxt3_block);
259
260     struct dxt5_block
261     {
262         uint8 m_endpoints[2];
263
264         enum
265         {
266             cNumSelectorBytes = 6
267         };
268         uint8 m_selectors[cNumSelectorBytes];
269
270         inline void clear()
271         {
272             utils::zero_this(this);
273         }
274
275         inline uint get_low_alpha() const
276         {
277             return m_endpoints[0];
278         }
279
280         inline uint get_high_alpha() const
281         {
282             return m_endpoints[1];
283         }
284
285         inline void set_low_alpha(uint i)
286         {
287             VOGL_ASSERT(i <= cUINT8_MAX);
288             m_endpoints[0] = static_cast<uint8>(i);
289         }
290
291         inline void set_high_alpha(uint i)
292         {
293             VOGL_ASSERT(i <= cUINT8_MAX);
294             m_endpoints[1] = static_cast<uint8>(i);
295         }
296
297         inline bool is_alpha6_block() const
298         {
299             return get_low_alpha() <= get_high_alpha();
300         }
301
302         uint get_endpoints_as_word() const
303         {
304             return m_endpoints[0] | (m_endpoints[1] << 8);
305         }
306         uint get_selectors_as_word(uint index)
307         {
308             VOGL_ASSERT(index < 3);
309             return m_selectors[index * 2] | (m_selectors[index * 2 + 1] << 8);
310         }
311
312         inline uint get_selector(uint x, uint y) const
313         {
314             VOGL_ASSERT((x < 4U) && (y < 4U));
315
316             uint selector_index = (y * 4) + x;
317             uint bit_index = selector_index * cDXT5SelectorBits;
318
319             uint byte_index = bit_index >> 3;
320             uint bit_ofs = bit_index & 7;
321
322             uint v = m_selectors[byte_index];
323             if (byte_index < (cNumSelectorBytes - 1))
324                 v |= (m_selectors[byte_index + 1] << 8);
325
326             return (v >> bit_ofs) & 7;
327         }
328
329         inline void set_selector(uint x, uint y, uint val)
330         {
331             VOGL_ASSERT((x < 4U) && (y < 4U) && (val < 8U));
332
333             uint selector_index = (y * 4) + x;
334             uint bit_index = selector_index * cDXT5SelectorBits;
335
336             uint byte_index = bit_index >> 3;
337             uint bit_ofs = bit_index & 7;
338
339             uint v = m_selectors[byte_index];
340             if (byte_index < (cNumSelectorBytes - 1))
341                 v |= (m_selectors[byte_index + 1] << 8);
342
343             v &= (~(7 << bit_ofs));
344             v |= (val << bit_ofs);
345
346             m_selectors[byte_index] = static_cast<uint8>(v);
347             if (byte_index < (cNumSelectorBytes - 1))
348                 m_selectors[byte_index + 1] = static_cast<uint8>(v >> 8);
349         }
350
351         inline void flip_x(uint w = 4, uint h = 4)
352         {
353             for (uint x = 0; x < (w / 2); x++)
354             {
355                 for (uint y = 0; y < h; y++)
356                 {
357                     const uint c = get_selector(x, y);
358                     set_selector(x, y, get_selector((w - 1) - x, y));
359                     set_selector((w - 1) - x, y, c);
360                 }
361             }
362         }
363
364         inline void flip_y(uint w = 4, uint h = 4)
365         {
366             for (uint y = 0; y < (h / 2); y++)
367             {
368                 for (uint x = 0; x < w; x++)
369                 {
370                     const uint c = get_selector(x, y);
371                     set_selector(x, y, get_selector(x, (h - 1) - y));
372                     set_selector(x, (h - 1) - y, c);
373                 }
374             }
375         }
376
377         enum
378         {
379             cMaxSelectorValues = 8
380         };
381
382         // Results written to alpha channel.
383         static uint get_block_values6(color_quad_u8 *pDst, uint l, uint h);
384         static uint get_block_values8(color_quad_u8 *pDst, uint l, uint h);
385         static uint get_block_values(color_quad_u8 *pDst, uint l, uint h);
386
387         static uint get_block_values6(uint *pDst, uint l, uint h);
388         static uint get_block_values8(uint *pDst, uint l, uint h);
389         // pDst must point to an array at least cDXT5SelectorValues long.
390         static uint get_block_values(uint *pDst, uint l, uint h);
391
392         static uint unpack_endpoint(uint packed, uint index);
393         static uint pack_endpoints(uint lo, uint hi);
394     };
395
396     VOGL_DEFINE_BITWISE_COPYABLE(dxt5_block);
397
398     struct dxt_pixel_block
399     {
400         color_quad_u8 m_pixels[cDXTBlockSize][cDXTBlockSize]; // [y][x]
401
402         inline void clear()
403         {
404             utils::zero_object(*this);
405         }
406     };
407
408     VOGL_DEFINE_BITWISE_COPYABLE(dxt_pixel_block);
409
410 } // namespace vogl