]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_dxt.cpp
Initial vogl checkin
[vogl] / src / voglcore / vogl_dxt.cpp
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.cpp
28 #include "vogl_core.h"
29 #include "vogl_dxt.h"
30 #include "vogl_dxt1.h"
31 #include "vogl_ryg_dxt.hpp"
32 #include "vogl_dxt_fast.h"
33 #include "vogl_intersect.h"
34
35 namespace vogl
36 {
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 };
39
40     const uint8 g_dxt5_alpha6_to_linear[cDXT5SelectorValues] = { 0U, 5U, 1U, 2U, 3U, 4U, 0U, 0U };
41
42     const uint8 g_dxt1_from_linear[cDXT1SelectorValues] = { 0U, 2U, 3U, 1U };
43     const uint8 g_dxt1_to_linear[cDXT1SelectorValues] = { 0U, 3U, 1U, 2U };
44
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 };
47
48     const char *get_dxt_format_string(dxt_format fmt)
49     {
50         switch (fmt)
51         {
52             case cDXT1:
53                 return "DXT1";
54             case cDXT1A:
55                 return "DXT1A";
56             case cDXT3:
57                 return "DXT3";
58             case cDXT5:
59                 return "DXT5";
60             case cDXT5A:
61                 return "DXT5A";
62             case cDXN_XY:
63                 return "DXN_XY";
64             case cDXN_YX:
65                 return "DXN_YX";
66             case cETC1:
67                 return "ETC1";
68             default:
69                 break;
70         }
71         VOGL_ASSERT(false);
72         return "?";
73     }
74
75     const char *get_dxt_compressor_name(vogl_dxt_compressor_type c)
76     {
77         switch (c)
78         {
79             case cCRNDXTCompressorCRN:
80                 return "CRN";
81             case cCRNDXTCompressorCRNF:
82                 return "CRNF";
83             case cCRNDXTCompressorRYG:
84                 return "RYG";
85 #if VOGL_SUPPORT_ATI_COMPRESS
86             case cCRNDXTCompressorATI:
87                 return "ATI";
88 #endif
89             default:
90                 break;
91         }
92         VOGL_ASSERT(false);
93         return "?";
94     }
95
96     uint get_dxt_format_bits_per_pixel(dxt_format fmt)
97     {
98         switch (fmt)
99         {
100             case cDXT1:
101             case cDXT1A:
102             case cDXT5A:
103             case cETC1:
104                 return 4;
105             case cDXT3:
106             case cDXT5:
107             case cDXN_XY:
108             case cDXN_YX:
109                 return 8;
110             default:
111                 break;
112         }
113         VOGL_ASSERT(false);
114         return 0;
115     }
116
117     bool get_dxt_format_has_alpha(dxt_format fmt)
118     {
119         switch (fmt)
120         {
121             case cDXT1A:
122             case cDXT3:
123             case cDXT5:
124             case cDXT5A:
125                 return true;
126             default:
127                 break;
128         }
129         return false;
130     }
131
132     uint16 dxt1_block::pack_color(const color_quad_u8 &color, bool scaled, uint bias)
133     {
134         uint r = color.r;
135         uint g = color.g;
136         uint b = color.b;
137
138         if (scaled)
139         {
140             r = (r * 31U + bias) / 255U;
141             g = (g * 63U + bias) / 255U;
142             b = (b * 31U + bias) / 255U;
143         }
144
145         r = math::minimum(r, 31U);
146         g = math::minimum(g, 63U);
147         b = math::minimum(b, 31U);
148
149         return static_cast<uint16>(b | (g << 5U) | (r << 11U));
150     }
151
152     uint16 dxt1_block::pack_color(uint r, uint g, uint b, bool scaled, uint bias)
153     {
154         return pack_color(color_quad_u8(r, g, b, 0), scaled, bias);
155     }
156
157     color_quad_u8 dxt1_block::unpack_color(uint16 packed_color, bool scaled, uint alpha)
158     {
159         uint b = packed_color & 31U;
160         uint g = (packed_color >> 5U) & 63U;
161         uint r = (packed_color >> 11U) & 31U;
162
163         if (scaled)
164         {
165             b = (b << 3U) | (b >> 2U);
166             g = (g << 2U) | (g >> 4U);
167             r = (r << 3U) | (r >> 2U);
168         }
169
170         return color_quad_u8(cNoClamp, r, g, b, math::minimum(alpha, 255U));
171     }
172
173     void dxt1_block::unpack_color(uint &r, uint &g, uint &b, uint16 packed_color, bool scaled)
174     {
175         color_quad_u8 c(unpack_color(packed_color, scaled, 0));
176         r = c.r;
177         g = c.g;
178         b = c.b;
179     }
180
181     void dxt1_block::get_block_colors_NV5x(color_quad_u8 *pDst, uint16 packed_col0, uint16 packed_col1, bool color4)
182     {
183         color_quad_u8 col0(unpack_color(packed_col0, false));
184         color_quad_u8 col1(unpack_color(packed_col1, false));
185
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);
189         pDst[0].a = 0xFF;
190
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;
194         pDst[1].a = 0xFF;
195
196         int gdiff = pDst[1].g - pDst[0].g;
197
198         if (color4) //(packed_col0 > packed_col1)
199         {
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);
203             pDst[2].a = 0xFF;
204
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);
208             pDst[3].a = 0xFF;
209         }
210         else
211         {
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);
215             pDst[2].a = 0xFF;
216
217             pDst[3].r = 0x00;
218             pDst[3].g = 0x00;
219             pDst[3].b = 0x00;
220             pDst[3].a = 0x00;
221         }
222     }
223
224     uint dxt1_block::get_block_colors3(color_quad_u8 *pDst, uint16 color0, uint16 color1)
225     {
226         color_quad_u8 c0(unpack_color(color0, true));
227         color_quad_u8 c1(unpack_color(color1, true));
228
229         pDst[0] = c0;
230         pDst[1] = c1;
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);
233
234         return 3;
235     }
236
237     uint dxt1_block::get_block_colors4(color_quad_u8 *pDst, uint16 color0, uint16 color1)
238     {
239         color_quad_u8 c0(unpack_color(color0, true));
240         color_quad_u8 c1(unpack_color(color1, true));
241
242         pDst[0] = c0;
243         pDst[1] = c1;
244
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);
248
249         return 4;
250     }
251
252     uint dxt1_block::get_block_colors3_round(color_quad_u8 *pDst, uint16 color0, uint16 color1)
253     {
254         color_quad_u8 c0(unpack_color(color0, true));
255         color_quad_u8 c1(unpack_color(color1, true));
256
257         pDst[0] = c0;
258         pDst[1] = c1;
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);
261
262         return 3;
263     }
264
265     uint dxt1_block::get_block_colors4_round(color_quad_u8 *pDst, uint16 color0, uint16 color1)
266     {
267         color_quad_u8 c0(unpack_color(color0, true));
268         color_quad_u8 c1(unpack_color(color1, true));
269
270         pDst[0] = c0;
271         pDst[1] = c1;
272
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);
277
278         return 4;
279     }
280
281     uint dxt1_block::get_block_colors(color_quad_u8 *pDst, uint16 color0, uint16 color1)
282     {
283         if (color0 > color1)
284             return get_block_colors4(pDst, color0, color1);
285         else
286             return get_block_colors3(pDst, color0, color1);
287     }
288
289     uint dxt1_block::get_block_colors_round(color_quad_u8 *pDst, uint16 color0, uint16 color1)
290     {
291         if (color0 > color1)
292             return get_block_colors4_round(pDst, color0, color1);
293         else
294             return get_block_colors3_round(pDst, color0, color1);
295     }
296
297     color_quad_u8 dxt1_block::unpack_endpoint(uint32 endpoints, uint index, bool scaled, uint alpha)
298     {
299         VOGL_ASSERT(index < 2);
300         return unpack_color(static_cast<uint16>((endpoints >> (index * 16U)) & 0xFFFFU), scaled, alpha);
301     }
302
303     uint dxt1_block::pack_endpoints(uint lo, uint hi)
304     {
305         VOGL_ASSERT((lo <= 0xFFFFU) && (hi <= 0xFFFFU));
306         return lo | (hi << 16U);
307     }
308
309     void dxt3_block::set_alpha(uint x, uint y, uint value, bool scaled)
310     {
311         VOGL_ASSERT((x < cDXTBlockSize) && (y < cDXTBlockSize));
312
313         if (scaled)
314         {
315             VOGL_ASSERT(value <= 0xFF);
316             value = (value * 15U + 128U) / 255U;
317         }
318         else
319         {
320             VOGL_ASSERT(value <= 0xF);
321         }
322
323         uint ofs = (y << 1U) + (x >> 1U);
324         uint c = m_alpha[ofs];
325
326         c &= ~(0xF << ((x & 1U) << 2U));
327         c |= (value << ((x & 1U) << 2U));
328
329         m_alpha[ofs] = static_cast<uint8>(c);
330     }
331
332     uint dxt3_block::get_alpha(uint x, uint y, bool scaled) const
333     {
334         VOGL_ASSERT((x < cDXTBlockSize) && (y < cDXTBlockSize));
335
336         uint value = m_alpha[(y << 1U) + (x >> 1U)];
337         if (x & 1)
338             value >>= 4;
339         value &= 0xF;
340
341         if (scaled)
342             value = (value << 4U) | value;
343
344         return value;
345     }
346
347     uint dxt5_block::get_block_values6(color_quad_u8 *pDst, uint l, uint h)
348     {
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);
355         pDst[6].a = 0;
356         pDst[7].a = 255;
357         return 6;
358     }
359
360     uint dxt5_block::get_block_values8(color_quad_u8 *pDst, uint l, uint h)
361     {
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);
370         return 8;
371     }
372
373     uint dxt5_block::get_block_values(color_quad_u8 *pDst, uint l, uint h)
374     {
375         if (l > h)
376             return get_block_values8(pDst, l, h);
377         else
378             return get_block_values6(pDst, l, h);
379     }
380
381     uint dxt5_block::get_block_values6(uint *pDst, uint l, uint h)
382     {
383         pDst[0] = l;
384         pDst[1] = 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;
389         pDst[6] = 0;
390         pDst[7] = 255;
391         return 6;
392     }
393
394     uint dxt5_block::get_block_values8(uint *pDst, uint l, uint h)
395     {
396         pDst[0] = l;
397         pDst[1] = 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;
404         return 8;
405     }
406
407     uint dxt5_block::unpack_endpoint(uint packed, uint index)
408     {
409         VOGL_ASSERT(index < 2);
410         return (packed >> (8 * index)) & 0xFF;
411     }
412
413     uint dxt5_block::pack_endpoints(uint lo, uint hi)
414     {
415         VOGL_ASSERT((lo <= 0xFF) && (hi <= 0xFF));
416         return lo | (hi << 8U);
417     }
418
419     uint dxt5_block::get_block_values(uint *pDst, uint l, uint h)
420     {
421         if (l > h)
422             return get_block_values8(pDst, l, h);
423         else
424             return get_block_values6(pDst, l, h);
425     }
426
427 } // namespace vogl