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 **************************************************************************/
28 #include "vogl_core.h"
30 #include "vogl_dxt1.h"
31 #include "vogl_ryg_dxt.hpp"
32 #include "vogl_dxt_fast.h"
33 #include "vogl_intersect.h"
37 const uint8 g_dxt5_from_linear[cDXT5SelectorValues] = { 0U, 2U, 3U, 4U, 5U, 6U, 7U, 1U };
38 const uint8 g_dxt5_to_linear[cDXT5SelectorValues] = { 0U, 7U, 1U, 2U, 3U, 4U, 5U, 6U };
40 const uint8 g_dxt5_alpha6_to_linear[cDXT5SelectorValues] = { 0U, 5U, 1U, 2U, 3U, 4U, 0U, 0U };
42 const uint8 g_dxt1_from_linear[cDXT1SelectorValues] = { 0U, 2U, 3U, 1U };
43 const uint8 g_dxt1_to_linear[cDXT1SelectorValues] = { 0U, 3U, 1U, 2U };
45 const uint8 g_six_alpha_invert_table[cDXT5SelectorValues] = { 1, 0, 5, 4, 3, 2, 6, 7 };
46 const uint8 g_eight_alpha_invert_table[cDXT5SelectorValues] = { 1, 0, 7, 6, 5, 4, 3, 2 };
48 const char *get_dxt_format_string(dxt_format fmt)
75 const char *get_dxt_compressor_name(vogl_dxt_compressor_type c)
79 case cCRNDXTCompressorCRN:
81 case cCRNDXTCompressorCRNF:
83 case cCRNDXTCompressorRYG:
85 #if VOGL_SUPPORT_ATI_COMPRESS
86 case cCRNDXTCompressorATI:
96 uint get_dxt_format_bits_per_pixel(dxt_format fmt)
117 bool get_dxt_format_has_alpha(dxt_format fmt)
132 uint16 dxt1_block::pack_color(const color_quad_u8 &color, bool scaled, uint bias)
140 r = (r * 31U + bias) / 255U;
141 g = (g * 63U + bias) / 255U;
142 b = (b * 31U + bias) / 255U;
145 r = math::minimum(r, 31U);
146 g = math::minimum(g, 63U);
147 b = math::minimum(b, 31U);
149 return static_cast<uint16>(b | (g << 5U) | (r << 11U));
152 uint16 dxt1_block::pack_color(uint r, uint g, uint b, bool scaled, uint bias)
154 return pack_color(color_quad_u8(r, g, b, 0), scaled, bias);
157 color_quad_u8 dxt1_block::unpack_color(uint16 packed_color, bool scaled, uint alpha)
159 uint b = packed_color & 31U;
160 uint g = (packed_color >> 5U) & 63U;
161 uint r = (packed_color >> 11U) & 31U;
165 b = (b << 3U) | (b >> 2U);
166 g = (g << 2U) | (g >> 4U);
167 r = (r << 3U) | (r >> 2U);
170 return color_quad_u8(cNoClamp, r, g, b, math::minimum(alpha, 255U));
173 void dxt1_block::unpack_color(uint &r, uint &g, uint &b, uint16 packed_color, bool scaled)
175 color_quad_u8 c(unpack_color(packed_color, scaled, 0));
181 void dxt1_block::get_block_colors_NV5x(color_quad_u8 *pDst, uint16 packed_col0, uint16 packed_col1, bool color4)
183 color_quad_u8 col0(unpack_color(packed_col0, false));
184 color_quad_u8 col1(unpack_color(packed_col1, false));
186 pDst[0].r = (3 * col0.r * 22) / 8;
187 pDst[0].b = (3 * col0.b * 22) / 8;
188 pDst[0].g = (col0.g << 2) | (col0.g >> 4);
191 pDst[1].r = (3 * col1.r * 22) / 8;
192 pDst[1].g = (col1.g << 2) | (col1.g >> 4);
193 pDst[1].b = (3 * col1.b * 22) / 8;
196 int gdiff = pDst[1].g - pDst[0].g;
198 if (color4) //(packed_col0 > packed_col1)
200 pDst[2].r = static_cast<uint8>(((2 * col0.r + col1.r) * 22) / 8);
201 pDst[2].g = static_cast<uint8>((256 * pDst[0].g + gdiff / 4 + 128 + gdiff * 80) / 256);
202 pDst[2].b = static_cast<uint8>(((2 * col0.b + col1.b) * 22) / 8);
205 pDst[3].r = static_cast<uint8>(((2 * col1.r + col0.r) * 22) / 8);
206 pDst[3].g = static_cast<uint8>((256 * pDst[1].g - gdiff / 4 + 128 - gdiff * 80) / 256);
207 pDst[3].b = static_cast<uint8>(((2 * col1.b + col0.b) * 22) / 8);
212 pDst[2].r = static_cast<uint8>(((col0.r + col1.r) * 33) / 8);
213 pDst[2].g = static_cast<uint8>((256 * pDst[0].g + gdiff / 4 + 128 + gdiff * 128) / 256);
214 pDst[2].b = static_cast<uint8>(((col0.b + col1.b) * 33) / 8);
224 uint dxt1_block::get_block_colors3(color_quad_u8 *pDst, uint16 color0, uint16 color1)
226 color_quad_u8 c0(unpack_color(color0, true));
227 color_quad_u8 c1(unpack_color(color1, true));
231 pDst[2].set_noclamp_rgba((c0.r + c1.r) >> 1U, (c0.g + c1.g) >> 1U, (c0.b + c1.b) >> 1U, 255U);
232 pDst[3].set_noclamp_rgba(0, 0, 0, 0);
237 uint dxt1_block::get_block_colors4(color_quad_u8 *pDst, uint16 color0, uint16 color1)
239 color_quad_u8 c0(unpack_color(color0, true));
240 color_quad_u8 c1(unpack_color(color1, true));
245 // The compiler changes the div3 into a mul by recip+shift.
246 pDst[2].set_noclamp_rgba((c0.r * 2 + c1.r) / 3, (c0.g * 2 + c1.g) / 3, (c0.b * 2 + c1.b) / 3, 255U);
247 pDst[3].set_noclamp_rgba((c1.r * 2 + c0.r) / 3, (c1.g * 2 + c0.g) / 3, (c1.b * 2 + c0.b) / 3, 255U);
252 uint dxt1_block::get_block_colors3_round(color_quad_u8 *pDst, uint16 color0, uint16 color1)
254 color_quad_u8 c0(unpack_color(color0, true));
255 color_quad_u8 c1(unpack_color(color1, true));
259 pDst[2].set_noclamp_rgba((c0.r + c1.r + 1) >> 1U, (c0.g + c1.g + 1) >> 1U, (c0.b + c1.b + 1) >> 1U, 255U);
260 pDst[3].set_noclamp_rgba(0, 0, 0, 0);
265 uint dxt1_block::get_block_colors4_round(color_quad_u8 *pDst, uint16 color0, uint16 color1)
267 color_quad_u8 c0(unpack_color(color0, true));
268 color_quad_u8 c1(unpack_color(color1, true));
273 // 12/14/08 - Supposed to round according to DX docs, but this conflicts with the OpenGL S3TC spec. ?
274 // The compiler changes the div3 into a mul by recip+shift.
275 pDst[2].set_noclamp_rgba((c0.r * 2 + c1.r + 1) / 3, (c0.g * 2 + c1.g + 1) / 3, (c0.b * 2 + c1.b + 1) / 3, 255U);
276 pDst[3].set_noclamp_rgba((c1.r * 2 + c0.r + 1) / 3, (c1.g * 2 + c0.g + 1) / 3, (c1.b * 2 + c0.b + 1) / 3, 255U);
281 uint dxt1_block::get_block_colors(color_quad_u8 *pDst, uint16 color0, uint16 color1)
284 return get_block_colors4(pDst, color0, color1);
286 return get_block_colors3(pDst, color0, color1);
289 uint dxt1_block::get_block_colors_round(color_quad_u8 *pDst, uint16 color0, uint16 color1)
292 return get_block_colors4_round(pDst, color0, color1);
294 return get_block_colors3_round(pDst, color0, color1);
297 color_quad_u8 dxt1_block::unpack_endpoint(uint32 endpoints, uint index, bool scaled, uint alpha)
299 VOGL_ASSERT(index < 2);
300 return unpack_color(static_cast<uint16>((endpoints >> (index * 16U)) & 0xFFFFU), scaled, alpha);
303 uint dxt1_block::pack_endpoints(uint lo, uint hi)
305 VOGL_ASSERT((lo <= 0xFFFFU) && (hi <= 0xFFFFU));
306 return lo | (hi << 16U);
309 void dxt3_block::set_alpha(uint x, uint y, uint value, bool scaled)
311 VOGL_ASSERT((x < cDXTBlockSize) && (y < cDXTBlockSize));
315 VOGL_ASSERT(value <= 0xFF);
316 value = (value * 15U + 128U) / 255U;
320 VOGL_ASSERT(value <= 0xF);
323 uint ofs = (y << 1U) + (x >> 1U);
324 uint c = m_alpha[ofs];
326 c &= ~(0xF << ((x & 1U) << 2U));
327 c |= (value << ((x & 1U) << 2U));
329 m_alpha[ofs] = static_cast<uint8>(c);
332 uint dxt3_block::get_alpha(uint x, uint y, bool scaled) const
334 VOGL_ASSERT((x < cDXTBlockSize) && (y < cDXTBlockSize));
336 uint value = m_alpha[(y << 1U) + (x >> 1U)];
342 value = (value << 4U) | value;
347 uint dxt5_block::get_block_values6(color_quad_u8 *pDst, uint l, uint h)
349 pDst[0].a = static_cast<uint8>(l);
350 pDst[1].a = static_cast<uint8>(h);
351 pDst[2].a = static_cast<uint8>((l * 4 + h) / 5);
352 pDst[3].a = static_cast<uint8>((l * 3 + h * 2) / 5);
353 pDst[4].a = static_cast<uint8>((l * 2 + h * 3) / 5);
354 pDst[5].a = static_cast<uint8>((l + h * 4) / 5);
360 uint dxt5_block::get_block_values8(color_quad_u8 *pDst, uint l, uint h)
362 pDst[0].a = static_cast<uint8>(l);
363 pDst[1].a = static_cast<uint8>(h);
364 pDst[2].a = static_cast<uint8>((l * 6 + h) / 7);
365 pDst[3].a = static_cast<uint8>((l * 5 + h * 2) / 7);
366 pDst[4].a = static_cast<uint8>((l * 4 + h * 3) / 7);
367 pDst[5].a = static_cast<uint8>((l * 3 + h * 4) / 7);
368 pDst[6].a = static_cast<uint8>((l * 2 + h * 5) / 7);
369 pDst[7].a = static_cast<uint8>((l + h * 6) / 7);
373 uint dxt5_block::get_block_values(color_quad_u8 *pDst, uint l, uint h)
376 return get_block_values8(pDst, l, h);
378 return get_block_values6(pDst, l, h);
381 uint dxt5_block::get_block_values6(uint *pDst, uint l, uint h)
385 pDst[2] = (l * 4 + h) / 5;
386 pDst[3] = (l * 3 + h * 2) / 5;
387 pDst[4] = (l * 2 + h * 3) / 5;
388 pDst[5] = (l + h * 4) / 5;
394 uint dxt5_block::get_block_values8(uint *pDst, uint l, uint h)
398 pDst[2] = (l * 6 + h) / 7;
399 pDst[3] = (l * 5 + h * 2) / 7;
400 pDst[4] = (l * 4 + h * 3) / 7;
401 pDst[5] = (l * 3 + h * 4) / 7;
402 pDst[6] = (l * 2 + h * 5) / 7;
403 pDst[7] = (l + h * 6) / 7;
407 uint dxt5_block::unpack_endpoint(uint packed, uint index)
409 VOGL_ASSERT(index < 2);
410 return (packed >> (8 * index)) & 0xFF;
413 uint dxt5_block::pack_endpoints(uint lo, uint hi)
415 VOGL_ASSERT((lo <= 0xFF) && (hi <= 0xFF));
416 return lo | (hi << 8U);
419 uint dxt5_block::get_block_values(uint *pDst, uint l, uint h)
422 return get_block_values8(pDst, l, h);
424 return get_block_values6(pDst, l, h);