mirror of
https://github.com/overte-org/overte.git
synced 2025-04-14 20:26:55 +02:00
Address review comments
This commit is contained in:
parent
7d9ad838c7
commit
2f7181fb32
6 changed files with 156 additions and 66 deletions
|
@ -1002,27 +1002,3 @@ Texture::ExternalUpdates Texture::getUpdates() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <ktx/KTX.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
42
libraries/gpu/src/gpu/Texture_ktx.cpp
Normal file
42
libraries/gpu/src/gpu/Texture_ktx.cpp
Normal file
|
@ -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 <ktx/KTX.h>
|
||||||
|
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;
|
||||||
|
}
|
|
@ -427,7 +427,22 @@ namespace ktx {
|
||||||
// Define a KTX object manually to write it somewhere (in a file on disk?)
|
// 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
|
// This path allocate the Storage where to store header, keyvalues and copy mips
|
||||||
// Then COPY all the data
|
// Then COPY all the data
|
||||||
static std::unique_ptr<KTX> create(const Header& header, const KeyValues& keyValues, const Images& images);
|
static std::unique_ptr<KTX> 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
|
// Parse a block of memory and create a KTX object from it
|
||||||
static std::unique_ptr<KTX> create(const Storage& src);
|
static std::unique_ptr<KTX> create(const Storage& src);
|
||||||
|
|
|
@ -16,12 +16,12 @@
|
||||||
namespace ktx {
|
namespace ktx {
|
||||||
class ReaderException: public std::exception {
|
class ReaderException: public std::exception {
|
||||||
public:
|
public:
|
||||||
ReaderException(std::string explanation) : _explanation(explanation) {}
|
ReaderException(const std::string& explanation) : _explanation("KTX deserialization error: " + explanation) {}
|
||||||
const char* what() const override {
|
const char* what() const override {
|
||||||
return ("KTX deserialization error: " + _explanation).c_str();
|
return _explanation.c_str();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
std::string _explanation;
|
const std::string _explanation;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool checkEndianness(uint32_t endianness, bool& matching) {
|
bool checkEndianness(uint32_t endianness, bool& matching) {
|
||||||
|
|
|
@ -15,30 +15,14 @@ namespace ktx {
|
||||||
|
|
||||||
class WriterException : public std::exception {
|
class WriterException : public std::exception {
|
||||||
public:
|
public:
|
||||||
WriterException(std::string explanation) : _explanation(explanation) {}
|
WriterException(const std::string& explanation) : _explanation("KTX serialization error: " + explanation) {}
|
||||||
const char* what() const override {
|
const char* what() const override {
|
||||||
return ("KTX serialization error: " + _explanation).c_str();
|
return _explanation.c_str();
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
std::string _explanation;
|
const std::string _explanation;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<Storage> 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> storage(new Storage(storageSize));
|
|
||||||
return storage;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void KTX::resetHeader(const Header& header) {
|
void KTX::resetHeader(const Header& header) {
|
||||||
if (!_storage) {
|
if (!_storage) {
|
||||||
|
@ -52,10 +36,84 @@ namespace ktx {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto allocatedImagesDataSize = getTexelsDataSize();
|
auto allocatedImagesDataSize = getTexelsDataSize();
|
||||||
|
|
||||||
|
// Just copy in our storage
|
||||||
|
_images = writeImages(imagesDataPtr, allocatedImagesDataSize, srcImages);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<KTX> KTX::create(const Header& header, const Images& images, const KeyValues& keyValues) {
|
||||||
|
auto storageSize = evalStorageSize(header, images, keyValues);
|
||||||
|
|
||||||
|
std::unique_ptr<KTX> 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<Header*>(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;
|
size_t currentDataSize = 0;
|
||||||
auto currentPtr = imagesDataPtr;
|
auto currentPtr = imagesDataPtr;
|
||||||
|
|
||||||
_images.clear();
|
|
||||||
|
|
||||||
|
|
||||||
for (uint32_t l = 0; l < srcImages.size(); l++) {
|
for (uint32_t l = 0; l < srcImages.size(); l++) {
|
||||||
|
@ -72,29 +130,15 @@ namespace ktx {
|
||||||
|
|
||||||
auto padding = Header::evalPadding(imageSize);
|
auto padding = Header::evalPadding(imageSize);
|
||||||
|
|
||||||
_images.emplace_back(Image(imageSize, padding, currentPtr));
|
destImages.emplace_back(Image(imageSize, padding, currentPtr));
|
||||||
|
|
||||||
currentPtr += imageSize + padding;
|
currentPtr += imageSize + padding;
|
||||||
currentDataSize += imageSize + padding;
|
currentDataSize += imageSize + padding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return destImages;
|
||||||
std::unique_ptr<KTX> KTX::create(const Header& header, const KeyValues& keyValues, const Images& images) {
|
|
||||||
|
|
||||||
std::unique_ptr<KTX> 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,9 @@
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
#include <Profile.h>
|
#include <Profile.h>
|
||||||
|
|
||||||
|
@ -269,7 +272,17 @@ gpu::Texture* TextureUsage::process2DTextureColorFromImage(const QImage& srcImag
|
||||||
auto theKTX = Texture::serialize(*theTexture);
|
auto theKTX = Texture::serialize(*theTexture);
|
||||||
if (theKTX) {
|
if (theKTX) {
|
||||||
// save that!
|
// 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 += std::to_string((size_t) theTexture);
|
||||||
filename += ".ktx";
|
filename += ".ktx";
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue