Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ccc98bdf62 |
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,11 +1,8 @@
|
|||||||
# idea
|
# idea
|
||||||
.idea/
|
.idea/
|
||||||
cmake-build-*/
|
cmake-build-debug/
|
||||||
|
cmake-build-release/
|
||||||
# build(仅根目录,不影响 vendor/lz4/build 等子目录)
|
cmake-build-minsizerel/
|
||||||
/build/
|
|
||||||
|
|
||||||
compile_commands.json
|
|
||||||
|
|
||||||
# vs
|
# vs
|
||||||
.vs/
|
.vs/
|
||||||
|
|||||||
@ -2,31 +2,9 @@ cmake_minimum_required(VERSION 3.31)
|
|||||||
|
|
||||||
project(expkg)
|
project(expkg)
|
||||||
|
|
||||||
|
# set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
||||||
|
|
||||||
# 默认 Release 构建(Debug 模式下 GIF/PNG 编码慢 3-5 倍)
|
add_subdirectory(expkg)
|
||||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
add_subdirectory(testApp)
|
||||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# 第三方依赖
|
|
||||||
add_subdirectory(vendor/lz4/build/cmake)
|
|
||||||
|
|
||||||
# 源文件(CONFIGURE_DEPENDS: 文件增删时自动重新配置)
|
|
||||||
file(GLOB_RECURSE SRC_SOURCE CONFIGURE_DEPENDS src/*.cpp)
|
|
||||||
file(GLOB STB_SOURCE CONFIGURE_DEPENDS vendor/stb/*.cpp)
|
|
||||||
|
|
||||||
# 可执行文件
|
|
||||||
add_executable(${PROJECT_NAME} ${SRC_SOURCE} ${STB_SOURCE})
|
|
||||||
|
|
||||||
# MSVC 默认编码设为 UTF-8
|
|
||||||
if(MSVC)
|
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE /utf-8)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# 依赖与头文件路径
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE lz4)
|
|
||||||
target_include_directories(${PROJECT_NAME}
|
|
||||||
PRIVATE vendor/stb vendor/gif-h src
|
|
||||||
)
|
|
||||||
39
README.md
39
README.md
@ -1,12 +1,35 @@
|
|||||||
# exPKG
|
# exPKG
|
||||||
|
|
||||||
## useage
|
## useage
|
||||||
```bash
|
> ```c++
|
||||||
expkg /path/to/file.pkg|file.mpkg [output/path]
|
> #include "EXPKG/EXPKG.h"
|
||||||
```
|
>
|
||||||
|
> int main(int argc, char** argv) {
|
||||||
|
> CommandArgs args{ argc, argv};
|
||||||
|
>
|
||||||
|
> PKG::EXPKG decompress(args);
|
||||||
|
> PKG::EXPKG decompress("path/to/file");
|
||||||
|
> PKG::EXPKG decompress("path/to/file", "path/to/output/directory");
|
||||||
|
>
|
||||||
|
> return 0;
|
||||||
|
> }
|
||||||
|
>```
|
||||||
|
|
||||||
build
|
## Cmake
|
||||||
```bash
|
>
|
||||||
cmake -B build
|
> use as subdirectory
|
||||||
cmake --build build --config Release -j8
|
>
|
||||||
```
|
> ```cmake
|
||||||
|
> add_subdirectory(path/to/expkg)
|
||||||
|
>
|
||||||
|
>add_executable(${TARGET} ${SRC_SOURCE})
|
||||||
|
>target_link_libraries(${TARGET} expkg-static)
|
||||||
|
>
|
||||||
|
> # or use dll by
|
||||||
|
> # target_link_libraries(${TARGET} expkg-shared)
|
||||||
|
>```
|
||||||
|
> then
|
||||||
|
> ```bash
|
||||||
|
> cmake -B build
|
||||||
|
> cmake --build build --config Release -j8
|
||||||
|
>```
|
||||||
40
expkg/CMakeLists.txt
Normal file
40
expkg/CMakeLists.txt
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
set(TARGET expkg)
|
||||||
|
project(${TARGET})
|
||||||
|
|
||||||
|
add_subdirectory(vendor/lz4/build/cmake)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SRC_SOURCE src/**.cpp vendor/gif-h/gif.h)
|
||||||
|
|
||||||
|
file(GLOB STB_SOURCE vendor/stb/*.cpp)
|
||||||
|
|
||||||
|
# static
|
||||||
|
add_library(expkg-static STATIC
|
||||||
|
${SRC_SOURCE}
|
||||||
|
${STB_SOURCE}
|
||||||
|
)
|
||||||
|
target_link_libraries(expkg-static PRIVATE lz4)
|
||||||
|
|
||||||
|
target_include_directories(expkg-static PRIVATE vendor/stb vendor/gif-h)
|
||||||
|
|
||||||
|
target_include_directories(expkg-static PUBLIC src)
|
||||||
|
|
||||||
|
|
||||||
|
# shared
|
||||||
|
add_library(expkg-shared SHARED
|
||||||
|
${SRC_SOURCE}
|
||||||
|
${STB_SOURCE}
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(expkg-shared PROPERTIES
|
||||||
|
OUTPUT_NAME "expkg"
|
||||||
|
PREFIX ""
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(expkg-shared PRIVATE lz4)
|
||||||
|
target_compile_definitions(expkg-shared PRIVATE -DPKG_SHARED -DPKG_BUILD_DLL)
|
||||||
|
|
||||||
|
target_include_directories(expkg-shared PRIVATE vendor/stb vendor/gif-h)
|
||||||
|
|
||||||
|
target_include_directories(expkg-shared PUBLIC src)
|
||||||
|
|
||||||
|
|
||||||
97
expkg/src/BinaryOPT/BinaryReader.cpp
Normal file
97
expkg/src/BinaryOPT/BinaryReader.cpp
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-4.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "BinaryReader.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
BinaryReader::BinaryReader(const std::filesystem::path& fileName)
|
||||||
|
{
|
||||||
|
m_FilePath = fileName.string();
|
||||||
|
|
||||||
|
m_File.open(m_FilePath, std::ios::in | std::ios::binary);
|
||||||
|
if (!m_File.is_open())
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to open file " << m_FilePath << std::endl;
|
||||||
|
system("pause");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryReader::~BinaryReader()
|
||||||
|
{
|
||||||
|
if (m_File.is_open())
|
||||||
|
m_File.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32_t BinaryReader::ReadInt32()
|
||||||
|
{
|
||||||
|
int32_t result = 0;
|
||||||
|
m_File.read(reinterpret_cast<char*>(&result), sizeof(int32_t));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t BinaryReader::ReadUInt32()
|
||||||
|
{
|
||||||
|
uint32_t result = 0;
|
||||||
|
m_File.read(reinterpret_cast<char*>(&result), sizeof(uint32_t));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
float_t BinaryReader::ReadSingle()
|
||||||
|
{
|
||||||
|
float_t result = 0;
|
||||||
|
m_File.read(reinterpret_cast<char*>(&result), sizeof(float_t));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char BinaryReader::ReadChar()
|
||||||
|
{
|
||||||
|
char result;
|
||||||
|
m_File.read(&result, sizeof(char));
|
||||||
|
pos_type a = m_File.tellg();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BinaryReader::ReadData(std::string& data, const uint32_t length)
|
||||||
|
{
|
||||||
|
data.resize(length);
|
||||||
|
m_File.read(data.data(), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BinaryReader::ReadData(std::vector<uint8_t>& data, uint32_t length)
|
||||||
|
{
|
||||||
|
data.resize(length);
|
||||||
|
m_File.read(reinterpret_cast<char*>(data.data()), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BinaryReader::ReadString(const uint32_t length)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> result;
|
||||||
|
result.resize(length);
|
||||||
|
|
||||||
|
m_File.read(reinterpret_cast<char*>(result.data()), length);
|
||||||
|
return std::filesystem::u8path(std::string(reinterpret_cast<const char*>(result.data()), length)).string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BinaryReader::ReadNString(const int32_t maxLength)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> result;
|
||||||
|
result.resize(0);
|
||||||
|
int count = maxLength <= 0 ? 16 : maxLength;
|
||||||
|
|
||||||
|
char chr = ReadChar();
|
||||||
|
while (chr != '\0' && (maxLength == -1 || count <= maxLength))
|
||||||
|
{
|
||||||
|
result.push_back(chr);
|
||||||
|
chr = ReadChar();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string(reinterpret_cast<const char*>(result.data()), result.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
49
expkg/src/BinaryOPT/BinaryReader.h
Normal file
49
expkg/src/BinaryOPT/BinaryReader.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-4.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BINARYREADER_H
|
||||||
|
#define BINARYREADER_H
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Core.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
using pos_type = long long;
|
||||||
|
|
||||||
|
class PKG_API BinaryReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BinaryReader() = delete;
|
||||||
|
explicit BinaryReader(const std::filesystem::path& fileName);
|
||||||
|
~BinaryReader();
|
||||||
|
|
||||||
|
int32_t ReadInt32();
|
||||||
|
uint32_t ReadUInt32();
|
||||||
|
float_t ReadSingle();
|
||||||
|
char ReadChar();
|
||||||
|
std::string ReadString(uint32_t length);
|
||||||
|
std::string ReadNString(int32_t maxLength = -1);
|
||||||
|
void ReadData(std::string& data, uint32_t length);
|
||||||
|
void ReadData(std::vector<uint8_t>& data, uint32_t length);
|
||||||
|
|
||||||
|
void seekg(const pos_type pos) { m_File.seekg(pos); }
|
||||||
|
pos_type tellg() { return m_File.tellg(); }
|
||||||
|
|
||||||
|
std::string GetFilePath() const { return m_FilePath; }
|
||||||
|
std::string GetFileName() const { return m_FilePath.substr(m_FilePath.find_last_of("\\/") + 1); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::ifstream m_File;
|
||||||
|
|
||||||
|
std::string m_FilePath;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //BINARYREADER_H
|
||||||
47
expkg/src/BinaryOPT/BinaryWriter.cpp
Normal file
47
expkg/src/BinaryOPT/BinaryWriter.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-4.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "BinaryWriter.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
BinaryWriter::BinaryWriter(const std::filesystem::path& fileName, const std::ios_base::openmode optMode)
|
||||||
|
{
|
||||||
|
m_FilePath = fileName.string();
|
||||||
|
const std::filesystem::path path(fileName.parent_path());
|
||||||
|
|
||||||
|
m_File.open(m_FilePath, optMode);
|
||||||
|
if (!m_File.is_open() && !std::filesystem::exists(path))
|
||||||
|
{
|
||||||
|
std::filesystem::create_directories(path);
|
||||||
|
m_File.open(m_FilePath, optMode);
|
||||||
|
if (!m_File.is_open())
|
||||||
|
std::cerr << "cound not create file: " << m_FilePath << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryWriter::~BinaryWriter()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BinaryWriter::WriteBytes(const char* data, const uint32_t size)
|
||||||
|
{
|
||||||
|
m_File.write(data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BinaryWriter::WriteString(const std::string& str)
|
||||||
|
{
|
||||||
|
m_File.write(str.c_str(), str.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BinaryWriter::close()
|
||||||
|
{
|
||||||
|
if (!m_File.is_open())
|
||||||
|
m_File.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
38
expkg/src/BinaryOPT/BinaryWriter.h
Normal file
38
expkg/src/BinaryOPT/BinaryWriter.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-4.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef BINARYWRITER_H
|
||||||
|
#define BINARYWRITER_H
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "Core.h"
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
class PKG_API BinaryWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BinaryWriter() = delete;
|
||||||
|
explicit BinaryWriter(const std::filesystem::path& fileName, std::ios_base::openmode optMode = std::ios::out);
|
||||||
|
~BinaryWriter();
|
||||||
|
|
||||||
|
void WriteBytes(const char* data, uint32_t size);
|
||||||
|
void WriteString(const std::string& str);
|
||||||
|
|
||||||
|
std::string GetFilePath() const { return m_FilePath; }
|
||||||
|
std::string GetFileName() const { return m_FilePath.substr(m_FilePath.find_last_of("\\/") + 1); }
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::ofstream m_File;
|
||||||
|
std::string m_FilePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //BINARYWRITER_H
|
||||||
265
expkg/src/BinaryOPT/ImageReader.cpp
Normal file
265
expkg/src/BinaryOPT/ImageReader.cpp
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-5.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "ImageReader.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "lz4.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
std::vector<unsigned char> Lz4Decompress(const unsigned char* compressedData,
|
||||||
|
size_t compressedSize,
|
||||||
|
size_t decompressedSize)
|
||||||
|
{
|
||||||
|
// 准备输出缓冲区
|
||||||
|
std::vector<unsigned char> output(decompressedSize);
|
||||||
|
|
||||||
|
// 执行解压缩
|
||||||
|
int result = LZ4_decompress_safe(
|
||||||
|
reinterpret_cast<const char*>(compressedData),
|
||||||
|
reinterpret_cast<char*>(output.data()),
|
||||||
|
static_cast<int>(compressedSize),
|
||||||
|
static_cast<int>(decompressedSize)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 检查解压结果
|
||||||
|
if (result < 0 || static_cast<size_t>(result) != decompressedSize) {
|
||||||
|
throw std::runtime_error("LZ4 decompression failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexImage ImageReader::ReadFrom(BinaryReader& reader, const TexImageContainer& container, const TexFormat format)
|
||||||
|
{
|
||||||
|
int mipMapCount = reader.ReadInt32();
|
||||||
|
|
||||||
|
auto aFormat = GetFormatFromTex(container.ImageFormat, format);
|
||||||
|
|
||||||
|
TexImage image{};
|
||||||
|
|
||||||
|
for (int i = 0; i < mipMapCount; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
TexMipMap mipmap;
|
||||||
|
|
||||||
|
switch (container.ImageContainerVersion)
|
||||||
|
{
|
||||||
|
case ImageContainerVersion::VERSION1:
|
||||||
|
mipmap = ReadMipMapV1(reader); break;
|
||||||
|
case ImageContainerVersion::VERSION2:
|
||||||
|
case ImageContainerVersion::VERSION3:
|
||||||
|
mipmap = ReadMipMapV2AndV3(reader); break;
|
||||||
|
case ImageContainerVersion::VERSION4:
|
||||||
|
mipmap = ReadMipMapV4(reader); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mipmap.Format = aFormat;
|
||||||
|
if (mipmap.IsZ4Compressed)
|
||||||
|
{
|
||||||
|
mipmap.Data = Lz4Decompress(mipmap.Data.data(), mipmap.Data.size(), mipmap.DecompressedDataCount);
|
||||||
|
mipmap.IsZ4Compressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
image.Mipmaps.push_back(mipmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexImageContainer ImageReader::ImageContainerReaderReadFrom(BinaryReader& reader, TexFormat texFormat)
|
||||||
|
{
|
||||||
|
TexImageContainer container;
|
||||||
|
|
||||||
|
container.Magic = reader.ReadNString();
|
||||||
|
|
||||||
|
int imageCount = reader.ReadInt32();
|
||||||
|
|
||||||
|
if (container.Magic == "TEXB0001")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (container.Magic == "TEXB0002")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (container.Magic == "TEXB0003")
|
||||||
|
{
|
||||||
|
container.ImageFormat = (FreeImageFormat)reader.ReadInt32();
|
||||||
|
}
|
||||||
|
else if (container.Magic == "TEXB0004")
|
||||||
|
{
|
||||||
|
auto format = (FreeImageFormat)reader.ReadInt32();
|
||||||
|
|
||||||
|
bool isVideoMp4 = reader.ReadInt32();
|
||||||
|
if (format == FreeImageFormat::FIF_UNKNOWN)
|
||||||
|
{
|
||||||
|
if (isVideoMp4)
|
||||||
|
format = FreeImageFormat::FIF_MP4;
|
||||||
|
}
|
||||||
|
container.ImageFormat = format;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "bad image format" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int version = std::stoi(container.Magic.substr(4, 4));
|
||||||
|
|
||||||
|
container.ImageContainerVersion = (ImageContainerVersion)version;
|
||||||
|
|
||||||
|
if (container.ImageContainerVersion == ImageContainerVersion::VERSION4 && container.ImageFormat != FreeImageFormat::FIF_MP4)
|
||||||
|
{
|
||||||
|
container.ImageContainerVersion = ImageContainerVersion::VERSION3;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < imageCount; i++)
|
||||||
|
{
|
||||||
|
container.Images.push_back(ReadFrom(reader, container, texFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexMipMap ImageReader::ReadMipMapV1(BinaryReader& reader)
|
||||||
|
{
|
||||||
|
TexMipMap mipmap{};
|
||||||
|
mipmap.Width = reader.ReadInt32();
|
||||||
|
mipmap.Height = reader.ReadInt32();
|
||||||
|
mipmap.Data = ReadBytes(reader);
|
||||||
|
|
||||||
|
return mipmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexMipMap ImageReader::ReadMipMapV2AndV3(BinaryReader& reader)
|
||||||
|
{
|
||||||
|
TexMipMap mipmap{};
|
||||||
|
|
||||||
|
mipmap.Width = reader.ReadInt32();
|
||||||
|
mipmap.Height = reader.ReadInt32();
|
||||||
|
mipmap.IsZ4Compressed = reader.ReadInt32() == 1;
|
||||||
|
mipmap.DecompressedDataCount = reader.ReadInt32();
|
||||||
|
mipmap.Data = ReadBytes(reader);
|
||||||
|
|
||||||
|
return mipmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexMipMap ImageReader::ReadMipMapV4(BinaryReader& reader)
|
||||||
|
{
|
||||||
|
int param1 = reader.ReadInt32();
|
||||||
|
if (param1 != 1)
|
||||||
|
{
|
||||||
|
std::cerr << "ReadMipmapV4 unknow param1: " << param1 << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int param2 = reader.ReadInt32();
|
||||||
|
if (param2 != 2)
|
||||||
|
{
|
||||||
|
std::cerr << "ReadMipmapV4 unknow param2: " << param1 << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string condition = reader.ReadNString();
|
||||||
|
|
||||||
|
int param3 = reader.ReadInt32();
|
||||||
|
if (param3 != 1)
|
||||||
|
{
|
||||||
|
std::cerr << "ReadMipmapV4 unknow param3: " << param1 << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexMipMap mipmap{};
|
||||||
|
mipmap.Width = reader.ReadInt32();
|
||||||
|
mipmap.Height = reader.ReadInt32();
|
||||||
|
mipmap.IsZ4Compressed = reader.ReadInt32() == 1;
|
||||||
|
mipmap.DecompressedDataCount = reader.ReadInt32();
|
||||||
|
mipmap.Data = ReadBytes(reader);
|
||||||
|
|
||||||
|
return mipmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> ImageReader::ReadBytes(BinaryReader& reader)
|
||||||
|
{
|
||||||
|
int count = reader.ReadInt32();
|
||||||
|
|
||||||
|
std::vector<uint8_t> bytes;
|
||||||
|
|
||||||
|
reader.ReadData(bytes, count);
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
MipmapFormat ImageReader::GetFormatFromTex(FreeImageFormat imageFormat, TexFormat format)
|
||||||
|
{
|
||||||
|
if (imageFormat != FreeImageFormat::FIF_UNKNOWN)
|
||||||
|
{
|
||||||
|
return FreeImageFormatToMipmapFormat(imageFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
case TexFormat::RGBA8888: return MipmapFormat::RGBA8888;
|
||||||
|
case TexFormat::DXT5: return MipmapFormat::CompressedDXT5;
|
||||||
|
case TexFormat::DXT3: return MipmapFormat::CompressedDXT3;
|
||||||
|
case TexFormat::DXT1: return MipmapFormat::CompressedDXT1;
|
||||||
|
case TexFormat::RG88: return MipmapFormat::RG88;
|
||||||
|
case TexFormat::R8: return MipmapFormat::R8;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "unknow format" << std::endl;
|
||||||
|
|
||||||
|
return MipmapFormat::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
MipmapFormat ImageReader::FreeImageFormatToMipmapFormat(FreeImageFormat imageFormat)
|
||||||
|
{
|
||||||
|
switch (imageFormat)
|
||||||
|
{
|
||||||
|
case FreeImageFormat::FIF_BMP: return MipmapFormat::ImageBMP;
|
||||||
|
case FreeImageFormat::FIF_ICO: return MipmapFormat::ImageICO;
|
||||||
|
case FreeImageFormat::FIF_JPEG: return MipmapFormat::ImageJPEG;
|
||||||
|
case FreeImageFormat::FIF_JNG: return MipmapFormat::ImageJNG;
|
||||||
|
case FreeImageFormat::FIF_KOALA: return MipmapFormat::ImageKOALA;
|
||||||
|
case FreeImageFormat::FIF_LBM: return MipmapFormat::ImageLBM;
|
||||||
|
case FreeImageFormat::FIF_MNG: return MipmapFormat::ImageMNG;
|
||||||
|
case FreeImageFormat::FIF_PBM: return MipmapFormat::ImagePBM;
|
||||||
|
case FreeImageFormat::FIF_PBMRAW: return MipmapFormat::ImagePBMRAW;
|
||||||
|
case FreeImageFormat::FIF_PCD: return MipmapFormat::ImagePCD;
|
||||||
|
case FreeImageFormat::FIF_PCX: return MipmapFormat::ImagePCX;
|
||||||
|
case FreeImageFormat::FIF_PGM: return MipmapFormat::ImagePGM;
|
||||||
|
case FreeImageFormat::FIF_PGMRAW: return MipmapFormat::ImagePGMRAW;
|
||||||
|
case FreeImageFormat::FIF_PNG: return MipmapFormat::ImagePNG;
|
||||||
|
case FreeImageFormat::FIF_PPM: return MipmapFormat::ImagePPM;
|
||||||
|
case FreeImageFormat::FIF_PPMRAW: return MipmapFormat::ImagePPMRAW;
|
||||||
|
case FreeImageFormat::FIF_RAS: return MipmapFormat::ImageRAS;
|
||||||
|
case FreeImageFormat::FIF_TARGA: return MipmapFormat::ImageTARGA;
|
||||||
|
case FreeImageFormat::FIF_TIFF: return MipmapFormat::ImageTIFF;
|
||||||
|
case FreeImageFormat::FIF_WBMP: return MipmapFormat::ImageWBMP;
|
||||||
|
case FreeImageFormat::FIF_PSD: return MipmapFormat::ImagePSD;
|
||||||
|
case FreeImageFormat::FIF_CUT: return MipmapFormat::ImageCUT;
|
||||||
|
case FreeImageFormat::FIF_XBM: return MipmapFormat::ImageXBM;
|
||||||
|
case FreeImageFormat::FIF_XPM: return MipmapFormat::ImageXPM;
|
||||||
|
case FreeImageFormat::FIF_DDS: return MipmapFormat::ImageDDS;
|
||||||
|
case FreeImageFormat::FIF_GIF: return MipmapFormat::ImageGIF;
|
||||||
|
case FreeImageFormat::FIF_HDR: return MipmapFormat::ImageHDR;
|
||||||
|
case FreeImageFormat::FIF_FAXG3: return MipmapFormat::ImageFAXG3;
|
||||||
|
case FreeImageFormat::FIF_SGI: return MipmapFormat::ImageSGI;
|
||||||
|
case FreeImageFormat::FIF_EXR: return MipmapFormat::ImageEXR;
|
||||||
|
case FreeImageFormat::FIF_J2K: return MipmapFormat::ImageJ2K;
|
||||||
|
case FreeImageFormat::FIF_JP2: return MipmapFormat::ImageJP2;
|
||||||
|
case FreeImageFormat::FIF_PFM: return MipmapFormat::ImagePFM;
|
||||||
|
case FreeImageFormat::FIF_PICT: return MipmapFormat::ImagePICT;
|
||||||
|
case FreeImageFormat::FIF_RAW: return MipmapFormat::ImageRAW;
|
||||||
|
case FreeImageFormat::FIF_MP4: return MipmapFormat::VideoMp4;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "unknown format" << std::endl;
|
||||||
|
return MipmapFormat::Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
expkg/src/BinaryOPT/ImageReader.h
Normal file
32
expkg/src/BinaryOPT/ImageReader.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-5.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef IMAGEREADER_H
|
||||||
|
#define IMAGEREADER_H
|
||||||
|
#include "BinaryOPT/BinaryReader.h"
|
||||||
|
#include "Tex/TexImageContainer.h"
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
class PKG_API ImageReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static TexImage ReadFrom(BinaryReader& reader, const TexImageContainer& container, TexFormat format);
|
||||||
|
|
||||||
|
static TexImageContainer ImageContainerReaderReadFrom(BinaryReader& reader, TexFormat texFormat);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static TexMipMap ReadMipMapV1(BinaryReader& reader);
|
||||||
|
static TexMipMap ReadMipMapV2AndV3(BinaryReader& reader);
|
||||||
|
static TexMipMap ReadMipMapV4(BinaryReader& reader);
|
||||||
|
|
||||||
|
static std::vector<uint8_t> ReadBytes(BinaryReader& reader);
|
||||||
|
|
||||||
|
static MipmapFormat GetFormatFromTex(FreeImageFormat imageFormat, TexFormat format);
|
||||||
|
static MipmapFormat FreeImageFormatToMipmapFormat(FreeImageFormat imageFormat);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //IMAGEREADER_H
|
||||||
5
expkg/src/Core.cpp
Normal file
5
expkg/src/Core.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-4.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Core.h"
|
||||||
19
expkg/src/Core.h
Normal file
19
expkg/src/Core.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-4.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef CORE_H
|
||||||
|
#define CORE_H
|
||||||
|
|
||||||
|
#ifdef PKG_SHARED
|
||||||
|
#ifdef PKG_BUILD_DLL
|
||||||
|
#define PKG_API __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define PKG_API __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define PKG_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //CORE_H
|
||||||
|
|
||||||
230
expkg/src/DXT/DXT.cpp
Normal file
230
expkg/src/DXT/DXT.cpp
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-9-21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "DXT.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
void DXT::DecompressImage(int width, int height, std::vector<uint8_t>& data, const DXTFlags flags)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> rgba(width * height * 4);
|
||||||
|
// uint8_t rgba[width * height * 4];
|
||||||
|
|
||||||
|
// init the block pos
|
||||||
|
int sourceBlockPos = 0;
|
||||||
|
int bytesPerBlock = flags == DXTFlags::DXT1 ? 8 : 16;
|
||||||
|
std::vector<uint8_t> targetRGBA(4 * 16);
|
||||||
|
|
||||||
|
// loop over blocks
|
||||||
|
for (int y = 0; y < height; y += 4)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < width; x += 4)
|
||||||
|
{
|
||||||
|
// decompress the block
|
||||||
|
uint8_t targetRGBA_pos = 0;
|
||||||
|
|
||||||
|
if (data.size() == sourceBlockPos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Decompress(targetRGBA, data, sourceBlockPos, flags);
|
||||||
|
|
||||||
|
// Write the decompressed pixels to the correct image locations
|
||||||
|
for (int py = 0; py < 4; py++)
|
||||||
|
{
|
||||||
|
for (int px = 0; px < 4; px++)
|
||||||
|
{
|
||||||
|
const int sx = x + px;
|
||||||
|
const int sy = y + py;
|
||||||
|
if (sx < width && sy < height)
|
||||||
|
{
|
||||||
|
const int targetPixel = 4 * (width * sy + sx);
|
||||||
|
|
||||||
|
rgba[targetPixel + 0] = targetRGBA[targetRGBA_pos + 0];
|
||||||
|
rgba[targetPixel + 1] = targetRGBA[targetRGBA_pos + 1];
|
||||||
|
rgba[targetPixel + 2] = targetRGBA[targetRGBA_pos + 2];
|
||||||
|
rgba[targetPixel + 3] = targetRGBA[targetRGBA_pos + 3];
|
||||||
|
|
||||||
|
targetRGBA_pos += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Ignore that pixel
|
||||||
|
targetRGBA_pos += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sourceBlockPos += bytesPerBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data = rgba;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DXT::Decompress(std::vector<uint8_t>& rgba, std::vector<uint8_t>& block, const int blockIndex, const DXTFlags flags)
|
||||||
|
{
|
||||||
|
// get block locations
|
||||||
|
int colorBlockIndex = blockIndex;
|
||||||
|
|
||||||
|
if (flags == DXTFlags::DXT3 | flags == DXTFlags::DXT5)
|
||||||
|
colorBlockIndex += 8;
|
||||||
|
|
||||||
|
DecompressColor(rgba, block, colorBlockIndex, flags == DXTFlags::DXT1);
|
||||||
|
|
||||||
|
|
||||||
|
// decompress alpha separately is necessary
|
||||||
|
if (flags == DXTFlags::DXT3)
|
||||||
|
DecompressAlphaDxt3(rgba, block, blockIndex);
|
||||||
|
else if (flags == DXTFlags::DXT5)
|
||||||
|
DecompressAlphaDxt5(rgba, block, blockIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DXT::DecompressColor(std::vector<uint8_t>& rgba, std::vector<uint8_t>& block, const int blockIndex, const bool isDxt1)
|
||||||
|
{
|
||||||
|
// unpack end points
|
||||||
|
std::vector<uint8_t> codes(16);
|
||||||
|
const int a = UnPack565(block, blockIndex, 0, codes, 0);
|
||||||
|
const int b = UnPack565(block, blockIndex, 2, codes, 4);
|
||||||
|
|
||||||
|
|
||||||
|
// generate Midpoints
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
const int c = codes[i];
|
||||||
|
const int d = codes[4 + i];
|
||||||
|
|
||||||
|
if (isDxt1 && a <= b)
|
||||||
|
{
|
||||||
|
codes[8 + i] = (uint8_t)((c + d) / 2);
|
||||||
|
codes[12 + i] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
codes[8 + i] = (uint8_t)((2 * c + d) / 3);
|
||||||
|
codes[12 + i] = (uint8_t)((c + 2 * d) / 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in alpha for intermediate values
|
||||||
|
codes[8 + 3] = 255;
|
||||||
|
codes[12 + 3] = (isDxt1 && a <= b) ? (uint8_t)0 : (uint8_t)255;
|
||||||
|
|
||||||
|
|
||||||
|
// unpack the indices
|
||||||
|
std::vector<uint8_t> indices(16);
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
const int packed = block[blockIndex + 4 + i];
|
||||||
|
|
||||||
|
indices[0 + i * 4] = (uint8_t)(packed & 0x3);
|
||||||
|
indices[1 + i * 4] = (uint8_t)((packed >> 2) & 0x3);
|
||||||
|
indices[2 + i * 4] = (uint8_t)((packed >> 4) & 0x3);
|
||||||
|
indices[3 + i * 4] = (uint8_t)((packed >> 6) & 0x3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// store out the colours
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
const int offset = 4 * indices[i];
|
||||||
|
|
||||||
|
rgba[4 * i + 0] = codes[offset + 0];
|
||||||
|
rgba[4 * i + 1] = codes[offset + 1];
|
||||||
|
rgba[4 * i + 2] = codes[offset + 2];
|
||||||
|
rgba[4 * i + 3] = codes[offset + 3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DXT::DecompressAlphaDxt3(std::vector<uint8_t>& rgba, std::vector<uint8_t>& block, const int blockIndex)
|
||||||
|
{
|
||||||
|
// Unpack the alpha values pairwise
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
// Quantise down to 4 bits
|
||||||
|
int quant = block[blockIndex + i];
|
||||||
|
|
||||||
|
const uint8_t lo = (uint8_t)(quant & 0x0F);
|
||||||
|
const uint8_t hi = (uint8_t)(quant & 0xF0);
|
||||||
|
|
||||||
|
// Convert back up to bytes
|
||||||
|
rgba[8 * i + 3] = (uint8_t)(lo | (lo << 4));
|
||||||
|
rgba[8 * i + 7] = (uint8_t)(hi | (hi >> 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DXT::DecompressAlphaDxt5(std::vector<uint8_t>& rgba, std::vector<uint8_t>& block, const int blockIndex)
|
||||||
|
{
|
||||||
|
// Get the two alpha values
|
||||||
|
uint8_t alpha0 = block[blockIndex + 0];
|
||||||
|
uint8_t alpha1 = block[blockIndex + 1];
|
||||||
|
|
||||||
|
// compare the values to build the codebook
|
||||||
|
std::vector<uint8_t> codes(8);
|
||||||
|
codes[0] = alpha0;
|
||||||
|
codes[1] = alpha1;
|
||||||
|
if (alpha0 <= alpha1)
|
||||||
|
{
|
||||||
|
// Use 5-Alpha Codebook
|
||||||
|
for (int i = 1; i < 5; i++)
|
||||||
|
codes[1 + i] = (uint8_t)(((5 - i) * alpha0 + i * alpha1) / 5);
|
||||||
|
codes[6] = 0;
|
||||||
|
codes[7] = 255;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Use 7-Alpha Codebook
|
||||||
|
for (int i = 1; i < 7; i++)
|
||||||
|
{
|
||||||
|
codes[i + 1] = (uint8_t)(((7 - i) * alpha0 + i * alpha1) / 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode indices
|
||||||
|
std::vector<uint8_t> indices(16);
|
||||||
|
uint8_t blockSrc_pos = 2;
|
||||||
|
uint8_t indices_pos = 0;
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
// grab 3 bytes
|
||||||
|
int value = 0;
|
||||||
|
for (int j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
int _byte = block[blockIndex + blockSrc_pos++];
|
||||||
|
value |= (_byte << 8 * j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unpack 8 3-bit values from it
|
||||||
|
for (int j = 0; j < 8; j++)
|
||||||
|
{
|
||||||
|
int index = (value >> 3 * j) & 0x07;
|
||||||
|
indices[indices_pos++] = (uint8_t)index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write out the indexed codebook values
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
rgba[4 * i + 3] = codes[indices[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int DXT::UnPack565(std::vector<uint8_t>& block, const int blockIndex, const int packedOffset, std::vector<uint8_t>& color, const int colorOffset)
|
||||||
|
{
|
||||||
|
// build packed value
|
||||||
|
const int value = block[blockIndex + packedOffset] | (block[blockIndex + packedOffset + 1] << 8);
|
||||||
|
|
||||||
|
// get components in the stored range
|
||||||
|
const uint16_t red = ((value >> 11) & 0x1F);
|
||||||
|
const uint16_t green = ((value >> 5) & 0x3F);
|
||||||
|
const uint16_t blue = (value & 0x1F);
|
||||||
|
|
||||||
|
|
||||||
|
// Scale up to 8 Bit
|
||||||
|
color[0 + colorOffset] = (uint8_t)((red << 3) | (red >> 2));
|
||||||
|
color[1 + colorOffset] = (uint8_t)((green << 2) | (green >> 4));
|
||||||
|
color[2 + colorOffset] = (uint8_t)((blue << 3) | (blue >> 2));
|
||||||
|
color[3 + colorOffset] = 255;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
38
expkg/src/DXT/DXT.h
Normal file
38
expkg/src/DXT/DXT.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-9-21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef DXT_H
|
||||||
|
#define DXT_H
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
enum class DXTFlags
|
||||||
|
{
|
||||||
|
DXT1 = 1,
|
||||||
|
DXT3 = 1 << 1,
|
||||||
|
DXT5 = 1 << 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DXT
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// public static byte[] DecompressImage(int width, int height, byte[] data, DXTFlags flags)
|
||||||
|
|
||||||
|
static void DecompressImage(int width, int height, std::vector<uint8_t>& data, DXTFlags flags);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void Decompress(std::vector<uint8_t>& rgba, std::vector<uint8_t>& block, int blockIndex, DXTFlags flags);
|
||||||
|
|
||||||
|
static int UnPack565(std::vector<uint8_t>& block, int blockIndex, int packedOffset, std::vector<uint8_t>& color, int colorOffset);
|
||||||
|
static void DecompressColor(std::vector<uint8_t>& rgba, std::vector<uint8_t>& block, int blockIndex, bool isDxt1);
|
||||||
|
static void DecompressAlphaDxt3(std::vector<uint8_t>& rgba, std::vector<uint8_t>& block, int blockIndex);
|
||||||
|
static void DecompressAlphaDxt5(std::vector<uint8_t>& rgba, std::vector<uint8_t>& block, int blockIndex);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //DXT_H
|
||||||
543
expkg/src/EXPKG/EXPKG.cpp
Normal file
543
expkg/src/EXPKG/EXPKG.cpp
Normal file
@ -0,0 +1,543 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-4.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "EXPKG.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "gif.h"
|
||||||
|
#include "BinaryOPT/BinaryWriter.h"
|
||||||
|
#include "BinaryOPT/ImageReader.h"
|
||||||
|
#include "DXT/DXT.h"
|
||||||
|
#include "Tex/Tex.h"
|
||||||
|
|
||||||
|
extern "C" unsigned char* stbi_write_png_to_mem(const unsigned char* pixels, int stride_bytes, int x, int y, int n,
|
||||||
|
int* out_len);
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
const char* help = R"(
|
||||||
|
usage:
|
||||||
|
expkg path/to/file.pkg [path/to/output](optional)
|
||||||
|
example:
|
||||||
|
expkg demo.pkg
|
||||||
|
expkg demo.pkg outdir
|
||||||
|
)";
|
||||||
|
|
||||||
|
enum class FILE_EXTENSION
|
||||||
|
{
|
||||||
|
TEX,
|
||||||
|
PKG,
|
||||||
|
UNKNOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPKG::EXPKG(const CommandArgs& commandArgs)
|
||||||
|
{
|
||||||
|
if (commandArgs.argc < 2)
|
||||||
|
{
|
||||||
|
std::cout << help << std::endl;
|
||||||
|
system("pause");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
m_Reader = std::make_shared<BinaryReader>(commandArgs.argv[1]);
|
||||||
|
|
||||||
|
if (commandArgs.argc == 3)
|
||||||
|
{
|
||||||
|
m_OutDir = commandArgs.argv[2];
|
||||||
|
m_OutDir = m_OutDir.make_preferred();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_OutDir = "out";
|
||||||
|
}
|
||||||
|
|
||||||
|
Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPKG::EXPKG(const std::string& filePath, const std::string& outDir)
|
||||||
|
{
|
||||||
|
m_Reader = std::make_shared<BinaryReader>(filePath);
|
||||||
|
m_OutDir = outDir;
|
||||||
|
m_OutDir = m_OutDir.make_preferred();
|
||||||
|
|
||||||
|
if (!m_Reader)
|
||||||
|
Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE_EXTENSION EXPKG::checkExtension(const std::filesystem::path& filePath)
|
||||||
|
{
|
||||||
|
if (filePath.extension() == ".pkg")
|
||||||
|
return FILE_EXTENSION::PKG;
|
||||||
|
if (filePath.extension() == ".mpkg")
|
||||||
|
return FILE_EXTENSION::PKG;
|
||||||
|
if (filePath.extension() == ".tex")
|
||||||
|
return FILE_EXTENSION::TEX;
|
||||||
|
|
||||||
|
std::cerr << "not a pkg file or mpkg file or tex file" << std::endl;
|
||||||
|
return FILE_EXTENSION::UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EXPKG::Run()
|
||||||
|
{
|
||||||
|
switch (checkExtension(m_Reader->GetFilePath()))
|
||||||
|
{
|
||||||
|
case FILE_EXTENSION::TEX:
|
||||||
|
ExtractTex();
|
||||||
|
break;
|
||||||
|
case FILE_EXTENSION::PKG:
|
||||||
|
ExtractPkg();
|
||||||
|
break;
|
||||||
|
case FILE_EXTENSION::UNKNOWN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EXPKG::ExtractPkg()
|
||||||
|
{
|
||||||
|
|
||||||
|
// Read Binary resource
|
||||||
|
const int head = m_Reader->ReadInt32();
|
||||||
|
const std::string magicHeader = m_Reader->ReadString(head);
|
||||||
|
|
||||||
|
|
||||||
|
if (magicHeader.substr(0,3) != "PKG")
|
||||||
|
{
|
||||||
|
std::cerr << "unknown header: " << m_Reader->GetFilePath() << std::endl;
|
||||||
|
std::cerr << "not a pkg file " << std::endl;
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int count = m_Reader->ReadInt32();
|
||||||
|
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
Entry entry;
|
||||||
|
|
||||||
|
const int size = m_Reader->ReadInt32();
|
||||||
|
entry.FullPath = m_Reader->ReadString(size);
|
||||||
|
entry.FullPath = entry.FullPath.make_preferred(); // conflict with system "\\" or "/", use it to solve
|
||||||
|
entry.Offset = m_Reader->ReadInt32();
|
||||||
|
entry.Length = m_Reader->ReadInt32();
|
||||||
|
entry.Type = entry.FullPath.extension().string();
|
||||||
|
|
||||||
|
m_Entries.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "could not get resource: " << m_Reader->GetFilePath() << std::endl;
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// try Extract
|
||||||
|
|
||||||
|
uint32_t offsetPosition = m_Reader->tellg();
|
||||||
|
for (const auto& entry : m_Entries)
|
||||||
|
{
|
||||||
|
std::cout << "convert file: " << m_OutDir / entry.FullPath << std::endl;
|
||||||
|
|
||||||
|
m_Reader->seekg(entry.Offset + offsetPosition);
|
||||||
|
|
||||||
|
if (entry.Type == ".tex")
|
||||||
|
{
|
||||||
|
|
||||||
|
std::filesystem::path texPath = m_OutDir / entry.FullPath;
|
||||||
|
BinaryWriter writer(texPath, std::ios::binary);
|
||||||
|
|
||||||
|
std::string texdata;
|
||||||
|
m_Reader->ReadData(texdata, entry.Length);
|
||||||
|
writer.WriteBytes(texdata.data(), texdata.size());
|
||||||
|
writer.close();
|
||||||
|
|
||||||
|
|
||||||
|
ExtractTex(texPath);
|
||||||
|
}
|
||||||
|
else if (entry.Type == ".gif" ||
|
||||||
|
entry.Type == ".jpg" ||
|
||||||
|
entry.Type == ".png" ||
|
||||||
|
entry.Type == ".jpeg" ||
|
||||||
|
entry.Type == ".webp")
|
||||||
|
{
|
||||||
|
BinaryWriter writer(m_OutDir / entry.FullPath, std::ios::binary);
|
||||||
|
|
||||||
|
std::string texdata;
|
||||||
|
m_Reader->ReadData(texdata, entry.Length);
|
||||||
|
writer.WriteBytes(texdata.data(), texdata.size());
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BinaryWriter writer(m_OutDir / entry.FullPath);
|
||||||
|
writer.WriteString(m_Reader->ReadString(entry.Length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EXPKG::ExtractTex(const std::filesystem::path& path) const
|
||||||
|
{
|
||||||
|
std::shared_ptr<BinaryReader> reader = m_Reader;
|
||||||
|
if (path != "")
|
||||||
|
{
|
||||||
|
reader = std::make_shared<BinaryReader>(path);
|
||||||
|
|
||||||
|
}
|
||||||
|
// Tex ReadHeader
|
||||||
|
Tex tex{};
|
||||||
|
|
||||||
|
|
||||||
|
tex.Magic1 = reader->ReadNString(16);
|
||||||
|
if (tex.Magic1 != "TEXV0005")
|
||||||
|
{
|
||||||
|
std::cerr << "bad magic" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tex.Magic2 = reader->ReadNString(16);
|
||||||
|
if (tex.Magic2 != "TEXI0001")
|
||||||
|
{
|
||||||
|
std::cerr << "bad magic" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tex.Header.Format = (TexFormat)reader->ReadInt32();
|
||||||
|
tex.Header.Flags = (TexType)reader->ReadInt32();
|
||||||
|
tex.Header.TextureWidth = reader->ReadInt32();
|
||||||
|
tex.Header.TextureHeight = reader->ReadInt32();
|
||||||
|
tex.Header.ImageWidth = reader->ReadInt32();
|
||||||
|
tex.Header.ImageHeight = reader->ReadInt32();
|
||||||
|
tex.Header.UnkInt0 = reader->ReadInt32();
|
||||||
|
if ((int)tex.Header.Flags & (int)TexType::IsGif) tex.IsGif = true;
|
||||||
|
if ((int)tex.Header.Flags & (int)TexType::IsVideoTexture) tex.IsVideoTexture = true;
|
||||||
|
|
||||||
|
tex.ImageContainer = ImageReader::ImageContainerReaderReadFrom(*reader, tex.Header.Format);
|
||||||
|
// ReadHeader end
|
||||||
|
|
||||||
|
if (!tex.ImageContainer.Images.empty())
|
||||||
|
{
|
||||||
|
// GetConvertFormat
|
||||||
|
MipmapFormat format;
|
||||||
|
if (tex.IsVideoTexture)
|
||||||
|
format = MipmapFormat::VideoMp4;
|
||||||
|
else
|
||||||
|
format = tex.ImageContainer.Images[0].Mipmaps[0].Format;
|
||||||
|
|
||||||
|
auto tmpfotmat = format;
|
||||||
|
for(auto& Image : tex.ImageContainer.Images)
|
||||||
|
{
|
||||||
|
auto& mipmap = Image.Mipmaps[0];
|
||||||
|
switch (tmpfotmat)
|
||||||
|
{
|
||||||
|
case MipmapFormat::CompressedDXT5:
|
||||||
|
DXT::DecompressImage(mipmap.Width, mipmap.Height, mipmap.Data, DXTFlags::DXT5);
|
||||||
|
mipmap.Format = MipmapFormat::RGBA8888; format = MipmapFormat::RGBA8888;
|
||||||
|
break;
|
||||||
|
case MipmapFormat::CompressedDXT3:
|
||||||
|
DXT::DecompressImage(mipmap.Width, mipmap.Height, mipmap.Data, DXTFlags::DXT3);
|
||||||
|
mipmap.Format = MipmapFormat::RGBA8888; format = MipmapFormat::RGBA8888;
|
||||||
|
break;
|
||||||
|
case MipmapFormat::CompressedDXT1:
|
||||||
|
DXT::DecompressImage(mipmap.Width, mipmap.Height, mipmap.Data, DXTFlags::DXT1);
|
||||||
|
mipmap.Format = MipmapFormat::RGBA8888; format = MipmapFormat::RGBA8888;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::cerr << "raw mipmap meybe compressed" << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((int)format >= 1 && (int)format <= 3)
|
||||||
|
{
|
||||||
|
format = MipmapFormat::ImagePNG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConvertFormat end
|
||||||
|
|
||||||
|
// Convert source
|
||||||
|
|
||||||
|
if (tex.IsGif)
|
||||||
|
{
|
||||||
|
// convert gif
|
||||||
|
|
||||||
|
// tex.GifContainer
|
||||||
|
auto& container = tex.FrameInfoContainer;
|
||||||
|
|
||||||
|
container.Magic = reader->ReadNString(16);
|
||||||
|
|
||||||
|
int frameCount = reader->ReadInt32();
|
||||||
|
|
||||||
|
/*
|
||||||
|
switch (container.Magic)
|
||||||
|
{
|
||||||
|
case "TEXS0001":
|
||||||
|
case "TEXS0002":
|
||||||
|
break;
|
||||||
|
case "TEXS0003":
|
||||||
|
container.GifWidth = reader->ReadInt32();
|
||||||
|
container.GifHeight = reader->ReadInt32();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
std::cerr << "bad magic" << std::endl;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
{
|
||||||
|
if (container.Magic == "TEXS0001" || container.Magic == "TEXS0002")
|
||||||
|
{
|
||||||
|
}else if (container.Magic == "TEXS0003")
|
||||||
|
{
|
||||||
|
container.GifWidth = reader->ReadInt32();
|
||||||
|
container.GifHeight = reader->ReadInt32();
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
std::cerr << "bad magic" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
switch (container.Magic)
|
||||||
|
{
|
||||||
|
case "TEXS0001":
|
||||||
|
for (int i = 0; i < frameCount; i++)
|
||||||
|
{
|
||||||
|
TexFrameInfo frameInfo = {};
|
||||||
|
frameInfo.ImageId = reader->ReadInt32();
|
||||||
|
frameInfo.Frametime = reader->ReadSingle();
|
||||||
|
frameInfo.X = reader->ReadInt32();
|
||||||
|
frameInfo.Y = reader->ReadInt32();
|
||||||
|
frameInfo.Width = reader->ReadInt32();
|
||||||
|
frameInfo.WidthY = reader->ReadInt32();
|
||||||
|
frameInfo.HeightX = reader->ReadInt32();
|
||||||
|
frameInfo.Height = reader->ReadInt32();
|
||||||
|
|
||||||
|
container.Frames.push_back(frameInfo);
|
||||||
|
}
|
||||||
|
case "TEXS0002":
|
||||||
|
case "TEXS0003":
|
||||||
|
for (int i = 0; i < frameCount; i++)
|
||||||
|
{
|
||||||
|
TexFrameInfo frameInfo = {};
|
||||||
|
frameInfo.ImageId = reader->ReadInt32();
|
||||||
|
frameInfo.Frametime = reader->ReadSingle();
|
||||||
|
frameInfo.X = reader->ReadSingle();
|
||||||
|
frameInfo.Y = reader->ReadSingle();
|
||||||
|
frameInfo.Width = reader->ReadSingle();
|
||||||
|
frameInfo.WidthY = reader->ReadSingle();
|
||||||
|
frameInfo.HeightX = reader->ReadSingle();
|
||||||
|
frameInfo.Height = reader->ReadSingle();
|
||||||
|
|
||||||
|
container.Frames.push_back(frameInfo);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
std::cerr << "bad magic" << std::endl;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if (container.Magic == "TEXS0001")
|
||||||
|
{
|
||||||
|
for (int i = 0; i < frameCount; i++)
|
||||||
|
{
|
||||||
|
TexFrameInfo frameInfo = {};
|
||||||
|
frameInfo.ImageId = reader->ReadInt32();
|
||||||
|
frameInfo.Frametime = reader->ReadSingle();
|
||||||
|
frameInfo.PosX = reader->ReadInt32();
|
||||||
|
frameInfo.PosY = reader->ReadInt32();
|
||||||
|
frameInfo.Width = reader->ReadInt32();
|
||||||
|
frameInfo.WidthY = reader->ReadInt32();
|
||||||
|
frameInfo.HeightX = reader->ReadInt32();
|
||||||
|
frameInfo.Height = reader->ReadInt32();
|
||||||
|
|
||||||
|
container.Frames.push_back(frameInfo);
|
||||||
|
}
|
||||||
|
}else if (container.Magic == "TEXS0002" || container.Magic == "TEXS0003")
|
||||||
|
{
|
||||||
|
for (int i = 0; i < frameCount; i++)
|
||||||
|
{
|
||||||
|
TexFrameInfo frameInfo = {};
|
||||||
|
frameInfo.ImageId = reader->ReadInt32();
|
||||||
|
frameInfo.Frametime = reader->ReadSingle();
|
||||||
|
frameInfo.PosX = reader->ReadSingle();
|
||||||
|
frameInfo.PosY = reader->ReadSingle();
|
||||||
|
frameInfo.Width = reader->ReadSingle();
|
||||||
|
frameInfo.WidthY = reader->ReadSingle();
|
||||||
|
frameInfo.HeightX = reader->ReadSingle();
|
||||||
|
frameInfo.Height = reader->ReadSingle();
|
||||||
|
|
||||||
|
container.Frames.push_back(frameInfo);
|
||||||
|
}
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
std::cerr << "bad magic" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (container.GifWidth == 0 || container.GifHeight == 0)
|
||||||
|
{
|
||||||
|
container.GifWidth = (int) container.Frames[0].Width;
|
||||||
|
container.GifHeight = (int) container.Frames[0].Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::filesystem::path outPath = reader->GetFilePath();
|
||||||
|
outPath.replace_extension("gif");
|
||||||
|
|
||||||
|
std::cout << "convert file: " << outPath << std::endl;
|
||||||
|
|
||||||
|
GifWriter writer;
|
||||||
|
|
||||||
|
uint32_t delay = (int)(tex.FrameInfoContainer.Frames[0].Frametime * 100);
|
||||||
|
|
||||||
|
GifBegin(&writer,
|
||||||
|
outPath.string().c_str(),
|
||||||
|
(uint32_t)tex.FrameInfoContainer.Frames[0].Width,
|
||||||
|
(uint32_t)tex.FrameInfoContainer.Frames[0].Height,
|
||||||
|
delay);
|
||||||
|
|
||||||
|
|
||||||
|
int frameIndex = 0;
|
||||||
|
int imageIndex = 1;
|
||||||
|
|
||||||
|
for (const auto& [Mipmap] : tex.ImageContainer.Images)
|
||||||
|
{
|
||||||
|
|
||||||
|
const auto& Image = Mipmap[0];
|
||||||
|
|
||||||
|
int SingleImageFrameCount = (Image.Width / container.GifWidth) * (Image.Height / container.GifHeight);
|
||||||
|
|
||||||
|
|
||||||
|
for (; frameIndex < SingleImageFrameCount * imageIndex; frameIndex++)
|
||||||
|
{
|
||||||
|
const auto& frameInfo = container.Frames[frameIndex];
|
||||||
|
std::vector<uint8_t> frameImage;
|
||||||
|
|
||||||
|
|
||||||
|
for (int heightIndex = 0; heightIndex < container.GifHeight; heightIndex++)
|
||||||
|
{
|
||||||
|
auto lineDataStart = Image.Data.begin() + Image.Width * 4 * ((int)frameInfo.PosY + heightIndex)+ (int)frameInfo.PosX * 4;
|
||||||
|
auto lineData = std::vector<uint8_t>(lineDataStart, lineDataStart + (int)frameInfo.Width * 4);
|
||||||
|
|
||||||
|
frameImage.insert(frameImage.end(), lineData.begin(), lineData.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// output by gif
|
||||||
|
{
|
||||||
|
GifWriteFrame(&writer, frameImage.data(), (uint32_t)frameInfo.Width, (uint32_t)frameInfo.Height, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// output one by one
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
static int index = 0;
|
||||||
|
|
||||||
|
auto* data = stbi_write_png_to_mem(frameImage.data(),
|
||||||
|
(int)frameInfo.Width * 4,
|
||||||
|
(int)frameInfo.Width,
|
||||||
|
(int)frameInfo.Height,
|
||||||
|
4,
|
||||||
|
&len);
|
||||||
|
|
||||||
|
std::filesystem::path outputfile = outPath;
|
||||||
|
std::string name = outputfile.filename().string();
|
||||||
|
outputfile = outputfile.parent_path();
|
||||||
|
|
||||||
|
|
||||||
|
std::string filename = std::to_string(index++) + "_" + name;
|
||||||
|
|
||||||
|
outputfile /= "out";
|
||||||
|
outputfile /= filename;
|
||||||
|
|
||||||
|
std::cout << "convert file: " << outputfile << std::endl;
|
||||||
|
|
||||||
|
BinaryWriter imageWriter(outputfile, std::ios::binary);
|
||||||
|
imageWriter.WriteBytes(reinterpret_cast<const char*>(data), len);
|
||||||
|
imageWriter.close();
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
data = nullptr;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
imageIndex ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
GifEnd(&writer);
|
||||||
|
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
auto& sourceMipmap = tex.ImageContainer.Images[0].Mipmaps[0];
|
||||||
|
|
||||||
|
if (tex.IsVideoTexture)
|
||||||
|
{
|
||||||
|
if (sourceMipmap.Data.size() < 12)
|
||||||
|
{
|
||||||
|
std::cerr << "expect mp4 magic header" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string mp4Magic = std::string(reinterpret_cast<const char*>(&sourceMipmap.Data[4]), 8);
|
||||||
|
|
||||||
|
if (mp4Magic != "ftypisom" && mp4Magic != "ftypmsnv" && mp4Magic != "ftypmp42")
|
||||||
|
{
|
||||||
|
std::cerr << "bad mp4 magic header" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto imgformat = sourceMipmap.Format;
|
||||||
|
|
||||||
|
if ((int)imgformat >= 1 && (int)imgformat <= 3)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
auto& imgData = tex.ImageContainer.Images[0].Mipmaps[0].Data;
|
||||||
|
|
||||||
|
uint8_t* data = nullptr;
|
||||||
|
int channel = 4;
|
||||||
|
|
||||||
|
switch (imgformat)
|
||||||
|
{
|
||||||
|
case MipmapFormat::R8: channel = 1; break;
|
||||||
|
case MipmapFormat::RG88: channel = 2; break;
|
||||||
|
case MipmapFormat::RGBA8888: channel = 4; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = stbi_write_png_to_mem(sourceMipmap.Data.data(),
|
||||||
|
sourceMipmap.Width * channel,
|
||||||
|
sourceMipmap.Width,
|
||||||
|
sourceMipmap.Height,
|
||||||
|
channel,
|
||||||
|
&len);
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
imgData.assign(data, data + len);
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return ImageResult
|
||||||
|
// data format
|
||||||
|
std::filesystem::path outPath = reader->GetFilePath();
|
||||||
|
outPath.replace_extension(GetFileExtension(format));
|
||||||
|
|
||||||
|
std::cout << "convert file: " << outPath << std::endl;
|
||||||
|
|
||||||
|
BinaryWriter imageWriter(outPath, std::ios::binary);
|
||||||
|
imageWriter.WriteBytes(reinterpret_cast<const char*>(sourceMipmap.Data.data()), sourceMipmap.Data.size());
|
||||||
|
imageWriter.close();
|
||||||
|
// Convert source end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
expkg/src/EXPKG/EXPKG.h
Normal file
48
expkg/src/EXPKG/EXPKG.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-4.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef EXPKG_H
|
||||||
|
#define EXPKG_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Entry.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct CommandArgs
|
||||||
|
{
|
||||||
|
int argc;
|
||||||
|
char** argv;
|
||||||
|
} CommandArgs;
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
class BinaryReader;
|
||||||
|
enum class FILE_EXTENSION;
|
||||||
|
|
||||||
|
class PKG_API EXPKG
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EXPKG(const CommandArgs& commandArgs);
|
||||||
|
EXPKG(const std::string& filePath, const std::string& outDir = "out");
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
static FILE_EXTENSION checkExtension(const std::filesystem::path& filePath);
|
||||||
|
|
||||||
|
void ExtractTex(const std::filesystem::path& path = "") const;
|
||||||
|
|
||||||
|
void ExtractPkg();
|
||||||
|
void Run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<BinaryReader> m_Reader;
|
||||||
|
std::filesystem::path m_OutDir;
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<Entry> m_Entries;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //EXPKG_H
|
||||||
5
expkg/src/Entry.cpp
Normal file
5
expkg/src/Entry.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-4.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Entry.h"
|
||||||
427
expkg/src/Entry.h
Normal file
427
expkg/src/Entry.h
Normal file
@ -0,0 +1,427 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-4.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ENTRY_H
|
||||||
|
#define ENTRY_H
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "Core.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
enum class TexFormat
|
||||||
|
{
|
||||||
|
RGBA8888 = 0,
|
||||||
|
DXT5 = 4,
|
||||||
|
DXT3 = 6,
|
||||||
|
DXT1 = 7,
|
||||||
|
RG88 = 8,
|
||||||
|
R8 = 9
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class TexType
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
NoInterpolation = 1,
|
||||||
|
ClampUVs = 2,
|
||||||
|
IsGif = 4,
|
||||||
|
// Placeholders
|
||||||
|
Unk3 = 8,
|
||||||
|
Unk4 = 16,
|
||||||
|
IsVideoTexture = 32,
|
||||||
|
Unk6 = 64,
|
||||||
|
Unk7 = 128,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum class MipmapFormat
|
||||||
|
{
|
||||||
|
Invalid = 0,
|
||||||
|
|
||||||
|
/// Raw pixels (4 bytes per pixel) (RGBA8888)
|
||||||
|
RGBA8888 = 1,
|
||||||
|
|
||||||
|
/// Raw pixels (1 byte per pixel) (R8)
|
||||||
|
R8 = 2,
|
||||||
|
|
||||||
|
/// Raw pixels (2 bytes per pixel) (RG88)
|
||||||
|
RG88 = 3,
|
||||||
|
|
||||||
|
/// Raw pixels compressed using DXT5
|
||||||
|
CompressedDXT5,
|
||||||
|
|
||||||
|
/// Raw pixels compressed using DXT3
|
||||||
|
CompressedDXT3,
|
||||||
|
|
||||||
|
/// Raw pixels compressed using DXT1
|
||||||
|
CompressedDXT1,
|
||||||
|
|
||||||
|
|
||||||
|
/// MP4 Video
|
||||||
|
VideoMp4,
|
||||||
|
|
||||||
|
|
||||||
|
/// Windows or OS/2 Bitmap File (*.BMP)
|
||||||
|
|
||||||
|
/// Keep '= 1000' because MipmapFormatExtensions.IsImage uses this to check if format is an image format
|
||||||
|
ImageBMP = 1000,
|
||||||
|
|
||||||
|
|
||||||
|
/// Windows Icon (*.ICO)
|
||||||
|
ImageICO,
|
||||||
|
|
||||||
|
|
||||||
|
/// Independent JPEG Group (*.JPG, *.JIF, *.JPEG, *.JPE)
|
||||||
|
ImageJPEG,
|
||||||
|
|
||||||
|
|
||||||
|
/// JPEG Network Graphics (*.JNG)
|
||||||
|
ImageJNG,
|
||||||
|
|
||||||
|
|
||||||
|
/// Commodore 64 Koala format (*.KOA)
|
||||||
|
ImageKOALA,
|
||||||
|
|
||||||
|
|
||||||
|
/// Amiga IFF (*.IFF, *.LBM)
|
||||||
|
ImageLBM,
|
||||||
|
|
||||||
|
|
||||||
|
/// Amiga IFF (*.IFF, *.LBM)
|
||||||
|
ImageIFF,
|
||||||
|
|
||||||
|
|
||||||
|
/// Multiple Network Graphics (*.MNG)
|
||||||
|
ImageMNG,
|
||||||
|
|
||||||
|
|
||||||
|
/// Portable Bitmap (ASCII) (*.PBM)
|
||||||
|
ImagePBM,
|
||||||
|
|
||||||
|
|
||||||
|
/// Portable Bitmap (BINARY) (*.PBM)
|
||||||
|
ImagePBMRAW,
|
||||||
|
|
||||||
|
|
||||||
|
/// Kodak PhotoCD (*.PCD)
|
||||||
|
ImagePCD,
|
||||||
|
|
||||||
|
|
||||||
|
/// Zsoft Paintbrush PCX bitmap format (*.PCX)
|
||||||
|
ImagePCX,
|
||||||
|
|
||||||
|
|
||||||
|
/// Portable Graymap (ASCII) (*.PGM)
|
||||||
|
ImagePGM,
|
||||||
|
|
||||||
|
|
||||||
|
/// Portable Graymap (BINARY) (*.PGM)
|
||||||
|
ImagePGMRAW,
|
||||||
|
|
||||||
|
|
||||||
|
/// Portable Network Graphics (*.PNG)
|
||||||
|
ImagePNG,
|
||||||
|
|
||||||
|
|
||||||
|
/// Portable Pixelmap (ASCII) (*.PPM)
|
||||||
|
ImagePPM,
|
||||||
|
|
||||||
|
|
||||||
|
/// Portable Pixelmap (BINARY) (*.PPM)
|
||||||
|
ImagePPMRAW,
|
||||||
|
|
||||||
|
|
||||||
|
/// Sun Rasterfile (*.RAS)
|
||||||
|
ImageRAS,
|
||||||
|
|
||||||
|
|
||||||
|
/// truevision Targa files (*.TGA, *.TARGA)
|
||||||
|
ImageTARGA,
|
||||||
|
|
||||||
|
|
||||||
|
/// Tagged Image File Format (*.TIF, *.TIFF)
|
||||||
|
ImageTIFF,
|
||||||
|
|
||||||
|
|
||||||
|
/// Wireless Bitmap (*.WBMP)
|
||||||
|
ImageWBMP,
|
||||||
|
|
||||||
|
|
||||||
|
/// Adobe Photoshop (*.PSD)
|
||||||
|
ImagePSD,
|
||||||
|
|
||||||
|
|
||||||
|
/// Dr. Halo (*.CUT)
|
||||||
|
ImageCUT,
|
||||||
|
|
||||||
|
|
||||||
|
/// X11 Bitmap Format (*.XBM)
|
||||||
|
ImageXBM,
|
||||||
|
|
||||||
|
|
||||||
|
/// X11 Pixmap Format (*.XPM)
|
||||||
|
ImageXPM,
|
||||||
|
|
||||||
|
|
||||||
|
/// DirectDraw Surface (*.DDS)
|
||||||
|
ImageDDS,
|
||||||
|
|
||||||
|
|
||||||
|
/// Graphics Interchange Format (*.GIF)
|
||||||
|
ImageGIF,
|
||||||
|
|
||||||
|
|
||||||
|
/// High Dynamic Range (*.HDR)
|
||||||
|
ImageHDR,
|
||||||
|
|
||||||
|
|
||||||
|
/// Raw Fax format CCITT G3 (*.G3)
|
||||||
|
ImageFAXG3,
|
||||||
|
|
||||||
|
|
||||||
|
/// Silicon Graphics SGI image format (*.SGI)
|
||||||
|
ImageSGI,
|
||||||
|
|
||||||
|
|
||||||
|
/// OpenEXR format (*.EXR)
|
||||||
|
ImageEXR,
|
||||||
|
|
||||||
|
|
||||||
|
/// JPEG-2000 format (*.J2K, *.J2C)
|
||||||
|
ImageJ2K,
|
||||||
|
|
||||||
|
|
||||||
|
/// JPEG-2000 format (*.JP2)
|
||||||
|
ImageJP2,
|
||||||
|
|
||||||
|
|
||||||
|
/// Portable FloatMap (*.PFM)
|
||||||
|
ImagePFM,
|
||||||
|
|
||||||
|
|
||||||
|
/// Macintosh PICT (*.PICT)
|
||||||
|
ImagePICT,
|
||||||
|
|
||||||
|
|
||||||
|
/// RAW camera image (*.*)
|
||||||
|
ImageRAW,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class FreeImageFormat {
|
||||||
|
/// <summary>
|
||||||
|
/// Unknown format (returned value only, never use it as input value)
|
||||||
|
/// </summary>
|
||||||
|
FIF_UNKNOWN = -1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Windows or OS/2 Bitmap File (*.BMP)
|
||||||
|
/// </summary>
|
||||||
|
FIF_BMP = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Windows Icon (*.ICO)
|
||||||
|
/// </summary>
|
||||||
|
FIF_ICO = 1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Independent JPEG Group (*.JPG, *.JIF, *.JPEG, *.JPE)
|
||||||
|
/// </summary>
|
||||||
|
FIF_JPEG = 2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// JPEG Network Graphics (*.JNG)
|
||||||
|
/// </summary>
|
||||||
|
FIF_JNG = 3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Commodore 64 Koala format (*.KOA)
|
||||||
|
/// </summary>
|
||||||
|
FIF_KOALA = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Amiga IFF (*.IFF, *.LBM)
|
||||||
|
/// </summary>
|
||||||
|
FIF_LBM = 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Amiga IFF (*.IFF, *.LBM)
|
||||||
|
/// </summary>
|
||||||
|
FIF_IFF = 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiple Network Graphics (*.MNG)
|
||||||
|
/// </summary>
|
||||||
|
FIF_MNG = 6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Portable Bitmap (ASCII) (*.PBM)
|
||||||
|
/// </summary>
|
||||||
|
FIF_PBM = 7,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Portable Bitmap (BINARY) (*.PBM)
|
||||||
|
/// </summary>
|
||||||
|
FIF_PBMRAW = 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Kodak PhotoCD (*.PCD)
|
||||||
|
/// </summary>
|
||||||
|
FIF_PCD = 9,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Zsoft Paintbrush PCX bitmap format (*.PCX)
|
||||||
|
/// </summary>
|
||||||
|
FIF_PCX = 10,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Portable Graymap (ASCII) (*.PGM)
|
||||||
|
/// </summary>
|
||||||
|
FIF_PGM = 11,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Portable Graymap (BINARY) (*.PGM)
|
||||||
|
/// </summary>
|
||||||
|
FIF_PGMRAW = 12,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Portable Network Graphics (*.PNG)
|
||||||
|
/// </summary>
|
||||||
|
FIF_PNG = 13,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Portable Pixelmap (ASCII) (*.PPM)
|
||||||
|
/// </summary>
|
||||||
|
FIF_PPM = 14,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Portable Pixelmap (BINARY) (*.PPM)
|
||||||
|
/// </summary>
|
||||||
|
FIF_PPMRAW = 15,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sun Rasterfile (*.RAS)
|
||||||
|
/// </summary>
|
||||||
|
FIF_RAS = 16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// truevision Targa files (*.TGA, *.TARGA)
|
||||||
|
/// </summary>
|
||||||
|
FIF_TARGA = 17,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tagged Image File Format (*.TIF, *.TIFF)
|
||||||
|
/// </summary>
|
||||||
|
FIF_TIFF = 18,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wireless Bitmap (*.WBMP)
|
||||||
|
/// </summary>
|
||||||
|
FIF_WBMP = 19,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adobe Photoshop (*.PSD)
|
||||||
|
/// </summary>
|
||||||
|
FIF_PSD = 20,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dr. Halo (*.CUT)
|
||||||
|
/// </summary>
|
||||||
|
FIF_CUT = 21,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// X11 Bitmap Format (*.XBM)
|
||||||
|
/// </summary>
|
||||||
|
FIF_XBM = 22,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// X11 Pixmap Format (*.XPM)
|
||||||
|
/// </summary>
|
||||||
|
FIF_XPM = 23,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DirectDraw Surface (*.DDS)
|
||||||
|
/// </summary>
|
||||||
|
FIF_DDS = 24,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Graphics Interchange Format (*.GIF)
|
||||||
|
/// </summary>
|
||||||
|
FIF_GIF = 25,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// High Dynamic Range (*.HDR)
|
||||||
|
/// </summary>
|
||||||
|
FIF_HDR = 26,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raw Fax format CCITT G3 (*.G3)
|
||||||
|
/// </summary>
|
||||||
|
FIF_FAXG3 = 27,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Silicon Graphics SGI image format (*.SGI)
|
||||||
|
/// </summary>
|
||||||
|
FIF_SGI = 28,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// OpenEXR format (*.EXR)
|
||||||
|
/// </summary>
|
||||||
|
FIF_EXR = 29,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// JPEG-2000 format (*.J2K, *.J2C)
|
||||||
|
/// </summary>
|
||||||
|
FIF_J2K = 30,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// JPEG-2000 format (*.JP2)
|
||||||
|
/// </summary>
|
||||||
|
FIF_JP2 = 31,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Portable FloatMap (*.PFM)
|
||||||
|
/// </summary>
|
||||||
|
FIF_PFM = 32,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Macintosh PICT (*.PICT)
|
||||||
|
/// </summary>
|
||||||
|
FIF_PICT = 33,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RAW camera image (*.*)
|
||||||
|
/// </summary>
|
||||||
|
FIF_RAW = 34,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RAW camera MP4 (*.mp4)
|
||||||
|
/// </summary>
|
||||||
|
FIF_MP4 = 35,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PKG_API Entry
|
||||||
|
{
|
||||||
|
std::filesystem::path FullPath;
|
||||||
|
int32_t Offset{};
|
||||||
|
int32_t Length{};
|
||||||
|
std::string Type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PKG_API TexHeader
|
||||||
|
{
|
||||||
|
TexFormat Format;
|
||||||
|
TexType Flags;
|
||||||
|
int32_t TextureWidth;
|
||||||
|
int32_t TextureHeight;
|
||||||
|
int32_t ImageWidth;
|
||||||
|
int32_t ImageHeight;
|
||||||
|
uint32_t UnkInt0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //ENTRY_H
|
||||||
5
expkg/src/Tex/Tex.cpp
Normal file
5
expkg/src/Tex/Tex.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-5.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Tex.h"
|
||||||
30
expkg/src/Tex/Tex.h
Normal file
30
expkg/src/Tex/Tex.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-5.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef TEX_H
|
||||||
|
#define TEX_H
|
||||||
|
|
||||||
|
#include "TexFrameInfoContainer.h"
|
||||||
|
#include "TexImageContainer.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
class Tex
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string Magic1;
|
||||||
|
std::string Magic2;
|
||||||
|
TexHeader Header = {};
|
||||||
|
TexImageContainer ImageContainer = {};
|
||||||
|
|
||||||
|
bool IsGif = false;
|
||||||
|
bool IsVideoTexture = false;
|
||||||
|
|
||||||
|
TexFrameInfoContainer FrameInfoContainer = {};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //TEX_H
|
||||||
5
expkg/src/Tex/TexFrameInfoContainer.cpp
Normal file
5
expkg/src/Tex/TexFrameInfoContainer.cpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-9-21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "TexFrameInfoContainer.h"
|
||||||
39
expkg/src/Tex/TexFrameInfoContainer.h
Normal file
39
expkg/src/Tex/TexFrameInfoContainer.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-9-21.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef TEXFRAMEINFOCONTAINER_H
|
||||||
|
#define TEXFRAMEINFOCONTAINER_H
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
|
||||||
|
struct TexFrameInfo
|
||||||
|
{
|
||||||
|
int ImageId;
|
||||||
|
float Frametime;
|
||||||
|
float PosX;
|
||||||
|
float PosY;
|
||||||
|
float Width;
|
||||||
|
float WidthY;
|
||||||
|
float HeightX;
|
||||||
|
float Height;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TexFrameInfoContainer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string Magic;
|
||||||
|
|
||||||
|
std::vector<TexFrameInfo> Frames;
|
||||||
|
int GifWidth;
|
||||||
|
int GifHeight;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //TEXFRAMEINFOCONTAINER_H
|
||||||
88
expkg/src/Tex/TexImage.cpp
Normal file
88
expkg/src/Tex/TexImage.cpp
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-5.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "TexImage.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
std::string PKG::GetFileExtension(const MipmapFormat format)
|
||||||
|
{
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
case MipmapFormat::ImageBMP:
|
||||||
|
return "bmp";
|
||||||
|
case MipmapFormat::ImageICO:
|
||||||
|
return "ico";
|
||||||
|
case MipmapFormat::ImageJPEG:
|
||||||
|
return "jpg";
|
||||||
|
case MipmapFormat::ImageJNG:
|
||||||
|
return "jng";
|
||||||
|
case MipmapFormat::ImageKOALA:
|
||||||
|
return "koa";
|
||||||
|
case MipmapFormat::ImageLBM:
|
||||||
|
return "lbm";
|
||||||
|
case MipmapFormat::ImageIFF:
|
||||||
|
return "iff";
|
||||||
|
case MipmapFormat::ImageMNG:
|
||||||
|
return "mng";
|
||||||
|
case MipmapFormat::ImagePBM:
|
||||||
|
case MipmapFormat::ImagePBMRAW:
|
||||||
|
return "pbm";
|
||||||
|
case MipmapFormat::ImagePCD:
|
||||||
|
return "pcd";
|
||||||
|
case MipmapFormat::ImagePCX:
|
||||||
|
return "pcx";
|
||||||
|
case MipmapFormat::ImagePGM:
|
||||||
|
case MipmapFormat::ImagePGMRAW:
|
||||||
|
return "pgm";
|
||||||
|
case MipmapFormat::ImagePNG:
|
||||||
|
return "png";
|
||||||
|
case MipmapFormat::ImagePPM:
|
||||||
|
case MipmapFormat::ImagePPMRAW:
|
||||||
|
return "ppm";
|
||||||
|
case MipmapFormat::ImageRAS:
|
||||||
|
return "ras";
|
||||||
|
case MipmapFormat::ImageTARGA:
|
||||||
|
return "tga";
|
||||||
|
case MipmapFormat::ImageTIFF:
|
||||||
|
return "tif";
|
||||||
|
case MipmapFormat::ImageWBMP:
|
||||||
|
return "wbmp";
|
||||||
|
case MipmapFormat::ImagePSD:
|
||||||
|
return "psd";
|
||||||
|
case MipmapFormat::ImageCUT:
|
||||||
|
return "cut";
|
||||||
|
case MipmapFormat::ImageXBM:
|
||||||
|
return "xbm";
|
||||||
|
case MipmapFormat::ImageXPM:
|
||||||
|
return "xpm";
|
||||||
|
case MipmapFormat::ImageDDS:
|
||||||
|
return "dds";
|
||||||
|
case MipmapFormat::ImageGIF:
|
||||||
|
return "gif";
|
||||||
|
case MipmapFormat::ImageHDR:
|
||||||
|
return "hdr";
|
||||||
|
case MipmapFormat::ImageFAXG3:
|
||||||
|
return "g3";
|
||||||
|
case MipmapFormat::ImageSGI:
|
||||||
|
return "sgi";
|
||||||
|
case MipmapFormat::ImageEXR:
|
||||||
|
return "exr";
|
||||||
|
case MipmapFormat::ImageJ2K:
|
||||||
|
return "j2k";
|
||||||
|
case MipmapFormat::ImageJP2:
|
||||||
|
return "jp2";
|
||||||
|
case MipmapFormat::ImagePFM:
|
||||||
|
return "pfm";
|
||||||
|
case MipmapFormat::ImagePICT:
|
||||||
|
return "pict";
|
||||||
|
case MipmapFormat::ImageRAW:
|
||||||
|
return "raw";
|
||||||
|
case MipmapFormat::VideoMp4:
|
||||||
|
return "mp4";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "unknown file type" << std::endl;
|
||||||
|
return ".unknown";
|
||||||
|
}
|
||||||
37
expkg/src/Tex/TexImage.h
Normal file
37
expkg/src/Tex/TexImage.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-5.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef TEXIMAGE_H
|
||||||
|
#define TEXIMAGE_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Entry.h"
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
|
||||||
|
std::string GetFileExtension(MipmapFormat format);
|
||||||
|
|
||||||
|
class TexMipMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int Width;
|
||||||
|
int Height;
|
||||||
|
int DecompressedDataCount;
|
||||||
|
bool IsZ4Compressed = false;
|
||||||
|
|
||||||
|
MipmapFormat Format;
|
||||||
|
|
||||||
|
std::vector<uint8_t> Data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TexImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<TexMipMap> Mipmaps;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //TEXIMAGE_H
|
||||||
6
expkg/src/Tex/TexImageContainer.cpp
Normal file
6
expkg/src/Tex/TexImageContainer.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-5.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "TexImageContainer.h"
|
||||||
|
|
||||||
31
expkg/src/Tex/TexImageContainer.h
Normal file
31
expkg/src/Tex/TexImageContainer.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-8-5.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef TEXIMAGECONTAINER_H
|
||||||
|
#define TEXIMAGECONTAINER_H
|
||||||
|
|
||||||
|
#include "TexImage.h"
|
||||||
|
|
||||||
|
namespace PKG
|
||||||
|
{
|
||||||
|
enum class ImageContainerVersion
|
||||||
|
{
|
||||||
|
VERSION1 = 1,
|
||||||
|
VERSION2 = 2,
|
||||||
|
VERSION3 = 3,
|
||||||
|
VERSION4 = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
class TexImageContainer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string Magic;
|
||||||
|
FreeImageFormat ImageFormat{};
|
||||||
|
ImageContainerVersion ImageContainerVersion;
|
||||||
|
|
||||||
|
std::vector<TexImage> Images;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //TEXIMAGECONTAINER_H
|
||||||
14
expkg/src/expkg.h
Normal file
14
expkg/src/expkg.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef EXPKG_H
|
||||||
|
#define EXPKG_H
|
||||||
|
|
||||||
|
#include "Entry.h"
|
||||||
|
#include "BinaryOPT/BinaryReader.h"
|
||||||
|
#include "BinaryOPT/BinaryWriter.h"
|
||||||
|
#include "BinaryOPT/ImageReader.h"
|
||||||
|
#include "EXPKG/EXPKG.h"
|
||||||
|
#include "Tex/Tex.h"
|
||||||
|
#include "Tex/TexImage.h"
|
||||||
|
#include "Tex/TexImageContainer.h"
|
||||||
|
|
||||||
|
|
||||||
|
#endif // EXPKG_H
|
||||||
0
vendor/lz4/NEWS → expkg/vendor/lz4/NEWS
vendored
0
vendor/lz4/NEWS → expkg/vendor/lz4/NEWS
vendored
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user