]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_dxt1.h
Initial vogl checkin
[vogl] / src / voglcore / vogl_dxt1.h
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_dxt1.h
28 #pragma once
29
30 #include "vogl_core.h"
31 #include "vogl_dxt.h"
32
33 namespace vogl
34 {
35     struct dxt1_solution_coordinates
36     {
37         inline dxt1_solution_coordinates()
38             : m_low_color(0), m_high_color(0)
39         {
40         }
41
42         inline dxt1_solution_coordinates(uint16 l, uint16 h)
43             : m_low_color(l), m_high_color(h)
44         {
45         }
46
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))
50         {
51         }
52
53         inline dxt1_solution_coordinates(vec3F nl, vec3F nh)
54         {
55 #if VOGL_DXT_ALT_ROUNDING
56             // Umm, wtf?
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);
61 #else
62             // Fixes the bins
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);
65 #endif
66
67             m_low_color = dxt1_block::pack_color(l, false);
68             m_high_color = dxt1_block::pack_color(h, false);
69         }
70
71         uint16 m_low_color;
72         uint16 m_high_color;
73
74         inline void clear()
75         {
76             m_low_color = 0;
77             m_high_color = 0;
78         }
79
80         inline dxt1_solution_coordinates &canonicalize()
81         {
82             if (m_low_color < m_high_color)
83                 utils::swap(m_low_color, m_high_color);
84             return *this;
85         }
86
87         inline operator size_t() const
88         {
89             return fast_hash(this, sizeof(*this));
90         }
91
92         inline bool operator==(const dxt1_solution_coordinates &other) const
93         {
94             uint16 l0 = math::minimum(m_low_color, m_high_color);
95             uint16 h0 = math::maximum(m_low_color, m_high_color);
96
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);
99
100             return (l0 == l1) && (h0 == h1);
101         }
102
103         inline bool operator!=(const dxt1_solution_coordinates &other) const
104         {
105             return !(*this == other);
106         }
107
108         inline bool operator<(const dxt1_solution_coordinates &other) const
109         {
110             uint16 l0 = math::minimum(m_low_color, m_high_color);
111             uint16 h0 = math::maximum(m_low_color, m_high_color);
112
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);
115
116             if (l0 < l1)
117                 return true;
118             else if (l0 == l1)
119             {
120                 if (h0 < h1)
121                     return true;
122             }
123
124             return false;
125         }
126     };
127
128     typedef vogl::vector<dxt1_solution_coordinates> dxt1_solution_coordinates_vec;
129
130     VOGL_DEFINE_BITWISE_COPYABLE(dxt1_solution_coordinates);
131
132     struct unique_color
133     {
134         inline unique_color()
135         {
136         }
137         inline unique_color(const color_quad_u8 &color, uint weight)
138             : m_color(color), m_weight(weight)
139         {
140         }
141
142         color_quad_u8 m_color;
143         uint m_weight;
144
145         inline bool operator<(const unique_color &c) const
146         {
147             return *reinterpret_cast<const uint32 *>(&m_color) < *reinterpret_cast<const uint32 *>(&c.m_color);
148         }
149
150         inline bool operator==(const unique_color &c) const
151         {
152             return *reinterpret_cast<const uint32 *>(&m_color) == *reinterpret_cast<const uint32 *>(&c.m_color);
153         }
154     };
155
156     VOGL_DEFINE_BITWISE_COPYABLE(unique_color);
157
158     class dxt1_endpoint_optimizer
159     {
160     public:
161         dxt1_endpoint_optimizer();
162
163         struct params
164         {
165             params()
166                 : m_block_index(0),
167                   m_pPixels(NULL),
168                   m_num_pixels(0),
169                   m_dxt1a_alpha_threshold(128U),
170                   m_quality(cCRNDXTQualityUber),
171                   m_pixels_have_alpha(false),
172                   m_use_alpha_blocks(true),
173                   m_perceptual(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)
178             {
179                 m_color_weights[0] = 1;
180                 m_color_weights[1] = 1;
181                 m_color_weights[2] = 1;
182             }
183
184             uint m_block_index;
185
186             const color_quad_u8 *m_pPixels;
187             uint m_num_pixels;
188             uint m_dxt1a_alpha_threshold;
189
190             vogl_dxt_quality m_quality;
191
192             bool m_pixels_have_alpha;
193             bool m_use_alpha_blocks;
194             bool m_perceptual;
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];
200         };
201
202         struct results
203         {
204             inline results()
205                 : m_pSelectors(NULL)
206             {
207             }
208
209             uint64_t m_error;
210
211             uint16 m_low_color;
212             uint16 m_high_color;
213
214             uint8 *m_pSelectors;
215             bool m_alpha_block;
216         };
217
218         struct solution
219         {
220             solution()
221             {
222             }
223
224             solution(const solution &other)
225             {
226                 m_results = other.m_results;
227                 m_selectors = other.m_selectors;
228                 m_results.m_pSelectors = m_selectors.begin();
229             }
230
231             solution &operator=(const solution &rhs)
232             {
233                 if (this == &rhs)
234                     return *this;
235
236                 m_results = rhs.m_results;
237                 m_selectors = rhs.m_selectors;
238                 m_results.m_pSelectors = m_selectors.begin();
239
240                 return *this;
241             }
242
243             results m_results;
244             vogl::vector<uint8> m_selectors;
245
246             inline bool operator<(const solution &other) const
247             {
248                 return m_results.m_error < other.m_results.m_error;
249             }
250             static inline bool coords_equal(const solution &lhs, const solution &rhs)
251             {
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);
253             }
254         };
255         typedef vogl::vector<solution> solution_vec;
256
257         bool compute(const params &p, results &r, solution_vec *pSolutions = NULL);
258
259     private:
260         const params *m_pParams;
261         results *m_pResults;
262         solution_vec *m_pSolutions;
263
264         bool m_perceptual;
265         bool m_has_color_weighting;
266
267         typedef vogl::vector<unique_color> unique_color_vec;
268
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;
272
273         unique_color_vec m_unique_colors; // excludes transparent colors!
274         unique_color_vec m_temp_unique_colors;
275
276         uint m_total_unique_color_weight;
277
278         bool m_has_transparent_pixels;
279
280         vec3F_array m_norm_unique_colors;
281         vec3F m_mean_norm_color;
282
283         vec3F_array m_norm_unique_colors_weighted;
284         vec3F m_mean_norm_color_weighted;
285
286         vec3F m_principle_axis;
287
288         bool m_all_pixels_grayscale;
289
290         vogl::vector<uint16> m_unique_packed_colors;
291         vogl::vector<uint8> m_trial_selectors;
292
293         vogl::vector<vec3F> m_low_coords;
294         vogl::vector<vec3F> m_high_coords;
295
296         enum
297         {
298             cMaxPrevResults = 4
299         };
300         dxt1_solution_coordinates m_prev_results[cMaxPrevResults];
301         uint m_num_prev_results;
302
303         vogl::vector<vec3I> m_lo_cells;
304         vogl::vector<vec3I> m_hi_cells;
305
306         uint m_total_evals;
307
308         struct potential_solution
309         {
310             potential_solution()
311                 : m_coords(), m_error(cUINT64_MAX), m_alpha_block(false), m_valid(false)
312             {
313             }
314
315             dxt1_solution_coordinates m_coords;
316             vogl::vector<uint8> m_selectors;
317             uint64_t m_error;
318             bool m_alpha_block;
319             bool m_valid;
320
321             void clear()
322             {
323                 m_coords.clear();
324                 m_selectors.resize(0);
325                 m_error = cUINT64_MAX;
326                 m_alpha_block = false;
327                 m_valid = false;
328             }
329
330             bool are_selectors_all_equal() const
331             {
332                 if (m_selectors.is_empty())
333                     return false;
334                 const uint s = m_selectors[0];
335                 for (uint i = 1; i < m_selectors.size(); i++)
336                     if (m_selectors[i] != s)
337                         return false;
338                 return true;
339             }
340         };
341
342         potential_solution m_trial_solution;
343         potential_solution m_best_solution;
344
345         typedef vogl::hash_map<uint, empty_type> solution_hash_map;
346         solution_hash_map m_solutions_tried;
347
348         bool refine_solution(int refinement_level = 0);
349
350         bool evaluate_solution(
351             const dxt1_solution_coordinates &coords,
352             bool early_out,
353             potential_solution *pBest_solution,
354             bool alternate_rounding = false);
355
356         bool evaluate_solution_uber(
357             potential_solution &solution,
358             const dxt1_solution_coordinates &coords,
359             bool early_out,
360             potential_solution *pBest_solution,
361             bool alternate_rounding = false);
362
363         bool evaluate_solution_fast(
364             potential_solution &solution,
365             const dxt1_solution_coordinates &coords,
366             bool early_out,
367             potential_solution *pBest_solution,
368             bool alternate_rounding = false);
369
370         void clear();
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);
385
386         bool compute_internal(const params &p, results &r, solution_vec *pSolutions);
387
388         unique_color lerp_color(const color_quad_u8 &a, const color_quad_u8 &b, float f, int rounding = 1);
389
390         inline uint color_distance(bool perceptual, const color_quad_u8 &e1, const color_quad_u8 &e2, bool alpha);
391
392         static inline vec3F unpack_to_vec3F_raw(uint16 packed_color);
393         static inline vec3F unpack_to_vec3F(uint16 packed_color);
394     };
395
396     inline void swap(dxt1_endpoint_optimizer::solution &a, dxt1_endpoint_optimizer::solution &b)
397     {
398         std::swap(a.m_results, b.m_results);
399         a.m_selectors.swap(b.m_selectors);
400     }
401
402 } // namespace vogl