diff --git a/include/vtfpp/PVR.h b/include/vtfpp/PVR.h new file mode 100644 index 00000000..85651708 --- /dev/null +++ b/include/vtfpp/PVR.h @@ -0,0 +1,89 @@ +#pragma once + +#include +#include + +#include +#include +#include + +#include "ImageConversion.h" + +namespace vtfpp { + +constexpr uint32_t GBIX_SIGNATURE = sourcepp::parser::binary::makeFourCC("GBIX"); +constexpr uint32_t PVR_SIGNATURE = sourcepp::parser::binary::makeFourCC("PVRT"); + +class PVR { +public: + enum ImageType : uint8_t { + IMAGE_TYPE_NONE = 0, + IMAGE_TYPE_TWIDDLED = 1, + IMAGE_TYPE_TWIDDLED_MM = 2, + IMAGE_TYPE_VQ = 3, + IMAGE_TYPE_VQ_MM = 4, + IMAGE_TYPE_PAL4 = 5, + IMAGE_TYPE_PAL4_MM = 6, + IMAGE_TYPE_PAL8 = 7, + IMAGE_TYPE_PAL8_MM = 8, + IMAGE_TYPE_RECTANGULAR = 9, + IMAGE_TYPE_RECTANGULAR_MM = 10, + IMAGE_TYPE_STRIDE = 11, + IMAGE_TYPE_STRIDE_MM = 12, + IMAGE_TYPE_RECTANGULAR_TWIDDLED = 13, + IMAGE_TYPE_BMP = 14, + IMAGE_TYPE_BMP_MM = 15, + IMAGE_TYPE_SMALLVQ = 16, + IMAGE_TYPE_SMALLVQ_MM = 17 + }; + enum PixelType : uint8_t { + PIXEL_TYPE_ARGB1555 = 0, + PIXEL_TYPE_RGB565 = 1, + PIXEL_TYPE_ARGB4444 = 2, + PIXEL_TYPE_YUV422 = 3, + PIXEL_TYPE_BUMP = 4, + PIXEL_TYPE_RGB555 = 5, + PIXEL_TYPE_YUV420 = 6 + }; + + explicit PVR(std::span pvrData); + + explicit PVR(const std::filesystem::path& pvrPath); + + [[nodiscard]] explicit operator bool() const; + + [[nodiscard]] uint16_t getWidth() const; + + [[nodiscard]] uint16_t getHeight() const; + + [[nodiscard]] bool hasImageData() const; + + [[nodiscard]] bool hasMips() const; + + [[nodiscard]] bool isTwiddled() const; + + [[nodiscard]] bool isPaletted() const; + + [[nodiscard]] ImageFormat getFormat() const; + + [[nodiscard]] uint8_t getMipCount() const; + + [[nodiscard]] std::span getImageDataRaw(uint8_t mip = 0) const; + + [[nodiscard]] std::span getImageDataRaw(uint8_t mip = 0); + + [[nodiscard]] std::vector getImageDataAs(ImageFormat newFormat, uint8_t mip = 0) const; + + [[nodiscard]] std::vector getImageDataAsRGBA8888(uint8_t mip = 0) const; + +protected: + std::span imageData; + uint16_t width = 0; + uint16_t height = 0; + ImageType imageType = IMAGE_TYPE_NONE; + PixelType pixelType = PIXEL_TYPE_ARGB1555; + ImageFormat format = ImageFormat::EMPTY; + uint8_t mipCount = 1; +}; + +} // namespace vtfpp diff --git a/include/vtfpp/vtfpp.h b/include/vtfpp/vtfpp.h index 2731ba49..ff0db2a8 100644 --- a/include/vtfpp/vtfpp.h +++ b/include/vtfpp/vtfpp.h @@ -13,6 +13,7 @@ #include "ImageQuantize.h" #include "PPL.h" #include "PSFrames.h" +#include "PVR.h" #include "SHT.h" #include "TTX.h" #include "VBF.h" diff --git a/src/vtfpp/PVR.cpp b/src/vtfpp/PVR.cpp new file mode 100644 index 00000000..d3a42d53 --- /dev/null +++ b/src/vtfpp/PVR.cpp @@ -0,0 +1,179 @@ +#include + +#include + +#include +#include + +using namespace sourcepp; +using namespace vtfpp; + +PVR::PVR(std::span pvrData) { + BufferStreamReadOnly stream{pvrData}; + + // skip GBIX ("global index") chunk found in many examples + if (stream.read() == GBIX_SIGNATURE) { + uint32_t len = stream.read(); + stream.skip(len); + } + + if (stream.read() != PVR_SIGNATURE) { + return; + } + + auto len = stream.read(); + auto type = stream.read(); + + this->imageType = static_cast(type & 0xFF00 >> 8); + this->pixelType = static_cast(type & 0xFF); + + stream >> this->width; + stream >> this->height; + + if (this->hasMips()) { + this->mipCount = 4; + } + + switch (this->pixelType) { + case PIXEL_TYPE_ARGB1555: + break; + case PIXEL_TYPE_RGB565: + this->format = ImageFormat::RGB565; + break; + case PIXEL_TYPE_ARGB4444: + break; + case PIXEL_TYPE_YUV422: + break; + case PIXEL_TYPE_BUMP: + break; + case PIXEL_TYPE_RGB555: + break; + case PIXEL_TYPE_YUV420: + break; + } + + switch (this->imageType) { + case IMAGE_TYPE_NONE: + break; + case IMAGE_TYPE_TWIDDLED: + break; + case IMAGE_TYPE_TWIDDLED_MM: + break; + case IMAGE_TYPE_VQ: + break; + case IMAGE_TYPE_VQ_MM: + break; + case IMAGE_TYPE_PAL4: + break; + case IMAGE_TYPE_PAL4_MM: + break; + case IMAGE_TYPE_PAL8: + break; + case IMAGE_TYPE_PAL8_MM: + break; + case IMAGE_TYPE_RECTANGULAR: + break; + case IMAGE_TYPE_RECTANGULAR_MM: + break; + case IMAGE_TYPE_STRIDE: + break; + case IMAGE_TYPE_STRIDE_MM: + break; + case IMAGE_TYPE_RECTANGULAR_TWIDDLED: + break; + case IMAGE_TYPE_BMP: + break; + case IMAGE_TYPE_BMP_MM: + break; + case IMAGE_TYPE_SMALLVQ: + break; + case IMAGE_TYPE_SMALLVQ_MM: + break; + } +} + +PVR::PVR(const std::filesystem::path& pvrPath) + : PVR(fs::readFileBuffer(pvrPath)) {} + +PVR::operator bool() const { + return this->format != ImageFormat::EMPTY && this->width > 0 && this->height > 0; +} + +uint16_t PVR::getWidth() const { + return this->width; +} + +uint16_t PVR::getHeight() const { + return this->height; +} + +bool PVR::hasImageData() const { + return this->format != ImageFormat::EMPTY && this->width > 0 && this->height > 0; +} + +bool PVR::hasMips() const { + return this->imageType == IMAGE_TYPE_TWIDDLED_MM || + this->imageType == IMAGE_TYPE_VQ_MM || + this->imageType == IMAGE_TYPE_PAL4_MM || + this->imageType == IMAGE_TYPE_PAL8_MM || + this->imageType == IMAGE_TYPE_RECTANGULAR_MM || + this->imageType == IMAGE_TYPE_STRIDE_MM || + this->imageType == IMAGE_TYPE_BMP_MM || + this->imageType == IMAGE_TYPE_SMALLVQ_MM; +} + +bool PVR::isTwiddled() const { + return this->imageType == IMAGE_TYPE_TWIDDLED || + this->imageType == IMAGE_TYPE_TWIDDLED_MM || + this->imageType == IMAGE_TYPE_RECTANGULAR_TWIDDLED; +} + +bool PVR::isPaletted() const { + return this->imageType == IMAGE_TYPE_PAL4 || + this->imageType == IMAGE_TYPE_PAL4_MM || + this->imageType == IMAGE_TYPE_PAL8 || + this->imageType == IMAGE_TYPE_PAL8_MM; +} + +ImageFormat PVR::getFormat() const { + return this->format; +} + +uint8_t PVR::getMipCount() const { + return this->mipCount; +} + +std::span PVR::getImageDataRaw(uint8_t mip) const { + if (uint32_t offset, length; ImageFormatDetails::getDataPosition(offset, length, this->format, mip, this->mipCount, 0, 1, 0, 1, this->width, this->height, 0, 1)) { + return this->imageData.subspan(offset, length); + } + return {}; +} + +std::span PVR::getImageDataRaw(uint8_t mip) { + if (uint32_t offset, length; ImageFormatDetails::getDataPosition(offset, length, this->format, mip, this->mipCount, 0, 1, 0, 1, this->width, this->height, 0, 1)) { + return this->imageData.subspan(offset, length); + } + return {}; +} + +std::vector PVR::getImageDataAs(ImageFormat newFormat, uint8_t mip) const { + const auto rawImageData = this->getImageDataRaw(mip); + if (rawImageData.empty()) { + return {}; + } +#if 0 + if (this->format == ImageFormat::P8) { + if (const auto paletteData = this->getPaletteResourceFrame(frame); !paletteData.empty()) { + const auto [mipWidth, mipHeight] = ImageDimensions::getMipDims(mip, this->width, this->height); + return ImageConversion::convertImageDataToFormat(ImageQuantize::convertP8ImageDataToBGRA8888(paletteData, rawImageData), ImageFormat::BGRA8888, newFormat, mipWidth, mipHeight); + } + } +#endif + const auto [mipWidth, mipHeight] = ImageDimensions::getMipDims(mip, this->width, this->height); + return ImageConversion::convertImageDataToFormat(rawImageData, this->format, newFormat, mipWidth, mipHeight); +} + +std::vector PVR::getImageDataAsRGBA8888(uint8_t mip) const { + return this->getImageDataAs(ImageFormat::RGBA8888, mip); +} diff --git a/src/vtfpp/_vtfpp.cmake b/src/vtfpp/_vtfpp.cmake index 9735c203..4f1af4e2 100644 --- a/src/vtfpp/_vtfpp.cmake +++ b/src/vtfpp/_vtfpp.cmake @@ -1,47 +1,48 @@ -add_pretty_parser(vtfpp - DEPS bcdec libzstd_static miniz sourcepp_compression sourcepp_parser sourcepp_stb - PRECOMPILED_HEADERS - "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/DistanceMapping.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/HOT.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/ImageConversion.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/ImageFormats.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/ImagePixel.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/ImageQuantize.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/PPL.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/PSFrames.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/SHT.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/TTX.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/VBF.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/VTF.h" - "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/vtfpp.h" - SOURCES - "${CMAKE_CURRENT_LIST_DIR}/DistanceMapping.cpp" - "${CMAKE_CURRENT_LIST_DIR}/HOT.cpp" - "${CMAKE_CURRENT_LIST_DIR}/ImageConversion.cpp" - "${CMAKE_CURRENT_LIST_DIR}/ImageQuantize.cpp" - "${CMAKE_CURRENT_LIST_DIR}/PPL.cpp" - "${CMAKE_CURRENT_LIST_DIR}/PSFrames.cpp" - "${CMAKE_CURRENT_LIST_DIR}/SHT.cpp" - "${CMAKE_CURRENT_LIST_DIR}/TTX.cpp" - "${CMAKE_CURRENT_LIST_DIR}/VBF.cpp" - "${CMAKE_CURRENT_LIST_DIR}/VTF.cpp") - -sourcepp_add_tbb(sourcepp_vtfpp) -sourcepp_add_threads(sourcepp_vtfpp) - -if(SOURCEPP_VTFPP_BUILD_WITH_COMPRESSONATOR) - target_link_libraries(sourcepp_vtfpp PRIVATE CMP_Compressonator) - target_compile_definitions(sourcepp_vtfpp PUBLIC VTFPP_BUILD_WITH_COMPRESSONATOR) -endif() -if(SOURCEPP_VTFPP_SUPPORT_EXR) - target_link_libraries(sourcepp_vtfpp PRIVATE tinyexr) - target_compile_definitions(sourcepp_vtfpp PUBLIC VTFPP_SUPPORT_EXR) -endif() -if(SOURCEPP_VTFPP_SUPPORT_QOI) - target_link_libraries(sourcepp_vtfpp PRIVATE qoi) - target_compile_definitions(sourcepp_vtfpp PUBLIC VTFPP_SUPPORT_QOI) -endif() -if(SOURCEPP_VTFPP_SUPPORT_WEBP) - target_link_libraries(sourcepp_vtfpp PRIVATE webp) - target_compile_definitions(sourcepp_vtfpp PUBLIC VTFPP_SUPPORT_WEBP) -endif() +add_pretty_parser(vtfpp + DEPS bcdec libzstd_static miniz sourcepp_compression sourcepp_parser sourcepp_stb + PRECOMPILED_HEADERS + "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/DistanceMapping.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/HOT.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/ImageConversion.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/ImageFormats.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/ImagePixel.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/ImageQuantize.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/PPL.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/PSFrames.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/SHT.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/TTX.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/VBF.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/VTF.h" + "${CMAKE_CURRENT_SOURCE_DIR}/include/vtfpp/vtfpp.h" + SOURCES + "${CMAKE_CURRENT_LIST_DIR}/DistanceMapping.cpp" + "${CMAKE_CURRENT_LIST_DIR}/HOT.cpp" + "${CMAKE_CURRENT_LIST_DIR}/ImageConversion.cpp" + "${CMAKE_CURRENT_LIST_DIR}/ImageQuantize.cpp" + "${CMAKE_CURRENT_LIST_DIR}/PPL.cpp" + "${CMAKE_CURRENT_LIST_DIR}/PSFrames.cpp" + "${CMAKE_CURRENT_LIST_DIR}/PVR.cpp" + "${CMAKE_CURRENT_LIST_DIR}/SHT.cpp" + "${CMAKE_CURRENT_LIST_DIR}/TTX.cpp" + "${CMAKE_CURRENT_LIST_DIR}/VBF.cpp" + "${CMAKE_CURRENT_LIST_DIR}/VTF.cpp") + +sourcepp_add_tbb(sourcepp_vtfpp) +sourcepp_add_threads(sourcepp_vtfpp) + +if(SOURCEPP_VTFPP_BUILD_WITH_COMPRESSONATOR) + target_link_libraries(sourcepp_vtfpp PRIVATE CMP_Compressonator) + target_compile_definitions(sourcepp_vtfpp PUBLIC VTFPP_BUILD_WITH_COMPRESSONATOR) +endif() +if(SOURCEPP_VTFPP_SUPPORT_EXR) + target_link_libraries(sourcepp_vtfpp PRIVATE tinyexr) + target_compile_definitions(sourcepp_vtfpp PUBLIC VTFPP_SUPPORT_EXR) +endif() +if(SOURCEPP_VTFPP_SUPPORT_QOI) + target_link_libraries(sourcepp_vtfpp PRIVATE qoi) + target_compile_definitions(sourcepp_vtfpp PUBLIC VTFPP_SUPPORT_QOI) +endif() +if(SOURCEPP_VTFPP_SUPPORT_WEBP) + target_link_libraries(sourcepp_vtfpp PRIVATE webp) + target_compile_definitions(sourcepp_vtfpp PUBLIC VTFPP_SUPPORT_WEBP) +endif()