diff --git a/libraries/ktx/src/ktx/KTX.cpp b/libraries/ktx/src/ktx/KTX.cpp index 2d5e0bc812..4ce4c94c69 100644 --- a/libraries/ktx/src/ktx/KTX.cpp +++ b/libraries/ktx/src/ktx/KTX.cpp @@ -49,8 +49,8 @@ size_t Header::evalRowSize(uint32_t level) const { auto pixelWidth = evalPixelWidth(level); auto pixSize = evalPixelSize(); auto netSize = pixelWidth * pixSize; - auto packing = netSize % 4; - return netSize + (packing ? 4 - packing : 0); + auto packing = netSize % PACKING_SIZE; + return netSize + (packing ? PACKING_SIZE - packing : 0); } size_t Header::evalFaceSize(uint32_t level) const { auto pixelHeight = evalPixelHeight(level); @@ -83,6 +83,23 @@ const Header* KTX::getHeader() const { } } + +size_t KTX::getKeyValueDataSize() const { + if (_storage) { + return getHeader()->bytesOfKeyValueData; + } else { + return 0; + } +} + +size_t KTX::getTexelsDataSize() const { + if (_storage) { + return _storage->size() - sizeof(Header) + getKeyValueDataSize(); + } else { + return 0; + } +} + const Byte* KTX::getKeyValueData() const { if (_storage) { return (_storage->_bytes + sizeof(Header)); @@ -90,3 +107,11 @@ const Byte* KTX::getKeyValueData() const { return nullptr; } } + +const Byte* KTX::getTexelsData() const { + if (_storage) { + return (_storage->_bytes + sizeof(Header) + getKeyValueDataSize()); + } else { + return nullptr; + } +} diff --git a/libraries/ktx/src/ktx/KTX.h b/libraries/ktx/src/ktx/KTX.h index 003d3f0d1b..b6a9240972 100644 --- a/libraries/ktx/src/ktx/KTX.h +++ b/libraries/ktx/src/ktx/KTX.h @@ -66,6 +66,7 @@ end namespace ktx { + const uint32_t PACKING_SIZE { sizeof(uint32_t) }; enum GLType : uint32_t { COMPRESSED_TYPE = 0, @@ -317,6 +318,17 @@ namespace ktx { { if (_size && _bytes) { _bytes = bytes; } } + Storage(size_t size, const Byte* bytes) : + Storage(size) + { + if (_size && _bytes && bytes) { + memcpy(_bytes, bytes, size); + } + } + Storage(const Storage& src) : + Storage(src.size(), src.data()) + {} + }; // Header @@ -364,8 +376,14 @@ namespace ktx { struct Mip { - uint32_t imageSize; + uint32_t _imageSize; + uint32_t _padding; const Byte* _bytes; + + Mip(uint32_t imageSize, uint32_t padding, const Byte* bytes) : + _imageSize(imageSize), + _padding(padding), + _bytes(bytes) {} }; using Mips = std::vector; @@ -375,21 +393,26 @@ namespace ktx { public: KTX(); + ~KTX(); - bool read(const Storage* src); - bool read(Storage* src); - - std::unique_ptr _storage; - - const Header* getHeader() const; - const Byte* getKeyValueData() const; - - KeyValues _keyValues; - - Mips _mips; + // 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 KTX* create(const Storage* src); + + // Access raw pointers to the main sections of the KTX + const Header* getHeader() const; + const Byte* getKeyValueData() const; + const Byte* getTexelsData() const; + + size_t getKeyValueDataSize() const; + size_t getTexelsDataSize() const; + + + std::unique_ptr _storage; + KeyValues _keyValues; + Mips _mips; }; } diff --git a/libraries/ktx/src/ktx/Reader.cpp b/libraries/ktx/src/ktx/Reader.cpp index 8ec4de7686..ff682d5bdb 100644 --- a/libraries/ktx/src/ktx/Reader.cpp +++ b/libraries/ktx/src/ktx/Reader.cpp @@ -73,7 +73,7 @@ namespace ktx { std::move(std::string(reinterpret_cast(src + keyLength), keyValueByteSize - keyLength))); // advance offset/src - uint32_t keyValuePadding = 3 - ((keyValueByteSize + 3) % 4); + uint32_t keyValuePadding = 3 - ((keyValueByteSize + 3) % PACKING_SIZE); offset += keyValueByteSize + keyValuePadding; src += keyValueByteSize + keyValuePadding; } @@ -81,16 +81,39 @@ namespace ktx { return keyValues; } - bool KTX::read(Storage* src) { - resetStorage(src); + Mips getMipsTable(const Header& header, size_t mipsDataSize, const Byte* mipsData) { + Mips mips; + auto currentPtr = mipsData; + auto numMips = header.numberOfMipmapLevels + 1; - return true; + // Keep identifying new mip as long as we can at list query the next imageSize + while ((currentPtr - mipsData) + sizeof(uint32_t) <= (mipsDataSize)) { + + // Grab the imageSize coming up + auto imageSize = *reinterpret_cast(currentPtr); + currentPtr += sizeof(uint32_t); + + // If enough data ahead then capture the pointer + if ((currentPtr - mipsData) + imageSize <= (mipsDataSize)) { + auto padding = imageSize % PACKING_SIZE; + padding = (padding ? 4 - padding : 0); + + mips.emplace_back(Mip(imageSize, padding, currentPtr)); + + currentPtr += imageSize + padding; + } else { + break; + } + } + + return mips; } + bool KTX::checkStorageHeader(const Storage& src) { try { - size_t srcSize = src.size(); - const uint8_t* srcBytes = src.data(); + auto srcSize = src.size(); + auto srcBytes = src.data(); // validation if (srcSize < sizeof(Header)) { @@ -121,16 +144,6 @@ namespace ktx { throw Exception("length is too short for data"); } - - // read metadata - KeyValues keyValues = getKeyValues(header->bytesOfKeyValueData, srcBytes + sizeof(Header)); - - // prepare gpu::Texture using header & key-values - // TODO - - // read data - // TODO - return true; } catch (Exception& e) { qWarning(e.what()); @@ -138,20 +151,34 @@ namespace ktx { } } - KTX* KTX::create(const Storage* data) { + std::unique_ptr KTX::create(const Storage& src) { + auto srcCopy = std::make_unique(src); + + return create(srcCopy); + } + + std::unique_ptr KTX::create(std::unique_ptr& src) { + if (!src) { + return nullptr; + } + try { - if (!checkStorageHeader(*data)) { - + if (!checkStorageHeader(*src)) { + } - auto result = new KTX(); - result->resetStorage(const_cast(data)); + std::unique_ptr result(new KTX()); + result->resetStorage(src.release()); // read metadata - KeyValues keyValues = getKeyValues(result->getHeader()->bytesOfKeyValueData, result->getKeyValueData()); + result->_keyValues = getKeyValues(result->getHeader()->bytesOfKeyValueData, result->getKeyValueData()); - return nullptr; - } catch (Exception& e) { + // populate mip table + result->_mips = getMipsTable(*result->getHeader(), result->getTexelsDataSize(), result->getTexelsData()); + + return result; + } + catch (Exception& e) { qWarning(e.what()); return nullptr; }