mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-04-27 04:41:39 +00:00
Implement ZSTD compression in file_to_c.
This commit is contained in:
parent
1a794ef9ee
commit
0a588949a7
7 changed files with 70 additions and 20 deletions
|
|
@ -4,7 +4,7 @@ set(TARGET_NAME "SWA")
|
||||||
option(SWA_XAUDIO2 "Use XAudio2 for audio playback" OFF)
|
option(SWA_XAUDIO2 "Use XAudio2 for audio playback" OFF)
|
||||||
|
|
||||||
function(BIN2C)
|
function(BIN2C)
|
||||||
cmake_parse_arguments(BIN2C_ARGS "" "TARGET_OBJ;SOURCE_FILE;DEST_FILE;ARRAY_TYPE;ARRAY_NAME" "" ${ARGN})
|
cmake_parse_arguments(BIN2C_ARGS "" "TARGET_OBJ;SOURCE_FILE;DEST_FILE;ARRAY_NAME;COMPRESSION_TYPE" "" ${ARGN})
|
||||||
|
|
||||||
if(NOT BIN2C_ARGS_TARGET_OBJ)
|
if(NOT BIN2C_ARGS_TARGET_OBJ)
|
||||||
message(FATAL_ERROR "TARGET_OBJ not specified.")
|
message(FATAL_ERROR "TARGET_OBJ not specified.")
|
||||||
|
|
@ -18,8 +18,12 @@ function(BIN2C)
|
||||||
set(BIN2C_ARGS_DEST_FILE "${BIN2C_ARGS_SOURCE_FILE}")
|
set(BIN2C_ARGS_DEST_FILE "${BIN2C_ARGS_SOURCE_FILE}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(NOT BIN2C_ARGS_COMPRESSION_TYPE)
|
||||||
|
set(BIN2C_ARGS_COMPRESSION_TYPE "none")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_custom_command(OUTPUT "${BIN2C_ARGS_DEST_FILE}.c"
|
add_custom_command(OUTPUT "${BIN2C_ARGS_DEST_FILE}.c"
|
||||||
COMMAND file_to_c "${BIN2C_ARGS_SOURCE_FILE}" "${BIN2C_ARGS_ARRAY_NAME}" "${BIN2C_ARGS_ARRAY_TYPE}" "${BIN2C_ARGS_DEST_FILE}.c" "${BIN2C_ARGS_DEST_FILE}.h"
|
COMMAND file_to_c "${BIN2C_ARGS_SOURCE_FILE}" "${BIN2C_ARGS_ARRAY_NAME}" "${BIN2C_ARGS_COMPRESSION_TYPE}" "${BIN2C_ARGS_DEST_FILE}.c" "${BIN2C_ARGS_DEST_FILE}.h"
|
||||||
DEPENDS "${BIN2C_ARGS_SOURCE_FILE}" file_to_c
|
DEPENDS "${BIN2C_ARGS_SOURCE_FILE}" file_to_c
|
||||||
BYPRODUCTS "${BIN2C_ARGS_DEST_FILE}.h"
|
BYPRODUCTS "${BIN2C_ARGS_DEST_FILE}.h"
|
||||||
COMMENT "Generating binary header for ${BIN2C_ARGS_SOURCE_FILE}..."
|
COMMENT "Generating binary header for ${BIN2C_ARGS_SOURCE_FILE}..."
|
||||||
|
|
@ -313,9 +317,9 @@ generate_aggregate_header(
|
||||||
set(RESOURCES_SOURCE_PATH "${PROJECT_SOURCE_DIR}/../UnleashedRecompResources")
|
set(RESOURCES_SOURCE_PATH "${PROJECT_SOURCE_DIR}/../UnleashedRecompResources")
|
||||||
set(RESOURCES_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/res")
|
set(RESOURCES_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/res")
|
||||||
|
|
||||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/achievements_menu/trophy.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/achievements_menu/trophy.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_trophy")
|
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/achievements_menu/trophy.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/achievements_menu/trophy.dds" ARRAY_NAME "g_trophy" COMPRESSION_TYPE "zstd")
|
||||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/general_window.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/general_window.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_general_window")
|
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/general_window.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/general_window.dds" ARRAY_NAME "g_general_window" COMPRESSION_TYPE "zstd")
|
||||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/select_fade.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/select_fade.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_select_fade")
|
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/select_fade.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/select_fade.dds" ARRAY_NAME "g_select_fade" COMPRESSION_TYPE "zstd")
|
||||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/select_fill.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/select_fill.dds" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_select_fill")
|
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/select_fill.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/select_fill.dds" ARRAY_NAME "g_select_fill" COMPRESSION_TYPE "zstd")
|
||||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/game_icon.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/game_icon.bmp" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_game_icon")
|
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/game_icon.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/game_icon.bmp" ARRAY_NAME "g_game_icon")
|
||||||
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/game_icon_night.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/game_icon_night.bmp" ARRAY_TYPE "unsigned char" ARRAY_NAME "g_game_icon_night")
|
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/game_icon_night.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/game_icon_night.bmp" ARRAY_NAME "g_game_icon_night")
|
||||||
|
|
|
||||||
9
UnleashedRecomp/decompressor.h
Normal file
9
UnleashedRecomp/decompressor.h
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
static std::unique_ptr<uint8_t[]> decompressZstd(const uint8_t(&data)[N], size_t decompressedSize)
|
||||||
|
{
|
||||||
|
auto decompressedData = std::make_unique<uint8_t[]>(decompressedSize);
|
||||||
|
ZSTD_decompress(decompressedData.get(), decompressedSize, data, N);
|
||||||
|
return decompressedData;
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include <user/config.h>
|
#include <user/config.h>
|
||||||
#include <app.h>
|
#include <app.h>
|
||||||
#include <exports.h>
|
#include <exports.h>
|
||||||
|
#include <decompressor.h>
|
||||||
#include <res/images/achievements_menu/trophy.dds.h>
|
#include <res/images/achievements_menu/trophy.dds.h>
|
||||||
#include <res/images/common/general_window.dds.h>
|
#include <res/images/common/general_window.dds.h>
|
||||||
#include <res/images/common/select_fill.dds.h>
|
#include <res/images/common/select_fill.dds.h>
|
||||||
|
|
@ -624,9 +625,9 @@ void AchievementMenu::Init()
|
||||||
g_fntNewRodinDB = io.Fonts->AddFontFromFileTTF("FOT-NewRodinPro-DB.otf", 20.0f * FONT_SCALE);
|
g_fntNewRodinDB = io.Fonts->AddFontFromFileTTF("FOT-NewRodinPro-DB.otf", 20.0f * FONT_SCALE);
|
||||||
g_fntNewRodinUB = io.Fonts->AddFontFromFileTTF("FOT-NewRodinPro-UB.otf", 20.0f * FONT_SCALE);
|
g_fntNewRodinUB = io.Fonts->AddFontFromFileTTF("FOT-NewRodinPro-UB.otf", 20.0f * FONT_SCALE);
|
||||||
|
|
||||||
g_upTrophyIcon = LoadTexture(g_trophy, sizeof(g_trophy));
|
g_upTrophyIcon = LoadTexture(decompressZstd(g_trophy, g_trophy_uncompressed_size).get(), g_trophy_uncompressed_size);
|
||||||
g_upSelectionCursor = LoadTexture(g_select_fill, sizeof(g_select_fill));
|
g_upSelectionCursor = LoadTexture(decompressZstd(g_select_fill, g_select_fill_uncompressed_size).get(), g_select_fill_uncompressed_size);
|
||||||
g_upWindow = LoadTexture(g_general_window, sizeof(g_general_window));
|
g_upWindow = LoadTexture(decompressZstd(g_general_window, g_general_window_uncompressed_size).get(), g_general_window_uncompressed_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AchievementMenu::Draw()
|
void AchievementMenu::Draw()
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include <user/achievement_data.h>
|
#include <user/achievement_data.h>
|
||||||
#include <app.h>
|
#include <app.h>
|
||||||
#include <exports.h>
|
#include <exports.h>
|
||||||
|
#include <decompressor.h>
|
||||||
#include <res/images/common/general_window.dds.h>
|
#include <res/images/common/general_window.dds.h>
|
||||||
|
|
||||||
constexpr double OVERLAY_CONTAINER_COMMON_MOTION_START = 0;
|
constexpr double OVERLAY_CONTAINER_COMMON_MOTION_START = 0;
|
||||||
|
|
@ -78,7 +79,7 @@ void AchievementOverlay::Init()
|
||||||
|
|
||||||
g_fntSeurat = io.Fonts->AddFontFromFileTTF("FOT-SeuratPro-M.otf", 24.0f * FONT_SCALE);
|
g_fntSeurat = io.Fonts->AddFontFromFileTTF("FOT-SeuratPro-M.otf", 24.0f * FONT_SCALE);
|
||||||
|
|
||||||
g_upWindow = LoadTexture(g_general_window, sizeof(g_general_window));
|
g_upWindow = LoadTexture(decompressZstd(g_general_window, g_general_window_uncompressed_size).get(), g_general_window_uncompressed_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AchievementOverlay::Draw()
|
void AchievementOverlay::Draw()
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include <api/SWA.h>
|
#include <api/SWA.h>
|
||||||
#include <gpu/video.h>
|
#include <gpu/video.h>
|
||||||
#include <exports.h>
|
#include <exports.h>
|
||||||
|
#include <decompressor.h>
|
||||||
#include <res/images/common/select_fade.dds.h>
|
#include <res/images/common/select_fade.dds.h>
|
||||||
|
|
||||||
constexpr double OVERLAY_CONTAINER_COMMON_MOTION_START = 0;
|
constexpr double OVERLAY_CONTAINER_COMMON_MOTION_START = 0;
|
||||||
|
|
@ -176,7 +177,7 @@ void MessageWindow::Init()
|
||||||
|
|
||||||
g_fntSeurat = io.Fonts->AddFontFromFileTTF("FOT-SeuratPro-M.otf", 28.0f * FONT_SCALE);
|
g_fntSeurat = io.Fonts->AddFontFromFileTTF("FOT-SeuratPro-M.otf", 28.0f * FONT_SCALE);
|
||||||
|
|
||||||
g_upSelectionCursor = LoadTexture(g_select_fade, sizeof(g_select_fade));
|
g_upSelectionCursor = LoadTexture(decompressZstd(g_select_fade, g_select_fade_uncompressed_size).get(), g_select_fade_uncompressed_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageWindow::Draw()
|
void MessageWindow::Draw()
|
||||||
|
|
|
||||||
|
|
@ -6,3 +6,6 @@ project("file_to_c")
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
add_executable(file_to_c "file_to_c.cpp")
|
add_executable(file_to_c "file_to_c.cpp")
|
||||||
|
|
||||||
|
find_package(zstd CONFIG REQUIRED)
|
||||||
|
target_link_libraries(file_to_c PRIVATE $<IF:$<TARGET_EXISTS:zstd::libzstd_static>,zstd::libzstd_static,zstd::libzstd>)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <zstd.h>
|
||||||
|
|
||||||
std::vector<char> read_file(const char* path) {
|
std::vector<char> read_file(const char* path) {
|
||||||
std::ifstream input_file{path, std::ios::binary};
|
std::ifstream input_file{path, std::ios::binary};
|
||||||
|
|
@ -55,13 +56,13 @@ void create_parent_if_needed(const char* path) {
|
||||||
|
|
||||||
int main(int argc, const char** argv) {
|
int main(int argc, const char** argv) {
|
||||||
if (argc != 6) {
|
if (argc != 6) {
|
||||||
printf("Usage: %s [input file] [array name] [array type] [output C file] [output C header]\n", argv[0]);
|
printf("Usage: %s [input file] [array name] [compression type] [output C file] [output C header]\n", argv[0]);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* input_path = argv[1];
|
const char* input_path = argv[1];
|
||||||
const char* array_name = argv[2];
|
const char* array_name = argv[2];
|
||||||
const char* array_type = argv[3];
|
std::string compression_type = argv[3];
|
||||||
const char* output_c_path = argv[4];
|
const char* output_c_path = argv[4];
|
||||||
const char* output_h_path = argv[5];
|
const char* output_h_path = argv[5];
|
||||||
|
|
||||||
|
|
@ -73,21 +74,44 @@ int main(int argc, const char** argv) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compress if requested.
|
||||||
|
std::vector<char> compressed_contents;
|
||||||
|
std::transform(compression_type.begin(), compression_type.end(), compression_type.begin(), tolower);
|
||||||
|
|
||||||
|
if (compression_type == "zstd") {
|
||||||
|
size_t bound_size = ZSTD_compressBound(contents.size());
|
||||||
|
compressed_contents.resize(bound_size);
|
||||||
|
|
||||||
|
size_t compressed_size = ZSTD_compress(compressed_contents.data(), bound_size, contents.data(), contents.size(), ZSTD_maxCLevel());
|
||||||
|
compressed_contents.resize(compressed_size);
|
||||||
|
}
|
||||||
|
else if (compression_type != "none") {
|
||||||
|
fprintf(stderr, "Unknown compression type %s!", compression_type.c_str());
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
// Create the output directories if they don't exist
|
// Create the output directories if they don't exist
|
||||||
create_parent_if_needed(output_c_path);
|
create_parent_if_needed(output_c_path);
|
||||||
create_parent_if_needed(output_h_path);
|
create_parent_if_needed(output_h_path);
|
||||||
|
|
||||||
// Write the C file with the array
|
// Write the C file with the array
|
||||||
|
std::vector<char>& contents_to_write = !compressed_contents.empty() ? compressed_contents : contents;
|
||||||
{
|
{
|
||||||
std::ofstream output_c_file{output_c_path};
|
std::ofstream output_c_file{output_c_path};
|
||||||
output_c_file << "extern " << array_type << " " << array_name << "[" << contents.size() << "];\n";
|
output_c_file << "extern unsigned char " << array_name << "[" << contents_to_write.size() << "];\n";
|
||||||
output_c_file << array_type << " " << array_name << "[" << contents.size() << "] = {";
|
output_c_file << "unsigned char " << array_name << "[" << contents_to_write.size() << "] = {";
|
||||||
|
|
||||||
for (char x : contents) {
|
for (char x : contents_to_write) {
|
||||||
output_c_file << (int)x << ", ";
|
output_c_file << (int)(unsigned char)x << ", ";
|
||||||
}
|
}
|
||||||
|
|
||||||
output_c_file << "};\n";
|
output_c_file << "};\n";
|
||||||
|
|
||||||
|
// Write decompressed size.
|
||||||
|
if (!compressed_contents.empty()) {
|
||||||
|
output_c_file << "extern size_t " << array_name << "_uncompressed_size;\n";
|
||||||
|
output_c_file << "size_t " << array_name << "_uncompressed_size = " << contents.size() << ";\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the header file with the extern array
|
// Write the header file with the extern array
|
||||||
|
|
@ -97,7 +121,14 @@ int main(int argc, const char** argv) {
|
||||||
"#ifdef __cplusplus\n"
|
"#ifdef __cplusplus\n"
|
||||||
" extern \"C\" {\n"
|
" extern \"C\" {\n"
|
||||||
"#endif\n"
|
"#endif\n"
|
||||||
"extern " << array_type << " " << array_name << "[" << contents.size() << "];\n"
|
"extern unsigned char " << array_name << "[" << contents_to_write.size() << "];\n";
|
||||||
|
|
||||||
|
// Write decompressed size.
|
||||||
|
if (!compressed_contents.empty()) {
|
||||||
|
output_h_file << "extern size_t " << array_name << "_uncompressed_size;\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
output_h_file <<
|
||||||
"#ifdef __cplusplus\n"
|
"#ifdef __cplusplus\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"#endif\n";
|
"#endif\n";
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue