]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_ktx_texture.h
Initial vogl checkin
[vogl] / src / voglcore / vogl_ktx_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_ktx_texture.h
28 #ifndef _KTX_TEXTURE_H_
29 #define _KTX_TEXTURE_H_
30 #ifdef _MSC_VER
31 #pragma once
32 #endif
33
34 #include "vogl_core.h"
35 #include "vogl_data_stream_serializer.h"
36
37 #define KTX_ENDIAN 0x04030201
38 #define KTX_OPPOSITE_ENDIAN 0x01020304
39
40 namespace vogl
41 {
42     extern const uint8 s_ktx_file_id[12];
43
44     struct ktx_header
45     {
46         uint8 m_identifier[12];
47         uint32 m_endianness;
48         uint32 m_glType;
49         uint32 m_glTypeSize;
50         uint32 m_glFormat;
51         uint32 m_glInternalFormat;
52         uint32 m_glBaseInternalFormat;
53         uint32 m_pixelWidth;
54         uint32 m_pixelHeight;
55         uint32 m_pixelDepth;
56         uint32 m_numberOfArrayElements;
57         uint32 m_numberOfFaces;
58         uint32 m_numberOfMipmapLevels;
59         uint32 m_bytesOfKeyValueData;
60
61         void clear()
62         {
63             memset(this, 0, sizeof(*this));
64         }
65
66         void endian_swap()
67         {
68             utils::endian_swap_mem32(&m_endianness, (sizeof(*this) - sizeof(m_identifier)) / sizeof(uint32));
69         }
70     };
71
72     typedef vogl::vector<uint8_vec> ktx_key_value_vec;
73     typedef vogl::vector<uint8_vec> ktx_image_data_vec;
74
75     // Compressed pixel data formats: ETC1, DXT1, DXT3, DXT5
76     // These enums should match the OpenGL enums
77     enum
78     {
79         KTX_ETC1_RGB8_OES = 0x8D64,
80         KTX_RGB_S3TC = 0x83A0,
81         KTX_RGB4_S3TC = 0x83A1,
82         KTX_COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0,
83         KTX_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1,
84         KTX_COMPRESSED_SRGB_S3TC_DXT1_EXT = 0x8C4C,
85         KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x8C4D,
86         KTX_COMPRESSED_RED_RGTC1 = 0x8DBB,
87         KTX_COMPRESSED_SIGNED_RED_RGTC1 = 0x8DBC,
88         KTX_COMPRESSED_RG_RGTC2 = 0x8DBD,
89         KTX_COMPRESSED_SIGNED_RG_RGTC2 = 0x8DBE,
90         KTX_RGBA_S3TC = 0x83A2,
91         KTX_RGBA4_S3TC = 0x83A3,
92         KTX_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2,
93         KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 0x8C4E,
94         KTX_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3,
95         KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 0x8C4F,
96         KTX_RGBA_DXT5_S3TC = 0x83A4,
97         KTX_RGBA4_DXT5_S3TC = 0x83A5,
98         KTX_COMPRESSED_SIGNED_RED_RGTC1_EXT = 0x8DBC,
99         KTX_COMPRESSED_RED_GREEN_RGTC2_EXT = 0x8DBD,
100         KTX_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT = 0x8DBE,
101         KTX_COMPRESSED_LUMINANCE_LATC1_EXT = 0x8C70,
102         KTX_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT = 0x8C71,
103         KTX_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT = 0x8C72,
104         KTX_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT = 0x8C73,
105         KTX_COMPRESSED_RGBA_BPTC_UNORM_ARB = 0x8E8C,
106         KTX_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB = 0x8E8D,
107         KTX_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB = 0x8E8E,
108         KTX_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB = 0x8E8F,
109         KTX_COMPRESSED_R11_EAC = 0x9270,
110         KTX_COMPRESSED_SIGNED_R11_EAC = 0x9271,
111         KTX_COMPRESSED_RG11_EAC = 0x9272,
112         KTX_COMPRESSED_SIGNED_RG11_EAC = 0x9273,
113         KTX_COMPRESSED_RGB8_ETC2 = 0x9274,
114         KTX_COMPRESSED_SRGB8_ETC2 = 0x9275,
115         KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276,
116         KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277,
117         KTX_COMPRESSED_RGBA8_ETC2_EAC = 0x9278,
118         KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279
119     };
120
121     // Pixel formats (various internal, base, and base internal formats)
122     enum
123     {
124         KTX_R8 = 0x8229,
125         KTX_R8UI = 0x8232,
126         KTX_RGB8 = 0x8051,
127         KTX_SRGB8 = 0x8C41,
128         KTX_SRGB = 0x8C40,
129         KTX_SRGB_ALPHA = 0x8C42,
130         KTX_SRGB8_ALPHA8 = 0x8C43,
131         KTX_RGBA8 = 0x8058,
132         KTX_STENCIL_INDEX = 0x1901,
133         KTX_DEPTH_COMPONENT = 0x1902,
134         KTX_DEPTH_STENCIL = 0x84F9,
135         KTX_RED = 0x1903,
136         KTX_GREEN = 0x1904,
137         KTX_BLUE = 0x1905,
138         KTX_ALPHA = 0x1906,
139         KTX_RG = 0x8227,
140         KTX_RGB = 0x1907,
141         KTX_RGBA = 0x1908,
142         KTX_BGR = 0x80E0,
143         KTX_BGRA = 0x80E1,
144         KTX_RED_INTEGER = 0x8D94,
145         KTX_GREEN_INTEGER = 0x8D95,
146         KTX_BLUE_INTEGER = 0x8D96,
147         KTX_ALPHA_INTEGER = 0x8D97,
148         KTX_LUMINANCE_INTEGER_EXT = 0x8D9C,
149         KTX_LUMINANCE_ALPHA_INTEGER_EXT = 0x8D9D,
150         KTX_RGB_INTEGER = 0x8D98,
151         KTX_RGBA_INTEGER = 0x8D99,
152         KTX_BGR_INTEGER = 0x8D9A,
153         KTX_BGRA_INTEGER = 0x8D9B,
154         KTX_LUMINANCE = 0x1909,
155         KTX_LUMINANCE_ALPHA = 0x190A,
156         KTX_RG_INTEGER = 0x8228,
157         KTX_RG8 = 0x822B,
158         KTX_ALPHA8 = 0x803C,
159         KTX_LUMINANCE8 = 0x8040,
160         KTX_LUMINANCE8_ALPHA8 = 0x8045,
161         KTX_DEPTH_COMPONENT24 = 0x81A6
162     };
163
164     // Pixel data types
165     enum
166     {
167         KTX_UNSIGNED_BYTE = 0x1401,
168         KTX_BYTE = 0x1400,
169         KTX_UNSIGNED_SHORT = 0x1403,
170         KTX_SHORT = 0x1402,
171         KTX_UNSIGNED_INT = 0x1405,
172         KTX_INT = 0x1404,
173         KTX_HALF_FLOAT = 0x140B,
174         KTX_FLOAT = 0x1406,
175         KTX_UNSIGNED_BYTE_3_3_2 = 0x8032,
176         KTX_UNSIGNED_BYTE_2_3_3_REV = 0x8362,
177         KTX_UNSIGNED_SHORT_5_6_5 = 0x8363,
178         KTX_UNSIGNED_SHORT_5_6_5_REV = 0x8364,
179         KTX_UNSIGNED_SHORT_4_4_4_4 = 0x8033,
180         KTX_UNSIGNED_SHORT_4_4_4_4_REV = 0x8365,
181         KTX_UNSIGNED_SHORT_5_5_5_1 = 0x8034,
182         KTX_UNSIGNED_SHORT_1_5_5_5_REV = 0x8366,
183         KTX_UNSIGNED_INT_8_8_8_8 = 0x8035,
184         KTX_UNSIGNED_INT_8_8_8_8_REV = 0x8367,
185         KTX_UNSIGNED_INT_10_10_10_2 = 0x8036,
186         KTX_UNSIGNED_INT_2_10_10_10_REV = 0x8368,
187         KTX_UNSIGNED_INT_24_8 = 0x84FA,
188         KTX_UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B,
189         KTX_UNSIGNED_INT_5_9_9_9_REV = 0x8C3E,
190         KTX_FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD
191     };
192
193     bool ktx_is_compressed_ogl_fmt(uint32 ogl_fmt);
194     bool ktx_is_packed_pixel_ogl_type(uint32 ogl_type);
195     uint ktx_get_ogl_type_size(uint32 ogl_type);
196     bool ktx_get_ogl_fmt_desc(uint32 ogl_fmt, uint32 ogl_type, uint &block_dim, uint &bytes_per_block);
197     uint32 ktx_get_ogl_compressed_base_internal_fmt(uint32 ogl_fmt);
198
199     class ktx_texture
200     {
201     public:
202         ktx_texture()
203         {
204             clear();
205         }
206
207         ktx_texture(const ktx_texture &other)
208         {
209             *this = other;
210         }
211
212         ktx_texture &operator=(const ktx_texture &rhs)
213         {
214             if (this == &rhs)
215                 return *this;
216
217             clear();
218
219             m_header = rhs.m_header;
220             m_key_values = rhs.m_key_values;
221             m_image_data = rhs.m_image_data;
222             m_block_dim = rhs.m_block_dim;
223             m_bytes_per_block = rhs.m_bytes_per_block;
224             m_opposite_endianness = rhs.m_opposite_endianness;
225
226             return *this;
227         }
228
229         void clear()
230         {
231             m_header.clear();
232             m_key_values.clear();
233             m_image_data.clear();
234
235             m_block_dim = 0;
236             m_bytes_per_block = 0;
237
238             m_opposite_endianness = false;
239         }
240
241         // High level methods
242         bool read_from_stream(data_stream_serializer &serializer);
243         bool write_to_stream(data_stream_serializer &serializer, bool no_keyvalue_data = false) const;
244
245         // For compressed internal formats, set ogl_fmt and ogl_type to 0 (GL_NONE). The base internal format will be computed automatically.
246         // Otherwise, if ogl_fmt/ogl_type are not 0 (GL_NONE) then the internal format must be uncompressed, and all fmt's must be valid.
247         bool init_1D(uint width, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
248         bool init_1D_array(uint width, uint num_mips, uint array_size, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
249         bool init_2D(uint width, uint height, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
250         bool init_2D_array(uint width, uint height, uint num_mips, uint array_size, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
251         bool init_3D(uint width, uint height, uint depth, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
252         bool init_cubemap(uint dim, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
253
254         bool check_header() const;
255         bool consistency_check() const;
256
257         // General info
258
259         bool is_valid() const
260         {
261             return (m_header.m_pixelWidth > 0) && (m_image_data.size() > 0);
262         }
263
264         uint get_width() const
265         {
266             return m_header.m_pixelWidth;
267         }
268         uint get_height() const
269         {
270             return VOGL_MAX(m_header.m_pixelHeight, 1);
271         }
272         uint get_depth() const
273         {
274             return VOGL_MAX(m_header.m_pixelDepth, 1);
275         }
276         uint get_num_mips() const
277         {
278             return VOGL_MAX(m_header.m_numberOfMipmapLevels, 1);
279         }
280         uint get_array_size() const
281         {
282             return VOGL_MAX(m_header.m_numberOfArrayElements, 1);
283         }
284         uint get_num_faces() const
285         {
286             return m_header.m_numberOfFaces;
287         }
288
289         uint32 get_ogl_type() const
290         {
291             return m_header.m_glType;
292         }
293         uint32 get_ogl_fmt() const
294         {
295             return m_header.m_glFormat;
296         }
297         uint32 get_ogl_base_fmt() const
298         {
299             return m_header.m_glBaseInternalFormat;
300         }
301         uint32 get_ogl_internal_fmt() const
302         {
303             return m_header.m_glInternalFormat;
304         }
305
306         uint get_total_images() const;
307
308         bool is_compressed() const
309         {
310             return m_block_dim > 1;
311         }
312         bool is_uncompressed() const
313         {
314             return !is_compressed();
315         }
316
317         bool get_opposite_endianness() const
318         {
319             return m_opposite_endianness;
320         }
321         void set_opposite_endianness(bool flag)
322         {
323             m_opposite_endianness = flag;
324         }
325
326         uint32 get_block_dim() const
327         {
328             return m_block_dim;
329         }
330         uint32 get_bytes_per_block() const
331         {
332             return m_bytes_per_block;
333         }
334
335         const ktx_header &get_header() const
336         {
337             return m_header;
338         }
339
340         // Key values
341         const ktx_key_value_vec &get_key_value_vec() const
342         {
343             return m_key_values;
344         }
345         ktx_key_value_vec &get_key_value_vec()
346         {
347             return m_key_values;
348         }
349
350         void get_keys(dynamic_string_array &keys) const;
351
352         const uint8_vec *find_key(const char *pKey) const;
353         bool get_key_value_data(const char *pKey, uint8_vec &data) const;
354         bool get_key_value_as_string(const char *pKey, dynamic_string &str) const;
355
356         uint add_key_value(const char *pKey, const void *pVal, uint val_size);
357         uint add_key_value(const char *pKey, const char *pVal)
358         {
359             return add_key_value(pKey, pVal, static_cast<uint>(strlen(pVal)) + 1);
360         }
361
362         // Image data
363         uint get_num_images() const
364         {
365             return m_image_data.size();
366         }
367
368         const uint8_vec &get_image_data(uint image_index) const
369         {
370             return m_image_data[image_index];
371         }
372         uint8_vec &get_image_data(uint image_index)
373         {
374             return m_image_data[image_index];
375         }
376
377         const uint8_vec &get_image_data(uint mip_index, uint array_index, uint face_index, uint zslice_index) const
378         {
379             return get_image_data(get_image_index(mip_index, array_index, face_index, zslice_index));
380         }
381         uint8_vec &get_image_data(uint mip_index, uint array_index, uint face_index, uint zslice_index)
382         {
383             return get_image_data(get_image_index(mip_index, array_index, face_index, zslice_index));
384         }
385
386         const ktx_image_data_vec &get_image_data_vec() const
387         {
388             return m_image_data;
389         }
390         ktx_image_data_vec &get_image_data_vec()
391         {
392             return m_image_data;
393         }
394
395         // Adds a single 2D image to the texture
396         void add_image(uint mip_index, uint array_index, uint face_index, uint zslice_index, const void *pImage, uint image_size)
397         {
398             const uint image_index = get_image_index(mip_index, array_index, face_index, zslice_index);
399             if (image_index >= m_image_data.size())
400                 m_image_data.resize(image_index + 1);
401             if (image_size)
402             {
403                 uint8_vec &v = m_image_data[image_index];
404                 v.resize(image_size);
405                 memcpy(&v[0], pImage, image_size);
406             }
407         }
408
409         // Adds a single 2D image to the texture
410         // Caller grants ownership of the indicated image data, on return img will be whatever previously in the target slot.
411         void add_image_grant_ownership(uint mip_index, uint array_index, uint face_index, uint zslice_index, uint8_vec &img)
412         {
413             const uint image_index = get_image_index(mip_index, array_index, face_index, zslice_index);
414             if (image_index >= m_image_data.size())
415                 m_image_data.resize(image_index + 1);
416
417             m_image_data[image_index].swap(img);
418         }
419
420         // Adds a single 2D image to the texture
421         // FIXME: voglcore uses this simplified helper, the order of params is inconsistent with the other add_image()
422         void add_image(uint face_index, uint mip_index, const void *pImage, uint image_size)
423         {
424             add_image(mip_index, 0, face_index, 0, pImage, image_size);
425         }
426
427         uint get_image_index(uint mip_index, uint array_index, uint face_index, uint zslice_index) const
428         {
429             VOGL_ASSERT((mip_index < get_num_mips()) && (array_index < get_array_size()) && (face_index < get_num_faces()) && (zslice_index < get_depth()));
430             return zslice_index + (face_index * get_depth()) + (array_index * (get_depth() * get_num_faces())) + (mip_index * (get_depth() * get_num_faces() * get_array_size()));
431         }
432
433         void get_mip_dim(uint mip_index, uint &mip_width, uint &mip_height) const
434         {
435             VOGL_ASSERT(mip_index < get_num_mips());
436             mip_width = VOGL_MAX(get_width() >> mip_index, 1);
437             mip_height = VOGL_MAX(get_height() >> mip_index, 1);
438         }
439
440         void get_mip_dim(uint mip_index, uint &mip_width, uint &mip_height, uint &mip_depth) const
441         {
442             VOGL_ASSERT(mip_index < get_num_mips());
443             mip_width = VOGL_MAX(get_width() >> mip_index, 1);
444             mip_height = VOGL_MAX(get_height() >> mip_index, 1);
445             mip_depth = VOGL_MAX(get_depth() >> mip_index, 1);
446         }
447
448         // Returns the expected size of a single 2D image. (For 3D, multiply by the depth, etc.)
449         uint get_expected_image_size(uint mip_index) const;
450
451         bool operator==(const ktx_texture &rhs) const;
452         bool operator!=(const ktx_texture &rhs) const
453         {
454             return !(*this == rhs);
455         }
456
457     private:
458         mutable ktx_header m_header;
459
460         ktx_key_value_vec m_key_values;
461         ktx_image_data_vec m_image_data;
462
463         uint32 m_block_dim;
464         uint32 m_bytes_per_block;
465
466         bool m_opposite_endianness;
467
468         bool compute_pixel_info();
469     };
470
471 } // namespace vogl
472
473 #endif // #ifndef _KTX_TEXTURE_H_