diff --git a/3rdparty/meshoptimizer/CMakeLists.txt b/3rdparty/meshoptimizer/CMakeLists.txt index cda378fb1..993d5247c 100644 --- a/3rdparty/meshoptimizer/CMakeLists.txt +++ b/3rdparty/meshoptimizer/CMakeLists.txt @@ -58,7 +58,7 @@ if(BUILD_DEMO) endif() if(BUILD_TOOLS) - add_executable(gltfpack tools/gltfpack.cpp tools/meshloader.cpp) + add_executable(gltfpack tools/gltfpack.cpp tools/meshloader.cpp tools/basistoktx.cpp) target_link_libraries(gltfpack meshoptimizer) list(APPEND TARGETS gltfpack) diff --git a/3rdparty/meshoptimizer/Makefile b/3rdparty/meshoptimizer/Makefile index 82843a962..c90406449 100644 --- a/3rdparty/meshoptimizer/Makefile +++ b/3rdparty/meshoptimizer/Makefile @@ -12,7 +12,7 @@ LIBRARY_OBJECTS=$(LIBRARY_SOURCES:%=$(BUILD)/%.o) DEMO_SOURCES=$(wildcard demo/*.c demo/*.cpp) tools/meshloader.cpp DEMO_OBJECTS=$(DEMO_SOURCES:%=$(BUILD)/%.o) -GLTFPACK_SOURCES=tools/gltfpack.cpp tools/meshloader.cpp +GLTFPACK_SOURCES=tools/gltfpack.cpp tools/meshloader.cpp tools/basistoktx.cpp GLTFPACK_OBJECTS=$(GLTFPACK_SOURCES:%=$(BUILD)/%.o) OBJECTS=$(LIBRARY_OBJECTS) $(DEMO_OBJECTS) $(GLTFPACK_OBJECTS) diff --git a/3rdparty/meshoptimizer/src/vertexcodec.cpp b/3rdparty/meshoptimizer/src/vertexcodec.cpp index ed9e41fc9..31b8a4de2 100644 --- a/3rdparty/meshoptimizer/src/vertexcodec.cpp +++ b/3rdparty/meshoptimizer/src/vertexcodec.cpp @@ -420,7 +420,8 @@ static unsigned char kDecodeBytesGroupCount[256]; #ifdef EMSCRIPTEN __attribute__((cold)) // this saves 500 bytes in the output binary - we don't need to vectorize this loop! #endif -static bool decodeBytesGroupBuildTables() +static bool +decodeBytesGroupBuildTables() { for (int mask = 0; mask < 256; ++mask) { diff --git a/3rdparty/meshoptimizer/tools/basistoktx.cpp b/3rdparty/meshoptimizer/tools/basistoktx.cpp new file mode 100644 index 000000000..6f716e4de --- /dev/null +++ b/3rdparty/meshoptimizer/tools/basistoktx.cpp @@ -0,0 +1,294 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include "basisu_format.h" +#include "khr_df.h" +#include "ktx2_format.h" + +template +static void read(const std::string& data, size_t offset, T& result) +{ + if (offset + sizeof(T) > data.size()) + throw std::out_of_range("read"); + + memcpy(&result, &data[offset], sizeof(T)); +} + +template +static void write(std::string& data, const T& value) +{ + data.append(reinterpret_cast(&value), sizeof(value)); +} + +template +static void write(std::string& data, size_t offset, const T& value) +{ + if (offset + sizeof(T) > data.size()) + throw std::out_of_range("write"); + + memcpy(&data[offset], &value, sizeof(T)); +} + +static void createDfd(std::vector& result, int channels, bool srgb) +{ + assert(channels <= 4); + + int descriptor_size = KHR_DF_WORD_SAMPLESTART + channels * KHR_DF_WORD_SAMPLEWORDS; + + result.clear(); + result.resize(1 + descriptor_size); + + result[0] = (1 + descriptor_size) * sizeof(uint32_t); + + uint32_t* dfd = &result[1]; + + KHR_DFDSETVAL(dfd, VENDORID, KHR_DF_VENDORID_KHRONOS); + KHR_DFDSETVAL(dfd, DESCRIPTORTYPE, KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT); + KHR_DFDSETVAL(dfd, VERSIONNUMBER, KHR_DF_VERSIONNUMBER_1_3); + KHR_DFDSETVAL(dfd, DESCRIPTORBLOCKSIZE, descriptor_size * sizeof(uint32_t)); + KHR_DFDSETVAL(dfd, MODEL, KHR_DF_MODEL_RGBSDA); + KHR_DFDSETVAL(dfd, PRIMARIES, KHR_DF_PRIMARIES_BT709); + KHR_DFDSETVAL(dfd, TRANSFER, srgb ? KHR_DF_TRANSFER_SRGB : KHR_DF_TRANSFER_LINEAR); + KHR_DFDSETVAL(dfd, FLAGS, KHR_DF_FLAG_ALPHA_STRAIGHT); + + static const khr_df_model_channels_e channel_enums[] = { + KHR_DF_CHANNEL_RGBSDA_R, + KHR_DF_CHANNEL_RGBSDA_G, + KHR_DF_CHANNEL_RGBSDA_B, + KHR_DF_CHANNEL_RGBSDA_A, + }; + + for (int i = 0; i < channels; ++i) + { + KHR_DFDSETSVAL(dfd, i, CHANNELID, channel_enums[i]); + } +} + +std::string basisToKtx(const std::string& basis, bool srgb) +{ + std::string ktx; + + basist::basis_file_header basis_header; + read(basis, 0, basis_header); + + assert(basis_header.m_sig == basist::basis_file_header::cBASISSigValue); + + assert(basis_header.m_total_slices > 0); + assert(basis_header.m_total_images == 1); + + assert(basis_header.m_format == 0); + assert(basis_header.m_flags & basist::cBASISHeaderFlagETC1S); + assert(!(basis_header.m_flags & basist::cBASISHeaderFlagYFlipped)); + assert(basis_header.m_tex_type == basist::cBASISTexType2D); + + bool has_alpha = (basis_header.m_flags & basist::cBASISHeaderFlagHasAlphaSlices) != 0; + + std::vector slices(basis_header.m_total_slices); + + for (size_t i = 0; i < basis_header.m_total_slices; ++i) + read(basis, basis_header.m_slice_desc_file_ofs + i * sizeof(basist::basis_slice_desc), slices[i]); + + assert(slices[0].m_level_index == 0); + uint32_t width = slices[0].m_orig_width; + uint32_t height = slices[0].m_orig_height; + uint32_t levels = has_alpha ? uint32_t(slices.size()) / 2 : uint32_t(slices.size()); + + KTX_header2 ktx_header = {KTX2_IDENTIFIER_REF}; + ktx_header.typeSize = 1; + ktx_header.pixelWidth = width; + ktx_header.pixelHeight = height; + ktx_header.layerCount = 0; + ktx_header.faceCount = 1; + ktx_header.levelCount = levels; + ktx_header.supercompressionScheme = KTX_SUPERCOMPRESSION_BASIS; + + size_t header_size = sizeof(KTX_header2) + levels * sizeof(ktxLevelIndexEntry); + + std::vector dfd; + createDfd(dfd, has_alpha ? 4 : 3, srgb); + + const char* kvp_data[][2] = { + {"KTXwriter", "gltfpack"}, + }; + + std::string kvp; + + for (size_t i = 0; i < sizeof(kvp_data) / sizeof(kvp_data[0]); ++i) + { + const char* key = kvp_data[i][0]; + const char* value = kvp_data[i][1]; + + write(kvp, uint32_t(strlen(key) + strlen(value) + 2)); + kvp += key; + kvp += '\0'; + kvp += value; + kvp += '\0'; + + if (i + 1 != kvp.size()) + kvp.resize((kvp.size() + 3) & ~3); + } + + size_t kvp_size = kvp.size(); + size_t dfd_size = dfd.size() * sizeof(uint32_t); + + size_t bgd_size = + sizeof(ktxBasisGlobalHeader) + sizeof(ktxBasisSliceDesc) * levels + + basis_header.m_endpoint_cb_file_size + basis_header.m_selector_cb_file_size + basis_header.m_tables_file_size; + + ktx_header.dataFormatDescriptor.byteOffset = uint32_t(header_size); + ktx_header.dataFormatDescriptor.byteLength = uint32_t(dfd_size); + + ktx_header.keyValueData.byteOffset = uint32_t(header_size + dfd_size); + ktx_header.keyValueData.byteLength = uint32_t(kvp_size); + + ktx_header.supercompressionGlobalData.byteOffset = (header_size + dfd_size + kvp_size + 7) & ~7; + ktx_header.supercompressionGlobalData.byteLength = bgd_size; + + // KTX2 header + write(ktx, ktx_header); + + size_t ktx_level_offset = ktx.size(); + + for (size_t i = 0; i < levels; ++i) + { + ktxLevelIndexEntry le = {}; // This will be patched later + write(ktx, le); + } + + // data format descriptor + for (size_t i = 0; i < dfd.size(); ++i) + write(ktx, dfd[i]); + + // key/value pair data + ktx += kvp; + ktx.resize((ktx.size() + 7) & ~7); + + // supercompression global data + ktxBasisGlobalHeader sgd_header = {}; + sgd_header.globalFlags = basis_header.m_flags; + sgd_header.endpointCount = basis_header.m_total_endpoints; + sgd_header.selectorCount = basis_header.m_total_selectors; + sgd_header.endpointsByteLength = basis_header.m_endpoint_cb_file_size; + sgd_header.selectorsByteLength = basis_header.m_selector_cb_file_size; + sgd_header.tablesByteLength = basis_header.m_tables_file_size; + sgd_header.extendedByteLength = basis_header.m_extended_file_size; + + write(ktx, sgd_header); + + size_t sgd_level_offset = ktx.size(); + + for (size_t i = 0; i < levels; ++i) + { + ktxBasisSliceDesc sgd_slice = {}; // This will be patched later + write(ktx, sgd_slice); + } + + ktx.append(basis.substr(basis_header.m_endpoint_cb_file_ofs, basis_header.m_endpoint_cb_file_size)); + ktx.append(basis.substr(basis_header.m_selector_cb_file_ofs, basis_header.m_selector_cb_file_size)); + ktx.append(basis.substr(basis_header.m_tables_file_ofs, basis_header.m_tables_file_size)); + ktx.append(basis.substr(basis_header.m_extended_file_ofs, basis_header.m_extended_file_size)); + + ktx.resize((ktx.size() + 7) & ~7); + + // mip levels + for (size_t i = 0; i < levels; ++i) + { + size_t slice_index = (levels - i - 1) * (has_alpha + 1); + const basist::basis_slice_desc& slice = slices[slice_index]; + const basist::basis_slice_desc* slice_alpha = has_alpha ? &slices[slice_index + 1] : 0; + + assert(slice.m_image_index == 0); + assert(slice.m_level_index == levels - i - 1); + + size_t file_offset = ktx.size(); + + ktx.append(basis.substr(slice.m_file_ofs, slice.m_file_size)); + + if (slice_alpha) + ktx.append(basis.substr(slice_alpha->m_file_ofs, slice_alpha->m_file_size)); + + ktxLevelIndexEntry le = {}; + le.byteOffset = file_offset; + le.byteLength = ktx.size() - file_offset; + le.uncompressedByteLength = 0; + + write(ktx, ktx_level_offset + i * sizeof(ktxLevelIndexEntry), le); + + ktxBasisSliceDesc sgd_slice = {}; + sgd_slice.sliceByteOffset = 0; + sgd_slice.sliceByteLength = slice.m_file_size; + + if (slice_alpha) + { + sgd_slice.alphaSliceByteOffset = slice.m_file_size; + sgd_slice.alphaSliceByteLength = slice_alpha->m_file_size; + } + + write(ktx, sgd_level_offset + i * sizeof(ktxBasisSliceDesc), sgd_slice); + + if (i + 1 != levels) + ktx.resize((ktx.size() + 7) & ~7); + } + + return ktx; +} + +#ifdef STANDALONE +bool readFile(const char* path, std::string& data) +{ + FILE* file = fopen(path, "rb"); + if (!file) + return false; + + fseek(file, 0, SEEK_END); + long length = ftell(file); + fseek(file, 0, SEEK_SET); + + if (length <= 0) + { + fclose(file); + return false; + } + + data.resize(length); + size_t result = fread(&data[0], 1, data.size(), file); + fclose(file); + + return result == data.size(); +} + +bool writeFile(const char* path, const std::string& data) +{ + FILE* file = fopen(path, "wb"); + if (!file) + return false; + + size_t result = fwrite(&data[0], 1, data.size(), file); + fclose(file); + + return result == data.size(); +} + +int main(int argc, const char** argv) +{ + if (argc < 2) + return 1; + + std::string basis; + if (!readFile(argv[1], basis)) + return 1; + + std::string ktx = basisToKtx(basis, true); + + if (!writeFile(argv[2], ktx)) + return 1; + + return 0; +} +#endif \ No newline at end of file diff --git a/3rdparty/meshoptimizer/tools/basisu_format.h b/3rdparty/meshoptimizer/tools/basisu_format.h new file mode 100644 index 000000000..88c53a40f --- /dev/null +++ b/3rdparty/meshoptimizer/tools/basisu_format.h @@ -0,0 +1,138 @@ +// basis_file_headers.h + basisu.h +// Copyright (C) 2019 Binomial LLC. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +namespace basisu +{ + // Always little endian 2-4 byte unsigned int + template + struct packed_uint + { + uint8_t m_bytes[NumBytes]; + + operator uint32_t() const + { + uint32_t result = 0; + for (uint32_t i = 0; i < NumBytes; i++) + result |= m_bytes[i] << (8 * i); + return result; + } + }; +} + +namespace basist +{ + // Slice desc header flags + enum basis_slice_desc_flags + { + cSliceDescFlagsIsAlphaData = 1, + cSliceDescFlagsFrameIsIFrame = 2 // Video only: Frame doesn't refer to previous frame (no usage of conditional replenishment pred symbols) + }; + +#pragma pack(push) +#pragma pack(1) + struct basis_slice_desc + { + basisu::packed_uint<3> m_image_index; // The index of the source image provided to the encoder (will always appear in order from first to last, first image index is 0, no skipping allowed) + basisu::packed_uint<1> m_level_index; // The mipmap level index (mipmaps will always appear from largest to smallest) + basisu::packed_uint<1> m_flags; // enum basis_slice_desc_flags + + basisu::packed_uint<2> m_orig_width; // The original image width (may not be a multiple of 4 pixels) + basisu::packed_uint<2> m_orig_height; // The original image height (may not be a multiple of 4 pixels) + + basisu::packed_uint<2> m_num_blocks_x; // The slice's block X dimensions. Each block is 4x4 pixels. The slice's pixel resolution may or may not be a power of 2. + basisu::packed_uint<2> m_num_blocks_y; // The slice's block Y dimensions. + + basisu::packed_uint<4> m_file_ofs; // Offset from the header to the start of the slice's data + basisu::packed_uint<4> m_file_size; // The size of the compressed slice data in bytes + + basisu::packed_uint<2> m_slice_data_crc16; // The CRC16 of the compressed slice data, for extra-paranoid use cases + }; + + // File header files + enum basis_header_flags + { + cBASISHeaderFlagETC1S = 1, // Always set for basis universal files + cBASISHeaderFlagYFlipped = 2, // Set if the texture had to be Y flipped before encoding + cBASISHeaderFlagHasAlphaSlices = 4 // True if the odd slices contain alpha data + }; + + // The image type field attempts to describe how to interpret the image data in a Basis file. + // The encoder library doesn't really do anything special or different with these texture types, this is mostly here for the benefit of the user. + // We do make sure the various constraints are followed (2DArray/cubemap/videoframes/volume implies that each image has the same resolution and # of mipmap levels, etc., cubemap implies that the # of image slices is a multiple of 6) + enum basis_texture_type + { + cBASISTexType2D = 0, // An arbitrary array of 2D RGB or RGBA images with optional mipmaps, array size = # images, each image may have a different resolution and # of mipmap levels + cBASISTexType2DArray = 1, // An array of 2D RGB or RGBA images with optional mipmaps, array size = # images, each image has the same resolution and mipmap levels + cBASISTexTypeCubemapArray = 2, // an array of cubemap levels, total # of images must be divisable by 6, in X+, X-, Y+, Y-, Z+, Z- order, with optional mipmaps + cBASISTexTypeVideoFrames = 3, // An array of 2D video frames, with optional mipmaps, # frames = # images, each image has the same resolution and # of mipmap levels + cBASISTexTypeVolume = 4, // A 3D texture with optional mipmaps, Z dimension = # images, each image has the same resolution and # of mipmap levels + + cBASISTexTypeTotal + }; + + enum + { + cBASISMaxUSPerFrame = 0xFFFFFF + }; + + struct basis_file_header + { + enum + { + cBASISSigValue = ('B' << 8) | 's', + cBASISFirstVersion = 0x10 + }; + + basisu::packed_uint<2> m_sig; // 2 byte file signature + basisu::packed_uint<2> m_ver; // Baseline file version + basisu::packed_uint<2> m_header_size; // Header size in bytes, sizeof(basis_file_header) + basisu::packed_uint<2> m_header_crc16; // crc16 of the remaining header data + + basisu::packed_uint<4> m_data_size; // The total size of all data after the header + basisu::packed_uint<2> m_data_crc16; // The CRC16 of all data after the header + + basisu::packed_uint<3> m_total_slices; // The total # of compressed slices (1 slice per image, or 2 for alpha basis files) + + basisu::packed_uint<3> m_total_images; // The total # of images + + basisu::packed_uint<1> m_format; // enum basist::block_format + basisu::packed_uint<2> m_flags; // enum basist::header_flags + basisu::packed_uint<1> m_tex_type; // enum basist::basis_texture_type + basisu::packed_uint<3> m_us_per_frame; // Framerate of video, in microseconds per frame + + basisu::packed_uint<4> m_reserved; // For future use + basisu::packed_uint<4> m_userdata0; // For client use + basisu::packed_uint<4> m_userdata1; // For client use + + basisu::packed_uint<2> m_total_endpoints; // The number of endpoints in the endpoint codebook + basisu::packed_uint<4> m_endpoint_cb_file_ofs; // The compressed endpoint codebook's file offset relative to the header + basisu::packed_uint<3> m_endpoint_cb_file_size; // The compressed endpoint codebook's size in bytes + + basisu::packed_uint<2> m_total_selectors; // The number of selectors in the endpoint codebook + basisu::packed_uint<4> m_selector_cb_file_ofs; // The compressed selectors codebook's file offset relative to the header + basisu::packed_uint<3> m_selector_cb_file_size; // The compressed selector codebook's size in bytes + + basisu::packed_uint<4> m_tables_file_ofs; // The file offset of the compressed Huffman codelength tables, for decompressing slices + basisu::packed_uint<4> m_tables_file_size; // The file size in bytes of the compressed huffman codelength tables + + basisu::packed_uint<4> m_slice_desc_file_ofs; // The file offset to the slice description array, usually follows the header + + basisu::packed_uint<4> m_extended_file_ofs; // The file offset of the "extended" header and compressed data, for future use + basisu::packed_uint<4> m_extended_file_size; // The file size in bytes of the "extended" header and compressed data, for future use + }; +#pragma pack (pop) + +} // namespace basist diff --git a/3rdparty/meshoptimizer/tools/cgltf.h b/3rdparty/meshoptimizer/tools/cgltf.h index 4ad7ef078..67d310efc 100644 --- a/3rdparty/meshoptimizer/tools/cgltf.h +++ b/3rdparty/meshoptimizer/tools/cgltf.h @@ -1,7 +1,7 @@ /** * cgltf - a single-file glTF 2.0 parser written in C99. * - * Version: 1.3 + * Version: 1.4 * * Website: https://github.com/jkuhlmann/cgltf * @@ -420,7 +420,7 @@ typedef struct cgltf_camera { union { cgltf_camera_perspective perspective; cgltf_camera_orthographic orthographic; - }; + } data; cgltf_extras extras; } cgltf_camera; @@ -1711,7 +1711,7 @@ cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size #define CGLTF_CHECK_TOKTYPE(tok_, type_) if ((tok_).type != (type_)) { return CGLTF_ERROR_JSON; } #define CGLTF_CHECK_KEY(tok_) if ((tok_).type != JSMN_STRING || (tok_).size == 0) { return CGLTF_ERROR_JSON; } /* checking size for 0 verifies that a value follows the key */ -#define CGLTF_PTRINDEX(type, idx) (type*)(cgltf_size)(idx + 1) +#define CGLTF_PTRINDEX(type, idx) (type*)((cgltf_size)idx + 1) #define CGLTF_PTRFIXUP(var, data, size) if (var) { if ((cgltf_size)var > size) { return CGLTF_ERROR_JSON; } var = &data[(cgltf_size)var-1]; } #define CGLTF_PTRFIXUP_REQ(var, data, size) if (!var || (cgltf_size)var > size) { return CGLTF_ERROR_JSON; } var = &data[(cgltf_size)var-1]; @@ -1727,7 +1727,7 @@ static int cgltf_json_to_int(jsmntok_t const* tok, const uint8_t* json_chunk) { CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE); char tmp[128]; - int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : sizeof(tmp) - 1; + int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; return atoi(tmp); @@ -1737,7 +1737,7 @@ static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json { CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE); char tmp[128]; - int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : sizeof(tmp) - 1; + int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1); strncpy(tmp, (const char*)json_chunk + tok->start, size); tmp[size] = 0; return (cgltf_float)atof(tmp); @@ -1865,7 +1865,7 @@ static int cgltf_parse_json_string_array(cgltf_options* options, jsmntok_t const static void cgltf_parse_attribute_type(const char* name, cgltf_attribute_type* out_type, int* out_index) { const char* us = strchr(name, '_'); - size_t len = us ? us - name : strlen(name); + size_t len = us ? (size_t)(us - name) : strlen(name); if (len == 8 && strncmp(name, "POSITION", 8) == 0) { @@ -3284,30 +3284,30 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke if (cgltf_json_strcmp(tokens+i, json_chunk, "aspectRatio") == 0) { ++i; - out_camera->perspective.aspect_ratio = cgltf_json_to_float(tokens + i, json_chunk); + out_camera->data.perspective.aspect_ratio = cgltf_json_to_float(tokens + i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "yfov") == 0) { ++i; - out_camera->perspective.yfov = cgltf_json_to_float(tokens + i, json_chunk); + out_camera->data.perspective.yfov = cgltf_json_to_float(tokens + i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "zfar") == 0) { ++i; - out_camera->perspective.zfar = cgltf_json_to_float(tokens + i, json_chunk); + out_camera->data.perspective.zfar = cgltf_json_to_float(tokens + i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "znear") == 0) { ++i; - out_camera->perspective.znear = cgltf_json_to_float(tokens + i, json_chunk); + out_camera->data.perspective.znear = cgltf_json_to_float(tokens + i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->perspective.extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->data.perspective.extras); } else { @@ -3338,30 +3338,30 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke if (cgltf_json_strcmp(tokens+i, json_chunk, "xmag") == 0) { ++i; - out_camera->orthographic.xmag = cgltf_json_to_float(tokens + i, json_chunk); + out_camera->data.orthographic.xmag = cgltf_json_to_float(tokens + i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "ymag") == 0) { ++i; - out_camera->orthographic.ymag = cgltf_json_to_float(tokens + i, json_chunk); + out_camera->data.orthographic.ymag = cgltf_json_to_float(tokens + i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "zfar") == 0) { ++i; - out_camera->orthographic.zfar = cgltf_json_to_float(tokens + i, json_chunk); + out_camera->data.orthographic.zfar = cgltf_json_to_float(tokens + i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens+i, json_chunk, "znear") == 0) { ++i; - out_camera->orthographic.znear = cgltf_json_to_float(tokens + i, json_chunk); + out_camera->data.orthographic.znear = cgltf_json_to_float(tokens + i, json_chunk); ++i; } else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) { - i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->orthographic.extras); + i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->data.orthographic.extras); } else { diff --git a/3rdparty/meshoptimizer/tools/gltfpack.cpp b/3rdparty/meshoptimizer/tools/gltfpack.cpp index 22378d91e..8ce29de00 100644 --- a/3rdparty/meshoptimizer/tools/gltfpack.cpp +++ b/3rdparty/meshoptimizer/tools/gltfpack.cpp @@ -91,6 +91,7 @@ struct Settings bool texture_embed; bool texture_basis; + bool texture_ktx2; int texture_quality; @@ -140,6 +141,15 @@ struct MaterialInfo struct ImageInfo { bool normal_map; + bool srgb; +}; + +struct ExtensionInfo +{ + const char* name; + + bool used; + bool required; }; struct BufferView @@ -2612,6 +2622,36 @@ void remapNodes(cgltf_data* data, std::vector& nodes, size_t& node_off } } +void analyzeImages(cgltf_data* data, std::vector& images) +{ + for (size_t i = 0; i < data->materials_count; ++i) + { + const cgltf_material& material = data->materials[i]; + + if (material.has_pbr_metallic_roughness) + { + const cgltf_pbr_metallic_roughness& pbr = material.pbr_metallic_roughness; + + if (pbr.base_color_texture.texture && pbr.base_color_texture.texture->image) + images[pbr.base_color_texture.texture->image - data->images].srgb = true; + } + + if (material.has_pbr_specular_glossiness) + { + const cgltf_pbr_specular_glossiness& pbr = material.pbr_specular_glossiness; + + if (pbr.diffuse_texture.texture && pbr.diffuse_texture.texture->image) + images[pbr.diffuse_texture.texture->image - data->images].srgb = true; + } + + if (material.emissive_texture.texture && material.emissive_texture.texture->image) + images[material.emissive_texture.texture->image - data->images].srgb = true; + + if (material.normal_texture.texture && material.normal_texture.texture->image) + images[material.normal_texture.texture->image - data->images].normal_map = true; + } +} + bool parseDataUri(const char* uri, std::string& mime_type, std::string& result) { if (strncmp(uri, "data:", 5) == 0) @@ -2772,7 +2812,7 @@ struct TempFile } }; -bool encodeBasis(const std::string& data, std::string& result, bool normal_map, int quality) +bool encodeBasis(const std::string& data, std::string& result, bool normal_map, bool srgb, int quality) { TempFile temp_input(".raw"); TempFile temp_output(".basis"); @@ -2790,11 +2830,16 @@ bool encodeBasis(const std::string& data, std::string& result, bool normal_map, cmd += ql; cmd += " -mipmap"; + if (normal_map) { cmd += " -normal_map"; // for optimal quality we should specify seperate_rg_to_color_alpha but this requires renderer awareness } + else if (!srgb) + { + cmd += " -linear"; + } cmd += " -file "; cmd += temp_input.path; @@ -2812,6 +2857,9 @@ bool encodeBasis(const std::string& data, std::string& result, bool normal_map, return rc == 0 && readFile(temp_output.path.c_str(), result); } +// basistoktx.cpp +extern std::string basisToKtx(const std::string& basis, bool srgb); + void writeImage(std::string& json, std::vector& views, const cgltf_image& image, const ImageInfo& info, size_t index, const char* input_path, const char* output_path, const Settings& settings) { std::string img_data; @@ -2846,9 +2894,12 @@ void writeImage(std::string& json, std::vector& views, const cgltf_i { std::string encoded; - if (encodeBasis(img_data, encoded, info.normal_map, settings.texture_quality)) + if (encodeBasis(img_data, encoded, info.normal_map, info.srgb, settings.texture_quality)) { - writeEmbeddedImage(json, views, encoded.c_str(), encoded.size(), "image/basis"); + if (settings.texture_ktx2) + encoded = basisToKtx(encoded, info.srgb); + + writeEmbeddedImage(json, views, encoded.c_str(), encoded.size(), settings.texture_ktx2 ? "image/ktx2" : "image/basis"); } else { @@ -2865,32 +2916,38 @@ void writeImage(std::string& json, std::vector& views, const cgltf_i if (settings.texture_basis) { std::string full_path = getFullPath(image.uri, input_path); - std::string basis_path = getFileName(image.uri) + ".basis"; + std::string basis_path = getFileName(image.uri) + (settings.texture_ktx2 ? ".ktx" : ".basis"); std::string basis_full_path = getFullPath(basis_path.c_str(), output_path); - if (!readFile(full_path.c_str(), img_data)) - { - fprintf(stderr, "Warning: unable to read image %s, skipping\n", image.uri); - } - else + if (readFile(full_path.c_str(), img_data)) { std::string encoded; - if (!encodeBasis(img_data, encoded, info.normal_map, settings.texture_quality)) + if (encodeBasis(img_data, encoded, info.normal_map, info.srgb, settings.texture_quality)) { - fprintf(stderr, "Warning: unable to encode image %s with Basis, skipping\n", image.uri); - } - else if (!writeFile(basis_full_path.c_str(), encoded)) - { - fprintf(stderr, "Warning: unable to save Basis image %s, skipping\n", image.uri); + if (settings.texture_ktx2) + encoded = basisToKtx(encoded, info.srgb); + + if (writeFile(basis_full_path.c_str(), encoded)) + { + append(json, "\"uri\":\""); + append(json, basis_path); + append(json, "\""); + } + else + { + fprintf(stderr, "Warning: unable to save Basis image %s, skipping\n", image.uri); + } } else { - append(json, "\"uri\":\""); - append(json, basis_path); - append(json, "\""); + fprintf(stderr, "Warning: unable to encode image %s with Basis, skipping\n", image.uri); } } + else + { + fprintf(stderr, "Warning: unable to read image %s, skipping\n", image.uri); + } } else { @@ -2905,6 +2962,24 @@ void writeImage(std::string& json, std::vector& views, const cgltf_i } } +void writeTexture(std::string& json, const cgltf_texture& texture, cgltf_data* data, const Settings& settings) +{ + if (texture.image) + { + if (settings.texture_ktx2) + { + append(json, "\"extensions\":{\"KHR_texture_basisu\":{\"source\":"); + append(json, size_t(texture.image - data->images)); + append(json, "}}"); + } + else + { + append(json, "\"source\":"); + append(json, size_t(texture.image - data->images)); + } + } +} + void writeMeshAttributes(std::string& json, std::vector& views, std::string& json_accessors, size_t& accr_offset, const Mesh& mesh, int target, const QuantizationParams& qp, const Settings& settings) { std::string scratch; @@ -3317,18 +3392,18 @@ void writeCamera(std::string& json, const cgltf_camera& camera) case cgltf_camera_type_perspective: append(json, "\"type\":\"perspective\",\"perspective\":{"); append(json, "\"yfov\":"); - append(json, camera.perspective.yfov); + append(json, camera.data.perspective.yfov); append(json, ",\"znear\":"); - append(json, camera.perspective.znear); - if (camera.perspective.aspect_ratio != 0.f) + append(json, camera.data.perspective.znear); + if (camera.data.perspective.aspect_ratio != 0.f) { append(json, ",\"aspectRatio\":"); - append(json, camera.perspective.aspect_ratio); + append(json, camera.data.perspective.aspect_ratio); } - if (camera.perspective.zfar != 0.f) + if (camera.data.perspective.zfar != 0.f) { append(json, ",\"zfar\":"); - append(json, camera.perspective.zfar); + append(json, camera.data.perspective.zfar); } append(json, "}"); break; @@ -3336,13 +3411,13 @@ void writeCamera(std::string& json, const cgltf_camera& camera) case cgltf_camera_type_orthographic: append(json, "\"type\":\"orthographic\",\"orthographic\":{"); append(json, "\"xmag\":"); - append(json, camera.orthographic.xmag); + append(json, camera.data.orthographic.xmag); append(json, ",\"ymag\":"); - append(json, camera.orthographic.ymag); + append(json, camera.data.orthographic.ymag); append(json, ",\"znear\":"); - append(json, camera.orthographic.znear); + append(json, camera.data.orthographic.znear); append(json, ",\"zfar\":"); - append(json, camera.orthographic.zfar); + append(json, camera.data.orthographic.zfar); append(json, "}"); break; @@ -3397,6 +3472,46 @@ void writeLight(std::string& json, const cgltf_light& light) append(json, "}"); } +void writeArray(std::string& json, const char* name, const std::string& contents) +{ + if (contents.empty()) + return; + + comma(json); + append(json, "\""); + append(json, name); + append(json, "\":["); + append(json, contents); + append(json, "]"); +} + +void writeExtensions(std::string& json, const ExtensionInfo* extensions, size_t count) +{ + comma(json); + append(json, "\"extensionsUsed\":["); + for (size_t i = 0; i < count; ++i) + if (extensions[i].used) + { + comma(json); + append(json, "\""); + append(json, extensions[i].name); + append(json, "\""); + } + append(json, "]"); + + comma(json); + append(json, "\"extensionsRequired\":["); + for (size_t i = 0; i < count; ++i) + if (extensions[i].used && extensions[i].required) + { + comma(json); + append(json, "\""); + append(json, extensions[i].name); + append(json, "\""); + } + append(json, "]"); +} + void finalizeBufferViews(std::string& json, std::vector& views, std::string& bin, std::string& fallback) { for (size_t i = 0; i < views.size(); ++i) @@ -3460,6 +3575,23 @@ void printMeshStats(const std::vector& meshes, const char* name) printf("%s: %d triangles, %d vertices\n", name, int(triangles), int(vertices)); } +void printSceneStats(const std::vector& views, const std::vector& meshes, size_t node_offset, size_t mesh_offset, size_t material_offset, size_t json_size, size_t bin_size) +{ + size_t bytes[BufferView::Kind_Count] = {}; + + for (size_t i = 0; i < views.size(); ++i) + { + const BufferView& view = views[i]; + bytes[view.kind] += view.bytes; + } + + printf("output: %d nodes, %d meshes (%d primitives), %d materials\n", int(node_offset), int(mesh_offset), int(meshes.size()), int(material_offset)); + printf("output: JSON %d bytes, buffers %d bytes\n", int(json_size), int(bin_size)); + printf("output: buffers: vertex %d bytes, index %d bytes, skin %d bytes, time %d bytes, keyframe %d bytes, image %d bytes\n", + int(bytes[BufferView::Kind_Vertex]), int(bytes[BufferView::Kind_Index]), int(bytes[BufferView::Kind_Skin]), + int(bytes[BufferView::Kind_Time]), int(bytes[BufferView::Kind_Keyframe]), int(bytes[BufferView::Kind_Image])); +} + void printAttributeStats(const std::vector& views, BufferView::Kind kind, const char* name) { for (size_t i = 0; i < views.size(); ++i) @@ -3561,13 +3693,7 @@ void process(cgltf_data* data, const char* input_path, const char* output_path, std::vector images(data->images_count); - for (size_t i = 0; i < data->materials_count; ++i) - { - const cgltf_material& material = data->materials[i]; - - if (material.normal_texture.texture && material.normal_texture.texture->image) - images[material.normal_texture.texture->image - data->images].normal_map = true; - } + analyzeImages(data, images); QuantizationParams qp = prepareQuantization(meshes, settings); @@ -3595,9 +3721,11 @@ void process(cgltf_data* data, const char* input_path, const char* output_path, for (size_t i = 0; i < data->images_count; ++i) { + const cgltf_image& image = data->images[i]; + if (settings.verbose && settings.texture_basis) { - const char* uri = data->images[i].uri; + const char* uri = image.uri; bool embedded = !uri || strncmp(uri, "data:", 5) == 0; printf("image %d (%s) is being encoded with Basis\n", int(i), embedded ? "embedded" : uri); @@ -3605,7 +3733,7 @@ void process(cgltf_data* data, const char* input_path, const char* output_path, comma(json_images); append(json_images, "{"); - writeImage(json_images, views, data->images[i], images[i], i, input_path, output_path, settings); + writeImage(json_images, views, image, images[i], i, input_path, output_path, settings); append(json_images, "}"); } @@ -3615,11 +3743,7 @@ void process(cgltf_data* data, const char* input_path, const char* output_path, comma(json_textures); append(json_textures, "{"); - if (texture.image) - { - append(json_textures, "\"source\":"); - append(json_textures, size_t(texture.image - data->images)); - } + writeTexture(json_textures, texture, data, settings); append(json_textures, "}"); } @@ -3834,110 +3958,42 @@ void process(cgltf_data* data, const char* input_path, const char* output_path, } append(json, "}"); - append(json, ",\"extensionsUsed\":["); - append(json, "\"KHR_mesh_quantization\""); - if (settings.compress) - { - comma(json); - append(json, "\"MESHOPT_compression\""); - } - if (!json_textures.empty()) - { - comma(json); - append(json, "\"KHR_texture_transform\""); - } - if (ext_pbr_specular_glossiness) - { - comma(json); - append(json, "\"KHR_materials_pbrSpecularGlossiness\""); - } - if (ext_unlit) - { - comma(json); - append(json, "\"KHR_materials_unlit\""); - } - if (data->lights_count) - { - comma(json); - append(json, "\"KHR_lights_punctual\""); - } - append(json, "]"); + const ExtensionInfo extensions[] = { + {"KHR_mesh_quantization", true, true}, + {"MESHOPT_compression", settings.compress, !settings.fallback}, + {"KHR_texture_transform", !json_textures.empty(), false}, + {"KHR_materials_pbrSpecularGlossiness", ext_pbr_specular_glossiness, false}, + {"KHR_materials_unlit", ext_unlit, false}, + {"KHR_lights_punctual", data->lights_count > 0, false}, + {"KHR_image_ktx2", !json_textures.empty() && settings.texture_ktx2, true}, + {"KHR_texture_basisu", !json_textures.empty() && settings.texture_ktx2, true}, + }; - append(json, ",\"extensionsRequired\":["); - append(json, "\"KHR_mesh_quantization\""); - if (settings.compress && !settings.fallback) - { - comma(json); - append(json, "\"MESHOPT_compression\""); - } - append(json, "]"); + writeExtensions(json, extensions, sizeof(extensions) / sizeof(extensions[0])); - if (!views.empty()) - { - std::string json_views; - finalizeBufferViews(json_views, views, bin, fallback); + std::string json_views; + finalizeBufferViews(json_views, views, bin, fallback); + + writeArray(json, "bufferViews", json_views); + writeArray(json, "accessors", json_accessors); + writeArray(json, "images", json_images); + writeArray(json, "textures", json_textures); + writeArray(json, "materials", json_materials); + writeArray(json, "meshes", json_meshes); + writeArray(json, "skins", json_skins); + writeArray(json, "animations", json_animations); + writeArray(json, "nodes", json_nodes); - append(json, ",\"bufferViews\":["); - append(json, json_views); - append(json, "]"); - } - if (!json_accessors.empty()) - { - append(json, ",\"accessors\":["); - append(json, json_accessors); - append(json, "]"); - } - if (!json_images.empty()) - { - append(json, ",\"images\":["); - append(json, json_images); - append(json, "]"); - } - if (!json_textures.empty()) - { - append(json, ",\"textures\":["); - append(json, json_textures); - append(json, "]"); - } - if (!json_materials.empty()) - { - append(json, ",\"materials\":["); - append(json, json_materials); - append(json, "]"); - } - if (!json_meshes.empty()) - { - append(json, ",\"meshes\":["); - append(json, json_meshes); - append(json, "]"); - } - if (!json_skins.empty()) - { - append(json, ",\"skins\":["); - append(json, json_skins); - append(json, "]"); - } - if (!json_animations.empty()) - { - append(json, ",\"animations\":["); - append(json, json_animations); - append(json, "]"); - } if (!json_roots.empty()) { - append(json, ",\"nodes\":["); - append(json, json_nodes); - append(json, "],\"scenes\":["); + append(json, ",\"scenes\":["); append(json, "{\"nodes\":["); append(json, json_roots); append(json, "]}]"); } - if (!json_cameras.empty()) - { - append(json, ",\"cameras\":["); - append(json, json_cameras); - append(json, "]"); - } + + writeArray(json, "cameras", json_cameras); + if (!json_lights.empty()) { append(json, ",\"extensions\":{\"KHR_lights_punctual\":{\"lights\":["); @@ -3951,19 +4007,7 @@ void process(cgltf_data* data, const char* input_path, const char* output_path, if (settings.verbose) { - size_t bytes[BufferView::Kind_Count] = {}; - - for (size_t i = 0; i < views.size(); ++i) - { - BufferView& view = views[i]; - bytes[view.kind] += view.bytes; - } - - printf("output: %d nodes, %d meshes (%d primitives), %d materials\n", int(node_offset), int(mesh_offset), int(meshes.size()), int(material_offset)); - printf("output: JSON %d bytes, buffers %d bytes\n", int(json.size()), int(bin.size())); - printf("output: buffers: vertex %d bytes, index %d bytes, skin %d bytes, time %d bytes, keyframe %d bytes, image %d bytes\n", - int(bytes[BufferView::Kind_Vertex]), int(bytes[BufferView::Kind_Index]), int(bytes[BufferView::Kind_Skin]), - int(bytes[BufferView::Kind_Time]), int(bytes[BufferView::Kind_Keyframe]), int(bytes[BufferView::Kind_Image])); + printSceneStats(views, meshes, node_offset, mesh_offset, material_offset, json.size(), bin.size()); } if (settings.verbose > 1) @@ -4254,6 +4298,11 @@ int main(int argc, char** argv) { settings.texture_basis = true; } + else if (strcmp(arg, "-tc") == 0) + { + settings.texture_basis = true; + settings.texture_ktx2 = true; + } else if (strcmp(arg, "-tq") == 0 && i + 1 < argc && isdigit(argv[i + 1][0])) { settings.texture_quality = atoi(argv[++i]); @@ -4328,6 +4377,7 @@ int main(int argc, char** argv) fprintf(stderr, "-sa: aggressively simplify to the target ratio disregarding quality\n"); fprintf(stderr, "-te: embed all textures into main buffer\n"); fprintf(stderr, "-tb: convert all textures to Basis Universal format (with basisu executable)\n"); + fprintf(stderr, "-tc: convert all textures to KTX2 with BasisU supercompression (using basisu executable)\n"); fprintf(stderr, "-tq N: set texture encoding quality (default: 50; N should be between 1 and 100\n"); fprintf(stderr, "-c: produce compressed gltf/glb files\n"); fprintf(stderr, "-cf: produce compressed gltf/glb files with fallback for loaders that don't support compression\n"); diff --git a/3rdparty/meshoptimizer/tools/khr_df.h b/3rdparty/meshoptimizer/tools/khr_df.h new file mode 100644 index 000000000..8788b0adf --- /dev/null +++ b/3rdparty/meshoptimizer/tools/khr_df.h @@ -0,0 +1,627 @@ +/* The Khronos Data Format Specification (version 1.3) */ +/* +** Copyright (c) 2015-19 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* This header defines a structure that can describe the layout of image + formats in memory. This means that the data format is transparent to + the application, and the expectation is that this should be used when + the layout is defined external to the API. Many Khronos APIs deliberately + keep the internal layout of images opaque, to allow proprietary layouts + and optimisations. This structure is not appropriate for describing + opaque layouts. */ + +/* We stick to standard C89 constructs for simplicity and portability. */ + +#ifndef _KHR_DATA_FORMAT_H_ +#define _KHR_DATA_FORMAT_H_ + +/* Accessors */ +typedef enum _khr_word_e { + KHR_DF_WORD_VENDORID = 0U, + KHR_DF_WORD_DESCRIPTORTYPE = 0U, + KHR_DF_WORD_VERSIONNUMBER = 1U, + KHR_DF_WORD_DESCRIPTORBLOCKSIZE = 1U, + KHR_DF_WORD_MODEL = 2U, + KHR_DF_WORD_PRIMARIES = 2U, + KHR_DF_WORD_TRANSFER = 2U, + KHR_DF_WORD_FLAGS = 2U, + KHR_DF_WORD_TEXELBLOCKDIMENSION0 = 3U, + KHR_DF_WORD_TEXELBLOCKDIMENSION1 = 3U, + KHR_DF_WORD_TEXELBLOCKDIMENSION2 = 3U, + KHR_DF_WORD_TEXELBLOCKDIMENSION3 = 3U, + KHR_DF_WORD_BYTESPLANE0 = 4U, + KHR_DF_WORD_BYTESPLANE1 = 4U, + KHR_DF_WORD_BYTESPLANE2 = 4U, + KHR_DF_WORD_BYTESPLANE3 = 4U, + KHR_DF_WORD_BYTESPLANE4 = 5U, + KHR_DF_WORD_BYTESPLANE5 = 5U, + KHR_DF_WORD_BYTESPLANE6 = 5U, + KHR_DF_WORD_BYTESPLANE7 = 5U, + KHR_DF_WORD_SAMPLESTART = 6U, + KHR_DF_WORD_SAMPLEWORDS = 4U +} khr_df_word_e; + +typedef enum _khr_df_shift_e { + KHR_DF_SHIFT_VENDORID = 0U, + KHR_DF_SHIFT_DESCRIPTORTYPE = 17U, + KHR_DF_SHIFT_VERSIONNUMBER = 0U, + KHR_DF_SHIFT_DESCRIPTORBLOCKSIZE = 16U, + KHR_DF_SHIFT_MODEL = 0U, + KHR_DF_SHIFT_PRIMARIES = 8U, + KHR_DF_SHIFT_TRANSFER = 16U, + KHR_DF_SHIFT_FLAGS = 24U, + KHR_DF_SHIFT_TEXELBLOCKDIMENSION0 = 0U, + KHR_DF_SHIFT_TEXELBLOCKDIMENSION1 = 8U, + KHR_DF_SHIFT_TEXELBLOCKDIMENSION2 = 16U, + KHR_DF_SHIFT_TEXELBLOCKDIMENSION3 = 24U, + KHR_DF_SHIFT_BYTESPLANE0 = 0U, + KHR_DF_SHIFT_BYTESPLANE1 = 8U, + KHR_DF_SHIFT_BYTESPLANE2 = 16U, + KHR_DF_SHIFT_BYTESPLANE3 = 24U, + KHR_DF_SHIFT_BYTESPLANE4 = 0U, + KHR_DF_SHIFT_BYTESPLANE5 = 8U, + KHR_DF_SHIFT_BYTESPLANE6 = 16U, + KHR_DF_SHIFT_BYTESPLANE7 = 24U +} khr_df_shift_e; + +typedef enum _khr_df_mask_e { + KHR_DF_MASK_VENDORID = 0x1FFFFU, + KHR_DF_MASK_DESCRIPTORTYPE = 0x7FFFU, + KHR_DF_MASK_VERSIONNUMBER = 0xFFFFU, + KHR_DF_MASK_DESCRIPTORBLOCKSIZE = 0xFFFFU, + KHR_DF_MASK_MODEL = 0xFFU, + KHR_DF_MASK_PRIMARIES = 0xFFU, + KHR_DF_MASK_TRANSFER = 0xFFU, + KHR_DF_MASK_FLAGS = 0xFFU, + KHR_DF_MASK_TEXELBLOCKDIMENSION0 = 0xFFU, + KHR_DF_MASK_TEXELBLOCKDIMENSION1 = 0xFFU, + KHR_DF_MASK_TEXELBLOCKDIMENSION2 = 0xFFU, + KHR_DF_MASK_TEXELBLOCKDIMENSION3 = 0xFFU, + KHR_DF_MASK_BYTESPLANE0 = 0xFFU, + KHR_DF_MASK_BYTESPLANE1 = 0xFFU, + KHR_DF_MASK_BYTESPLANE2 = 0xFFU, + KHR_DF_MASK_BYTESPLANE3 = 0xFFU, + KHR_DF_MASK_BYTESPLANE4 = 0xFFU, + KHR_DF_MASK_BYTESPLANE5 = 0xFFU, + KHR_DF_MASK_BYTESPLANE6 = 0xFFU, + KHR_DF_MASK_BYTESPLANE7 = 0xFFU +} khr_df_mask_e; + +/* Helper macro: + Extract field X from basic descriptor block BDB */ +#define KHR_DFDVAL(BDB, X) \ + (((BDB)[KHR_DF_WORD_ ## X] >> (KHR_DF_SHIFT_ ## X)) \ + & (KHR_DF_MASK_ ## X)) + +/* Helper macro: + Set field X of basic descriptor block BDB */ +#define KHR_DFDSETVAL(BDB, X, val) \ + ((BDB)[KHR_DF_WORD_ ## X] = \ + ((BDB)[KHR_DF_WORD_ ## X] & \ + ~((KHR_DF_MASK_ ## X) << (KHR_DF_SHIFT_ ## X))) | \ + (((val) & (KHR_DF_MASK_ ## X)) << (KHR_DF_SHIFT_ ## X))) + +/* Offsets relative to the start of a sample */ +typedef enum _khr_df_sampleword_e { + KHR_DF_SAMPLEWORD_BITOFFSET = 0U, + KHR_DF_SAMPLEWORD_BITLENGTH = 0U, + KHR_DF_SAMPLEWORD_CHANNELID = 0U, + KHR_DF_SAMPLEWORD_QUALIFIERS = 0U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION0 = 1U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION1 = 1U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION2 = 1U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION3 = 1U, + KHR_DF_SAMPLEWORD_SAMPLEPOSITION_ALL = 1U, + KHR_DF_SAMPLEWORD_SAMPLELOWER = 2U, + KHR_DF_SAMPLEWORD_SAMPLEUPPER = 3U +} khr_df_sampleword_e; + +typedef enum _khr_df_sampleshift_e { + KHR_DF_SAMPLESHIFT_BITOFFSET = 0U, + KHR_DF_SAMPLESHIFT_BITLENGTH = 16U, + KHR_DF_SAMPLESHIFT_CHANNELID = 24U, + /* N.B. Qualifiers are defined as an offset into a byte */ + KHR_DF_SAMPLESHIFT_QUALIFIERS = 24U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION0 = 0U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION1 = 8U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION2 = 16U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION3 = 24U, + KHR_DF_SAMPLESHIFT_SAMPLEPOSITION_ALL = 0U, + KHR_DF_SAMPLESHIFT_SAMPLELOWER = 0U, + KHR_DF_SAMPLESHIFT_SAMPLEUPPER = 0U +} khr_df_sampleshift_e; + +typedef enum _khr_df_samplemask_e { + KHR_DF_SAMPLEMASK_BITOFFSET = 0xFFFFU, + KHR_DF_SAMPLEMASK_BITLENGTH = 0xFF, + KHR_DF_SAMPLEMASK_CHANNELID = 0xF, + /* N.B. Qualifiers are defined as an offset into a byte */ + KHR_DF_SAMPLEMASK_QUALIFIERS = 0xF0, + KHR_DF_SAMPLEMASK_SAMPLEPOSITION0 = 0xFF, + KHR_DF_SAMPLEMASK_SAMPLEPOSITION1 = 0xFF, + KHR_DF_SAMPLEMASK_SAMPLEPOSITION2 = 0xFF, + KHR_DF_SAMPLEMASK_SAMPLEPOSITION3 = 0xFF, + /* ISO C restricts enum values to range of int hence the + cast. We do it verbosely instead of using -1 to ensure + it is a 32-bit value even if int is 64 bits. */ + KHR_DF_SAMPLEMASK_SAMPLEPOSITION_ALL = (int) 0xFFFFFFFFU, + KHR_DF_SAMPLEMASK_SAMPLELOWER = (int) 0xFFFFFFFFU, + KHR_DF_SAMPLEMASK_SAMPLEUPPER = (int) 0xFFFFFFFFU +} khr_df_samplemask_e; + +/* Helper macro: + Extract field X of sample S from basic descriptor block BDB */ +#define KHR_DFDSVAL(BDB, S, X) \ + (((BDB)[KHR_DF_WORD_SAMPLESTART + \ + ((S) * KHR_DF_WORD_SAMPLEWORDS) + \ + KHR_DF_SAMPLEWORD_ ## X] >> (KHR_DF_SAMPLESHIFT_ ## X)) \ + & (KHR_DF_SAMPLEMASK_ ## X)) + +/* Helper macro: + Set field X of sample S of basic descriptor block BDB */ +#define KHR_DFDSETSVAL(BDB, S, X, val) \ + ((BDB)[KHR_DF_WORD_SAMPLESTART + \ + ((S) * KHR_DF_WORD_SAMPLEWORDS) + \ + KHR_DF_SAMPLEWORD_ ## X] = \ + ((BDB)[KHR_DF_WORD_SAMPLESTART + \ + ((S) * KHR_DF_WORD_SAMPLEWORDS) + \ + KHR_DF_SAMPLEWORD_ ## X] & \ + ~((uint32_t)(KHR_DF_SAMPLEMASK_ ## X) << (KHR_DF_SAMPLESHIFT_ ## X))) | \ + (((val) & (uint32_t)(KHR_DF_SAMPLEMASK_ ## X)) << (KHR_DF_SAMPLESHIFT_ ## X))) + +/* Helper macro: + Number of samples in basic descriptor block BDB */ +#define KHR_DFDSAMPLECOUNT(BDB) \ + (((KHR_DFDVAL(BDB, DESCRIPTORBLOCKSIZE) >> 2) - \ + KHR_DF_WORD_SAMPLESTART) \ + / KHR_DF_WORD_SAMPLEWORDS) + +/* Helper macro: + Size in words of basic descriptor block for S samples */ +#define KHR_DFDSIZEWORDS(S) \ + (KHR_DF_WORD_SAMPLESTART + \ + (S) * KHR_DF_WORD_SAMPLEWORDS) + +/* Vendor ids */ +typedef enum _khr_df_vendorid_e { + /* Standard Khronos descriptor */ + KHR_DF_VENDORID_KHRONOS = 0U, + KHR_DF_VENDORID_MAX = 0x1FFFFU +} khr_df_vendorid_e; + +/* Descriptor types */ +typedef enum _khr_df_khr_descriptortype_e { + /* Default Khronos basic descriptor block */ + KHR_DF_KHR_DESCRIPTORTYPE_BASICFORMAT = 0U, + /* Extension descriptor block for additional planes */ + KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_PLANES = 0x6001U, + /* Extension descriptor block for additional dimensions */ + KHR_DF_KHR_DESCRIPTORTYPE_ADDITIONAL_DIMENSIONS = 0x6002U, + /* Bit indicates modifying requires understanding this extension */ + KHR_DF_KHR_DESCRIPTORTYPE_NEEDED_FOR_WRITE_BIT = 0x2000U, + /* Bit indicates processing requires understanding this extension */ + KHR_DF_KHR_DESCRIPTORTYPE_NEEDED_FOR_DECODE_BIT = 0x4000U, + KHR_DF_KHR_DESCRIPTORTYPE_MAX = 0x7FFFU +} khr_df_khr_descriptortype_e; + +/* Descriptor block version */ +typedef enum _khr_df_versionnumber_e { + /* Standard Khronos descriptor */ + KHR_DF_VERSIONNUMBER_1_0 = 0U, /* Version 1.0 of the specification */ + KHR_DF_VERSIONNUMBER_1_1 = 0U, /* Version 1.1 did not bump the version number */ + KHR_DF_VERSIONNUMBER_1_2 = 1U, /* Version 1.2 increased the version number */ + KHR_DF_VERSIONNUMBER_1_3 = 2U, /* Version 1.3 increased the version number */ + KHR_DF_VERSIONNUMBER_LATEST = KHR_DF_VERSIONNUMBER_1_3, + KHR_DF_VERSIONNUMBER_MAX = 0xFFFFU +} khr_df_versionnumber_e; + +/* Model in which the color coordinate space is defined. + There is no requirement that a color format use all the + channel types that are defined in the color model. */ +typedef enum _khr_df_model_e { + /* No interpretation of color channels defined */ + KHR_DF_MODEL_UNSPECIFIED = 0U, + /* Color primaries (red, green, blue) + alpha, depth and stencil */ + KHR_DF_MODEL_RGBSDA = 1U, + /* Color differences (Y', Cb, Cr) + alpha, depth and stencil */ + KHR_DF_MODEL_YUVSDA = 2U, + /* Color differences (Y', I, Q) + alpha, depth and stencil */ + KHR_DF_MODEL_YIQSDA = 3U, + /* Perceptual color (CIE L*a*b*) + alpha, depth and stencil */ + KHR_DF_MODEL_LABSDA = 4U, + /* Subtractive colors (cyan, magenta, yellow, black) + alpha */ + KHR_DF_MODEL_CMYKA = 5U, + /* Non-color coordinate data (X, Y, Z, W) */ + KHR_DF_MODEL_XYZW = 6U, + /* Hue, saturation, value, hue angle on color circle, plus alpha */ + KHR_DF_MODEL_HSVA_ANG = 7U, + /* Hue, saturation, lightness, hue angle on color circle, plus alpha */ + KHR_DF_MODEL_HSLA_ANG = 8U, + /* Hue, saturation, value, hue on color hexagon, plus alpha */ + KHR_DF_MODEL_HSVA_HEX = 9U, + /* Hue, saturation, lightness, hue on color hexagon, plus alpha */ + KHR_DF_MODEL_HSLA_HEX = 10U, + /* Lightweight approximate color difference (luma, orange, green) */ + KHR_DF_MODEL_YCGCOA = 11U, + /* ITU BT.2020 constant luminance YcCbcCrc */ + KHR_DF_MODEL_YCCBCCRC = 12U, + /* ITU BT.2100 constant intensity ICtCp */ + KHR_DF_MODEL_ICTCP = 13U, + /* CIE 1931 XYZ color coordinates (X, Y, Z) */ + KHR_DF_MODEL_CIEXYZ = 14U, + /* CIE 1931 xyY color coordinates (X, Y, Y) */ + KHR_DF_MODEL_CIEXYY = 15U, + + /* Compressed formats start at 128. */ + /* These compressed formats should generally have a single sample, + sited at the 0,0 position of the texel block. Where multiple + channels are used to distinguish formats, these should be cosited. */ + /* Direct3D (and S3) compressed formats */ + /* Note that premultiplied status is recorded separately */ + /* DXT1 "channels" are RGB (0), Alpha (1) */ + /* DXT1/BC1 with one channel is opaque */ + /* DXT1/BC1 with a cosited alpha sample is transparent */ + KHR_DF_MODEL_DXT1A = 128U, + KHR_DF_MODEL_BC1A = 128U, + /* DXT2/DXT3/BC2, with explicit 4-bit alpha */ + KHR_DF_MODEL_DXT2 = 129U, + KHR_DF_MODEL_DXT3 = 129U, + KHR_DF_MODEL_BC2 = 129U, + /* DXT4/DXT5/BC3, with interpolated alpha */ + KHR_DF_MODEL_DXT4 = 130U, + KHR_DF_MODEL_DXT5 = 130U, + KHR_DF_MODEL_BC3 = 130U, + /* BC4 - single channel interpolated 8-bit data */ + /* (The UNORM/SNORM variation is recorded in the channel data) */ + KHR_DF_MODEL_BC4 = 131U, + /* BC5 - two channel interpolated 8-bit data */ + /* (The UNORM/SNORM variation is recorded in the channel data) */ + KHR_DF_MODEL_BC5 = 132U, + /* BC6H - DX11 format for 16-bit float channels */ + KHR_DF_MODEL_BC6H = 133U, + /* BC7 - DX11 format */ + KHR_DF_MODEL_BC7 = 134U, + /* Gap left for future desktop expansion */ + + /* Mobile compressed formats follow */ + /* A format of ETC1 indicates that the format shall be decodable + by an ETC1-compliant decoder and not rely on ETC2 features */ + KHR_DF_MODEL_ETC1 = 160U, + /* A format of ETC2 is permitted to use ETC2 encodings on top of + the baseline ETC1 specification */ + /* The ETC2 format has channels "red", "green", "RGB" and "alpha", + which should be cosited samples */ + /* Punch-through alpha can be distinguished from full alpha by + the plane size in bytes required for the texel block */ + KHR_DF_MODEL_ETC2 = 161U, + /* Adaptive Scalable Texture Compression */ + /* ASTC HDR vs LDR is determined by the float flag in the channel */ + /* ASTC block size can be distinguished by texel block size */ + KHR_DF_MODEL_ASTC = 162U, + /* ETC1S is a simplified subset of ETC1 */ + KHR_DF_MODEL_ETC1S = 163U, + /* PowerVR Texture Compression */ + KHR_DF_MODEL_PVRTC = 164U, + KHR_DF_MODEL_PVRTC2 = 165U, + /* Proprietary formats (ATITC, etc.) should follow */ + KHR_DF_MODEL_MAX = 0xFFU +} khr_df_model_e; + +/* Definition of channel names for each color model */ +typedef enum _khr_df_model_channels_e { + /* Unspecified format with nominal channel numbering */ + KHR_DF_CHANNEL_UNSPECIFIED_0 = 0U, + KHR_DF_CHANNEL_UNSPECIFIED_1 = 1U, + KHR_DF_CHANNEL_UNSPECIFIED_2 = 2U, + KHR_DF_CHANNEL_UNSPECIFIED_3 = 3U, + KHR_DF_CHANNEL_UNSPECIFIED_4 = 4U, + KHR_DF_CHANNEL_UNSPECIFIED_5 = 5U, + KHR_DF_CHANNEL_UNSPECIFIED_6 = 6U, + KHR_DF_CHANNEL_UNSPECIFIED_7 = 7U, + KHR_DF_CHANNEL_UNSPECIFIED_8 = 8U, + KHR_DF_CHANNEL_UNSPECIFIED_9 = 9U, + KHR_DF_CHANNEL_UNSPECIFIED_10 = 10U, + KHR_DF_CHANNEL_UNSPECIFIED_11 = 11U, + KHR_DF_CHANNEL_UNSPECIFIED_12 = 12U, + KHR_DF_CHANNEL_UNSPECIFIED_13 = 13U, + KHR_DF_CHANNEL_UNSPECIFIED_14 = 14U, + KHR_DF_CHANNEL_UNSPECIFIED_15 = 15U, + /* MODEL_RGBSDA - red, green, blue, stencil, depth, alpha */ + KHR_DF_CHANNEL_RGBSDA_RED = 0U, + KHR_DF_CHANNEL_RGBSDA_R = 0U, + KHR_DF_CHANNEL_RGBSDA_GREEN = 1U, + KHR_DF_CHANNEL_RGBSDA_G = 1U, + KHR_DF_CHANNEL_RGBSDA_BLUE = 2U, + KHR_DF_CHANNEL_RGBSDA_B = 2U, + KHR_DF_CHANNEL_RGBSDA_STENCIL = 13U, + KHR_DF_CHANNEL_RGBSDA_S = 13U, + KHR_DF_CHANNEL_RGBSDA_DEPTH = 14U, + KHR_DF_CHANNEL_RGBSDA_D = 14U, + KHR_DF_CHANNEL_RGBSDA_ALPHA = 15U, + KHR_DF_CHANNEL_RGBSDA_A = 15U, + /* MODEL_YUVSDA - luma, Cb, Cr, stencil, depth, alpha */ + KHR_DF_CHANNEL_YUVSDA_Y = 0U, + KHR_DF_CHANNEL_YUVSDA_CB = 1U, + KHR_DF_CHANNEL_YUVSDA_U = 1U, + KHR_DF_CHANNEL_YUVSDA_CR = 2U, + KHR_DF_CHANNEL_YUVSDA_V = 2U, + KHR_DF_CHANNEL_YUVSDA_STENCIL = 13U, + KHR_DF_CHANNEL_YUVSDA_S = 13U, + KHR_DF_CHANNEL_YUVSDA_DEPTH = 14U, + KHR_DF_CHANNEL_YUVSDA_D = 14U, + KHR_DF_CHANNEL_YUVSDA_ALPHA = 15U, + KHR_DF_CHANNEL_YUVSDA_A = 15U, + /* MODEL_YIQSDA - luma, in-phase, quadrature, stencil, depth, alpha */ + KHR_DF_CHANNEL_YIQSDA_Y = 0U, + KHR_DF_CHANNEL_YIQSDA_I = 1U, + KHR_DF_CHANNEL_YIQSDA_Q = 2U, + KHR_DF_CHANNEL_YIQSDA_STENCIL = 13U, + KHR_DF_CHANNEL_YIQSDA_S = 13U, + KHR_DF_CHANNEL_YIQSDA_DEPTH = 14U, + KHR_DF_CHANNEL_YIQSDA_D = 14U, + KHR_DF_CHANNEL_YIQSDA_ALPHA = 15U, + KHR_DF_CHANNEL_YIQSDA_A = 15U, + /* MODEL_LABSDA - CIELAB/L*a*b* luma, red-green, blue-yellow, stencil, depth, alpha */ + KHR_DF_CHANNEL_LABSDA_L = 0U, + KHR_DF_CHANNEL_LABSDA_A = 1U, + KHR_DF_CHANNEL_LABSDA_B = 2U, + KHR_DF_CHANNEL_LABSDA_STENCIL = 13U, + KHR_DF_CHANNEL_LABSDA_S = 13U, + KHR_DF_CHANNEL_LABSDA_DEPTH = 14U, + KHR_DF_CHANNEL_LABSDA_D = 14U, + KHR_DF_CHANNEL_LABSDA_ALPHA = 15U, + /* NOTE: KHR_DF_CHANNEL_LABSDA_A is not a synonym for alpha! */ + /* MODEL_CMYKA - cyan, magenta, yellow, key/blacK, alpha */ + KHR_DF_CHANNEL_CMYKSDA_CYAN = 0U, + KHR_DF_CHANNEL_CMYKSDA_C = 0U, + KHR_DF_CHANNEL_CMYKSDA_MAGENTA = 1U, + KHR_DF_CHANNEL_CMYKSDA_M = 1U, + KHR_DF_CHANNEL_CMYKSDA_YELLOW = 2U, + KHR_DF_CHANNEL_CMYKSDA_Y = 2U, + KHR_DF_CHANNEL_CMYKSDA_KEY = 3U, + KHR_DF_CHANNEL_CMYKSDA_BLACK = 3U, + KHR_DF_CHANNEL_CMYKSDA_K = 3U, + KHR_DF_CHANNEL_CMYKSDA_ALPHA = 15U, + KHR_DF_CHANNEL_CMYKSDA_A = 15U, + /* MODEL_XYZW - coordinates x, y, z, w */ + KHR_DF_CHANNEL_XYZW_X = 0U, + KHR_DF_CHANNEL_XYZW_Y = 1U, + KHR_DF_CHANNEL_XYZW_Z = 2U, + KHR_DF_CHANNEL_XYZW_W = 3U, + /* MODEL_HSVA_ANG - value (luma), saturation, hue, alpha, angular projection, conical space */ + KHR_DF_CHANNEL_HSVA_ANG_VALUE = 0U, + KHR_DF_CHANNEL_HSVA_ANG_V = 0U, + KHR_DF_CHANNEL_HSVA_ANG_SATURATION = 1U, + KHR_DF_CHANNEL_HSVA_ANG_S = 1U, + KHR_DF_CHANNEL_HSVA_ANG_HUE = 2U, + KHR_DF_CHANNEL_HSVA_ANG_H = 2U, + KHR_DF_CHANNEL_HSVA_ANG_ALPHA = 15U, + KHR_DF_CHANNEL_HSVA_ANG_A = 15U, + /* MODEL_HSLA_ANG - lightness (luma), saturation, hue, alpha, angular projection, double conical space */ + KHR_DF_CHANNEL_HSLA_ANG_LIGHTNESS = 0U, + KHR_DF_CHANNEL_HSLA_ANG_L = 0U, + KHR_DF_CHANNEL_HSLA_ANG_SATURATION = 1U, + KHR_DF_CHANNEL_HSLA_ANG_S = 1U, + KHR_DF_CHANNEL_HSLA_ANG_HUE = 2U, + KHR_DF_CHANNEL_HSLA_ANG_H = 2U, + KHR_DF_CHANNEL_HSLA_ANG_ALPHA = 15U, + KHR_DF_CHANNEL_HSLA_ANG_A = 15U, + /* MODEL_HSVA_HEX - value (luma), saturation, hue, alpha, hexagonal projection, conical space */ + KHR_DF_CHANNEL_HSVA_HEX_VALUE = 0U, + KHR_DF_CHANNEL_HSVA_HEX_V = 0U, + KHR_DF_CHANNEL_HSVA_HEX_SATURATION = 1U, + KHR_DF_CHANNEL_HSVA_HEX_S = 1U, + KHR_DF_CHANNEL_HSVA_HEX_HUE = 2U, + KHR_DF_CHANNEL_HSVA_HEX_H = 2U, + KHR_DF_CHANNEL_HSVA_HEX_ALPHA = 15U, + KHR_DF_CHANNEL_HSVA_HEX_A = 15U, + /* MODEL_HSLA_HEX - lightness (luma), saturation, hue, alpha, hexagonal projection, double conical space */ + KHR_DF_CHANNEL_HSLA_HEX_LIGHTNESS = 0U, + KHR_DF_CHANNEL_HSLA_HEX_L = 0U, + KHR_DF_CHANNEL_HSLA_HEX_SATURATION = 1U, + KHR_DF_CHANNEL_HSLA_HEX_S = 1U, + KHR_DF_CHANNEL_HSLA_HEX_HUE = 2U, + KHR_DF_CHANNEL_HSLA_HEX_H = 2U, + KHR_DF_CHANNEL_HSLA_HEX_ALPHA = 15U, + KHR_DF_CHANNEL_HSLA_HEX_A = 15U, + /* MODEL_YCGCOA - luma, green delta, orange delta, alpha */ + KHR_DF_CHANNEL_YCGCOA_Y = 0U, + KHR_DF_CHANNEL_YCGCOA_CG = 1U, + KHR_DF_CHANNEL_YCGCOA_CO = 2U, + KHR_DF_CHANNEL_YCGCOA_ALPHA = 15U, + KHR_DF_CHANNEL_YCGCOA_A = 15U, + /* MODEL_CIEXYZ - CIE 1931 X, Y, Z */ + KHR_DF_CHANNEL_CIEXYZ_X = 0U, + KHR_DF_CHANNEL_CIEXYZ_Y = 1U, + KHR_DF_CHANNEL_CIEXYZ_Z = 2U, + /* MODEL_CIEXYY - CIE 1931 x, y, Y */ + KHR_DF_CHANNEL_CIEXYY_X = 0U, + KHR_DF_CHANNEL_CIEXYY_YCHROMA = 1U, + KHR_DF_CHANNEL_CIEXYY_YLUMA = 2U, + + /* Compressed formats */ + /* MODEL_DXT1A/MODEL_BC1A */ + KHR_DF_CHANNEL_DXT1A_COLOR = 0U, + KHR_DF_CHANNEL_BC1A_COLOR = 0U, + KHR_DF_CHANNEL_DXT1A_ALPHAPRESENT = 1U, + KHR_DF_CHANNEL_DXT1A_ALPHA = 1U, + KHR_DF_CHANNEL_BC1A_ALPHAPRESENT = 1U, + KHR_DF_CHANNEL_BC1A_ALPHA = 1U, + /* MODEL_DXT2/3/MODEL_BC2 */ + KHR_DF_CHANNEL_DXT2_COLOR = 0U, + KHR_DF_CHANNEL_DXT3_COLOR = 0U, + KHR_DF_CHANNEL_BC2_COLOR = 0U, + KHR_DF_CHANNEL_DXT2_ALPHA = 15U, + KHR_DF_CHANNEL_DXT3_ALPHA = 15U, + KHR_DF_CHANNEL_BC2_ALPHA = 15U, + /* MODEL_DXT4/5/MODEL_BC3 */ + KHR_DF_CHANNEL_DXT4_COLOR = 0U, + KHR_DF_CHANNEL_DXT5_COLOR = 0U, + KHR_DF_CHANNEL_BC3_COLOR = 0U, + KHR_DF_CHANNEL_DXT4_ALPHA = 15U, + KHR_DF_CHANNEL_DXT5_ALPHA = 15U, + KHR_DF_CHANNEL_BC3_ALPHA = 15U, + /* MODEL_BC4 */ + KHR_DF_CHANNEL_BC4_DATA = 0U, + /* MODEL_BC5 */ + KHR_DF_CHANNEL_BC5_RED = 0U, + KHR_DF_CHANNEL_BC5_R = 0U, + KHR_DF_CHANNEL_BC5_GREEN = 1U, + KHR_DF_CHANNEL_BC5_G = 1U, + /* MODEL_BC6H */ + KHR_DF_CHANNEL_BC6H_COLOR = 0U, + KHR_DF_CHANNEL_BC6H_DATA = 0U, + /* MODEL_BC7 */ + KHR_DF_CHANNEL_BC7_DATA = 0U, + KHR_DF_CHANNEL_BC7_COLOR = 0U, + /* MODEL_ETC1 */ + KHR_DF_CHANNEL_ETC1_DATA = 0U, + KHR_DF_CHANNEL_ETC1_COLOR = 0U, + /* MODEL_ETC2 */ + KHR_DF_CHANNEL_ETC2_RED = 0U, + KHR_DF_CHANNEL_ETC2_R = 0U, + KHR_DF_CHANNEL_ETC2_GREEN = 1U, + KHR_DF_CHANNEL_ETC2_G = 1U, + KHR_DF_CHANNEL_ETC2_COLOR = 2U, + KHR_DF_CHANNEL_ETC2_ALPHA = 15U, + KHR_DF_CHANNEL_ETC2_A = 15U, + /* MODEL_ASTC */ + KHR_DF_CHANNEL_ASTC_DATA = 0U, + /* MODEL_ETC1S */ + KHR_DF_CHANNEL_ETC1S_DATA = 0U, + KHR_DF_CHANNEL_ETC1S_COLOR = 0U, + /* MODEL_PVRTC */ + KHR_DF_CHANNEL_PVRTC_DATA = 0U, + KHR_DF_CHANNEL_PVRTC_COLOR = 0U, + /* MODEL_PVRTC2 */ + KHR_DF_CHANNEL_PVRTC2_DATA = 0U, + KHR_DF_CHANNEL_PVRTC2_COLOR = 0U, + + /* Common channel names shared by multiple formats */ + KHR_DF_CHANNEL_COMMON_LUMA = 0U, + KHR_DF_CHANNEL_COMMON_L = 0U, + KHR_DF_CHANNEL_COMMON_STENCIL = 13U, + KHR_DF_CHANNEL_COMMON_S = 13U, + KHR_DF_CHANNEL_COMMON_DEPTH = 14U, + KHR_DF_CHANNEL_COMMON_D = 14U, + KHR_DF_CHANNEL_COMMON_ALPHA = 15U, + KHR_DF_CHANNEL_COMMON_A = 15U +} khr_df_model_channels_e; + +/* Definition of the primary colors in color coordinates. + This is implicitly responsible for defining the conversion + between RGB an YUV color spaces. + LAB and related absolute color models should use + KHR_DF_PRIMARIES_CIEXYZ. */ +typedef enum _khr_df_primaries_e { + /* No color primaries defined */ + KHR_DF_PRIMARIES_UNSPECIFIED = 0U, + /* Color primaries of ITU-R BT.709 and sRGB */ + KHR_DF_PRIMARIES_BT709 = 1U, + /* Synonym for KHR_DF_PRIMARIES_BT709 */ + KHR_DF_PRIMARIES_SRGB = 1U, + /* Color primaries of ITU-R BT.601 (625-line EBU variant) */ + KHR_DF_PRIMARIES_BT601_EBU = 2U, + /* Color primaries of ITU-R BT.601 (525-line SMPTE C variant) */ + KHR_DF_PRIMARIES_BT601_SMPTE = 3U, + /* Color primaries of ITU-R BT.2020 */ + KHR_DF_PRIMARIES_BT2020 = 4U, + /* CIE theoretical color coordinate space */ + KHR_DF_PRIMARIES_CIEXYZ = 5U, + /* Academy Color Encoding System primaries */ + KHR_DF_PRIMARIES_ACES = 6U, + /* Color primaries of ACEScc */ + KHR_DF_PRIMARIES_ACESCC = 7U, + /* Legacy NTSC 1953 primaries */ + KHR_DF_PRIMARIES_NTSC1953 = 8U, + /* Legacy PAL 525-line primaries */ + KHR_DF_PRIMARIES_PAL525 = 9U, + /* Color primaries of Display P3 */ + KHR_DF_PRIMARIES_DISPLAYP3 = 10U, + /* Color primaries of Adobe RGB (1998) */ + KHR_DF_PRIMARIES_ADOBERGB = 11U, + KHR_DF_PRIMARIES_MAX = 0xFFU +} khr_df_primaries_e; + +/* Definition of the optical to digital transfer function + ("gamma correction"). Most transfer functions are not a pure + power function and also include a linear element. + LAB and related absolute color representations should use + KHR_DF_TRANSFER_UNSPECIFIED. */ +typedef enum _khr_df_transfer_e { + /* No transfer function defined */ + KHR_DF_TRANSFER_UNSPECIFIED = 0U, + /* Linear transfer function (value proportional to intensity) */ + KHR_DF_TRANSFER_LINEAR = 1U, + /* Perceptually-linear transfer function of sRGH (~2.4) */ + KHR_DF_TRANSFER_SRGB = 2U, + /* Perceptually-linear transfer function of ITU non-HDR specifications (~1/.45) */ + KHR_DF_TRANSFER_ITU = 3U, + /* SMTPE170M (digital NTSC) defines an alias for the ITU transfer function (~1/.45) */ + KHR_DF_TRANSFER_SMTPE170M = 3U, + /* Perceptually-linear gamma function of original NTSC (simple 2.2 gamma) */ + KHR_DF_TRANSFER_NTSC = 4U, + /* Sony S-log used by Sony video cameras */ + KHR_DF_TRANSFER_SLOG = 5U, + /* Sony S-log 2 used by Sony video cameras */ + KHR_DF_TRANSFER_SLOG2 = 6U, + /* ITU BT.1886 EOTF */ + KHR_DF_TRANSFER_BT1886 = 7U, + /* ITU BT.2100 HLG OETF */ + KHR_DF_TRANSFER_HLG_OETF = 8U, + /* ITU BT.2100 HLG EOTF */ + KHR_DF_TRANSFER_HLG_EOTF = 9U, + /* ITU BT.2100 PQ EOTF */ + KHR_DF_TRANSFER_PQ_EOTF = 10U, + /* ITU BT.2100 PQ OETF */ + KHR_DF_TRANSFER_PQ_OETF = 11U, + /* DCI P3 transfer function */ + KHR_DF_TRANSFER_DCIP3 = 12U, + /* Legacy PAL OETF */ + KHR_DF_TRANSFER_PAL_OETF = 13U, + /* Legacy PAL 625-line EOTF */ + KHR_DF_TRANSFER_PAL625_EOTF = 14U, + /* Legacy ST240 transfer function */ + KHR_DF_TRANSFER_ST240 = 15U, + /* ACEScc transfer function */ + KHR_DF_TRANSFER_ACESCC = 16U, + /* ACEScct transfer function */ + KHR_DF_TRANSFER_ACESCCT = 17U, + /* Adobe RGB (1998) transfer function */ + KHR_DF_TRANSFER_ADOBERGB = 18U, + KHR_DF_TRANSFER_MAX = 0xFFU +} khr_df_transfer_e; + +typedef enum _khr_df_flags_e { + KHR_DF_FLAG_ALPHA_STRAIGHT = 0U, + KHR_DF_FLAG_ALPHA_PREMULTIPLIED = 1U +} khr_df_flags_e; + +typedef enum _khr_df_sample_datatype_qualifiers_e { + KHR_DF_SAMPLE_DATATYPE_LINEAR = 1U << 4U, + KHR_DF_SAMPLE_DATATYPE_EXPONENT = 1U << 5U, + KHR_DF_SAMPLE_DATATYPE_SIGNED = 1U << 6U, + KHR_DF_SAMPLE_DATATYPE_FLOAT = 1U << 7U +} khr_df_sample_datatype_qualifiers_e; + +#endif diff --git a/3rdparty/meshoptimizer/tools/ktx2_format.h b/3rdparty/meshoptimizer/tools/ktx2_format.h new file mode 100644 index 000000000..e97f8c4fa --- /dev/null +++ b/3rdparty/meshoptimizer/tools/ktx2_format.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2010-2018 The Khronos Group Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/* + * Author: Mark Callow from original code by Georg Kolling + */ + +/* + * Converted from ktxint.h + basis_sgd.h by extracting meaningful structures for gltfpack + */ + +#pragma once + +#include + +#define KTX2_IDENTIFIER_REF { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A } +#define KTX2_HEADER_SIZE (80) + +typedef enum ktxSupercmpScheme { + KTX_SUPERCOMPRESSION_NONE = 0, /*!< No supercompression. */ + KTX_SUPERCOMPRESSION_BASIS = 1, /*!< Basis Universal supercompression. */ + KTX_SUPERCOMPRESSION_LZMA = 2, /*!< LZMA supercompression. */ + KTX_SUPERCOMPRESSION_ZLIB = 3, /*!< Zlib supercompression. */ + KTX_SUPERCOMPRESSION_ZSTD = 4, /*!< ZStd supercompression. */ + KTX_SUPERCOMPRESSION_BEGIN_RANGE = KTX_SUPERCOMPRESSION_NONE, + KTX_SUPERCOMPRESSION_END_RANGE = KTX_SUPERCOMPRESSION_ZSTD, + KTX_SUPERCOMPRESSION_BEGIN_VENDOR_RANGE = 0x10000, + KTX_SUPERCOMPRESSION_END_VENDOR_RANGE = 0x1ffff, + KTX_SUPERCOMPRESSION_BEGIN_RESERVED = 0x20000, +} ktxSupercmpScheme; + +/** + * @internal + * @~English + * @brief 32-bit KTX 2 index entry. + */ +typedef struct ktxIndexEntry32 { + uint32_t byteOffset; /*!< Offset of item from start of file. */ + uint32_t byteLength; /*!< Number of bytes of data in the item. */ +} ktxIndexEntry32; +/** + * @internal + * @~English + * @brief 64-bit KTX 2 index entry. + */ +typedef struct ktxIndexEntry64 { + uint64_t byteOffset; /*!< Offset of item from start of file. */ + uint64_t byteLength; /*!< Number of bytes of data in the item. */ +} ktxIndexEntry64; + +/** + * @internal + * @~English + * @brief KTX 2 file header. + * + * See the KTX 2 specification for descriptions. + */ +typedef struct KTX_header2 { + uint8_t identifier[12]; + uint32_t vkFormat; + uint32_t typeSize; + uint32_t pixelWidth; + uint32_t pixelHeight; + uint32_t pixelDepth; + uint32_t layerCount; + uint32_t faceCount; + uint32_t levelCount; + uint32_t supercompressionScheme; + ktxIndexEntry32 dataFormatDescriptor; + ktxIndexEntry32 keyValueData; + ktxIndexEntry64 supercompressionGlobalData; +} KTX_header2; + +/* This will cause compilation to fail if the struct size doesn't match */ +typedef int KTX_header2_SIZE_ASSERT [sizeof(KTX_header2) == KTX2_HEADER_SIZE]; + +/** + * @internal + * @~English + * @brief KTX 2 level index entry. + */ +typedef struct ktxLevelIndexEntry { + uint64_t byteOffset; /*!< Offset of level from start of file. */ + uint64_t byteLength; + /*!< Number of bytes of compressed image data in the level. */ + uint64_t uncompressedByteLength; + /*!< Number of bytes of uncompressed image data in the level. */ +} ktxLevelIndexEntry; + +typedef struct ktxBasisGlobalHeader { + uint32_t globalFlags; + uint16_t endpointCount; + uint16_t selectorCount; + uint32_t endpointsByteLength; + uint32_t selectorsByteLength; + uint32_t tablesByteLength; + uint32_t extendedByteLength; +} ktxBasisGlobalHeader; + +// This header is followed by imageCount "slice" descriptions. + +// 1, or 2 slices per image (i.e. layer, face & slice). +// These offsets are relative to start of a mip level as given by the +// main levelIndex. +typedef struct ktxBasisSliceDesc { + uint32_t sliceFlags; + uint32_t sliceByteOffset; + uint32_t sliceByteLength; + uint32_t alphaSliceByteOffset; + uint32_t alphaSliceByteLength; +} ktxBasisSliceDesc; \ No newline at end of file