]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_mipmapped_texture.h
Initial vogl checkin
[vogl] / src / voglcore / vogl_mipmapped_texture.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_mipmapped_texture.h
28 #pragma once
29
30 #include "vogl_core.h"
31 #include "vogl_dxt_image.h"
32 #include "dds_defs.h"
33 #include "vogl_pixel_format.h"
34 #include "vogl_image.h"
35 #include "vogl_resampler.h"
36 #include "vogl_data_stream_serializer.h"
37 #include "vogl_texture_file_types.h"
38 #include "vogl_image_utils.h"
39
40 namespace vogl
41 {
42     class ktx_texture;
43
44     extern const vec2I g_vertical_cross_image_offsets[6];
45
46     enum orientation_flags_t
47     {
48         cOrientationFlagXFlipped = 1,
49         cOrientationFlagYFlipped = 2,
50         cDefaultOrientationFlags = 0
51     };
52
53     enum unpack_flags_t
54     {
55         cUnpackFlagUncook = 1,
56         cUnpackFlagUnflip = 2
57     };
58
59     class mip_level
60     {
61         friend class mipmapped_texture;
62
63     public:
64         mip_level();
65         ~mip_level();
66
67         mip_level(const mip_level &other);
68         mip_level &operator=(const mip_level &rhs);
69
70         // Assumes ownership.
71         void assign(image_u8 *p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
72         void assign(dxt_image *p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
73
74         void clear();
75
76         inline uint get_width() const
77         {
78             return m_width;
79         }
80         inline uint get_height() const
81         {
82             return m_height;
83         }
84         inline uint get_total_pixels() const
85         {
86             return m_width * m_height;
87         }
88
89         orientation_flags_t get_orientation_flags() const
90         {
91             return m_orient_flags;
92         }
93         void set_orientation_flags(orientation_flags_t flags)
94         {
95             m_orient_flags = flags;
96         }
97
98         inline image_u8 *get_image() const
99         {
100             return m_pImage;
101         }
102         inline dxt_image *get_dxt_image() const
103         {
104             return m_pDXTImage;
105         }
106
107         image_u8 *get_unpacked_image(image_u8 &tmp, uint unpack_flags) const;
108
109         inline bool is_packed() const
110         {
111             return m_pDXTImage != NULL;
112         }
113
114         inline bool is_valid() const
115         {
116             return (m_pImage != NULL) || (m_pDXTImage != NULL);
117         }
118
119         inline pixel_format_helpers::component_flags get_comp_flags() const
120         {
121             return m_comp_flags;
122         }
123         inline void set_comp_flags(pixel_format_helpers::component_flags comp_flags)
124         {
125             m_comp_flags = comp_flags;
126         }
127
128         inline pixel_format get_format() const
129         {
130             return m_format;
131         }
132         inline void set_format(pixel_format fmt)
133         {
134             m_format = fmt;
135         }
136
137         bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params &p);
138
139         bool pack_to_dxt(const image_u8 &img, pixel_format fmt, bool cook, const dxt_image::pack_params &p, orientation_flags_t orient_flags = cDefaultOrientationFlags);
140         bool pack_to_dxt(pixel_format fmt, bool cook, const dxt_image::pack_params &p);
141
142         bool unpack_from_dxt(bool uncook = true);
143
144         // Returns true if flipped on either axis.
145         bool is_flipped() const;
146
147         bool is_x_flipped() const;
148         bool is_y_flipped() const;
149
150         bool can_unflip_without_unpacking() const;
151
152         // Returns true if unflipped on either axis.
153         // Will try to flip packed (DXT/ETC) data in-place, if this isn't possible it'll unpack/uncook the mip level then unflip.
154         bool unflip(bool allow_unpacking_to_flip, bool uncook_during_unpack);
155
156         bool set_alpha_to_luma();
157         bool convert(image_utils::conversion_type conv_type);
158
159         bool flip_x();
160         bool flip_y();
161
162     private:
163         uint m_width;
164         uint m_height;
165
166         pixel_format_helpers::component_flags m_comp_flags;
167         pixel_format m_format;
168
169         image_u8 *m_pImage;
170         dxt_image *m_pDXTImage;
171
172         orientation_flags_t m_orient_flags;
173
174         void cook_image(image_u8 &img) const;
175         void uncook_image(image_u8 &img) const;
176     };
177
178     // A face is an array of mip_level ptr's.
179     typedef vogl::vector<mip_level *> mip_ptr_vec;
180
181     // And an array of one, six, or N faces make up a texture.
182     typedef vogl::vector<mip_ptr_vec> face_vec;
183
184     class mipmapped_texture
185     {
186     public:
187         // Construction/destruction
188         mipmapped_texture();
189         ~mipmapped_texture();
190
191         mipmapped_texture(const mipmapped_texture &other);
192         mipmapped_texture &operator=(const mipmapped_texture &rhs);
193
194         void clear();
195
196         void init(uint width, uint height, uint levels, uint faces, pixel_format fmt, const char *pName, orientation_flags_t orient_flags);
197
198         // Assumes ownership.
199         void assign(face_vec &faces);
200         void assign(mip_level *pLevel);
201         void assign(image_u8 *p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
202         void assign(dxt_image *p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
203
204         void set(texture_file_types::format source_file_type, const mipmapped_texture &mipmapped_texture);
205
206         // Accessors
207         image_u8 *get_level_image(uint face, uint level, image_u8 &img, uint unpack_flags = cUnpackFlagUncook | cUnpackFlagUnflip) const;
208
209         inline bool is_valid() const
210         {
211             return m_faces.size() > 0;
212         }
213
214         const dynamic_string &get_name() const
215         {
216             return m_name;
217         }
218         void set_name(const dynamic_string &name)
219         {
220             m_name = name;
221         }
222
223         const dynamic_string &get_source_filename() const
224         {
225             return get_name();
226         }
227         texture_file_types::format get_source_file_type() const
228         {
229             return m_source_file_type;
230         }
231
232         inline uint get_width() const
233         {
234             return m_width;
235         }
236         inline uint get_height() const
237         {
238             return m_height;
239         }
240         inline uint get_total_pixels() const
241         {
242             return m_width * m_height;
243         }
244         uint get_total_pixels_in_all_faces_and_mips() const;
245
246         inline uint get_num_faces() const
247         {
248             return m_faces.size();
249         }
250         inline uint get_num_levels() const
251         {
252             if (m_faces.is_empty())
253                 return 0;
254             else
255                 return m_faces[0].size();
256         }
257
258         inline pixel_format_helpers::component_flags get_comp_flags() const
259         {
260             return m_comp_flags;
261         }
262         inline pixel_format get_format() const
263         {
264             return m_format;
265         }
266
267         inline bool is_unpacked() const
268         {
269             if (get_num_faces())
270             {
271                 return get_level(0, 0)->get_image() != NULL;
272             }
273             return false;
274         }
275
276         inline const mip_ptr_vec &get_face(uint face) const
277         {
278             return m_faces[face];
279         }
280         inline mip_ptr_vec &get_face(uint face)
281         {
282             return m_faces[face];
283         }
284
285         inline const mip_level *get_level(uint face, uint mip) const
286         {
287             return m_faces[face][mip];
288         }
289         inline mip_level *get_level(uint face, uint mip)
290         {
291             return m_faces[face][mip];
292         }
293
294         bool has_alpha() const;
295         bool is_normal_map() const;
296         bool is_vertical_cross() const;
297         bool is_packed() const;
298         texture_type determine_texture_type() const;
299
300         const dynamic_string &get_last_error() const
301         {
302             return m_last_error;
303         }
304         void clear_last_error()
305         {
306             m_last_error.clear();
307         }
308
309         // Reading/writing
310         bool read_dds(data_stream_serializer &serializer);
311         bool write_dds(data_stream_serializer &serializer) const;
312
313         bool read_ktx(data_stream_serializer &serializer);
314         bool read_ktx(const vogl::ktx_texture &ktx);
315         bool write_ktx(data_stream_serializer &serializer) const;
316
317         // If file_format is texture_file_types::cFormatInvalid, the format will be determined from the filename's extension.
318         bool read_from_file(const char *pFilename, texture_file_types::format file_format = texture_file_types::cFormatInvalid);
319         bool read_from_stream(data_stream_serializer &serializer, texture_file_types::format file_format = texture_file_types::cFormatInvalid);
320
321         bool write_to_file(
322             const char *pFilename,
323             texture_file_types::format file_format = texture_file_types::cFormatInvalid,
324             vogl_comp_params *pComp_params = NULL,
325             uint32 *pActual_quality_level = NULL, float *pActual_bitrate = NULL,
326             uint32 image_write_flags = 0);
327
328         // Conversion
329         bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params &p);
330         bool convert(pixel_format fmt, const dxt_image::pack_params &p);
331         bool convert(image_utils::conversion_type conv_type);
332
333         bool unpack_from_dxt(bool uncook = true);
334
335         bool set_alpha_to_luma();
336
337         void discard_mipmaps();
338
339         void discard_mips();
340
341         struct resample_params
342         {
343             resample_params()
344                 : m_pFilter("kaiser"),
345                   m_wrapping(false),
346                   m_srgb(false),
347                   m_renormalize(false),
348                   m_filter_scale(.9f),
349                   m_gamma(1.75f), // or 2.2f
350                   m_multithreaded(true)
351             {
352             }
353
354             const char *m_pFilter;
355             bool m_wrapping;
356             bool m_srgb;
357             bool m_renormalize;
358             float m_filter_scale;
359             float m_gamma;
360             bool m_multithreaded;
361         };
362
363         bool resize(uint new_width, uint new_height, const resample_params &params);
364
365         struct generate_mipmap_params : public resample_params
366         {
367             generate_mipmap_params()
368                 : resample_params(),
369                   m_min_mip_size(1),
370                   m_max_mips(0)
371             {
372             }
373
374             uint m_min_mip_size;
375             uint m_max_mips; // actually the max # of total levels
376         };
377
378         bool generate_mipmaps(const generate_mipmap_params &params, bool force);
379
380         bool crop(uint x, uint y, uint width, uint height);
381
382         bool vertical_cross_to_cubemap();
383
384         void swap(mipmapped_texture &img);
385
386         bool check() const;
387
388         void set_orientation_flags(orientation_flags_t flags);
389
390         // Returns true if any face/miplevel is flipped.
391         bool is_flipped() const;
392         bool is_x_flipped() const;
393         bool is_y_flipped() const;
394         bool can_unflip_without_unpacking() const;
395         bool unflip(bool allow_unpacking_to_flip, bool uncook_if_necessary_to_unpack);
396
397         bool flip_y(bool update_orientation_flags);
398
399     private:
400         dynamic_string m_name;
401
402         uint m_width;
403         uint m_height;
404
405         pixel_format_helpers::component_flags m_comp_flags;
406         pixel_format m_format;
407
408         face_vec m_faces;
409
410         texture_file_types::format m_source_file_type;
411
412         mutable dynamic_string m_last_error;
413
414         inline void clear_last_error() const
415         {
416             m_last_error.clear();
417         }
418         inline void set_last_error(const char *p) const
419         {
420             m_last_error = p;
421         }
422
423         void free_all_mips();
424         bool read_regular_image(data_stream_serializer &serializer, texture_file_types::format file_format);
425         bool write_regular_image(const char *pFilename, uint32 image_write_flags);
426         bool read_dds_internal(data_stream_serializer &serializer);
427         void change_dxt1_to_dxt1a();
428         bool flip_y_helper();
429     };
430
431     inline void swap(mipmapped_texture &a, mipmapped_texture &b)
432     {
433         a.swap(b);
434     }
435
436 } // namespace vogl