]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_dxt5a.cpp
Initial vogl checkin
[vogl] / src / voglcore / vogl_dxt5a.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_dxt5a.cpp
28 #include "vogl_core.h"
29 #include "vogl_dxt5a.h"
30 #include "vogl_ryg_dxt.hpp"
31 #include "vogl_dxt_fast.h"
32 #include "vogl_intersect.h"
33
34 namespace vogl
35 {
36     dxt5_endpoint_optimizer::dxt5_endpoint_optimizer()
37         : m_pParams(NULL),
38           m_pResults(NULL)
39     {
40         m_unique_values.reserve(16);
41         m_unique_value_weights.reserve(16);
42     }
43
44     bool dxt5_endpoint_optimizer::compute(const params &p, results &r)
45     {
46         m_pParams = &p;
47         m_pResults = &r;
48
49         if ((!p.m_num_pixels) || (!p.m_pPixels))
50             return false;
51
52         m_unique_values.resize(0);
53         m_unique_value_weights.resize(0);
54
55         for (uint i = 0; i < 256; i++)
56             m_unique_value_map[i] = -1;
57
58         for (uint i = 0; i < p.m_num_pixels; i++)
59         {
60             uint alpha = p.m_pPixels[i][p.m_comp_index];
61
62             int index = m_unique_value_map[alpha];
63
64             if (index == -1)
65             {
66                 index = m_unique_values.size();
67
68                 m_unique_value_map[alpha] = index;
69
70                 m_unique_values.push_back(static_cast<uint8>(alpha));
71                 m_unique_value_weights.push_back(0);
72             }
73
74             m_unique_value_weights[index]++;
75         }
76
77         if (m_unique_values.size() == 1)
78         {
79             r.m_block_type = 0;
80             r.m_error = 0;
81             r.m_first_endpoint = m_unique_values[0];
82             r.m_second_endpoint = m_unique_values[0];
83             memset(r.m_pSelectors, 0, p.m_num_pixels);
84             return true;
85         }
86
87         m_trial_selectors.resize(m_unique_values.size());
88         m_best_selectors.resize(m_unique_values.size());
89
90         r.m_error = cUINT64_MAX;
91
92         for (uint i = 0; i < m_unique_values.size() - 1; i++)
93         {
94             const uint low_endpoint = m_unique_values[i];
95
96             for (uint j = i + 1; j < m_unique_values.size(); j++)
97             {
98                 const uint high_endpoint = m_unique_values[j];
99
100                 evaluate_solution(low_endpoint, high_endpoint);
101             }
102         }
103
104         if ((m_pParams->m_quality >= cCRNDXTQualityBetter) && (m_pResults->m_error))
105         {
106             m_flags.resize(256 * 256);
107             m_flags.clear_all_bits();
108
109             const int cProbeAmount = (m_pParams->m_quality == cCRNDXTQualityUber) ? 16 : 8;
110
111             for (int l_delta = -cProbeAmount; l_delta <= cProbeAmount; l_delta++)
112             {
113                 const int l = m_pResults->m_first_endpoint + l_delta;
114                 if (l < 0)
115                     continue;
116                 else if (l > 255)
117                     break;
118
119                 const uint bit_index = l * 256;
120
121                 for (int h_delta = -cProbeAmount; h_delta <= cProbeAmount; h_delta++)
122                 {
123                     const int h = m_pResults->m_second_endpoint + h_delta;
124                     if (h < 0)
125                         continue;
126                     else if (h > 255)
127                         break;
128
129                     //if (m_flags.get_bit(bit_index + h))
130                     //   continue;
131                     if ((m_flags.get_bit(bit_index + h)) || (m_flags.get_bit(h * 256 + l)))
132                         continue;
133                     m_flags.set_bit(bit_index + h);
134
135                     evaluate_solution(static_cast<uint>(l), static_cast<uint>(h));
136                 }
137             }
138         }
139
140         if (m_pResults->m_first_endpoint == m_pResults->m_second_endpoint)
141         {
142             for (uint i = 0; i < m_best_selectors.size(); i++)
143                 m_best_selectors[i] = 0;
144         }
145         else if (m_pResults->m_block_type)
146         {
147             //if (l > h)
148             //   eight alpha
149             // else
150             //   six alpha
151
152             if (m_pResults->m_first_endpoint > m_pResults->m_second_endpoint)
153             {
154                 utils::swap(m_pResults->m_first_endpoint, m_pResults->m_second_endpoint);
155                 for (uint i = 0; i < m_best_selectors.size(); i++)
156                     m_best_selectors[i] = g_six_alpha_invert_table[m_best_selectors[i]];
157             }
158         }
159         else if (!(m_pResults->m_first_endpoint > m_pResults->m_second_endpoint))
160         {
161             utils::swap(m_pResults->m_first_endpoint, m_pResults->m_second_endpoint);
162             for (uint i = 0; i < m_best_selectors.size(); i++)
163                 m_best_selectors[i] = g_eight_alpha_invert_table[m_best_selectors[i]];
164         }
165
166         for (uint i = 0; i < m_pParams->m_num_pixels; i++)
167         {
168             uint alpha = m_pParams->m_pPixels[i][m_pParams->m_comp_index];
169
170             int index = m_unique_value_map[alpha];
171
172             m_pResults->m_pSelectors[i] = m_best_selectors[index];
173         }
174
175         return true;
176     }
177
178     void dxt5_endpoint_optimizer::evaluate_solution(uint low_endpoint, uint high_endpoint)
179     {
180         for (uint block_type = 0; block_type < (m_pParams->m_use_both_block_types ? 2U : 1U); block_type++)
181         {
182             uint selector_values[8];
183
184             if (!block_type)
185                 dxt5_block::get_block_values8(selector_values, low_endpoint, high_endpoint);
186             else
187                 dxt5_block::get_block_values6(selector_values, low_endpoint, high_endpoint);
188
189             uint64_t trial_error = 0;
190
191             for (uint i = 0; i < m_unique_values.size(); i++)
192             {
193                 const uint val = m_unique_values[i];
194                 const uint weight = m_unique_value_weights[i];
195
196                 uint best_selector_error = UINT_MAX;
197                 uint best_selector = 0;
198
199                 for (uint j = 0; j < 8; j++)
200                 {
201                     int selector_error = val - selector_values[j];
202                     selector_error = selector_error * selector_error * (int)weight;
203
204                     if (static_cast<uint>(selector_error) < best_selector_error)
205                     {
206                         best_selector_error = selector_error;
207                         best_selector = j;
208                         if (!best_selector_error)
209                             break;
210                     }
211                 }
212
213                 m_trial_selectors[i] = static_cast<uint8>(best_selector);
214                 trial_error += best_selector_error;
215
216                 if (trial_error > m_pResults->m_error)
217                     break;
218             }
219
220             if (trial_error < m_pResults->m_error)
221             {
222                 m_pResults->m_error = trial_error;
223                 m_pResults->m_first_endpoint = static_cast<uint8>(low_endpoint);
224                 m_pResults->m_second_endpoint = static_cast<uint8>(high_endpoint);
225                 m_pResults->m_block_type = static_cast<uint8>(block_type);
226                 m_best_selectors.swap(m_trial_selectors);
227
228                 if (!trial_error)
229                     break;
230             }
231         }
232     }
233
234 } // namespace vogl