From 896cfe2c4c1b401eeb9c0041c156d3b38f4fc033 Mon Sep 17 00:00:00 2001 From: Almamu Date: Fri, 5 Sep 2025 01:56:22 +0200 Subject: [PATCH] chore: moved texture assets parsing into the data model too --- CMakeLists.txt | 7 + .../Application/CApplicationContext.cpp | 8 +- .../Application/CApplicationContext.h | 7 +- src/WallpaperEngine/Assets/CContainer.cpp | 14 +- src/WallpaperEngine/Assets/CContainer.h | 1 + src/WallpaperEngine/Assets/CTexture.cpp | 322 ++---------------- src/WallpaperEngine/Assets/CTexture.h | 168 +-------- src/WallpaperEngine/Assets/ITexture.h | 64 +--- src/WallpaperEngine/Data/Assets/Texture.h | 170 +++++++++ src/WallpaperEngine/Data/Assets/Types.h | 15 + src/WallpaperEngine/Data/Model/Types.h | 5 + .../Data/Parsers/TextureParser.cpp | 257 ++++++++++++++ .../Data/Parsers/TextureParser.h | 25 ++ .../Data/Utils/BinaryReader.cpp | 63 ++++ src/WallpaperEngine/Data/Utils/BinaryReader.h | 21 ++ src/WallpaperEngine/Data/Utils/MemoryStream.h | 13 + src/WallpaperEngine/Render/CFBO.cpp | 16 +- src/WallpaperEngine/Render/CFBO.h | 14 +- src/WallpaperEngine/Render/CFBOProvider.cpp | 8 +- src/WallpaperEngine/Render/CFBOProvider.h | 4 +- src/WallpaperEngine/Render/CWallpaper.cpp | 21 +- src/WallpaperEngine/Render/CWallpaper.h | 4 +- .../Render/CWallpaperState.cpp | 4 +- src/WallpaperEngine/Render/CWallpaperState.h | 7 +- src/WallpaperEngine/Render/Objects/CImage.cpp | 6 +- .../Render/Objects/Effects/CPass.cpp | 4 +- .../Render/Wallpapers/CScene.cpp | 10 +- .../Render/Wallpapers/CScene.h | 2 +- .../Render/Wallpapers/CVideo.cpp | 2 +- .../Render/Wallpapers/CVideo.h | 2 +- .../Render/Wallpapers/CWeb.cpp | 2 +- src/WallpaperEngine/Render/Wallpapers/CWeb.h | 2 +- 32 files changed, 704 insertions(+), 564 deletions(-) create mode 100644 src/WallpaperEngine/Data/Assets/Texture.h create mode 100644 src/WallpaperEngine/Data/Assets/Types.h create mode 100644 src/WallpaperEngine/Data/Parsers/TextureParser.cpp create mode 100644 src/WallpaperEngine/Data/Parsers/TextureParser.h create mode 100644 src/WallpaperEngine/Data/Utils/BinaryReader.cpp create mode 100644 src/WallpaperEngine/Data/Utils/BinaryReader.h create mode 100644 src/WallpaperEngine/Data/Utils/MemoryStream.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f31433..73a7144 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -400,6 +400,8 @@ add_executable( src/WallpaperEngine/WebBrowser/CWebBrowserContext.cpp src/WallpaperEngine/WebBrowser/CWebBrowserContext.h + src/WallpaperEngine/Data/Assets/Types.h + src/WallpaperEngine/Data/Assets/Texture.h src/WallpaperEngine/Data/Model/Types.h src/WallpaperEngine/Data/Model/Project.h src/WallpaperEngine/Data/Model/Wallpaper.h @@ -413,6 +415,9 @@ add_executable( src/WallpaperEngine/Data/Model/Property.h src/WallpaperEngine/Data/Utils/TypeCaster.cpp src/WallpaperEngine/Data/Utils/TypeCaster.h + src/WallpaperEngine/Data/Utils/BinaryReader.cpp + src/WallpaperEngine/Data/Utils/BinaryReader.h + src/WallpaperEngine/Data/Utils/MemoryStream.h src/WallpaperEngine/Data/Utils/SFINAE.h src/WallpaperEngine/Data/Parsers/ProjectParser.cpp src/WallpaperEngine/Data/Parsers/ProjectParser.h @@ -430,6 +435,8 @@ add_executable( src/WallpaperEngine/Data/Parsers/ShaderConstantParser.h src/WallpaperEngine/Data/Parsers/PropertyParser.cpp src/WallpaperEngine/Data/Parsers/PropertyParser.h + src/WallpaperEngine/Data/Parsers/TextureParser.cpp + src/WallpaperEngine/Data/Parsers/TextureParser.h src/WallpaperEngine/Data/Builders/UserSettingBuilder.h src/WallpaperEngine/Data/Builders/VectorBuilder.cpp src/WallpaperEngine/Data/Builders/VectorBuilder.h diff --git a/src/WallpaperEngine/Application/CApplicationContext.cpp b/src/WallpaperEngine/Application/CApplicationContext.cpp index 581cabe..aca9b3a 100644 --- a/src/WallpaperEngine/Application/CApplicationContext.cpp +++ b/src/WallpaperEngine/Application/CApplicationContext.cpp @@ -118,14 +118,14 @@ CApplicationContext::CApplicationContext (int argc, char* argv []) : .help ("Clamp mode to use when rendering the background, this applies to the previous --window or --screen-root output, or the default background if no other background is specified") .choices("clamp", "border", "repeat") .action([this, &lastScreen](const std::string& value) -> void { - WallpaperEngine::Assets::ITexture::TextureFlags flags; + TextureFlags flags; if (value == "clamp") { - flags = WallpaperEngine::Assets::ITexture::TextureFlags::ClampUVs; + flags = TextureFlags_ClampUVs; } else if (value == "border") { - flags = WallpaperEngine::Assets::ITexture::TextureFlags::ClampUVsBorder; + flags = TextureFlags_ClampUVsBorder; } else if (value == "repeat") { - flags = WallpaperEngine::Assets::ITexture::TextureFlags::NoFlags; + flags = TextureFlags_NoFlags; } else { sLog.exception ("Invalid clamp mode: ", value); } diff --git a/src/WallpaperEngine/Application/CApplicationContext.h b/src/WallpaperEngine/Application/CApplicationContext.h index 20eb075..4650a52 100644 --- a/src/WallpaperEngine/Application/CApplicationContext.h +++ b/src/WallpaperEngine/Application/CApplicationContext.h @@ -15,6 +15,7 @@ #include "WallpaperEngine/Data/Model/Project.h" namespace WallpaperEngine::Application { +using namespace WallpaperEngine::Data::Assets; /** * Application information as parsed off the command line arguments */ @@ -51,7 +52,7 @@ class CApplicationContext { /** The scaling mode for different screens */ std::map screenScalings; /** The clamping mode for different screens */ - std::map screenClamps; + std::map screenClamps; } general; /** @@ -68,7 +69,7 @@ class CApplicationContext { struct { /** The window size used in explicit window */ glm::ivec4 geometry; - WallpaperEngine::Assets::ITexture::TextureFlags clamp; + TextureFlags clamp; WallpaperEngine::Render::CWallpaperState::TextureUVsScaling scalingMode; } window; } render; @@ -125,7 +126,7 @@ class CApplicationContext { .pauseOnFullscreen = true, .window = { .geometry = {}, - .clamp = WallpaperEngine::Assets::ITexture::TextureFlags::ClampUVs, + .clamp = TextureFlags_ClampUVs, .scalingMode = WallpaperEngine::Render::CWallpaperState::TextureUVsScaling::DefaultUVs, }, }, diff --git a/src/WallpaperEngine/Assets/CContainer.cpp b/src/WallpaperEngine/Assets/CContainer.cpp index c30c3c4..93851be 100644 --- a/src/WallpaperEngine/Assets/CContainer.cpp +++ b/src/WallpaperEngine/Assets/CContainer.cpp @@ -1,6 +1,9 @@ #include "CContainer.h" #include "CAssetLoadException.h" #include "CTexture.h" +#include "WallpaperEngine/Data/Utils/BinaryReader.h" +#include "WallpaperEngine/Data/Utils/MemoryStream.h" +#include "WallpaperEngine/Data/Parsers/TextureParser.h" #include "WallpaperEngine/Logging/CLog.h" #include @@ -8,6 +11,8 @@ #include using namespace WallpaperEngine::Assets; +using namespace WallpaperEngine::Data::Utils; +using namespace WallpaperEngine::Data::Parsers; std::filesystem::path CContainer::resolveRealFile (const std::filesystem::path& filename) const { throw CAssetLoadException (filename, "Cannot resolve physical file in this container"); @@ -17,8 +22,13 @@ std::shared_ptr CContainer::readTexture (const std::filesystem: // get the texture's filename (usually .tex) std::filesystem::path texture = "materials" / std::filesystem::path (filename.string ().append (".tex")); - const auto textureContents = this->readFile (texture, nullptr); - const auto result = std::make_shared (textureContents); + uint32_t length = 0; + const auto textureContents = this->readFile (texture, &length); + // TODO: MAKE PROPER USE OF I/OSTREAMS IN THE CLASS INSTEAD OF INSTANTIATING THINGS HERE... + auto buffer = MemoryStream (reinterpret_cast (const_cast (&textureContents.get () [0])), length); + auto istream = std::istream (&buffer); + auto binaryReader = BinaryReader (istream); + const auto result = std::make_shared (TextureParser::parse (binaryReader)); #if !NDEBUG glObjectLabel (GL_TEXTURE, result->getTextureID (0), -1, texture.c_str ()); diff --git a/src/WallpaperEngine/Assets/CContainer.h b/src/WallpaperEngine/Assets/CContainer.h index 4990145..dffb8da 100644 --- a/src/WallpaperEngine/Assets/CContainer.h +++ b/src/WallpaperEngine/Assets/CContainer.h @@ -6,6 +6,7 @@ #include namespace WallpaperEngine::Assets { +class ITexture; /** * File container, provides access to files for backgrounds diff --git a/src/WallpaperEngine/Assets/CTexture.cpp b/src/WallpaperEngine/Assets/CTexture.cpp index 19ab50f..642afe8 100644 --- a/src/WallpaperEngine/Assets/CTexture.cpp +++ b/src/WallpaperEngine/Assets/CTexture.cpp @@ -10,10 +10,8 @@ using namespace WallpaperEngine::Assets; -CTexture::CTexture (const std::shared_ptr& buffer) : m_resolution () { +CTexture::CTexture (TextureUniquePtr header) : m_header (std::move(header)) { // ensure the header is parsed - const void* fileData = buffer.get (); - this->m_header = parseHeader (static_cast (fileData)); this->setupResolution (); GLint internalFormat = this->setupInternalFormat(); @@ -39,7 +37,7 @@ CTexture::CTexture (const std::shared_ptr& buffer) : m_resoluti uint32_t bufferSize = (*cur)->uncompressedSize; GLenum textureFormat = GL_RGBA; - if (this->m_header->freeImageFormat != FreeImageFormat::FIF_UNKNOWN) { + if (this->m_header->freeImageFormat != FIF_UNKNOWN) { int fileChannels; dataptr = handle = stbi_load_from_memory ( @@ -50,11 +48,11 @@ CTexture::CTexture (const std::shared_ptr& buffer) : m_resoluti &fileChannels, 4); } else { - if (this->m_header->format == TextureFormat::R8) { + if (this->m_header->format == TextureFormat_R8) { // red textures are 1-byte-per-pixel, so it's alignment has to be set manually glPixelStorei (GL_UNPACK_ALIGNMENT, 1); textureFormat = GL_RED; - } else if (this->m_header->format == TextureFormat::RG88) { + } else if (this->m_header->format == TextureFormat_RG88) { textureFormat = GL_RG; } } @@ -78,7 +76,7 @@ CTexture::CTexture (const std::shared_ptr& buffer) : m_resoluti } // stbi_image buffer won't be used anymore, so free memory - if (this->m_header->freeImageFormat != FreeImageFormat::FIF_UNKNOWN) { + if (this->m_header->freeImageFormat != FIF_UNKNOWN) { stbi_image_free (handle); } } @@ -87,10 +85,12 @@ CTexture::CTexture (const std::shared_ptr& buffer) : m_resoluti void CTexture::setupResolution () { if (this->isAnimated ()) { - this->m_resolution = {this->m_header->textureWidth, this->m_header->textureHeight, this->m_header->gifWidth, - this->m_header->gifHeight}; + this->m_resolution = { + this->m_header->textureWidth, this->m_header->textureHeight, + this->m_header->gifWidth, this->m_header->gifHeight + }; } else { - if (this->m_header->freeImageFormat != FreeImageFormat::FIF_UNKNOWN) { + if (this->m_header->freeImageFormat != FIF_UNKNOWN) { // wpengine-texture format always has one mipmap // get first image size auto element = this->m_header->images.find (0)->second.begin (); @@ -99,14 +99,16 @@ void CTexture::setupResolution () { this->m_resolution = {(*element)->width, (*element)->height, this->m_header->width, this->m_header->height}; } else { // set the texture resolution - this->m_resolution = {this->m_header->textureWidth, this->m_header->textureHeight, this->m_header->width, - this->m_header->height}; + this->m_resolution = { + this->m_header->textureWidth, this->m_header->textureHeight, + this->m_header->width, this->m_header->height + }; } } } GLint CTexture::setupInternalFormat () { - if (this->m_header->freeImageFormat != FreeImageFormat::FIF_UNKNOWN) { + if (this->m_header->freeImageFormat != FIF_UNKNOWN) { return GL_RGBA8; // set some extra information too as it's used for image sizing // this ensures that a_TexCoord uses the full image instead of just part of it @@ -118,12 +120,12 @@ GLint CTexture::setupInternalFormat () { } else { // detect the image format and hand it to openGL to be used switch (this->m_header->format) { - case TextureFormat::DXT5: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; - case TextureFormat::DXT3: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; - case TextureFormat::DXT1: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; - case TextureFormat::ARGB8888: return GL_RGBA8; break; - case TextureFormat::R8: return GL_R8; break; - case TextureFormat::RG88: return GL_RG8; break; + case TextureFormat_DXT5: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; + case TextureFormat_DXT3: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; + case TextureFormat_DXT1: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; + case TextureFormat_ARGB8888: return GL_RGBA8; break; + case TextureFormat_R8: return GL_R8; break; + case TextureFormat_RG88: return GL_RG8; break; default: sLog.exception ("Cannot determine texture format"); } } @@ -138,7 +140,7 @@ void CTexture::setupOpenGLParameters (uint32_t textureID) { glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, this->m_header->images [textureID].size () - 1); // setup texture wrapping and filtering - if (this->m_header->flags & TextureFlags::ClampUVs) { + if (this->m_header->flags & TextureFlags_ClampUVs) { glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else { @@ -146,7 +148,7 @@ void CTexture::setupOpenGLParameters (uint32_t textureID) { glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } - if (this->m_header->flags & TextureFlags::NoInterpolation) { + if (this->m_header->flags & TextureFlags_NoInterpolation) { glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); } else { @@ -167,298 +169,46 @@ GLuint CTexture::getTextureID (uint32_t imageIndex) const { uint32_t CTexture::getTextureWidth (uint32_t imageIndex) const { if (imageIndex >= this->m_header->imageCount) - return this->getHeader ()->textureWidth; + return this->getHeader ().textureWidth; return (*this->m_header->images [imageIndex].begin ())->width; } uint32_t CTexture::getTextureHeight (uint32_t imageIndex) const { if (imageIndex >= this->m_header->imageCount) - return this->getHeader ()->textureHeight; + return this->getHeader ().textureHeight; return (*this->m_header->images [imageIndex].begin ())->height; } uint32_t CTexture::getRealWidth () const { - return this->isAnimated () ? this->getHeader ()->gifWidth : this->getHeader ()->width; + return this->isAnimated () ? this->getHeader ().gifWidth : this->getHeader ().width; } uint32_t CTexture::getRealHeight () const { - return this->isAnimated () ? this->getHeader ()->gifHeight : this->getHeader ()->height; + return this->isAnimated () ? this->getHeader ().gifHeight : this->getHeader ().height; } -ITexture::TextureFormat CTexture::getFormat () const { - return this->getHeader ()->format; +TextureFormat CTexture::getFormat () const { + return this->getHeader ().format; } -ITexture::TextureFlags CTexture::getFlags () const { - return this->getHeader ()->flags; +uint32_t CTexture::getFlags () const { + return this->getHeader ().flags; } -const CTexture::TextureHeader* CTexture::getHeader () const { - return this->m_header.get (); +const Texture& CTexture::getHeader () const { + return *this->m_header; } const glm::vec4* CTexture::getResolution () const { return &this->m_resolution; } -const std::vector>& CTexture::getFrames () const { - return this->getHeader ()->frames; +const std::vector& CTexture::getFrames () const { + return this->getHeader ().frames; } bool CTexture::isAnimated () const { - return this->getHeader ()->isAnimated (); + return this->getHeader ().isAnimated (); } - -void CTexture::TextureMipmap::decompressData () { - if (this->compression != 1) { - return; - } - - this->uncompressedData = std::unique_ptr (new char [this->uncompressedSize]); - - const int result = LZ4_decompress_safe ( - this->compressedData.get (), this->uncompressedData.get (), this->compressedSize, - this->uncompressedSize); - - if (!result) - sLog.exception ("Cannot decompress texture data, LZ4_decompress_safe returned an error"); -} - -CTexture::TextureFrame::TextureFrame () : - frameNumber (0), - frametime (0.0f), - x (0), - y (0), - width1 (0), - width2 (0), - height1 (0), - height2 (0) {} - -CTexture::TextureHeader::TextureHeader () : - flags (NoFlags), - width (0), - height (0), - textureWidth (0), - textureHeight (0), - gifWidth (0), - gifHeight (0), - format (TextureFormat::UNKNOWN), - imageCount (0), - isVideoMp4 (false) {} - -std::unique_ptr CTexture::parseHeader (const char* fileData) { - // check the magic value on the header first - if (strncmp (fileData, "TEXV0005", 9) != 0) - sLog.exception ("unexpected texture container type: ", std::string_view (fileData, 9)); - // jump to the next value - fileData += 9; - // check the sub-magic value on the header - if (strncmp (fileData, "TEXI0001", 9) != 0) - sLog.exception ("unexpected texture sub-container type: ", std::string_view (fileData, 9)); - // jump through the string again - fileData += 9; - - auto header = std::make_unique (); - const auto* pointer = reinterpret_cast (fileData); - - header->format = static_cast (*pointer++); - header->flags = static_cast (*pointer++); - header->textureWidth = *pointer++; - header->textureHeight = *pointer++; - header->width = *pointer++; - header->height = *pointer++; - pointer++; // ignore some more bytes - - // now we're going to parse some more data that is string - // so get the current position back as string - fileData = reinterpret_cast (pointer); - // get the position of what comes after the texture data - pointer = reinterpret_cast (fileData + 9); - - header->imageCount = *pointer++; - - if (strncmp (fileData, "TEXB0004", 9) == 0) { - header->containerVersion = ContainerVersion::TEXB0004; - header->freeImageFormat = static_cast (*pointer++); - header->isVideoMp4 = *pointer++ == 1; - - if (header->freeImageFormat == FIF_UNKNOWN && header->isVideoMp4) { - header->freeImageFormat = FIF_MP4; - } - - // default to TEXB0003 behavior if no mp4 video is there - if (header->freeImageFormat != FIF_MP4) { - header->containerVersion = ContainerVersion::TEXB0003; - } - } else if (strncmp (fileData, "TEXB0003", 9) == 0) { - header->containerVersion = ContainerVersion::TEXB0003; - header->freeImageFormat = static_cast (*pointer++); - } else if (strncmp (fileData, "TEXB0002", 9) == 0) { - header->containerVersion = ContainerVersion::TEXB0002; - } else if (strncmp (fileData, "TEXB0001", 9) == 0) { - header->containerVersion = ContainerVersion::TEXB0001; - } else { - sLog.exception ("unknown texture format type: ", std::string_view (fileData, 9)); - } - - for (uint32_t image = 0; image < header->imageCount; image++) { - // read the number of mipmaps available for this image - uint32_t mipmapCount = *pointer++; - std::vector> mipmaps; - - fileData = reinterpret_cast (pointer); - - for (uint32_t i = 0; i < mipmapCount; i++) - mipmaps.emplace_back (parseMipmap (header.get (), &fileData)); - - // add the pixmaps back - header->images.emplace (image, mipmaps); - - pointer = reinterpret_cast (fileData); - } - - // gifs have extra information after the mipmaps - if (header->isAnimated ()) { - if (strncmp (fileData, "TEXS0002", 9) == 0) { - header->animatedVersion = AnimatedVersion::TEXS0002; - } else if (strncmp (fileData, "TEXS0003", 9) == 0) { - header->animatedVersion = AnimatedVersion::TEXS0003; - } else { - sLog.exception ("found animation information of unknown type: ", std::string_view (fileData, 9)); - } - - // get an integer pointer back to read the frame count - pointer = reinterpret_cast (fileData + 9); - uint32_t framecount = *pointer++; - - if (header->animatedVersion == AnimatedVersion::TEXS0003) { - // ignore two extra integers as those are width and height of the git - header->gifWidth = *pointer++; - header->gifHeight = *pointer++; - } - - // get back the pointer into filedata - fileData = reinterpret_cast (pointer); - - while (framecount > 0) { - // add the frame to the list - header->frames.push_back (parseAnimation (&fileData)); - - framecount--; - } - - // ensure gif width and height is right for TEXS0002 - if (header->animatedVersion == AnimatedVersion::TEXS0002) { - auto first = *header->frames.begin (); - - header->gifWidth = first->width1; - header->gifHeight = first->height1; - } - } - - return header; -} - -std::shared_ptr CTexture::parseAnimation (const char** originalFileData) { - const char* fileData = *originalFileData; - // get back the pointer into integer - const auto* pointer = reinterpret_cast (fileData); - - // start reading frame information - auto frame = std::make_shared (); - - frame->frameNumber = *pointer++; - - // reinterpret the pointer into float - const auto* fPointer = reinterpret_cast (pointer); - - frame->frametime = *fPointer++; - frame->x = *fPointer++; - frame->y = *fPointer++; - frame->width1 = *fPointer++; - frame->width2 = *fPointer++; - frame->height2 = *fPointer++; - frame->height1 = *fPointer++; - - // get back the pointer into fileData so it can be reused later - *originalFileData = reinterpret_cast (fPointer); - - return frame; -} - -std::shared_ptr CTexture::parseMipmap (const TextureHeader* header, const char** originalFileData) { - auto mipmap = std::make_shared (); - // get the current position - const char* fileData = *originalFileData; - - // get an integer pointer - const auto* pointer = reinterpret_cast (fileData); - - // TEXB004 have some extra data (and even json) that we have to take into account - if (header->containerVersion == ContainerVersion::TEXB0004) { - // ignore various params, RePKG doesn't really use them - // and could be related to the editor really, so just ignore them - pointer++; - pointer++; - - fileData = reinterpret_cast (pointer); - while (*fileData != 0) { - mipmap->json += *fileData++; - } - - // skip the null terminator - fileData ++; - - pointer = reinterpret_cast (fileData); - // this is another param to ignore - pointer++; - } - - mipmap->width = *pointer++; - mipmap->height = *pointer++; - - if (header->containerVersion == ContainerVersion::TEXB0002 || - header->containerVersion == ContainerVersion::TEXB0003 || - header->containerVersion == ContainerVersion::TEXB0004) { - mipmap->compression = *pointer++; - mipmap->uncompressedSize = *pointer++; - } - - mipmap->compressedSize = *pointer++; - - // get back a normal char pointer - fileData = reinterpret_cast (pointer); - - if (mipmap->compression == 0) { - // this might be better named as mipmap_bytes_size instead of compressedSize - // as in uncompressed files this variable actually holds the file length - mipmap->uncompressedSize = mipmap->compressedSize; - } - - mipmap->uncompressedData = std::unique_ptr(new char [mipmap->uncompressedSize]); - - if (mipmap->compression == 1) { - mipmap->compressedData = std::unique_ptr(new char [mipmap->compressedSize]); - - memcpy (mipmap->compressedData.get (), fileData, mipmap->compressedSize); - - mipmap->decompressData (); - // advance to the end of the mipmap - fileData += mipmap->compressedSize; - } else { - memcpy (mipmap->uncompressedData.get (), fileData, mipmap->uncompressedSize); - // advance to the end of the mipmap - fileData += mipmap->uncompressedSize; - } - - // ensure the pointer is updated with the latest position when reading the data - *originalFileData = fileData; - - return mipmap; -} - -bool CTexture::TextureHeader::isAnimated () const { - return this->flags & TextureFlags::IsGif; -} \ No newline at end of file diff --git a/src/WallpaperEngine/Assets/CTexture.h b/src/WallpaperEngine/Assets/CTexture.h index 2c81a2b..c1a6215 100644 --- a/src/WallpaperEngine/Assets/CTexture.h +++ b/src/WallpaperEngine/Assets/CTexture.h @@ -1,6 +1,7 @@ #pragma once #include "ITexture.h" +#include "WallpaperEngine/Data/Assets/Texture.h" #include #include @@ -11,144 +12,14 @@ #include namespace WallpaperEngine::Assets { +using namespace WallpaperEngine::Data::Assets; + /** * A normal texture file in WallpaperEngine's format */ class CTexture final : public ITexture { - /** - * Different texture container versions supported - */ - enum ContainerVersion : int { - UNKNOWN = -1, - TEXB0004 = 4, - TEXB0003 = 3, - TEXB0002 = 2, - TEXB0001 = 1 - }; - - /** - * Different texture animation versions supported - */ - enum AnimatedVersion : int { - TEXSUNKN = -1, - TEXS0002 = 0, - TEXS0003 = 1, - }; - - enum FreeImageFormat : int { - FIF_UNKNOWN = -1, - FIF_BMP = 0, - FIF_ICO = 1, - FIF_JPEG = 2, - FIF_JNG = 3, - FIF_KOALA = 4, - FIF_LBM = 5, - FIF_IFF = FIF_LBM, - FIF_MNG = 6, - FIF_PBM = 7, - FIF_PBMRAW = 8, - FIF_PCD = 9, - FIF_PCX = 10, - FIF_PGM = 11, - FIF_PGMRAW = 12, - FIF_PNG = 13, - FIF_PPM = 14, - FIF_PPMRAW = 15, - FIF_RAS = 16, - FIF_TARGA = 17, - FIF_TIFF = 18, - FIF_WBMP = 19, - FIF_PSD = 20, - FIF_CUT = 21, - FIF_XBM = 22, - FIF_XPM = 23, - FIF_DDS = 24, - FIF_GIF = 25, - FIF_HDR = 26, - FIF_FAXG3 = 27, - FIF_SGI = 28, - FIF_EXR = 29, - FIF_J2K = 30, - FIF_JP2 = 31, - FIF_PFM = 32, - FIF_PICT = 33, - FIF_RAW = 34, - FIF_WEBP = 35, - FIF_MP4 = FIF_WEBP, - FIF_JXR = 36 - }; - - /** - * Texture mipmap data - */ - class TextureMipmap { - public: - /** Width of the mipmap */ - uint32_t width = 0; - /** Height of the mipmap */ - uint32_t height = 0; - /** If the mipmap data is compressed */ - uint32_t compression = 0; - /** Uncompressed size of the mipmap */ - uint32_t uncompressedSize = 0; - /** Compress size of the mipmap */ - uint32_t compressedSize = 0; - /** Pointer to the compressed data */ - std::unique_ptr compressedData = nullptr; - /** Pointer to the uncompressed data */ - std::unique_ptr uncompressedData = nullptr; - /** JSON data */ - std::string json {}; - /** - * Performs actual decompression of the compressed data - */ - void decompressData (); - }; - - /** - * Texture header data - */ - class TextureHeader { - public: - TextureHeader (); - ~TextureHeader () = default; - - [[nodiscard]] bool isAnimated () const; - - /** The version of the texture container */ - ContainerVersion containerVersion = ContainerVersion::UNKNOWN; - /** The version of the animated data */ - AnimatedVersion animatedVersion = AnimatedVersion::TEXSUNKN; - /** Flags with extra texture information */ - TextureFlags flags = TextureFlags::NoFlags; - /** Real width of the texture */ - uint32_t width = 0; - /** Real height of the texture */ - uint32_t height = 0; - /** Texture width in memory (power of 2) */ - uint32_t textureWidth = 0; - /** Texture height in memory (power of 2) */ - uint32_t textureHeight = 0; - /** Gif width */ - uint32_t gifWidth = 0; - /** Gif height */ - uint32_t gifHeight = 0; - /** Texture data format */ - TextureFormat format = TextureFormat::UNKNOWN; - /** Free Image format */ - FreeImageFormat freeImageFormat = FreeImageFormat::FIF_UNKNOWN; - /** Indicates if we have an MP4 video */ - bool isVideoMp4 = false; - /** The amount of images in the texture file */ - uint32_t imageCount = 0; - /** List of mipmaps */ - std::map>> images {}; - /** List of animation frames */ - std::vector> frames {}; - }; - public: - explicit CTexture (const std::shared_ptr& fileData); + explicit CTexture (TextureUniquePtr header); [[nodiscard]] GLuint getTextureID (uint32_t imageIndex) const override; [[nodiscard]] uint32_t getTextureWidth (uint32_t imageIndex) const override; @@ -156,39 +27,16 @@ class CTexture final : public ITexture { [[nodiscard]] uint32_t getRealWidth () const override; [[nodiscard]] uint32_t getRealHeight () const override; [[nodiscard]] TextureFormat getFormat () const override; - [[nodiscard]] TextureFlags getFlags () const override; + [[nodiscard]] uint32_t getFlags () const override; [[nodiscard]] const glm::vec4* getResolution () const override; - [[nodiscard]] const std::vector>& getFrames () const override; + [[nodiscard]] const std::vector& getFrames () const override; [[nodiscard]] bool isAnimated () const override; private: /** * @return The texture header */ - [[nodiscard]] const TextureHeader* getHeader () const; - - /** - * Tries to parse a header off the given data pointer - * - * @param fileData The point at which to start reading data off from - * @return - */ - static std::unique_ptr parseHeader (const char* fileData); - /** - * Tries to parse an animation frame off the given data pointer - * - * @param originalFileData The point at which to start reading data off from - * @return - */ - static std::shared_ptr parseAnimation (const char** originalFileData); - /** - * Tries to parse mipmap information off the given data pointer - * - * @param header The file header - * @param fileData The point at which to start reading data off from - * @return - */ - static std::shared_ptr parseMipmap (const TextureHeader* header, const char** fileData); + [[nodiscard]] const Texture& getHeader () const; /** * Calculate's texture's resolution vec4 @@ -204,7 +52,7 @@ class CTexture final : public ITexture { void setupOpenGLParameters (uint32_t textureID); /** The texture header */ - std::unique_ptr m_header = nullptr; + TextureUniquePtr m_header; /** OpenGL's texture ID */ GLuint* m_textureID = nullptr; /** Resolution vector of the texture */ diff --git a/src/WallpaperEngine/Assets/ITexture.h b/src/WallpaperEngine/Assets/ITexture.h index f647059..b251e97 100644 --- a/src/WallpaperEngine/Assets/ITexture.h +++ b/src/WallpaperEngine/Assets/ITexture.h @@ -6,7 +6,11 @@ #include #include +#include "WallpaperEngine/Data/Assets/Texture.h" +#include "WallpaperEngine/Data/Model/Types.h" + namespace WallpaperEngine::Assets { +using namespace WallpaperEngine::Data::Assets; /** * Base interface that describes the minimum information required for a texture * to be displayed by the engine @@ -15,62 +19,6 @@ class ITexture { public: virtual ~ITexture () = default; - /** - * Texture frame information for animated textures - */ - class TextureFrame final { - public: - TextureFrame (); - virtual ~TextureFrame () = default; - - /** The image index of this frame */ - uint32_t frameNumber = 0; - /** The amount of time this frame spends being displayed */ - float frametime = 0.0f; - /** The x position of the frame in the texture */ - float x = 0.0f; - /** The y position of the frame in the texture */ - float y = 0.0f; - /** The width of the frame in the texture */ - float width1 = 0.0f; - float width2 = 0.0f; - /** The height of the frame in the texture */ - float height1 = 0.0f; - float height2 = 0.0f; - }; - - /** - * Data formats for textures in memory - */ - enum TextureFormat : uint32_t { - UNKNOWN = 0xFFFFFFFF, - ARGB8888 = 0, - RGB888 = 1, - RGB565 = 2, - DXT5 = 4, - DXT3 = 6, - DXT1 = 7, - RG88 = 8, - R8 = 9, - RG1616f = 10, - R16f = 11, - BC7 = 12, - RGBa1010102 = 13, - RGBA16161616f = 14, - RGB161616f = 15, - }; - - /** - * Different settings of the textures - */ - enum TextureFlags : uint32_t { - NoFlags = 0, - NoInterpolation = 1, - ClampUVs = 2, - IsGif = 4, - ClampUVsBorder = 8, - }; - /** * @param imageIndex For animated textures, the frame to get the ID of * @return The OpenGL texture to use when rendering @@ -101,11 +49,11 @@ class ITexture { /** * @return The texture's settings */ - [[nodiscard]] virtual TextureFlags getFlags () const = 0; + [[nodiscard]] virtual uint32_t getFlags () const = 0; /** * @return The list of frames this texture has */ - [[nodiscard]] virtual const std::vector>& getFrames () const = 0; + [[nodiscard]] virtual const std::vector& getFrames () const = 0; /** * @return The texture's resolution vector */ diff --git a/src/WallpaperEngine/Data/Assets/Texture.h b/src/WallpaperEngine/Data/Assets/Texture.h new file mode 100644 index 0000000..bf8c7b5 --- /dev/null +++ b/src/WallpaperEngine/Data/Assets/Texture.h @@ -0,0 +1,170 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "Types.h" + +namespace WallpaperEngine::Data::Assets { +enum ContainerVersion { + ContainerVersion_UNKNOWN = 0, + ContainerVersion_TEXB0001 = 1, + ContainerVersion_TEXB0002 = 2, + ContainerVersion_TEXB0003 = 3, + ContainerVersion_TEXB0004 = 4, +}; + +enum AnimatedVersion { + AnimatedVersion_UNKNOWN = 0, + AnimatedVersion_TEXS0002 = 2, + AnimatedVersion_TEXS0003 = 3, +}; + +enum FIF { + FIF_UNKNOWN = -1, + FIF_BMP = 0, + FIF_ICO = 1, + FIF_JPEG = 2, + FIF_JNG = 3, + FIF_KOALA = 4, + FIF_LBM = 5, + FIF_IFF = FIF_LBM, + FIF_MNG = 6, + FIF_PBM = 7, + FIF_PBMRAW = 8, + FIF_PCD = 9, + FIF_PCX = 10, + FIF_PGM = 11, + FIF_PGMRAW = 12, + FIF_PNG = 13, + FIF_PPM = 14, + FIF_PPMRAW = 15, + FIF_RAS = 16, + FIF_TARGA = 17, + FIF_TIFF = 18, + FIF_WBMP = 19, + FIF_PSD = 20, + FIF_CUT = 21, + FIF_XBM = 22, + FIF_XPM = 23, + FIF_DDS = 24, + FIF_GIF = 25, + FIF_HDR = 26, + FIF_FAXG3 = 27, + FIF_SGI = 28, + FIF_EXR = 29, + FIF_J2K = 30, + FIF_JP2 = 31, + FIF_PFM = 32, + FIF_PICT = 33, + FIF_RAW = 34, + FIF_WEBP = 35, + FIF_MP4 = FIF_WEBP, + FIF_JXR = 36 +}; + +enum TextureFormat { + TextureFormat_UNKNOWN = 0xFFFFFFFF, + TextureFormat_ARGB8888 = 0, + TextureFormat_RGB888 = 1, + TextureFormat_RGB565 = 2, + TextureFormat_DXT5 = 4, + TextureFormat_DXT3 = 6, + TextureFormat_DXT1 = 7, + TextureFormat_RG88 = 8, + TextureFormat_R8 = 9, + TextureFormat_RG1616f = 10, + TextureFormat_R16f = 11, + TextureFormat_BC7 = 12, + TextureFormat_RGBa1010102 = 13, + TextureFormat_RGBA16161616f = 14, + TextureFormat_RGB161616f = 15, +}; + +enum TextureFlags { + TextureFlags_NoFlags = 0, + TextureFlags_NoInterpolation = 1, + TextureFlags_ClampUVs = 2, + TextureFlags_IsGif = 4, + TextureFlags_ClampUVsBorder = 8, + TextureFlags_All = + TextureFlags_NoInterpolation | TextureFlags_ClampUVs | + TextureFlags_IsGif | TextureFlags_ClampUVsBorder, +}; + +struct Mipmap { + /** Width of the mipmap */ + uint32_t width = 0; + /** Height of the mipmap */ + uint32_t height = 0; + /** If the mipmap data is compressed */ + uint32_t compression = 0; + /** Uncompressed size of the mipmap */ + int uncompressedSize = 0; + /** Compress size of the mipmap */ + int compressedSize = 0; + /** Pointer to the compressed data */ + std::unique_ptr compressedData = nullptr; + /** Pointer to the uncompressed data */ + std::unique_ptr uncompressedData = nullptr; + /** JSON data */ + std::string json {}; +}; + +struct Frame { + /** The image index of this frame */ + uint32_t frameNumber = 0; + /** The amount of time this frame spends being displayed */ + float frametime = 0.0f; + /** The x position of the frame in the texture */ + float x = 0.0f; + /** The y position of the frame in the texture */ + float y = 0.0f; + /** The width of the frame in the texture */ + float width1 = 0.0f; + float width2 = 0.0f; + /** The height of the frame in the texture */ + float height1 = 0.0f; + float height2 = 0.0f; +}; + +struct Texture { + /** The version of the texture container */ + ContainerVersion containerVersion = ContainerVersion_UNKNOWN; + /** The version of the animated data */ + AnimatedVersion animatedVersion = AnimatedVersion_UNKNOWN; + /** Flags with extra texture information @see TextureFlags */ + uint32_t flags = TextureFlags_NoFlags; + /** Real width of the texture */ + uint32_t width = 0; + /** Real height of the texture */ + uint32_t height = 0; + /** Texture width in memory (power of 2) */ + uint32_t textureWidth = 0; + /** Texture height in memory (power of 2) */ + uint32_t textureHeight = 0; + /** Gif width */ + uint32_t gifWidth = 0; + /** Gif height */ + uint32_t gifHeight = 0; + /** Texture data format */ + TextureFormat format = TextureFormat_UNKNOWN; + /** Free Image format */ + FIF freeImageFormat = FIF_UNKNOWN; + /** Indicates if we have an MP4 video */ + bool isVideoMp4 = false; + /** The amount of images in the texture file */ + uint32_t imageCount = 0; + /** List of mipmaps */ + std::map images {}; + /** List of animation frames */ + std::vector frames {}; + + [[nodiscard]] bool isAnimated () const { + return (flags & TextureFlags_IsGif) == TextureFlags_IsGif; + } +}; +} \ No newline at end of file diff --git a/src/WallpaperEngine/Data/Assets/Types.h b/src/WallpaperEngine/Data/Assets/Types.h new file mode 100644 index 0000000..f548676 --- /dev/null +++ b/src/WallpaperEngine/Data/Assets/Types.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +namespace WallpaperEngine::Data::Assets { +struct Mipmap; +struct Frame; +struct Texture; + +using MipmapSharedPtr = std::shared_ptr ; +using FrameSharedPtr = std::shared_ptr ; +using TextureUniquePtr = std::unique_ptr ; +using MipmapList = std::vector ; +} \ No newline at end of file diff --git a/src/WallpaperEngine/Data/Model/Types.h b/src/WallpaperEngine/Data/Model/Types.h index d57ea83..33e8d38 100644 --- a/src/WallpaperEngine/Data/Model/Types.h +++ b/src/WallpaperEngine/Data/Model/Types.h @@ -8,6 +8,11 @@ #include "WallpaperEngine/Assets/CContainer.h" +namespace WallpaperEngine::Assets { +class CContainer; +} + + namespace WallpaperEngine::Data::Model { struct Project; class Wallpaper; diff --git a/src/WallpaperEngine/Data/Parsers/TextureParser.cpp b/src/WallpaperEngine/Data/Parsers/TextureParser.cpp new file mode 100644 index 0000000..568971a --- /dev/null +++ b/src/WallpaperEngine/Data/Parsers/TextureParser.cpp @@ -0,0 +1,257 @@ +#include + +#include + +#include "TextureParser.h" +#include "WallpaperEngine/Data/Assets/Texture.h" +#include "WallpaperEngine/Logging/CLog.h" + +using namespace WallpaperEngine::Data::Assets; +using namespace WallpaperEngine::Data::Parsers; + +TextureUniquePtr TextureParser::parse (BinaryReader& file) { + char magic[9] = { 0 }; + file.next (magic, 9); + + if (strncmp (magic, "TEXV0005", 9) != 0) + sLog.exception ("unexpected texture container type: ", std::string_view (magic, 9)); + + file.next (magic, 9); + + if (strncmp (magic, "TEXI0001", 9) != 0) + sLog.exception ("unexpected texture sub-container type: ", std::string_view (magic, 9)); + + auto result = std::make_unique (); + + result->format = parseTextureFormat (file.nextUInt32 ()); + result->flags = parseTextureFlags (file.nextUInt32 ()); + result->textureWidth = file.nextUInt32 (); + result->textureHeight = file.nextUInt32 (); + result->width = file.nextUInt32 (); + result->height = file.nextUInt32 (); + + // ignore some more bytes + file.nextUInt32 (); + + file.next (magic, 9); + + result->imageCount = file.nextUInt32 (); + + if (strncmp (magic, "TEXB0004", 9) == 0) { + result->containerVersion = ContainerVersion_TEXB0004; + result->freeImageFormat = parseFIF (file.nextUInt32 ()); + result->isVideoMp4 = file.nextUInt32 () == 1; + + if (result->freeImageFormat == FIF_UNKNOWN && result->isVideoMp4) { + result->freeImageFormat = FIF_MP4; + } + + // default to TEXB0003 format here + if (result->freeImageFormat != FIF_MP4) { + result->containerVersion = ContainerVersion_TEXB0003; + } + } else if (strncmp (magic, "TEXB0003", 9) == 0) { + result->containerVersion = ContainerVersion_TEXB0003; + result->freeImageFormat = parseFIF (file.nextUInt32 ()); + } else if (strncmp (magic, "TEXB0002", 9) == 0) { + result->containerVersion = ContainerVersion_TEXB0002; + } else if (strncmp (magic, "TEXB0001", 9) == 0) { + result->containerVersion = ContainerVersion_TEXB0001; + } else { + sLog.exception ("unknown texture format type: ", std::string_view (magic, 9)); + } + + for (uint32_t image = 0; image < result->imageCount; image++) { + uint32_t mipmapCount = file.nextUInt32 (); + MipmapList mipmaps; + + for (uint32_t mipmap = 0; mipmap < mipmapCount; mipmap++) { + mipmaps.emplace_back (parseMipmap (file, *result)); + } + + result->images.emplace (image, mipmaps); + } + + if (!result->isAnimated ()) { + return result; + } + + // image is animated, keep parsing the rest of the image info + file.next (magic, 9); + + if (strncmp (magic, "TEXS0002", 9) == 0) { + result->animatedVersion = AnimatedVersion_TEXS0002; + } else if (strncmp (magic, "TEXS0003", 9) == 0) { + result->animatedVersion = AnimatedVersion_TEXS0003; + } else { + sLog.exception ("found animation information of unknown type: ", std::string_view (magic, 9)); + } + + uint32_t frameCount = file.nextUInt32 (); + + if (result->animatedVersion == AnimatedVersion_TEXS0003) { + result->gifWidth = file.nextUInt32 (); + result->gifHeight = file.nextUInt32 (); + } + + while (frameCount-- > 0) { + result->frames.push_back (parseFrame (file, *result)); + } + + // ensure gif width and height is right for TEXS0002 + if (result->animatedVersion == AnimatedVersion_TEXS0002) { + result->gifWidth = (*result->frames.begin ())->width1; + result->gifHeight = (*result->frames.begin ())->height1; + } + + return result; +} + +MipmapSharedPtr TextureParser::parseMipmap (BinaryReader& file, Texture& header) { + auto result = std::make_shared (); + + // TEXB0004 has some extra data in the header that has to be handled + if (header.containerVersion == ContainerVersion_TEXB0004) { + // some integers that we can ignore as they only seem to affect + // the editor + file.nextUInt32 (); + file.nextUInt32 (); + // this format includes some json in the header that we might need + // to parse at some point... + result->json = file.nextNullTerminatedString (); + // last ignorable integer + file.nextUInt32 (); + } + + result->width = file.nextUInt32 (); + result->height = file.nextUInt32 (); + + if (header.containerVersion == ContainerVersion_TEXB0004 || + header.containerVersion == ContainerVersion_TEXB0003 || + header.containerVersion == ContainerVersion_TEXB0002) { + result->compression = file.nextUInt32 (); + result->uncompressedSize = file.nextInt (); + } + + result->compressedSize = file.nextInt (); + + if (result->compression == 0) { + // this might be better named as mipmap_bytes_size instead of compressedSize + // as in uncompressed files this variable actually holds the file length + result->uncompressedSize = result->compressedSize; + } + + result->uncompressedData = std::unique_ptr (new char [result->uncompressedSize]); + + if (result->compression == 1) { + result->compressedData = std::unique_ptr (new char [result->compressedSize]); + // read the compressed data into the buffer + file.next (result->compressedData.get (), result->compressedSize); + // finally decompress it + int bytes = LZ4_decompress_safe ( + result->compressedData.get (), result->uncompressedData.get (), result->compressedSize, + result->uncompressedSize + ); + + if (bytes < 0) + sLog.exception ("Cannot decompress texture data, LZ4_decompress_safe returned an error"); + } else { + file.next (result->uncompressedData.get (), result->uncompressedSize); + } + + return result; +} + +FrameSharedPtr TextureParser::parseFrame (BinaryReader& file, Texture& header) { + auto result = std::make_shared (); + + result->frameNumber = file.nextUInt32 (); + result->frametime = file.nextFloat (); + result->x = file.nextFloat (); + result->y = file.nextFloat (); + result->width1 = file.nextFloat (); + result->width2 = file.nextFloat (); + result->height2 = file.nextFloat (); + result->height1 = file.nextFloat (); + + return result; +} + +TextureFormat TextureParser::parseTextureFormat (uint32_t value) { + switch (value) { + case TextureFormat_UNKNOWN: + case TextureFormat_ARGB8888: + case TextureFormat_RGB888: + case TextureFormat_RGB565: + case TextureFormat_DXT5: + case TextureFormat_DXT3: + case TextureFormat_DXT1: + case TextureFormat_RG88: + case TextureFormat_R8: + case TextureFormat_RG1616f: + case TextureFormat_R16f: + case TextureFormat_BC7: + case TextureFormat_RGBa1010102: + case TextureFormat_RGBA16161616f: + case TextureFormat_RGB161616f: + return static_cast (value); + + default: + sLog.exception ("unknown texture format: ", value); + } +} + +uint32_t TextureParser::parseTextureFlags (uint32_t value) { + if (value < TextureFlags_All) { + return value; + } + + sLog.exception ("unknown texture flags: ", value); +} + +FIF TextureParser::parseFIF (uint32_t value) { + switch (value) { + case FIF_UNKNOWN: + case FIF_BMP: + case FIF_ICO: + case FIF_JPEG: + case FIF_JNG: + case FIF_KOALA: + case FIF_LBM: + case FIF_MNG: + case FIF_PBM: + case FIF_PBMRAW: + case FIF_PCD: + case FIF_PCX: + case FIF_PGM: + case FIF_PGMRAW: + case FIF_PNG: + case FIF_PPM: + case FIF_PPMRAW: + case FIF_RAS: + case FIF_TARGA: + case FIF_TIFF: + case FIF_WBMP: + case FIF_PSD: + case FIF_CUT: + case FIF_XBM: + case FIF_XPM: + case FIF_DDS: + case FIF_GIF: + case FIF_HDR: + case FIF_FAXG3: + case FIF_SGI: + case FIF_EXR: + case FIF_J2K: + case FIF_JP2: + case FIF_PFM: + case FIF_PICT: + case FIF_RAW: + case FIF_WEBP: + case FIF_JXR: + return static_cast (value); + + default: + sLog.exception ("unknown free image format: ", value); + } +} \ No newline at end of file diff --git a/src/WallpaperEngine/Data/Parsers/TextureParser.h b/src/WallpaperEngine/Data/Parsers/TextureParser.h new file mode 100644 index 0000000..f1b7b19 --- /dev/null +++ b/src/WallpaperEngine/Data/Parsers/TextureParser.h @@ -0,0 +1,25 @@ +#pragma once + +#include "WallpaperEngine/Data/Assets/Texture.h" + +#include + +#include "WallpaperEngine/Data/Model/Types.h" +#include "WallpaperEngine/Data/Utils/BinaryReader.h" + +namespace WallpaperEngine::Data::Parsers { +using namespace WallpaperEngine::Data::Utils; +using namespace WallpaperEngine::Data::Assets; + +class TextureParser { + public: + static TextureUniquePtr parse (BinaryReader& file); + static MipmapSharedPtr parseMipmap (BinaryReader& file, Texture& header); + static FrameSharedPtr parseFrame (BinaryReader& file, Texture& header); + + private: + static TextureFormat parseTextureFormat (uint32_t value); + static uint32_t parseTextureFlags (uint32_t value); + static FIF parseFIF (uint32_t value); +}; +} \ No newline at end of file diff --git a/src/WallpaperEngine/Data/Utils/BinaryReader.cpp b/src/WallpaperEngine/Data/Utils/BinaryReader.cpp new file mode 100644 index 0000000..9c87d31 --- /dev/null +++ b/src/WallpaperEngine/Data/Utils/BinaryReader.cpp @@ -0,0 +1,63 @@ +#include + +#include "BinaryReader.h" + +#include + +using namespace WallpaperEngine::Data::Utils; + +BinaryReader::BinaryReader (std::istream& file) : m_input (file) { } + +uint32_t BinaryReader::nextUInt32 () { + char buffer[4]; + + this->m_input.read (buffer, 4); + + return (buffer [3] & 0xFF) << 24 | + (buffer [2] & 0xFF) << 16 | + (buffer [1] & 0xFF) << 8 | + (buffer [0] & 0xFF); +} + +int BinaryReader::nextInt () { + char buffer[4]; + + this->m_input.read (buffer, 4); + + return (buffer [3] & 0xFF) << 24 | + (buffer [2] & 0xFF) << 16 | + (buffer [1] & 0xFF) << 8 | + (buffer [0] & 0xFF); +} + + +float BinaryReader::nextFloat () { + float result {}; + uint32_t bytes = this->nextUInt32 (); + + memcpy (&result, &bytes, sizeof (result)); + + return result; +} + + +std::string BinaryReader::nextNullTerminatedString () { + std::string output; + + while (const auto c = this->next ()) { + output += c; + } + + return output; +} + +void BinaryReader::next (char* out, size_t size) { + this->m_input.read (out, size); +} + +char BinaryReader::next () { + char buffer; + this->m_input.read (&buffer, 1); + return buffer; +} + diff --git a/src/WallpaperEngine/Data/Utils/BinaryReader.h b/src/WallpaperEngine/Data/Utils/BinaryReader.h new file mode 100644 index 0000000..3af526a --- /dev/null +++ b/src/WallpaperEngine/Data/Utils/BinaryReader.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace WallpaperEngine::Data::Utils { +class BinaryReader { + public: + explicit BinaryReader (std::istream& file); + + uint32_t nextUInt32 (); + int nextInt (); + float nextFloat (); + std::string nextNullTerminatedString (); + void next(char* out, size_t size); + char next (); + + private: + std::istream& m_input; +}; +} diff --git a/src/WallpaperEngine/Data/Utils/MemoryStream.h b/src/WallpaperEngine/Data/Utils/MemoryStream.h new file mode 100644 index 0000000..36fbcc0 --- /dev/null +++ b/src/WallpaperEngine/Data/Utils/MemoryStream.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace WallpaperEngine::Data::Utils { +struct MemoryStream : std::streambuf +{ + MemoryStream (char* p, size_t size) + { + this->setg(p, p, p + size); // set start end end pointers + } +}; +} \ No newline at end of file diff --git a/src/WallpaperEngine/Render/CFBO.cpp b/src/WallpaperEngine/Render/CFBO.cpp index d345164..1605c1c 100644 --- a/src/WallpaperEngine/Render/CFBO.cpp +++ b/src/WallpaperEngine/Render/CFBO.cpp @@ -3,7 +3,7 @@ using namespace WallpaperEngine::Render; -CFBO::CFBO (std::string name, ITexture::TextureFormat format, ITexture::TextureFlags flags, float scale, +CFBO::CFBO (std::string name, TextureFormat format, uint32_t flags, float scale, uint32_t realWidth, uint32_t realHeight, uint32_t textureWidth, uint32_t textureHeight) : m_scale (scale), m_name (std::move (name)), @@ -25,10 +25,10 @@ CFBO::CFBO (std::string name, ITexture::TextureFormat format, ITexture::TextureF glObjectLabel (GL_TEXTURE, this->m_texture, -1, this->m_name.c_str ()); #endif /* DEBUG */ // set filtering parameters, otherwise the texture is not rendered - if (flags & TextureFlags::ClampUVs) { + if (flags & TextureFlags_ClampUVs) { glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } else if (flags & TextureFlags::ClampUVsBorder) { + } else if (flags & TextureFlags_ClampUVsBorder) { glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); } else { @@ -36,7 +36,7 @@ CFBO::CFBO (std::string name, ITexture::TextureFormat format, ITexture::TextureF glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } - if (flags & TextureFlags::NoInterpolation) { + if (flags & TextureFlags_NoInterpolation) { glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } else { @@ -61,7 +61,7 @@ CFBO::CFBO (std::string name, ITexture::TextureFormat format, ITexture::TextureF this->m_resolution = {textureWidth, textureHeight, realWidth, realHeight}; // create the textureframe entries - auto frame = std::make_shared (); + auto frame = std::make_shared (); frame->frameNumber = 0; frame->frametime = 0; @@ -89,11 +89,11 @@ const float& CFBO::getScale () const { return this->m_scale; } -ITexture::TextureFormat CFBO::getFormat () const { +TextureFormat CFBO::getFormat () const { return this->m_format; } -ITexture::TextureFlags CFBO::getFlags () const { +uint32_t CFBO::getFlags () const { return this->m_flags; } @@ -125,7 +125,7 @@ uint32_t CFBO::getRealHeight () const { return this->m_resolution.w; } -const std::vector>& CFBO::getFrames () const { +const std::vector& CFBO::getFrames () const { return this->m_frames; } diff --git a/src/WallpaperEngine/Render/CFBO.h b/src/WallpaperEngine/Render/CFBO.h index 9d62be0..d8e7165 100644 --- a/src/WallpaperEngine/Render/CFBO.h +++ b/src/WallpaperEngine/Render/CFBO.h @@ -9,7 +9,7 @@ using namespace WallpaperEngine::Assets; namespace WallpaperEngine::Render { class CFBO final : public ITexture { public: - CFBO (std::string name, ITexture::TextureFormat format, ITexture::TextureFlags flags, float scale, + CFBO (std::string name, TextureFormat format, uint32_t flags, float scale, uint32_t realWidth, uint32_t realHeight, uint32_t textureWidth, uint32_t textureHeight); ~CFBO () override; @@ -17,8 +17,8 @@ class CFBO final : public ITexture { [[nodiscard]] const std::string& getName () const; [[nodiscard]] const float& getScale () const; - [[nodiscard]] ITexture::TextureFormat getFormat () const override; - [[nodiscard]] ITexture::TextureFlags getFlags () const override; + [[nodiscard]] TextureFormat getFormat () const override; + [[nodiscard]] uint32_t getFlags () const override; [[nodiscard]] GLuint getFramebuffer () const; [[nodiscard]] GLuint getDepthbuffer () const; [[nodiscard]] GLuint getTextureID (uint32_t imageIndex) const override; @@ -26,7 +26,7 @@ class CFBO final : public ITexture { [[nodiscard]] uint32_t getTextureHeight (uint32_t imageIndex) const override; [[nodiscard]] uint32_t getRealWidth () const override; [[nodiscard]] uint32_t getRealHeight () const override; - [[nodiscard]] const std::vector>& getFrames () const override; + [[nodiscard]] const std::vector& getFrames () const override; [[nodiscard]] const glm::vec4* getResolution () const override; [[nodiscard]] bool isAnimated () const override; @@ -37,9 +37,9 @@ class CFBO final : public ITexture { glm::vec4 m_resolution = {}; float m_scale = 0; std::string m_name = ""; - ITexture::TextureFormat m_format = UNKNOWN; - ITexture::TextureFlags m_flags = NoFlags; + TextureFormat m_format = TextureFormat_UNKNOWN; + uint32_t m_flags = TextureFlags_NoFlags; /** Placeholder for frames, FBOs only have ONE */ - std::vector> m_frames = {}; + std::vector m_frames = {}; }; } // namespace WallpaperEngine::Render diff --git a/src/WallpaperEngine/Render/CFBOProvider.cpp b/src/WallpaperEngine/Render/CFBOProvider.cpp index 4b9c3bf..4de1990 100644 --- a/src/WallpaperEngine/Render/CFBOProvider.cpp +++ b/src/WallpaperEngine/Render/CFBOProvider.cpp @@ -9,11 +9,11 @@ CFBOProvider::CFBOProvider (const CFBOProvider* parent) : m_parent (parent) {} -std::shared_ptr CFBOProvider::create(const FBO& base, ITexture::TextureFlags flags, glm::vec2 size) { +std::shared_ptr CFBOProvider::create(const FBO& base, uint32_t flags, glm::vec2 size) { return this->m_fbos[base.name] = std::make_shared ( base.name, // TODO: PROPERLY DETERMINE FBO FORMAT BASED ON THE STRING - ITexture::TextureFormat::ARGB8888, + TextureFormat_ARGB8888, flags, base.scale, size.x / base.scale, @@ -24,12 +24,12 @@ std::shared_ptr CFBOProvider::create(const FBO& base, ITexture::TextureFla } std::shared_ptr CFBOProvider::create ( - const std::string& name, ITexture::TextureFormat format, ITexture::TextureFlags flags, float scale, + const std::string& name, TextureFormat format, uint32_t flags, float scale, glm::vec2 realSize, glm::vec2 textureSize ) { return this->m_fbos[name] = std::make_shared ( name, - ITexture::TextureFormat::ARGB8888, + TextureFormat_ARGB8888, flags, scale, realSize.x, diff --git a/src/WallpaperEngine/Render/CFBOProvider.h b/src/WallpaperEngine/Render/CFBOProvider.h index 027ca55..e65eb97 100644 --- a/src/WallpaperEngine/Render/CFBOProvider.h +++ b/src/WallpaperEngine/Render/CFBOProvider.h @@ -12,9 +12,9 @@ class CFBOProvider { public: CFBOProvider (const CFBOProvider* parent); - std::shared_ptr create (const FBO& base, ITexture::TextureFlags flags, glm::vec2 size); + std::shared_ptr create (const FBO& base, uint32_t flags, glm::vec2 size); std::shared_ptr create ( - const std::string& name, ITexture::TextureFormat format, ITexture::TextureFlags flags, float scale, + const std::string& name, TextureFormat format, uint32_t flags, float scale, glm::vec2 realSize, glm::vec2 textureSize); std::shared_ptr alias (const std::string& newName, const std::string& original); [[nodiscard]] std::shared_ptr find (const std::string& name) const; diff --git a/src/WallpaperEngine/Render/CWallpaper.cpp b/src/WallpaperEngine/Render/CWallpaper.cpp index b8da029..05af66c 100644 --- a/src/WallpaperEngine/Render/CWallpaper.cpp +++ b/src/WallpaperEngine/Render/CWallpaper.cpp @@ -15,7 +15,7 @@ using namespace WallpaperEngine::Render; CWallpaper::CWallpaper ( const Wallpaper& wallpaperData, CRenderContext& context,CAudioContext& audioContext, const CWallpaperState::TextureUVsScaling& scalingMode, - const WallpaperEngine::Assets::ITexture::TextureFlags& clampMode + const uint32_t& clampMode ) : CContextAware (context), CFBOProvider (nullptr), @@ -245,11 +245,11 @@ void CWallpaper::setPause (bool newState) {} void CWallpaper::setupFramebuffers () { const uint32_t width = this->getWidth (); const uint32_t height = this->getHeight (); - const ITexture::TextureFlags clamp = this->m_state.getClampingMode (); + const uint32_t clamp = this->m_state.getClampingMode (); // create framebuffer for the scene this->m_sceneFBO = this->create ( - "_rt_FullFrameBuffer", ITexture::TextureFormat::ARGB8888, clamp, 1.0, {width, + "_rt_FullFrameBuffer", TextureFormat_ARGB8888, clamp, 1.0, {width, height}, {width, height}); this->alias ("_rt_MipMappedFrameBuffer", "_rt_FullFrameBuffer"); @@ -275,17 +275,22 @@ std::shared_ptr CWallpaper::getFBO () const { std::unique_ptr CWallpaper::fromWallpaper ( const Wallpaper& wallpaper, CRenderContext& context, CAudioContext& audioContext, WebBrowser::CWebBrowserContext* browserContext, const CWallpaperState::TextureUVsScaling& scalingMode, - const WallpaperEngine::Assets::ITexture::TextureFlags& clampMode + const uint32_t& clampMode ) { if (wallpaper.is ()) { return std::make_unique ( wallpaper, context, audioContext, scalingMode, clampMode); - } else if (wallpaper.is