Starting to work on the writer side

This commit is contained in:
samcake 2017-02-15 17:04:40 -08:00
parent 4ac87c6851
commit 7343c2f90b
4 changed files with 84 additions and 37 deletions

View file

@ -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;
}
}

View file

@ -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<KeyValue>;
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<Mip>;
using Images = std::vector<Image>;
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<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(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
const Header* getHeader() const;
@ -412,7 +419,7 @@ namespace ktx {
std::unique_ptr<Storage> _storage;
KeyValues _keyValues;
Mips _mips;
Images _images;
};
}

View file

@ -14,9 +14,9 @@
#include <QtGlobal>
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<const char*>(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<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;
}
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<const Header*>(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;
}

View file

@ -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<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;
}
}