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 **************************************************************************/
27 // File: vogl_ktx_texture.h
28 #ifndef _KTX_TEXTURE_H_
29 #define _KTX_TEXTURE_H_
34 #include "vogl_core.h"
35 #include "vogl_data_stream_serializer.h"
37 #define KTX_ENDIAN 0x04030201
38 #define KTX_OPPOSITE_ENDIAN 0x01020304
42 extern const uint8 s_ktx_file_id[12];
46 uint8 m_identifier[12];
51 uint32 m_glInternalFormat;
52 uint32 m_glBaseInternalFormat;
56 uint32 m_numberOfArrayElements;
57 uint32 m_numberOfFaces;
58 uint32 m_numberOfMipmapLevels;
59 uint32 m_bytesOfKeyValueData;
63 memset(this, 0, sizeof(*this));
68 utils::endian_swap_mem32(&m_endianness, (sizeof(*this) - sizeof(m_identifier)) / sizeof(uint32));
72 typedef vogl::vector<uint8_vec> ktx_key_value_vec;
73 typedef vogl::vector<uint8_vec> ktx_image_data_vec;
75 // Compressed pixel data formats: ETC1, DXT1, DXT3, DXT5
76 // These enums should match the OpenGL enums
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
121 // Pixel formats (various internal, base, and base internal formats)
129 KTX_SRGB_ALPHA = 0x8C42,
130 KTX_SRGB8_ALPHA8 = 0x8C43,
132 KTX_STENCIL_INDEX = 0x1901,
133 KTX_DEPTH_COMPONENT = 0x1902,
134 KTX_DEPTH_STENCIL = 0x84F9,
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,
159 KTX_LUMINANCE8 = 0x8040,
160 KTX_LUMINANCE8_ALPHA8 = 0x8045,
161 KTX_DEPTH_COMPONENT24 = 0x81A6
167 KTX_UNSIGNED_BYTE = 0x1401,
169 KTX_UNSIGNED_SHORT = 0x1403,
171 KTX_UNSIGNED_INT = 0x1405,
173 KTX_HALF_FLOAT = 0x140B,
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
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);
207 ktx_texture(const ktx_texture &other)
212 ktx_texture &operator=(const ktx_texture &rhs)
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;
232 m_key_values.clear();
233 m_image_data.clear();
236 m_bytes_per_block = 0;
238 m_opposite_endianness = false;
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;
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);
254 bool check_header() const;
255 bool consistency_check() const;
259 bool is_valid() const
261 return (m_header.m_pixelWidth > 0) && (m_image_data.size() > 0);
264 uint get_width() const
266 return m_header.m_pixelWidth;
268 uint get_height() const
270 return VOGL_MAX(m_header.m_pixelHeight, 1);
272 uint get_depth() const
274 return VOGL_MAX(m_header.m_pixelDepth, 1);
276 uint get_num_mips() const
278 return VOGL_MAX(m_header.m_numberOfMipmapLevels, 1);
280 uint get_array_size() const
282 return VOGL_MAX(m_header.m_numberOfArrayElements, 1);
284 uint get_num_faces() const
286 return m_header.m_numberOfFaces;
289 uint32 get_ogl_type() const
291 return m_header.m_glType;
293 uint32 get_ogl_fmt() const
295 return m_header.m_glFormat;
297 uint32 get_ogl_base_fmt() const
299 return m_header.m_glBaseInternalFormat;
301 uint32 get_ogl_internal_fmt() const
303 return m_header.m_glInternalFormat;
306 uint get_total_images() const;
308 bool is_compressed() const
310 return m_block_dim > 1;
312 bool is_uncompressed() const
314 return !is_compressed();
317 bool get_opposite_endianness() const
319 return m_opposite_endianness;
321 void set_opposite_endianness(bool flag)
323 m_opposite_endianness = flag;
326 uint32 get_block_dim() const
330 uint32 get_bytes_per_block() const
332 return m_bytes_per_block;
335 const ktx_header &get_header() const
341 const ktx_key_value_vec &get_key_value_vec() const
345 ktx_key_value_vec &get_key_value_vec()
350 void get_keys(dynamic_string_array &keys) const;
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;
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)
359 return add_key_value(pKey, pVal, static_cast<uint>(strlen(pVal)) + 1);
363 uint get_num_images() const
365 return m_image_data.size();
368 const uint8_vec &get_image_data(uint image_index) const
370 return m_image_data[image_index];
372 uint8_vec &get_image_data(uint image_index)
374 return m_image_data[image_index];
377 const uint8_vec &get_image_data(uint mip_index, uint array_index, uint face_index, uint zslice_index) const
379 return get_image_data(get_image_index(mip_index, array_index, face_index, zslice_index));
381 uint8_vec &get_image_data(uint mip_index, uint array_index, uint face_index, uint zslice_index)
383 return get_image_data(get_image_index(mip_index, array_index, face_index, zslice_index));
386 const ktx_image_data_vec &get_image_data_vec() const
390 ktx_image_data_vec &get_image_data_vec()
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)
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);
403 uint8_vec &v = m_image_data[image_index];
404 v.resize(image_size);
405 memcpy(&v[0], pImage, image_size);
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)
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);
417 m_image_data[image_index].swap(img);
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)
424 add_image(mip_index, 0, face_index, 0, pImage, image_size);
427 uint get_image_index(uint mip_index, uint array_index, uint face_index, uint zslice_index) const
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()));
433 void get_mip_dim(uint mip_index, uint &mip_width, uint &mip_height) const
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);
440 void get_mip_dim(uint mip_index, uint &mip_width, uint &mip_height, uint &mip_depth) const
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);
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;
451 bool operator==(const ktx_texture &rhs) const;
452 bool operator!=(const ktx_texture &rhs) const
454 return !(*this == rhs);
458 mutable ktx_header m_header;
460 ktx_key_value_vec m_key_values;
461 ktx_image_data_vec m_image_data;
464 uint32 m_bytes_per_block;
466 bool m_opposite_endianness;
468 bool compute_pixel_info();
473 #endif // #ifndef _KTX_TEXTURE_H_