diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 80d636eec2..d7ae202e7d 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -1002,27 +1002,3 @@ Texture::ExternalUpdates Texture::getUpdates() const { return result; } -#include - -ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { - - ktx::Header header; - header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 4, ktx::GLFormat::BGRA, ktx::GLInternalFormat_Uncompressed::RGBA8, ktx::GLBaseInternalFormat::RGBA); - header.pixelWidth = texture.getWidth(); - header.pixelHeight = texture.getHeight(); - header.numberOfMipmapLevels = texture.mipLevels(); - - ktx::Images images; - for (int level = 0; level < header.numberOfMipmapLevels; level++) { - auto mip = texture.accessStoredMipFace(level); - if (mip) { - images.emplace_back(ktx::Image(mip->getSize(), 0, mip->readData())); - } - } - - auto ktxBuffer = ktx::KTX::create(header, ktx::KeyValues(), images); - return ktxBuffer; -} -TexturePointer Texture::unserialize(const ktx::KTXUniquePointer& srcData) { - return nullptr; -} \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Texture_ktx.cpp b/libraries/gpu/src/gpu/Texture_ktx.cpp new file mode 100644 index 0000000000..d06454b933 --- /dev/null +++ b/libraries/gpu/src/gpu/Texture_ktx.cpp @@ -0,0 +1,42 @@ +// +// Texture_ktx.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 2/16/2017. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + + +#include "Texture.h" + +#include +using namespace gpu; + +ktx::KTXUniquePointer Texture::serialize(const Texture& texture) { + + ktx::Header header; + header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 4, ktx::GLFormat::BGRA, ktx::GLInternalFormat_Uncompressed::RGBA8, ktx::GLBaseInternalFormat::RGBA); + header.pixelWidth = texture.getWidth(); + header.pixelHeight = texture.getHeight(); + header.numberOfMipmapLevels = texture.mipLevels(); + + ktx::Images images; + for (int level = 0; level < header.numberOfMipmapLevels; level++) { + auto mip = texture.accessStoredMipFace(level); + if (mip) { + images.emplace_back(ktx::Image(mip->getSize(), 0, mip->readData())); + } + } + + auto ktxBuffer = ktx::KTX::create(header, images); + return ktxBuffer; +} +TexturePointer Texture::unserialize(const ktx::KTXUniquePointer& srcData) { + + const auto& header = *srcData->getHeader(); + + return nullptr; +} \ No newline at end of file diff --git a/libraries/ktx/src/ktx/KTX.h b/libraries/ktx/src/ktx/KTX.h index 1006124693..41032c8222 100644 --- a/libraries/ktx/src/ktx/KTX.h +++ b/libraries/ktx/src/ktx/KTX.h @@ -427,7 +427,22 @@ namespace ktx { // 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); + static std::unique_ptr create(const Header& header, const Images& images, const KeyValues& keyValues = KeyValues()); + + // Instead of creating a full Copy of the src data in a KTX object, the write serialization can be performed with the + // following two functions + // size_t sizeNeeded = KTX::evalStorageSize(header, images); + // + // //allocate a buffer of size "sizeNeeded" or map a file with enough capacity + // Byte* destBytes = new Byte[sizeNeeded]; + // + // // THen perform the writing of the src data to the destinnation buffer + // write(destBytes, sizeNeeded, header, images); + // + // This is exactly what is done in the create function + static size_t evalStorageSize(const Header& header, const Images& images, const KeyValues& keyValues = KeyValues()); + static size_t write(Byte* destBytes, size_t destByteSize, const Header& header, const Images& images, const KeyValues& keyValues = KeyValues()); + static Images writeImages(Byte* destBytes, size_t destByteSize, const Images& images); // Parse a block of memory and create a KTX object from it static std::unique_ptr create(const Storage& src); diff --git a/libraries/ktx/src/ktx/Reader.cpp b/libraries/ktx/src/ktx/Reader.cpp index 9586a9c033..4099aa6ef8 100644 --- a/libraries/ktx/src/ktx/Reader.cpp +++ b/libraries/ktx/src/ktx/Reader.cpp @@ -16,12 +16,12 @@ namespace ktx { class ReaderException: public std::exception { public: - ReaderException(std::string explanation) : _explanation(explanation) {} + ReaderException(const std::string& explanation) : _explanation("KTX deserialization error: " + explanation) {} const char* what() const override { - return ("KTX deserialization error: " + _explanation).c_str(); + return _explanation.c_str(); } private: - std::string _explanation; + const std::string _explanation; }; bool checkEndianness(uint32_t endianness, bool& matching) { diff --git a/libraries/ktx/src/ktx/Writer.cpp b/libraries/ktx/src/ktx/Writer.cpp index ae2dfc2d6d..75836ad5b5 100644 --- a/libraries/ktx/src/ktx/Writer.cpp +++ b/libraries/ktx/src/ktx/Writer.cpp @@ -15,30 +15,14 @@ namespace ktx { class WriterException : public std::exception { public: - WriterException(std::string explanation) : _explanation(explanation) {} + WriterException(const std::string& explanation) : _explanation("KTX serialization error: " + explanation) {} const char* what() const override { - return ("KTX serialization error: " + _explanation).c_str(); + return _explanation.c_str(); } private: - std::string _explanation; + const std::string _explanation; }; - std::unique_ptr generateStorage(const Header& header, const KeyValues& keyValues, const Images& images) { - size_t storageSize = sizeof(Header); - auto numMips = header.getNumberOfLevels(); - - for (uint32_t l = 0; l < numMips; l++) { - if (images.size() > l) { - storageSize += sizeof(uint32_t); - storageSize += images[l]._imageSize; - storageSize += Header::evalPadding(images[l]._imageSize); - } - } - - std::unique_ptr storage(new Storage(storageSize)); - return storage; - } - void KTX::resetHeader(const Header& header) { if (!_storage) { @@ -52,10 +36,84 @@ namespace ktx { return; } auto allocatedImagesDataSize = getTexelsDataSize(); + + // Just copy in our storage + _images = writeImages(imagesDataPtr, allocatedImagesDataSize, srcImages); + } + + std::unique_ptr KTX::create(const Header& header, const Images& images, const KeyValues& keyValues) { + auto storageSize = evalStorageSize(header, images, keyValues); + + std::unique_ptr result(new KTX()); + + result->resetStorage(new Storage(storageSize)); + + result->resetHeader(header); + + // read metadata + result->_keyValues = keyValues; + + // populate image table + result->resetImages(images); + + return result; + } + + size_t KTX::evalStorageSize(const Header& header, const Images& images, const KeyValues& keyValues) { + size_t storageSize = sizeof(Header); + + if (header.bytesOfKeyValueData && !keyValues.empty()) { + + } + + auto numMips = header.getNumberOfLevels(); + for (uint32_t l = 0; l < numMips; l++) { + if (images.size() > l) { + storageSize += sizeof(uint32_t); + storageSize += images[l]._imageSize; + storageSize += Header::evalPadding(images[l]._imageSize); + } + } + return storageSize; + } + + size_t KTX::write(Byte* destBytes, size_t destByteSize, const Header& header, const Images& srcImages, const KeyValues& keyValues) { + // Check again that we have enough destination capacity + if (!destBytes || (destByteSize < evalStorageSize(header, srcImages, keyValues))) { + return 0; + } + + auto currentDestPtr = destBytes; + // Header + auto destHeader = reinterpret_cast(currentDestPtr); + memcpy(currentDestPtr, &header, sizeof(Header)); + currentDestPtr += sizeof(Header); + + // KeyValues + // Skip for now + if (header.bytesOfKeyValueData && !keyValues.empty()) { + + } + destHeader->bytesOfKeyValueData = 0; + currentDestPtr += destHeader->bytesOfKeyValueData; + + // Images + auto destImages = writeImages(currentDestPtr, destByteSize - sizeof(Header) - destHeader->bytesOfKeyValueData, srcImages); + // We chould check here that the amoutn of dest IMages generated is the same as the source + + return destByteSize; + } + + Images KTX::writeImages(Byte* destBytes, size_t destByteSize, const Images& srcImages) { + Images destImages; + auto imagesDataPtr = destBytes; + if (!imagesDataPtr) { + return destImages; + } + auto allocatedImagesDataSize = destByteSize; size_t currentDataSize = 0; auto currentPtr = imagesDataPtr; - _images.clear(); for (uint32_t l = 0; l < srcImages.size(); l++) { @@ -72,29 +130,15 @@ namespace ktx { auto padding = Header::evalPadding(imageSize); - _images.emplace_back(Image(imageSize, padding, currentPtr)); + destImages.emplace_back(Image(imageSize, padding, currentPtr)); currentPtr += imageSize + padding; currentDataSize += imageSize + padding; } } } - } - - 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()); - - result->resetHeader(header); - - // read metadata - result->_keyValues = keyValues; - - // populate image table - result->resetImages(images); - - return result; + + return destImages; } } diff --git a/libraries/model/src/model/TextureMap.cpp b/libraries/model/src/model/TextureMap.cpp index 42f908c754..37c35ef250 100755 --- a/libraries/model/src/model/TextureMap.cpp +++ b/libraries/model/src/model/TextureMap.cpp @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include #include @@ -269,7 +272,17 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag auto theKTX = Texture::serialize(*theTexture); if (theKTX) { // save that! - std::string filename("C://temp//ktxCache//texmex"); + QString path("hifi_ktx/"); + QFileInfo originalFileInfo(path); + QString docsLocation = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); + path = docsLocation + "/" + path; + QFileInfo info(path); + if (!info.absoluteDir().exists()) { + QString originalRelativePath = originalFileInfo.path(); + QDir(docsLocation).mkpath(originalRelativePath); + } + + std::string filename(path.toStdString()); filename += std::to_string((size_t) theTexture); filename += ".ktx";