]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_dxt_image.h
Initial vogl checkin
[vogl] / src / voglcore / vogl_dxt_image.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_dxt_image.h
28 #pragma once
29
30 #include "vogl_core.h"
31 #include "vogl_dxt1.h"
32 #include "vogl_dxt5a.h"
33 #include "vogl_image.h"
34 #include "vogl_rg_etc1.h"
35
36 #define VOGL_SUPPORT_ATI_COMPRESS 0
37
38 namespace vogl
39 {
40     class task_pool;
41
42     class dxt_image
43     {
44     public:
45         dxt_image();
46         dxt_image(const dxt_image &other);
47         dxt_image &operator=(const dxt_image &rhs);
48
49         void clear();
50
51         inline bool is_valid() const
52         {
53             return m_blocks_x > 0;
54         }
55
56         uint get_width() const
57         {
58             return m_width;
59         }
60         uint get_height() const
61         {
62             return m_height;
63         }
64
65         uint get_blocks_x() const
66         {
67             return m_blocks_x;
68         }
69         uint get_blocks_y() const
70         {
71             return m_blocks_y;
72         }
73         uint get_total_blocks() const
74         {
75             return m_blocks_x * m_blocks_y;
76         }
77
78         uint get_elements_per_block() const
79         {
80             return m_num_elements_per_block;
81         }
82         uint get_bytes_per_block() const
83         {
84             return m_bytes_per_block;
85         }
86
87         dxt_format get_format() const
88         {
89             return m_format;
90         }
91
92         bool has_color() const
93         {
94             return (m_format == cDXT1) || (m_format == cDXT1A) || (m_format == cDXT3) || (m_format == cDXT5) || (m_format == cETC1);
95         }
96
97         // Will be pretty slow if the image is DXT1, as this method scans for alpha blocks/selectors.
98         bool has_alpha() const;
99
100         enum element_type
101         {
102             cUnused = 0,
103             cColorDXT1, // DXT1 color block
104             cAlphaDXT3, // DXT3 alpha block (only)
105             cAlphaDXT5, // DXT5 alpha block (only)
106             cColorETC1, // ETC1 color block
107         };
108
109         element_type get_element_type(uint element_index) const
110         {
111             VOGL_ASSERT(element_index < m_num_elements_per_block);
112             return m_element_type[element_index];
113         }
114
115         //Returns -1 for RGB, or [0,3]
116         int8 get_element_component_index(uint element_index) const
117         {
118             VOGL_ASSERT(element_index < m_num_elements_per_block);
119             return m_element_component_index[element_index];
120         }
121
122         struct element
123         {
124             uint8 m_bytes[8];
125
126             uint get_le_word(uint index) const
127             {
128                 VOGL_ASSERT(index < 4);
129                 return m_bytes[index * 2] | (m_bytes[index * 2 + 1] << 8);
130             }
131             uint get_be_word(uint index) const
132             {
133                 VOGL_ASSERT(index < 4);
134                 return m_bytes[index * 2 + 1] | (m_bytes[index * 2] << 8);
135             }
136
137             void set_le_word(uint index, uint val)
138             {
139                 VOGL_ASSERT((index < 4) && (val <= cUINT16_MAX));
140                 m_bytes[index * 2] = static_cast<uint8>(val & 0xFF);
141                 m_bytes[index * 2 + 1] = static_cast<uint8>((val >> 8) & 0xFF);
142             }
143             void set_be_word(uint index, uint val)
144             {
145                 VOGL_ASSERT((index < 4) && (val <= cUINT16_MAX));
146                 m_bytes[index * 2 + 1] = static_cast<uint8>(val & 0xFF);
147                 m_bytes[index * 2] = static_cast<uint8>((val >> 8) & 0xFF);
148             }
149
150             void clear()
151             {
152                 memset(this, 0, sizeof(*this));
153             }
154         };
155
156         typedef vogl::vector<element> element_vec;
157
158         bool init(dxt_format fmt, uint width, uint height, bool clear_elements);
159         bool init(dxt_format fmt, uint width, uint height, uint num_elements, element *pElements, bool create_copy);
160
161         struct pack_params
162         {
163             pack_params()
164             {
165                 clear();
166             }
167
168             void clear()
169             {
170                 m_quality = cCRNDXTQualityUber;
171                 m_perceptual = true;
172                 m_dithering = false;
173                 m_grayscale_sampling = false;
174                 m_use_both_block_types = true;
175                 m_endpoint_caching = true;
176                 m_compressor = cCRNDXTCompressorCRN;
177                 m_pProgress_callback = NULL;
178                 m_pProgress_callback_user_data_ptr = NULL;
179                 m_dxt1a_alpha_threshold = 128;
180                 m_num_helper_threads = 0;
181                 m_progress_start = 0;
182                 m_progress_range = 100;
183                 m_use_transparent_indices_for_black = false;
184                 m_pTask_pool = NULL;
185                 m_color_weights[0] = 1;
186                 m_color_weights[1] = 1;
187                 m_color_weights[2] = 1;
188             }
189
190             void init(const vogl_comp_params &params)
191             {
192                 m_perceptual = (params.m_flags & cCRNCompFlagPerceptual) != 0;
193                 m_num_helper_threads = params.m_num_helper_threads;
194                 m_use_both_block_types = (params.m_flags & cCRNCompFlagUseBothBlockTypes) != 0;
195                 m_use_transparent_indices_for_black = (params.m_flags & cCRNCompFlagUseTransparentIndicesForBlack) != 0;
196                 m_dxt1a_alpha_threshold = params.m_dxt1a_alpha_threshold;
197                 m_quality = params.m_dxt_quality;
198                 m_endpoint_caching = (params.m_flags & cCRNCompFlagDisableEndpointCaching) == 0;
199                 m_grayscale_sampling = (params.m_flags & cCRNCompFlagGrayscaleSampling) != 0;
200                 m_compressor = params.m_dxt_compressor_type;
201             }
202
203             uint m_dxt1a_alpha_threshold;
204
205             uint m_num_helper_threads;
206
207             vogl_dxt_quality m_quality;
208
209             vogl_dxt_compressor_type m_compressor;
210
211             bool m_perceptual;
212             bool m_dithering;
213             bool m_grayscale_sampling;
214             bool m_use_both_block_types;
215             bool m_endpoint_caching;
216             bool m_use_transparent_indices_for_black;
217
218             typedef bool (*progress_callback_func)(uint percentage_complete, void *pUser_data_ptr);
219             progress_callback_func m_pProgress_callback;
220             void *m_pProgress_callback_user_data_ptr;
221
222             uint m_progress_start;
223             uint m_progress_range;
224
225             task_pool *m_pTask_pool;
226
227             int m_color_weights[3];
228         };
229
230         bool init(dxt_format fmt, const image_u8 &img, const pack_params &p = dxt_image::pack_params());
231
232         bool unpack(image_u8 &img) const;
233
234         void endian_swap();
235
236         uint get_total_elements() const
237         {
238             return m_elements.size();
239         }
240
241         const element_vec &get_element_vec() const
242         {
243             return m_elements;
244         }
245         element_vec &get_element_vec()
246         {
247             return m_elements;
248         }
249
250         const element &get_element(uint block_x, uint block_y, uint element_index) const;
251         element &get_element(uint block_x, uint block_y, uint element_index);
252
253         const element *get_element_ptr() const
254         {
255             return m_pElements;
256         }
257         element *get_element_ptr()
258         {
259             return m_pElements;
260         }
261
262         uint get_size_in_bytes() const
263         {
264             return m_elements.size() * sizeof(element);
265         }
266         uint get_row_pitch_in_bytes() const
267         {
268             return m_blocks_x * m_bytes_per_block;
269         }
270
271         color_quad_u8 get_pixel(uint x, uint y) const;
272         uint get_pixel_alpha(uint x, uint y, uint element_index) const;
273
274         void set_pixel(uint x, uint y, const color_quad_u8 &c, bool perceptual = true);
275
276         // get_block_pixels() only sets those components stored in the image!
277         bool get_block_pixels(uint block_x, uint block_y, color_quad_u8 *pPixels) const;
278
279         struct set_block_pixels_context
280         {
281             dxt1_endpoint_optimizer m_dxt1_optimizer;
282             dxt5_endpoint_optimizer m_dxt5_optimizer;
283         };
284
285         void set_block_pixels(uint block_x, uint block_y, const color_quad_u8 *pPixels, const pack_params &p, set_block_pixels_context &context);
286         void set_block_pixels(uint block_x, uint block_y, const color_quad_u8 *pPixels, const pack_params &p);
287
288         void get_block_endpoints(uint block_x, uint block_y, uint element_index, uint &packed_low_endpoint, uint &packed_high_endpoint) const;
289
290         // Returns a value representing the component(s) that where actually set, where -1 = RGB.
291         // This method does not always set every component!
292         int get_block_endpoints(uint block_x, uint block_y, uint element_index, color_quad_u8 &low_endpoint, color_quad_u8 &high_endpoint, bool scaled = true) const;
293
294         // pColors should point to a 16 entry array, to handle DXT3.
295         // Returns the number of block colors: 3, 4, 6, 8, or 16.
296         uint get_block_colors(uint block_x, uint block_y, uint element_index, color_quad_u8 *pColors, uint subblock_index = 0);
297
298         uint get_subblock_index(uint x, uint y, uint element_index) const;
299         uint get_total_subblocks(uint element_index) const;
300
301         uint get_selector(uint x, uint y, uint element_index) const;
302
303         void change_dxt1_to_dxt1a();
304
305         bool can_flip(uint axis_index);
306
307         // Returns true if the texture can actually be flipped.
308         bool flip_x();
309         bool flip_y();
310
311     private:
312         element_vec m_elements;
313         element *m_pElements;
314
315         uint m_width;
316         uint m_height;
317
318         uint m_blocks_x;
319         uint m_blocks_y;
320         uint m_total_blocks;
321         uint m_total_elements;
322
323         uint m_num_elements_per_block; // 1 or 2
324         uint m_bytes_per_block;        // 8 or 16
325
326         int8 m_element_component_index[2];
327         element_type m_element_type[2];
328
329         dxt_format m_format; // DXT1, 1A, 3, 5, N/3DC, or 5A
330
331         bool init_internal(dxt_format fmt, uint width, uint height);
332         void init_task(uint64_t data, void *pData_ptr);
333
334 #if VOGL_SUPPORT_ATI_COMPRESS
335         bool init_ati_compress(dxt_format fmt, const image_u8 &img, const pack_params &p);
336 #endif
337
338         void flip_col(uint x);
339         void flip_row(uint y);
340     };
341
342 } // namespace vogl