From cf9fc17c4d640041a16a42296e72ea11a3f472bd Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 15 Feb 2017 17:04:40 -0800 Subject: [PATCH] Starting to work on the writer side --- libraries/ktx/src/ktx/KTX.cpp | 10 +++++-- libraries/ktx/src/ktx/KTX.h | 23 ++++++++++------ libraries/ktx/src/ktx/Reader.cpp | 42 ++++++++++++++--------------- libraries/ktx/src/ktx/Writer.cpp | 46 +++++++++++++++++++++++++++----- 4 files changed, 84 insertions(+), 37 deletions(-) diff --git a/libraries/ktx/src/ktx/KTX.cpp b/libraries/ktx/src/ktx/KTX.cpp index 4ce4c94c69..d2872e76b5 100644 --- a/libraries/ktx/src/ktx/KTX.cpp +++ b/libraries/ktx/src/ktx/KTX.cpp @@ -15,6 +15,11 @@ using namespace ktx; +uint32_t evalPadding(size_t byteSize) { + auto padding = byteSize % PACKING_SIZE; + return (padding ? PACKING_SIZE - padding : 0); +} + const Header::Identifier ktx::Header::IDENTIFIER {{ 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }}; @@ -49,8 +54,8 @@ size_t Header::evalRowSize(uint32_t level) const { auto pixelWidth = evalPixelWidth(level); auto pixSize = evalPixelSize(); auto netSize = pixelWidth * pixSize; - auto packing = netSize % PACKING_SIZE; - return netSize + (packing ? PACKING_SIZE - packing : 0); + auto padding = evalPadding(netSize); + return netSize + padding; } size_t Header::evalFaceSize(uint32_t level) const { auto pixelHeight = evalPixelHeight(level); @@ -115,3 +120,4 @@ const Byte* KTX::getTexelsData() const { return nullptr; } } + diff --git a/libraries/ktx/src/ktx/KTX.h b/libraries/ktx/src/ktx/KTX.h index b6a9240972..5b72c4c1ce 100644 --- a/libraries/ktx/src/ktx/KTX.h +++ b/libraries/ktx/src/ktx/KTX.h @@ -67,6 +67,8 @@ end namespace ktx { const uint32_t PACKING_SIZE { sizeof(uint32_t) }; + using Byte = uint8_t; + uint32_t evalPadding(size_t byteSize); enum GLType : uint32_t { COMPRESSED_TYPE = 0, @@ -289,7 +291,6 @@ namespace ktx { NUM_CUBEMAPFACES = 6, }; - using Byte = uint8_t; // Chunk of data struct Storage { @@ -375,31 +376,37 @@ namespace ktx { using KeyValues = std::list; - struct Mip { + struct Image { uint32_t _imageSize; uint32_t _padding; const Byte* _bytes; - Mip(uint32_t imageSize, uint32_t padding, const Byte* bytes) : + Image(uint32_t imageSize, uint32_t padding, const Byte* bytes) : _imageSize(imageSize), _padding(padding), _bytes(bytes) {} }; - using Mips = std::vector; + using Images = std::vector; + class KTX { void resetStorage(Storage* src); + KTX(); public: - KTX(); ~KTX(); - // parse a block of memory and create a KTX object from it + // Define a KTX object manually to write it somewhere (in a file on disk?) + // This path allocate the Storage where to store header, keyvalues and copy mips + // Then COPY all the data + static std::unique_ptr create(const Header& header, const KeyValues& keyValues, const Images& images); + + // Parse a block of memory and create a KTX object from it static std::unique_ptr create(const Storage& src); static std::unique_ptr create(std::unique_ptr& src); - static bool checkStorageHeader(const Storage& storage); + static bool checkHeaderFromStorage(const Storage& storage); // Access raw pointers to the main sections of the KTX const Header* getHeader() const; @@ -412,7 +419,7 @@ namespace ktx { std::unique_ptr _storage; KeyValues _keyValues; - Mips _mips; + Images _images; }; } diff --git a/libraries/ktx/src/ktx/Reader.cpp b/libraries/ktx/src/ktx/Reader.cpp index ff682d5bdb..2b45d30786 100644 --- a/libraries/ktx/src/ktx/Reader.cpp +++ b/libraries/ktx/src/ktx/Reader.cpp @@ -14,9 +14,9 @@ #include namespace ktx { - class Exception: public std::exception { + class ReaderException: public std::exception { public: - Exception(std::string explanation) : _explanation(explanation) {} + ReaderException(std::string explanation) : _explanation(explanation) {} const char* what() const override { return ("KTX deserialization error: " + _explanation).c_str(); } @@ -55,7 +55,7 @@ namespace ktx { uint32_t keyValueByteSize; memcpy(&keyValueByteSize, src, sizeof(uint32_t)); if (keyValueByteSize > length - offset) { - throw Exception("invalid key-value size"); + throw ReaderException("invalid key-value size"); } // find the first null character \0 @@ -63,7 +63,7 @@ namespace ktx { while (reinterpret_cast(src[++keyLength]) != '\0') { if (keyLength == keyValueByteSize) { // key must be null-terminated, and there must be space for the value - throw Exception("invalid key-value " + std::string(reinterpret_cast(src), keyLength)); + throw ReaderException("invalid key-value " + std::string(reinterpret_cast(src), keyLength)); } } @@ -81,8 +81,8 @@ namespace ktx { return keyValues; } - Mips getMipsTable(const Header& header, size_t mipsDataSize, const Byte* mipsData) { - Mips mips; + Images getImagesTable(const Header& header, size_t mipsDataSize, const Byte* mipsData) { + Images images; auto currentPtr = mipsData; auto numMips = header.numberOfMipmapLevels + 1; @@ -95,10 +95,9 @@ namespace ktx { // If enough data ahead then capture the pointer if ((currentPtr - mipsData) + imageSize <= (mipsDataSize)) { - auto padding = imageSize % PACKING_SIZE; - padding = (padding ? 4 - padding : 0); + auto padding = evalPadding(imageSize); - mips.emplace_back(Mip(imageSize, padding, currentPtr)); + images.emplace_back(Image(imageSize, padding, currentPtr)); currentPtr += imageSize + padding; } else { @@ -106,28 +105,28 @@ namespace ktx { } } - return mips; + return images; } - bool KTX::checkStorageHeader(const Storage& src) { + bool KTX::checkHeaderFromStorage(const Storage& src) { try { auto srcSize = src.size(); auto srcBytes = src.data(); // validation if (srcSize < sizeof(Header)) { - throw Exception("length is too short for header"); + throw ReaderException("length is too short for header"); } const Header* header = reinterpret_cast(srcBytes); if (!checkIdentifier(header->identifier)) { - throw Exception("identifier field invalid"); + throw ReaderException("identifier field invalid"); } bool endianMatch { true }; if (!checkEndianness(header->endianness, endianMatch)) { - throw Exception("endianness field has invalid value"); + throw ReaderException("endianness field has invalid value"); } // TODO: endian conversion if !endianMatch - for now, this is for local use and is unnecessary @@ -135,17 +134,18 @@ namespace ktx { // TODO: calculated bytesOfTexData if (srcSize < (sizeof(Header) + header->bytesOfKeyValueData)) { - throw Exception("length is too short for metadata"); + throw ReaderException("length is too short for metadata"); } size_t bytesOfTexData = 0; if (srcSize < (sizeof(Header) + header->bytesOfKeyValueData + bytesOfTexData)) { - throw Exception("length is too short for data"); + throw ReaderException("length is too short for data"); } return true; - } catch (Exception& e) { + } + catch (ReaderException& e) { qWarning(e.what()); return false; } @@ -163,7 +163,7 @@ namespace ktx { } try { - if (!checkStorageHeader(*src)) { + if (!checkHeaderFromStorage(*src)) { } @@ -173,12 +173,12 @@ namespace ktx { // read metadata result->_keyValues = getKeyValues(result->getHeader()->bytesOfKeyValueData, result->getKeyValueData()); - // populate mip table - result->_mips = getMipsTable(*result->getHeader(), result->getTexelsDataSize(), result->getTexelsData()); + // populate image table + result->_images = getImagesTable(*result->getHeader(), result->getTexelsDataSize(), result->getTexelsData()); return result; } - catch (Exception& e) { + catch (ReaderException& e) { qWarning(e.what()); return nullptr; } diff --git a/libraries/ktx/src/ktx/Writer.cpp b/libraries/ktx/src/ktx/Writer.cpp index d502a4a29a..a2b3d55178 100644 --- a/libraries/ktx/src/ktx/Writer.cpp +++ b/libraries/ktx/src/ktx/Writer.cpp @@ -12,10 +12,44 @@ namespace ktx { - /* size_t serialize(const gpu::Texture& texture, uint8_t* data) { - return 0; - }*/ - /* KTX serialize(const gpu::Texture& texture) { - return KTX(0, nullptr); - }*/ + + class WriterException : public std::exception { + public: + WriterException(std::string explanation) : _explanation(explanation) {} + const char* what() const override { + return ("KTX serialization error: " + _explanation).c_str(); + } + private: + std::string _explanation; + }; + + std::unique_ptr generateStorage(const Header& header, const KeyValues& keyValues, const Images& images) { + size_t storageSize = sizeof(Header); + auto numMips = header.numberOfMipmapLevels + 1; + + for (uint32_t l = 0; l < numMips; l++) { + if (images.size() > l) { + + storageSize += images[l]._imageSize; + storageSize += images[l]._imageSize; + } + + } + + } + + std::unique_ptr KTX::create(const Header& header, const KeyValues& keyValues, const Images& images) { + + std::unique_ptr result(new KTX()); + result->resetStorage(generateStorage(header, keyValues, images).release()); + + // read metadata + result->_keyValues = keyValues; + + // populate image table + result->_images = images; + + return result; + } + }