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 **************************************************************************/
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"
36 dxt5_endpoint_optimizer::dxt5_endpoint_optimizer()
40 m_unique_values.reserve(16);
41 m_unique_value_weights.reserve(16);
44 bool dxt5_endpoint_optimizer::compute(const params &p, results &r)
49 if ((!p.m_num_pixels) || (!p.m_pPixels))
52 m_unique_values.resize(0);
53 m_unique_value_weights.resize(0);
55 for (uint i = 0; i < 256; i++)
56 m_unique_value_map[i] = -1;
58 for (uint i = 0; i < p.m_num_pixels; i++)
60 uint alpha = p.m_pPixels[i][p.m_comp_index];
62 int index = m_unique_value_map[alpha];
66 index = m_unique_values.size();
68 m_unique_value_map[alpha] = index;
70 m_unique_values.push_back(static_cast<uint8>(alpha));
71 m_unique_value_weights.push_back(0);
74 m_unique_value_weights[index]++;
77 if (m_unique_values.size() == 1)
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);
87 m_trial_selectors.resize(m_unique_values.size());
88 m_best_selectors.resize(m_unique_values.size());
90 r.m_error = cUINT64_MAX;
92 for (uint i = 0; i < m_unique_values.size() - 1; i++)
94 const uint low_endpoint = m_unique_values[i];
96 for (uint j = i + 1; j < m_unique_values.size(); j++)
98 const uint high_endpoint = m_unique_values[j];
100 evaluate_solution(low_endpoint, high_endpoint);
104 if ((m_pParams->m_quality >= cCRNDXTQualityBetter) && (m_pResults->m_error))
106 m_flags.resize(256 * 256);
107 m_flags.clear_all_bits();
109 const int cProbeAmount = (m_pParams->m_quality == cCRNDXTQualityUber) ? 16 : 8;
111 for (int l_delta = -cProbeAmount; l_delta <= cProbeAmount; l_delta++)
113 const int l = m_pResults->m_first_endpoint + l_delta;
119 const uint bit_index = l * 256;
121 for (int h_delta = -cProbeAmount; h_delta <= cProbeAmount; h_delta++)
123 const int h = m_pResults->m_second_endpoint + h_delta;
129 //if (m_flags.get_bit(bit_index + h))
131 if ((m_flags.get_bit(bit_index + h)) || (m_flags.get_bit(h * 256 + l)))
133 m_flags.set_bit(bit_index + h);
135 evaluate_solution(static_cast<uint>(l), static_cast<uint>(h));
140 if (m_pResults->m_first_endpoint == m_pResults->m_second_endpoint)
142 for (uint i = 0; i < m_best_selectors.size(); i++)
143 m_best_selectors[i] = 0;
145 else if (m_pResults->m_block_type)
152 if (m_pResults->m_first_endpoint > m_pResults->m_second_endpoint)
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]];
159 else if (!(m_pResults->m_first_endpoint > m_pResults->m_second_endpoint))
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]];
166 for (uint i = 0; i < m_pParams->m_num_pixels; i++)
168 uint alpha = m_pParams->m_pPixels[i][m_pParams->m_comp_index];
170 int index = m_unique_value_map[alpha];
172 m_pResults->m_pSelectors[i] = m_best_selectors[index];
178 void dxt5_endpoint_optimizer::evaluate_solution(uint low_endpoint, uint high_endpoint)
180 for (uint block_type = 0; block_type < (m_pParams->m_use_both_block_types ? 2U : 1U); block_type++)
182 uint selector_values[8];
185 dxt5_block::get_block_values8(selector_values, low_endpoint, high_endpoint);
187 dxt5_block::get_block_values6(selector_values, low_endpoint, high_endpoint);
189 uint64_t trial_error = 0;
191 for (uint i = 0; i < m_unique_values.size(); i++)
193 const uint val = m_unique_values[i];
194 const uint weight = m_unique_value_weights[i];
196 uint best_selector_error = UINT_MAX;
197 uint best_selector = 0;
199 for (uint j = 0; j < 8; j++)
201 int selector_error = val - selector_values[j];
202 selector_error = selector_error * selector_error * (int)weight;
204 if (static_cast<uint>(selector_error) < best_selector_error)
206 best_selector_error = selector_error;
208 if (!best_selector_error)
213 m_trial_selectors[i] = static_cast<uint8>(best_selector);
214 trial_error += best_selector_error;
216 if (trial_error > m_pResults->m_error)
220 if (trial_error < m_pResults->m_error)
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);