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"
35 struct dxt1_solution_coordinates
37 inline dxt1_solution_coordinates()
38 : m_low_color(0), m_high_color(0)
42 inline dxt1_solution_coordinates(uint16 l, uint16 h)
43 : m_low_color(l), m_high_color(h)
47 inline dxt1_solution_coordinates(const color_quad_u8 &l, const color_quad_u8 &h, bool scaled = true)
48 : m_low_color(dxt1_block::pack_color(l, scaled)),
49 m_high_color(dxt1_block::pack_color(h, scaled))
53 inline dxt1_solution_coordinates(vec3F nl, vec3F nh)
55 #if VOGL_DXT_ALT_ROUNDING
57 nl.clamp(0.0f, .999f);
58 nh.clamp(0.0f, .999f);
59 color_quad_u8 l((int)floor(nl[0] * 32.0f), (int)floor(nl[1] * 64.0f), (int)floor(nl[2] * 32.0f), 255);
60 color_quad_u8 h((int)floor(nh[0] * 32.0f), (int)floor(nh[1] * 64.0f), (int)floor(nh[2] * 32.0f), 255);
63 color_quad_u8 l((int)floor(.5f + nl[0] * 31.0f), (int)floor(.5f + nl[1] * 63.0f), (int)floor(.5f + nl[2] * 31.0f), 255);
64 color_quad_u8 h((int)floor(.5f + nh[0] * 31.0f), (int)floor(.5f + nh[1] * 63.0f), (int)floor(.5f + nh[2] * 31.0f), 255);
67 m_low_color = dxt1_block::pack_color(l, false);
68 m_high_color = dxt1_block::pack_color(h, false);
80 inline dxt1_solution_coordinates &canonicalize()
82 if (m_low_color < m_high_color)
83 utils::swap(m_low_color, m_high_color);
87 inline operator size_t() const
89 return fast_hash(this, sizeof(*this));
92 inline bool operator==(const dxt1_solution_coordinates &other) const
94 uint16 l0 = math::minimum(m_low_color, m_high_color);
95 uint16 h0 = math::maximum(m_low_color, m_high_color);
97 uint16 l1 = math::minimum(other.m_low_color, other.m_high_color);
98 uint16 h1 = math::maximum(other.m_low_color, other.m_high_color);
100 return (l0 == l1) && (h0 == h1);
103 inline bool operator!=(const dxt1_solution_coordinates &other) const
105 return !(*this == other);
108 inline bool operator<(const dxt1_solution_coordinates &other) const
110 uint16 l0 = math::minimum(m_low_color, m_high_color);
111 uint16 h0 = math::maximum(m_low_color, m_high_color);
113 uint16 l1 = math::minimum(other.m_low_color, other.m_high_color);
114 uint16 h1 = math::maximum(other.m_low_color, other.m_high_color);
128 typedef vogl::vector<dxt1_solution_coordinates> dxt1_solution_coordinates_vec;
130 VOGL_DEFINE_BITWISE_COPYABLE(dxt1_solution_coordinates);
134 inline unique_color()
137 inline unique_color(const color_quad_u8 &color, uint weight)
138 : m_color(color), m_weight(weight)
142 color_quad_u8 m_color;
145 inline bool operator<(const unique_color &c) const
147 return *reinterpret_cast<const uint32 *>(&m_color) < *reinterpret_cast<const uint32 *>(&c.m_color);
150 inline bool operator==(const unique_color &c) const
152 return *reinterpret_cast<const uint32 *>(&m_color) == *reinterpret_cast<const uint32 *>(&c.m_color);
156 VOGL_DEFINE_BITWISE_COPYABLE(unique_color);
158 class dxt1_endpoint_optimizer
161 dxt1_endpoint_optimizer();
169 m_dxt1a_alpha_threshold(128U),
170 m_quality(cCRNDXTQualityUber),
171 m_pixels_have_alpha(false),
172 m_use_alpha_blocks(true),
174 m_grayscale_sampling(false),
175 m_endpoint_caching(true),
176 m_use_transparent_indices_for_black(false),
177 m_force_alpha_blocks(false)
179 m_color_weights[0] = 1;
180 m_color_weights[1] = 1;
181 m_color_weights[2] = 1;
186 const color_quad_u8 *m_pPixels;
188 uint m_dxt1a_alpha_threshold;
190 vogl_dxt_quality m_quality;
192 bool m_pixels_have_alpha;
193 bool m_use_alpha_blocks;
195 bool m_grayscale_sampling;
196 bool m_endpoint_caching;
197 bool m_use_transparent_indices_for_black;
198 bool m_force_alpha_blocks;
199 int m_color_weights[3];
224 solution(const solution &other)
226 m_results = other.m_results;
227 m_selectors = other.m_selectors;
228 m_results.m_pSelectors = m_selectors.begin();
231 solution &operator=(const solution &rhs)
236 m_results = rhs.m_results;
237 m_selectors = rhs.m_selectors;
238 m_results.m_pSelectors = m_selectors.begin();
244 vogl::vector<uint8> m_selectors;
246 inline bool operator<(const solution &other) const
248 return m_results.m_error < other.m_results.m_error;
250 static inline bool coords_equal(const solution &lhs, const solution &rhs)
252 return (lhs.m_results.m_low_color == rhs.m_results.m_low_color) && (lhs.m_results.m_high_color == rhs.m_results.m_high_color);
255 typedef vogl::vector<solution> solution_vec;
257 bool compute(const params &p, results &r, solution_vec *pSolutions = NULL);
260 const params *m_pParams;
262 solution_vec *m_pSolutions;
265 bool m_has_color_weighting;
267 typedef vogl::vector<unique_color> unique_color_vec;
269 //typedef vogl::hash_map<uint32, uint32, bit_hasher<uint32> > unique_color_hash_map;
270 typedef vogl::hash_map<uint32, uint32> unique_color_hash_map;
271 unique_color_hash_map m_unique_color_hash_map;
273 unique_color_vec m_unique_colors; // excludes transparent colors!
274 unique_color_vec m_temp_unique_colors;
276 uint m_total_unique_color_weight;
278 bool m_has_transparent_pixels;
280 vec3F_array m_norm_unique_colors;
281 vec3F m_mean_norm_color;
283 vec3F_array m_norm_unique_colors_weighted;
284 vec3F m_mean_norm_color_weighted;
286 vec3F m_principle_axis;
288 bool m_all_pixels_grayscale;
290 vogl::vector<uint16> m_unique_packed_colors;
291 vogl::vector<uint8> m_trial_selectors;
293 vogl::vector<vec3F> m_low_coords;
294 vogl::vector<vec3F> m_high_coords;
300 dxt1_solution_coordinates m_prev_results[cMaxPrevResults];
301 uint m_num_prev_results;
303 vogl::vector<vec3I> m_lo_cells;
304 vogl::vector<vec3I> m_hi_cells;
308 struct potential_solution
311 : m_coords(), m_error(cUINT64_MAX), m_alpha_block(false), m_valid(false)
315 dxt1_solution_coordinates m_coords;
316 vogl::vector<uint8> m_selectors;
324 m_selectors.resize(0);
325 m_error = cUINT64_MAX;
326 m_alpha_block = false;
330 bool are_selectors_all_equal() const
332 if (m_selectors.is_empty())
334 const uint s = m_selectors[0];
335 for (uint i = 1; i < m_selectors.size(); i++)
336 if (m_selectors[i] != s)
342 potential_solution m_trial_solution;
343 potential_solution m_best_solution;
345 typedef vogl::hash_map<uint, empty_type> solution_hash_map;
346 solution_hash_map m_solutions_tried;
348 bool refine_solution(int refinement_level = 0);
350 bool evaluate_solution(
351 const dxt1_solution_coordinates &coords,
353 potential_solution *pBest_solution,
354 bool alternate_rounding = false);
356 bool evaluate_solution_uber(
357 potential_solution &solution,
358 const dxt1_solution_coordinates &coords,
360 potential_solution *pBest_solution,
361 bool alternate_rounding = false);
363 bool evaluate_solution_fast(
364 potential_solution &solution,
365 const dxt1_solution_coordinates &coords,
367 potential_solution *pBest_solution,
368 bool alternate_rounding = false);
371 void find_unique_colors();
372 bool handle_all_transparent_block();
373 bool handle_solid_block();
374 bool handle_multicolor_block();
375 bool handle_grayscale_block();
376 void compute_pca(vec3F &axis, const vec3F_array &norm_colors, const vec3F &def);
377 void compute_vectors(const vec3F &perceptual_weights);
378 void return_solution(results &results, const potential_solution &solution);
379 void try_combinatorial_encoding();
380 void optimize_endpoint_comps();
381 bool optimize_endpoints(vec3F &low_color, vec3F &high_color);
382 bool try_alpha_as_black_optimization();
383 bool try_average_block_as_solid();
384 bool try_median4(const vec3F &low_color, const vec3F &high_color);
386 bool compute_internal(const params &p, results &r, solution_vec *pSolutions);
388 unique_color lerp_color(const color_quad_u8 &a, const color_quad_u8 &b, float f, int rounding = 1);
390 inline uint color_distance(bool perceptual, const color_quad_u8 &e1, const color_quad_u8 &e2, bool alpha);
392 static inline vec3F unpack_to_vec3F_raw(uint16 packed_color);
393 static inline vec3F unpack_to_vec3F(uint16 packed_color);
396 inline void swap(dxt1_endpoint_optimizer::solution &a, dxt1_endpoint_optimizer::solution &b)
398 std::swap(a.m_results, b.m_results);
399 a.m_selectors.swap(b.m_selectors);