1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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
25 **************************************************************************/
30 #include "vogl_core.h"
32 #include "vogl_color.h"
34 #include "vogl_rand.h"
35 #include "vogl_sparse_bit_array.h"
36 #include "vogl_hash_map.h"
39 #define VOGL_DXT_ALT_ROUNDING 1
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,
54 cDXTBlockSize = 1U << cDXTBlockShift
61 // cDXT1/1A must appear first!
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)
72 const float cDXT1MaxLinearValue = 3.0f;
73 const float cDXT1InvMaxLinearValue = 1.0f / 3.0f;
75 const float cDXT5MaxLinearValue = 7.0f;
76 const float cDXT5InvMaxLinearValue = 1.0f / 7.0f;
78 // Converts DXT1 raw color selector index to a linear value.
79 extern const uint8 g_dxt1_to_linear[cDXT1SelectorValues];
81 // Converts DXT5 raw alpha selector index to a linear value.
82 extern const uint8 g_dxt5_to_linear[cDXT5SelectorValues];
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];
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];
90 extern const uint8 g_dxt5_alpha6_to_linear[cDXT5SelectorValues];
92 extern const uint8 g_six_alpha_invert_table[cDXT5SelectorValues];
93 extern const uint8 g_eight_alpha_invert_table[cDXT5SelectorValues];
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);
99 const char *get_dxt_quality_string(vogl_dxt_quality q);
101 const char *get_dxt_compressor_name(vogl_dxt_compressor_type c);
105 uint8 m_low_color[2];
106 uint8 m_high_color[2];
110 cNumSelectorBytes = 4
112 uint8 m_selectors[cNumSelectorBytes];
116 utils::zero_this(this);
119 // These methods assume the in-memory rep is in LE byte order.
120 inline uint get_low_color() const
122 return m_low_color[0] | (m_low_color[1] << 8U);
125 inline uint get_high_color() const
127 return m_high_color[0] | (m_high_color[1] << 8U);
130 inline void set_low_color(uint16 c)
132 m_low_color[0] = static_cast<uint8>(c & 0xFF);
133 m_low_color[1] = static_cast<uint8>((c >> 8) & 0xFF);
136 inline void set_high_color(uint16 c)
138 m_high_color[0] = static_cast<uint8>(c & 0xFF);
139 m_high_color[1] = static_cast<uint8>((c >> 8) & 0xFF);
142 inline bool is_constant_color_block() const
144 return get_low_color() == get_high_color();
146 inline bool is_alpha_block() const
148 return get_low_color() <= get_high_color();
150 inline bool is_non_alpha_block() const
152 return !is_alpha_block();
155 inline uint get_selector(uint x, uint y) const
157 VOGL_ASSERT((x < 4U) && (y < 4U));
158 return (m_selectors[y] >> (x * cDXT1SelectorBits)) & cDXT1SelectorMask;
161 inline void set_selector(uint x, uint y, uint val)
163 VOGL_ASSERT((x < 4U) && (y < 4U) && (val < 4U));
165 m_selectors[y] &= (~(cDXT1SelectorMask << (x * cDXT1SelectorBits)));
166 m_selectors[y] |= (val << (x * cDXT1SelectorBits));
169 inline void flip_x(uint w = 4, uint h = 4)
171 for (uint x = 0; x < (w / 2); x++)
173 for (uint y = 0; y < h; y++)
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);
182 inline void flip_y(uint w = 4, uint h = 4)
184 for (uint y = 0; y < (h / 2); y++)
186 for (uint x = 0; x < w; x++)
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);
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);
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);
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);
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);
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);
210 static uint get_block_colors_round(color_quad_u8 *pDst, uint16 color0, uint16 color1);
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);
215 static void get_block_colors_NV5x(color_quad_u8 *pDst, uint16 packed_col0, uint16 packed_col1, bool color4);
218 VOGL_DEFINE_BITWISE_COPYABLE(dxt1_block);
226 uint8 m_alpha[cNumAlphaBytes];
228 void set_alpha(uint x, uint y, uint value, bool scaled);
229 uint get_alpha(uint x, uint y, bool scaled) const;
231 inline void flip_x(uint w = 4, uint h = 4)
233 for (uint x = 0; x < (w / 2); x++)
235 for (uint y = 0; y < h; y++)
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);
244 inline void flip_y(uint w = 4, uint h = 4)
246 for (uint y = 0; y < (h / 2); y++)
248 for (uint x = 0; x < w; x++)
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);
258 VOGL_DEFINE_BITWISE_COPYABLE(dxt3_block);
262 uint8 m_endpoints[2];
266 cNumSelectorBytes = 6
268 uint8 m_selectors[cNumSelectorBytes];
272 utils::zero_this(this);
275 inline uint get_low_alpha() const
277 return m_endpoints[0];
280 inline uint get_high_alpha() const
282 return m_endpoints[1];
285 inline void set_low_alpha(uint i)
287 VOGL_ASSERT(i <= cUINT8_MAX);
288 m_endpoints[0] = static_cast<uint8>(i);
291 inline void set_high_alpha(uint i)
293 VOGL_ASSERT(i <= cUINT8_MAX);
294 m_endpoints[1] = static_cast<uint8>(i);
297 inline bool is_alpha6_block() const
299 return get_low_alpha() <= get_high_alpha();
302 uint get_endpoints_as_word() const
304 return m_endpoints[0] | (m_endpoints[1] << 8);
306 uint get_selectors_as_word(uint index)
308 VOGL_ASSERT(index < 3);
309 return m_selectors[index * 2] | (m_selectors[index * 2 + 1] << 8);
312 inline uint get_selector(uint x, uint y) const
314 VOGL_ASSERT((x < 4U) && (y < 4U));
316 uint selector_index = (y * 4) + x;
317 uint bit_index = selector_index * cDXT5SelectorBits;
319 uint byte_index = bit_index >> 3;
320 uint bit_ofs = bit_index & 7;
322 uint v = m_selectors[byte_index];
323 if (byte_index < (cNumSelectorBytes - 1))
324 v |= (m_selectors[byte_index + 1] << 8);
326 return (v >> bit_ofs) & 7;
329 inline void set_selector(uint x, uint y, uint val)
331 VOGL_ASSERT((x < 4U) && (y < 4U) && (val < 8U));
333 uint selector_index = (y * 4) + x;
334 uint bit_index = selector_index * cDXT5SelectorBits;
336 uint byte_index = bit_index >> 3;
337 uint bit_ofs = bit_index & 7;
339 uint v = m_selectors[byte_index];
340 if (byte_index < (cNumSelectorBytes - 1))
341 v |= (m_selectors[byte_index + 1] << 8);
343 v &= (~(7 << bit_ofs));
344 v |= (val << bit_ofs);
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);
351 inline void flip_x(uint w = 4, uint h = 4)
353 for (uint x = 0; x < (w / 2); x++)
355 for (uint y = 0; y < h; y++)
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);
364 inline void flip_y(uint w = 4, uint h = 4)
366 for (uint y = 0; y < (h / 2); y++)
368 for (uint x = 0; x < w; x++)
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);
379 cMaxSelectorValues = 8
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);
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);
392 static uint unpack_endpoint(uint packed, uint index);
393 static uint pack_endpoints(uint lo, uint hi);
396 VOGL_DEFINE_BITWISE_COPYABLE(dxt5_block);
398 struct dxt_pixel_block
400 color_quad_u8 m_pixels[cDXTBlockSize][cDXTBlockSize]; // [y][x]
404 utils::zero_object(*this);
408 VOGL_DEFINE_BITWISE_COPYABLE(dxt_pixel_block);