Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions include/vtfpp/PVR.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#pragma once

#include <array>
#include <filesystem>

#include <sourcepp/parser/Binary.h>
#include <sourcepp/Macros.h>
#include <sourcepp/Math.h>

#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<const std::byte> 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<const std::byte> getImageDataRaw(uint8_t mip = 0) const;

[[nodiscard]] std::span<std::byte> getImageDataRaw(uint8_t mip = 0);

[[nodiscard]] std::vector<std::byte> getImageDataAs(ImageFormat newFormat, uint8_t mip = 0) const;

[[nodiscard]] std::vector<std::byte> getImageDataAsRGBA8888(uint8_t mip = 0) const;

protected:
std::span<std::byte> 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
1 change: 1 addition & 0 deletions include/vtfpp/vtfpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
179 changes: 179 additions & 0 deletions src/vtfpp/PVR.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
#include <vtfpp/PVR.h>

#include <vector>

#include <BufferStream.h>
#include <sourcepp/FS.h>

using namespace sourcepp;
using namespace vtfpp;

PVR::PVR(std::span<const std::byte> pvrData) {
BufferStreamReadOnly stream{pvrData};

// skip GBIX ("global index") chunk found in many examples
if (stream.read<uint32_t>() == GBIX_SIGNATURE) {
uint32_t len = stream.read<uint32_t>();
stream.skip(len);
}

if (stream.read<uint32_t>() != PVR_SIGNATURE) {
return;
}

auto len = stream.read<uint32_t>();
auto type = stream.read<uint32_t>();

this->imageType = static_cast<PVR::ImageType>(type & 0xFF00 >> 8);
this->pixelType = static_cast<PVR::PixelType>(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<const std::byte> 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<std::byte> 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<std::byte> 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<std::byte> PVR::getImageDataAsRGBA8888(uint8_t mip) const {
return this->getImageDataAs(ImageFormat::RGBA8888, mip);
}
95 changes: 48 additions & 47 deletions src/vtfpp/_vtfpp.cmake
Original file line number Diff line number Diff line change
@@ -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()
Loading