diff --git a/kraken/CMakeLists.txt b/kraken/CMakeLists.txt index 1f7f763..e294d90 100644 --- a/kraken/CMakeLists.txt +++ b/kraken/CMakeLists.txt @@ -92,6 +92,7 @@ add_sources(KRTexture2D.cpp) add_sources(KRTextureAnimated.cpp) add_sources(KRTextureCube.cpp) add_sources(KRTextureKTX.cpp) +add_sources(KRTextureKTX2.cpp) add_sources(KRTextureManager.cpp) add_sources(KRTexturePVR.cpp) add_sources(KRTextureTGA.cpp) diff --git a/kraken/KRContext.cpp b/kraken/KRContext.cpp index e5d6d1e..551dfd7 100755 --- a/kraken/KRContext.cpp +++ b/kraken/KRContext.cpp @@ -348,6 +348,8 @@ KRResource* KRContext::loadResource(const std::string& file_name, KRDataBlock* d resource = m_pTextureManager->loadTexture(name.c_str(), extension.c_str(), data); } else if (extension.compare("ktx") == 0) { resource = m_pTextureManager->loadTexture(name.c_str(), extension.c_str(), data); + } else if (extension.compare("ktx2") == 0) { + resource = m_pTextureManager->loadTexture(name.c_str(), extension.c_str(), data); } else if (extension.compare("tga") == 0) { resource = m_pTextureManager->loadTexture(name.c_str(), extension.c_str(), data); } else if (extension.compare("spv") == 0) { diff --git a/kraken/KRTextureKTX2.cpp b/kraken/KRTextureKTX2.cpp new file mode 100644 index 0000000..6b1507c --- /dev/null +++ b/kraken/KRTextureKTX2.cpp @@ -0,0 +1,180 @@ +// +// KRTextureKTX2.cpp +// Kraken Engine +// +// Copyright 2022 Kearwood Gilbert. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The views and conclusions contained in the software and documentation are those of the +// authors and should not be interpreted as representing official policies, either expressed +// or implied, of Kearwood Gilbert. +// + +#include "KRTextureKTX2.h" +#include "KRTextureManager.h" + +#include "KREngine-common.h" + +__uint8_t _KTX2FileIdentifier[12] = { + 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A +}; + +KRTextureKTX2::KRTextureKTX2(KRContext& context, KRDataBlock* data, std::string name) : KRTexture2D(context, data, name) +{ + m_pData->copy(&m_header, 0, sizeof(KTX2Header)); + if (memcmp(_KTX2FileIdentifier, m_header.identifier, 12) != 0) { + assert(false); // Header not recognized + } + if (m_header.pixelDepth != 0) { + assert(false); // 3d textures not (yet) supported + } + if (m_header.layerCount != 0) { + assert(false); // Array textures not (yet) supported + } + if (m_header.faceCount != 1 && m_header.faceCount != 6) { + assert(false); + } + if (m_header.supercompressionScheme != 0) { + assert(false); // Not yet supported + } + + uint32_t width = m_header.pixelWidth >> m_header.levelCount; + uint32_t height = m_header.pixelHeight >> m_header.levelCount; + if (width < 1) { + width = 1; + } + if (height < 1) { + height = 1; + } + m_max_lod_max_dim = KRMAX(m_header.pixelWidth, m_header.pixelHeight); + m_min_lod_max_dim = KRMAX(width, height); +} + +KRTextureKTX2::~KRTextureKTX2() +{ +} + +Vector2i KRTextureKTX2::getDimensions() const +{ + return Vector2i::Create(Vector2i::Create(m_header.pixelWidth, m_header.pixelHeight)); +} + +long KRTextureKTX2::getMemRequiredForSize(int max_dim) +{ + int target_dim = max_dim; + if (target_dim < (int)m_min_lod_max_dim) target_dim = target_dim; + + // Determine how much memory will be consumed + + int width = m_header.pixelWidth; + int height = m_header.pixelHeight; + long memoryRequired = 0; + + for (__uint32_t level = 0; level < m_header.levelCount; level++) { + KTX2LevelIndex levelIndex; + m_pData->copy(&levelIndex, sizeof(m_header) + sizeof(KTX2LevelIndex) * level, sizeof(KTX2LevelIndex)); + if (width <= target_dim && height <= target_dim) { + memoryRequired += (long)levelIndex.byteLength; + } + + width = width >> 1; + if (width < 1) { + width = 1; + } + height = height >> 1; + if (height < 1) { + height = 1; + } + } + + return memoryRequired; +} + +bool KRTextureKTX2::uploadTexture(KRDevice& device, VkImage& image, int lod_max_dim, int& current_lod_max_dim, bool premultiply_alpha) +{ + int target_dim = lod_max_dim; + if (target_dim < (int)m_min_lod_max_dim) target_dim = m_min_lod_max_dim; + + // Determine how much memory will be consumed + int width = m_header.pixelWidth; + int height = m_header.pixelHeight; + long memoryRequired = 0; + long memoryTransferred = 0; + + + // Upload texture data + int destination_level = 0; + int source_level = 0; + + for (__uint32_t level = 0; level < m_header.levelCount; level++) { + KTX2LevelIndex levelIndex; + m_pData->copy(&levelIndex, sizeof(m_header) + sizeof(KTX2LevelIndex) * level, sizeof(KTX2LevelIndex)); + + if (width <= target_dim && height <= target_dim) { + + if (width > current_lod_max_dim) { + current_lod_max_dim = width; + } + if (height > current_lod_max_dim) { + current_lod_max_dim = height; + } + + /* + * TODO - Vulkan Refactoring + GLDEBUG(glCompressedTexImage2D(target, destination_level, (unsigned int)m_header.glInternalFormat, width, height, 0, (int)block->getSize(), block->getStart())); + */ + + memoryTransferred += (long)levelIndex.byteLength; // memoryTransferred does not include throughput of mipmap levels copied through glCopyTextureLevelsAPPLE + memoryRequired += (long)levelIndex.byteLength; + // + // err = glGetError(); + // if (err != GL_NO_ERROR) { + // assert(false); + // return false; + // } + // + + destination_level++; + } + + if (width <= m_current_lod_max_dim && height <= m_current_lod_max_dim) { + source_level++; + } + + width = width >> 1; + if (width < 1) { + width = 1; + } + height = height >> 1; + if (height < 1) { + height = 1; + } + } + + return true; + +} + +std::string KRTextureKTX2::getExtension() +{ + return "ktx2"; +} diff --git a/kraken/KRTextureKTX2.h b/kraken/KRTextureKTX2.h new file mode 100644 index 0000000..f3743fe --- /dev/null +++ b/kraken/KRTextureKTX2.h @@ -0,0 +1,79 @@ +// +// KRTextureKTX2.h +// Kraken Engine +// +// Copyright 2022 Kearwood Gilbert. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other materials +// provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY KEARWOOD GILBERT ''AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KEARWOOD GILBERT OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The views and conclusions contained in the software and documentation are those of the +// authors and should not be interpreted as representing official policies, either expressed +// or implied, of Kearwood Gilbert. +// + +#pragma once + +#include "KRTexture2D.h" + +class KRTextureKTX2 : public KRTexture2D +{ +public: + KRTextureKTX2(KRContext& context, KRDataBlock* data, std::string name); + virtual ~KRTextureKTX2(); + virtual std::string getExtension(); + + bool uploadTexture(KRDevice& device, VkImage& image, int lod_max_dim, int& current_lod_max_dim, bool premultiply_alpha = false) override; + + virtual long getMemRequiredForSize(int max_dim); + virtual Vector2i getDimensions() const override; + +protected: + + typedef struct + { + __uint8_t identifier[12]; + __uint32_t vkFormat; + __uint32_t typeSize; + __uint32_t pixelWidth; + __uint32_t pixelHeight; + __uint32_t pixelDepth; + __uint32_t layerCount; + __uint32_t faceCount; + __uint32_t levelCount; + __uint32_t supercompressionScheme; + // Index + __uint32_t dfdByteOffset; + __uint32_t dfdByteLength; + __uint32_t kvdByteOffset; + __uint32_t kvdByteLength; + __uint32_t sgdByteOffset; + __uint32_t sgdByteLength; + } KTX2Header; + + typedef struct + { + __uint64_t byteOffset; + __uint64_t byteLength; + __uint64_t uncompressedByteLength; + } KTX2LevelIndex; + + KTX2Header m_header; +}; diff --git a/kraken/KRTextureManager.cpp b/kraken/KRTextureManager.cpp index d874a82..8f21c74 100755 --- a/kraken/KRTextureManager.cpp +++ b/kraken/KRTextureManager.cpp @@ -36,6 +36,7 @@ #include "KRTexturePVR.h" #include "KRTextureTGA.h" #include "KRTextureKTX.h" +#include "KRTextureKTX2.h" #include "KRTextureCube.h" #include "KRTextureAnimated.h" #include "KRContext.h" @@ -69,17 +70,9 @@ void KRTextureManager::setMaxAnisotropy(float max_anisotropy) KRResource* KRTextureManager::loadResource(const std::string& name, const std::string& extension, KRDataBlock* data) { - /* - - } else if(extension.compare("pvr") == 0) { - resource = m_pTextureManager->loadTexture(name.c_str(), extension.c_str(), data); - } else if(extension.compare("ktx") == 0) { - resource = m_pTextureManager->loadTexture(name.c_str(), extension.c_str(), data); - } else if(extension.compare("tga") == 0) { - - */ if (extension.compare("pvr") == 0 || extension.compare("ktx") == 0 || + extension.compare("ktx2") == 0 || extension.compare("tga") == 0) { return loadTexture(name.c_str(), extension.c_str(), data); } @@ -90,6 +83,7 @@ KRResource* KRTextureManager::getResource(const std::string& name, const std::st { if (extension.compare("pvr") == 0 || extension.compare("ktx") == 0 || + extension.compare("ktx2") == 0 || extension.compare("tga") == 0) { // TODO - Currently textures must have a unique name, without consideration // of extensions. When textures are compressed, the uncompressed versions @@ -120,6 +114,8 @@ KRTexture* KRTextureManager::loadTexture(const char* szName, const char* szExten pTexture = new KRTextureTGA(getContext(), data, szName); } else if (strcmp(szExtension, "ktx") == 0) { pTexture = new KRTextureKTX(getContext(), data, szName); + } else if (strcmp(szExtension, "ktx2") == 0) { + pTexture = new KRTextureKTX2(getContext(), data, szName); } if (pTexture) { diff --git a/kraken/KRTextureTGA.cpp b/kraken/KRTextureTGA.cpp index ff013b0..807587d 100755 --- a/kraken/KRTextureTGA.cpp +++ b/kraken/KRTextureTGA.cpp @@ -31,7 +31,7 @@ #include "KRTextureTGA.h" #include "KREngine-common.h" #include "KRContext.h" -#include "KRTextureKTX.h" +#include "KRTextureKTX2.h" #if defined(_WIN32) || defined(_WIN64) #pragma pack(1)