Starting to work on the writer side

This commit is contained in:
samcake 2017-02-15 17:04:40 -08:00 committed by Brad Davis
parent 894f1b8e66
commit cf9fc17c4d
4 changed files with 84 additions and 37 deletions

View file

@ -15,6 +15,11 @@
using namespace ktx; 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 {{ const Header::Identifier ktx::Header::IDENTIFIER {{
0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A 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 pixelWidth = evalPixelWidth(level);
auto pixSize = evalPixelSize(); auto pixSize = evalPixelSize();
auto netSize = pixelWidth * pixSize; auto netSize = pixelWidth * pixSize;
auto packing = netSize % PACKING_SIZE; auto padding = evalPadding(netSize);
return netSize + (packing ? PACKING_SIZE - packing : 0); return netSize + padding;
} }
size_t Header::evalFaceSize(uint32_t level) const { size_t Header::evalFaceSize(uint32_t level) const {
auto pixelHeight = evalPixelHeight(level); auto pixelHeight = evalPixelHeight(level);
@ -115,3 +120,4 @@ const Byte* KTX::getTexelsData() const {
return nullptr; return nullptr;
} }
} }

View file

@ -67,6 +67,8 @@ end
namespace ktx { namespace ktx {
const uint32_t PACKING_SIZE { sizeof(uint32_t) }; const uint32_t PACKING_SIZE { sizeof(uint32_t) };
using Byte = uint8_t;
uint32_t evalPadding(size_t byteSize);
enum GLType : uint32_t { enum GLType : uint32_t {
COMPRESSED_TYPE = 0, COMPRESSED_TYPE = 0,
@ -289,7 +291,6 @@ namespace ktx {
NUM_CUBEMAPFACES = 6, NUM_CUBEMAPFACES = 6,
}; };
using Byte = uint8_t;
// Chunk of data // Chunk of data
struct Storage { struct Storage {
@ -375,31 +376,37 @@ namespace ktx {
using KeyValues = std::list<KeyValue>; using KeyValues = std::list<KeyValue>;
struct Mip { struct Image {
uint32_t _imageSize; uint32_t _imageSize;
uint32_t _padding; uint32_t _padding;
const Byte* _bytes; 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), _imageSize(imageSize),
_padding(padding), _padding(padding),
_bytes(bytes) {} _bytes(bytes) {}
}; };
using Mips = std::vector<Mip>; using Images = std::vector<Image>;
class KTX { class KTX {
void resetStorage(Storage* src); void resetStorage(Storage* src);
KTX();
public: public:
KTX();
~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<KTX> 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<KTX> create(const Storage& src); static std::unique_ptr<KTX> create(const Storage& src);
static std::unique_ptr<KTX> create(std::unique_ptr<Storage>& src); static std::unique_ptr<KTX> create(std::unique_ptr<Storage>& src);
static bool checkStorageHeader(const Storage& storage); static bool checkHeaderFromStorage(const Storage& storage);
// Access raw pointers to the main sections of the KTX // Access raw pointers to the main sections of the KTX
const Header* getHeader() const; const Header* getHeader() const;
@ -412,7 +419,7 @@ namespace ktx {
std::unique_ptr<Storage> _storage; std::unique_ptr<Storage> _storage;
KeyValues _keyValues; KeyValues _keyValues;
Mips _mips; Images _images;
}; };
} }

View file

@ -14,9 +14,9 @@
#include <QtGlobal> #include <QtGlobal>
namespace ktx { namespace ktx {
class Exception: public std::exception { class ReaderException: public std::exception {
public: public:
Exception(std::string explanation) : _explanation(explanation) {} ReaderException(std::string explanation) : _explanation(explanation) {}
const char* what() const override { const char* what() const override {
return ("KTX deserialization error: " + _explanation).c_str(); return ("KTX deserialization error: " + _explanation).c_str();
} }
@ -55,7 +55,7 @@ namespace ktx {
uint32_t keyValueByteSize; uint32_t keyValueByteSize;
memcpy(&keyValueByteSize, src, sizeof(uint32_t)); memcpy(&keyValueByteSize, src, sizeof(uint32_t));
if (keyValueByteSize > length - offset) { if (keyValueByteSize > length - offset) {
throw Exception("invalid key-value size"); throw ReaderException("invalid key-value size");
} }
// find the first null character \0 // find the first null character \0
@ -63,7 +63,7 @@ namespace ktx {
while (reinterpret_cast<const char*>(src[++keyLength]) != '\0') { while (reinterpret_cast<const char*>(src[++keyLength]) != '\0') {
if (keyLength == keyValueByteSize) { if (keyLength == keyValueByteSize) {
// key must be null-terminated, and there must be space for the value // key must be null-terminated, and there must be space for the value
throw Exception("invalid key-value " + std::string(reinterpret_cast<const char*>(src), keyLength)); throw ReaderException("invalid key-value " + std::string(reinterpret_cast<const char*>(src), keyLength));
} }
} }
@ -81,8 +81,8 @@ namespace ktx {
return keyValues; return keyValues;
} }
Mips getMipsTable(const Header& header, size_t mipsDataSize, const Byte* mipsData) { Images getImagesTable(const Header& header, size_t mipsDataSize, const Byte* mipsData) {
Mips mips; Images images;
auto currentPtr = mipsData; auto currentPtr = mipsData;
auto numMips = header.numberOfMipmapLevels + 1; auto numMips = header.numberOfMipmapLevels + 1;
@ -95,10 +95,9 @@ namespace ktx {
// If enough data ahead then capture the pointer // If enough data ahead then capture the pointer
if ((currentPtr - mipsData) + imageSize <= (mipsDataSize)) { if ((currentPtr - mipsData) + imageSize <= (mipsDataSize)) {
auto padding = imageSize % PACKING_SIZE; auto padding = evalPadding(imageSize);
padding = (padding ? 4 - padding : 0);
mips.emplace_back(Mip(imageSize, padding, currentPtr)); images.emplace_back(Image(imageSize, padding, currentPtr));
currentPtr += imageSize + padding; currentPtr += imageSize + padding;
} else { } else {
@ -106,28 +105,28 @@ namespace ktx {
} }
} }
return mips; return images;
} }
bool KTX::checkStorageHeader(const Storage& src) { bool KTX::checkHeaderFromStorage(const Storage& src) {
try { try {
auto srcSize = src.size(); auto srcSize = src.size();
auto srcBytes = src.data(); auto srcBytes = src.data();
// validation // validation
if (srcSize < sizeof(Header)) { 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<const Header*>(srcBytes); const Header* header = reinterpret_cast<const Header*>(srcBytes);
if (!checkIdentifier(header->identifier)) { if (!checkIdentifier(header->identifier)) {
throw Exception("identifier field invalid"); throw ReaderException("identifier field invalid");
} }
bool endianMatch { true }; bool endianMatch { true };
if (!checkEndianness(header->endianness, endianMatch)) { 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 // TODO: endian conversion if !endianMatch - for now, this is for local use and is unnecessary
@ -135,17 +134,18 @@ namespace ktx {
// TODO: calculated bytesOfTexData // TODO: calculated bytesOfTexData
if (srcSize < (sizeof(Header) + header->bytesOfKeyValueData)) { 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; size_t bytesOfTexData = 0;
if (srcSize < (sizeof(Header) + header->bytesOfKeyValueData + bytesOfTexData)) { 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; return true;
} catch (Exception& e) { }
catch (ReaderException& e) {
qWarning(e.what()); qWarning(e.what());
return false; return false;
} }
@ -163,7 +163,7 @@ namespace ktx {
} }
try { try {
if (!checkStorageHeader(*src)) { if (!checkHeaderFromStorage(*src)) {
} }
@ -173,12 +173,12 @@ namespace ktx {
// read metadata // read metadata
result->_keyValues = getKeyValues(result->getHeader()->bytesOfKeyValueData, result->getKeyValueData()); result->_keyValues = getKeyValues(result->getHeader()->bytesOfKeyValueData, result->getKeyValueData());
// populate mip table // populate image table
result->_mips = getMipsTable(*result->getHeader(), result->getTexelsDataSize(), result->getTexelsData()); result->_images = getImagesTable(*result->getHeader(), result->getTexelsDataSize(), result->getTexelsData());
return result; return result;
} }
catch (Exception& e) { catch (ReaderException& e) {
qWarning(e.what()); qWarning(e.what());
return nullptr; return nullptr;
} }

View file

@ -12,10 +12,44 @@
namespace ktx { namespace ktx {
/* size_t serialize(const gpu::Texture& texture, uint8_t* data) {
return 0; class WriterException : public std::exception {
}*/ public:
/* KTX serialize(const gpu::Texture& texture) { WriterException(std::string explanation) : _explanation(explanation) {}
return KTX(0, nullptr); const char* what() const override {
}*/ return ("KTX serialization error: " + _explanation).c_str();
}
private:
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.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> 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());
// read metadata
result->_keyValues = keyValues;
// populate image table
result->_images = images;
return result;
}
} }