Add New Logo By @MasterHimuro (#17)

* Add New Logo By @MasterHimuro
* Fix compiler issues for VS 2019
* Extractor cli is completed, still has some issues for file name for us and jp
* Add Linux 32bit Toolchain
This commit is contained in:
William Adam-Grenier 2022-06-02 14:27:12 -04:00 committed by GitHub
parent 569a77c4fb
commit 911b59c202
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 70335 additions and 72 deletions

View File

@ -1,5 +1,9 @@
cmake_minimum_required(VERSION 3.20.2)
if (UNIX)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/cmake/linux-compiler-i386-multilib.cmake CACHE STRING "")
endif ()
project(Mikompilation CXX)
set(CMAKE_CXX_STANDARD 20)
@ -20,7 +24,11 @@ set(SOURCES
src/main.cpp
)
add_executable(Mikompilation ${SOURCES})
if (WIN32)
set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_CURRENT_SOURCE_DIR}/icon.rc")
ENDIF ()
add_executable(Mikompilation ${SOURCES} ${APP_ICON_RESOURCE_WINDOWS})
target_link_libraries(Mikompilation PUBLIC
${UI_LIB}
@ -35,8 +43,8 @@ target_include_directories(Mikompilation PUBLIC
)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/resources $<TARGET_FILE_DIR:${PROJECT_NAME}>/resources)
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/resources $<TARGET_FILE_DIR:${PROJECT_NAME}>/resources)
file(
GENERATE

View File

@ -1,11 +1,17 @@
# Mikompilation
[![Build Mikompilation](https://github.com/wagrenier/Mikompilation/actions/workflows/Build.yml/badge.svg)](https://github.com/wagrenier/Mikompilation/actions/workflows/Build.yml) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/Ap4Sfcmwd9)
![Logo](logo/logo_blood.png)
Decompilation project for the Fatal Frame 2 : Crimson ButterflyProject Zero 2<ruby><rt>ぜろ</rt></ruby><ruby>紅い蝶<rt>あかいちょう</rt> game engine. Our goal is to have a fully playable port on PC and maybe on future platforms too.
Mainly a project to learn about reversing and coding in OpenGL.
## Special Thanks
* [@MasterHimuro](https://twitter.com/masterhimuro) for doing the logo
## Build
Right now, the application only builds for `x32` due to restrictions from the game's code and memory layout.
### Linux
Run the following commands to install the required dependencies:
@ -15,22 +21,26 @@ sudo apt install xorg-dev
```
## Common
Library containing all common functions needed by most libraries of the proejct. Contains things like vector math, configurations and printing.
Library containing all common functions needed by most libraries of the project. Contains things like vector math, configurations and printing.
## Engine
This folder contains all sources related to the game engine.
## Extractor
Tools for extracting game files.
## Tools
### Argparse
Library for making cli simple
## Render
Library for interfacing with the graphics api, for the moment it is only OpenGL
### ExportStruct
Tool to export raw values from an elf to a well formatted struct.
### Extractor
Tools for extracting game files. This tool should run before the main executable
## Third-Party
Library containing all of the project's external libraries.
Library containing all the project's external libraries.
## UI
Library containing the source code for the UI, mostly ImGui realted stuff.
Library containing the source code for the UI, mostly ImGui related stuff.
## Src
Folder containing the main logic of the application.

View File

@ -0,0 +1,55 @@
# Tell cmake we are cross compiling and targeting linux
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR i686)
# It could be i?86-*linux-gnu, x86_64-*linux-gnu, x86_64-*linux-gnux32, etc.
# Leave it generic to only support amd64 or x32 to i386 with any compiler.
if ("$ENV{CC}" STREQUAL "")
set(CMAKE_C_COMPILER cc -m32)
elseif(NOT "$ENV{CC}" MATCHES "-m32")
set(CMAKE_C_COMPILER $ENV{CC} -m32)
endif()
if ("$ENV{CXX}" STREQUAL "")
set(CMAKE_CXX_COMPILER c++ -m32)
elseif(NOT "$ENV{CXX}" MATCHES "-m32")
set(CMAKE_CXX_COMPILER $ENV{CXX} -m32)
endif()
# cmake 2.8.5 correctly sets CMAKE_LIBRARY_ARCHITECTURE for Debian multiarch.
# Be really strict about what gets used.
if(EXISTS /usr/lib/i386-linux-gnu)
set(CMAKE_SYSTEM_IGNORE_PATH
/lib /lib64 /lib32
/usr/lib /usr/lib64 /usr/lib32
/usr/local/lib /usr/local/lib64 /usr/local/lib32)
list(APPEND CMAKE_LIBRARY_PATH /usr/local/lib/i386-linux-gnu)
list(APPEND CMAKE_LIBRARY_PATH /usr/lib/i386-linux-gnu)
list(APPEND CMAKE_LIBRARY_PATH /lib/i386-linux-gnu)
elseif(EXISTS /usr/lib32)
set(CMAKE_SYSTEM_IGNORE_PATH
/lib /lib64
/usr/lib /usr/lib64
/usr/local/lib /usr/local/lib64)
set(CMAKE_LIBRARY_ARCHITECTURE "../lib32")
list(APPEND CMAKE_LIBRARY_PATH /usr/local/lib32)
list(APPEND CMAKE_LIBRARY_PATH /usr/lib32)
list(APPEND CMAKE_LIBRARY_PATH /lib32)
else()
set(CMAKE_SYSTEM_IGNORE_PATH
/lib64
/usr/lib64
/usr/local/lib64)
set(CMAKE_LIBRARY_ARCHITECTURE ".")
list(APPEND CMAKE_LIBRARY_PATH /usr/local/lib)
list(APPEND CMAKE_LIBRARY_PATH /usr/lib)
list(APPEND CMAKE_LIBRARY_PATH /lib)
endif()
list(REMOVE_DUPLICATES CMAKE_LIBRARY_PATH)
# If given a CMAKE_FIND_ROOT_PATH then
# FIND_PROGRAM ignores CMAKE_FIND_ROOT_PATH (probably can't run)
# FIND_{LIBRARY,INCLUDE,PACKAGE} only uses the files in CMAKE_FIND_ROOT_PATH.
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

View File

@ -1,5 +1,6 @@
#pragma once
#include <string>
#include <thread>
#include <vector>

View File

@ -1,23 +1,20 @@
#include "glf3_render.h"
#include "GFX_CONFIG.h"
#include <cstdio>
#include <iostream>
#include "spdlog/spdlog.h"
#include "logging/printing.h"
#include "spdlog/spdlog.h"
#include <cstdio>
void GLAPIENTRY
MessageCallback(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam )
#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"
void GLAPIENTRY MessageCallback(GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length,
const GLchar *message, const void *userParam)
{
const auto logger = spdlog::get(ENGINE_LOGGER);
logger->error("GL CALLBACK: {} type = {:x}, severity = {:x}, message = {}",
(type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
type, severity, message);
(type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), type,
severity, message);
}
GLFWwindow *InitializeWindow()
@ -36,22 +33,36 @@ GLFWwindow *InitializeWindow()
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glEnable(GL_DEBUG_OUTPUT );
glEnable(GL_DEBUG_OUTPUT);
engineLogger->info("Creating GLFW window");
GLFWwindow *window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Mikompilation", NULL, NULL);
GLFWwindow *window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT,
"Mikompilation", NULL, NULL);
int width, height, channel;
stbi_uc *img = stbi_load("resources/icon.png", &width, &height, &channel, 0);
GLFWimage glfwImage;
glfwImage.width = width;
glfwImage.height = height;
glfwImage.pixels = img;
glfwSetWindowIcon(window, 1, &glfwImage);
stbi_image_free(img);
glfwMakeContextCurrent(window);
glewExperimental = GL_TRUE;
GLenum err = glewInit();
glDebugMessageCallback( MessageCallback, 0 );
glDebugMessageCallback(MessageCallback, 0);
if (GLEW_OK != err)
{
engineLogger->critical("GLFW failed to initialize: {}", glewGetErrorString(err));
engineLogger->critical("GLFW failed to initialize: {}",
glewGetErrorString(err));
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
@ -89,7 +100,7 @@ void teardown(GLFWwindow *window)
void startNewFrame()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f );
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}

1
icon.rc Normal file
View File

@ -0,0 +1 @@
IDI_ICON1 ICON "logo/logo_blood_icon.ico"

BIN
logo/logo_blood.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

BIN
logo/logo_blood_icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

BIN
logo/logo_icon_png.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

BIN
logo/logo_water.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 KiB

BIN
resources/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

View File

@ -1,4 +1,3 @@
#pragma once
#include "gfx/glf3_render.h"
#include "MainWindow.h"
#include "game_main.h"

View File

@ -27,6 +27,7 @@ set(THIRDPARTY_SOURCES
set(THIRDPARTY_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/imgui_memory_editor/imgui_memory_editor.h
${CMAKE_CURRENT_SOURCE_DIR}/stb/stb_image.h
)

7897
third-party/stb/stb_image.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +1,47 @@
#include <string>
#include <filesystem>
#include <fstream>
#include <stdio.h>
#include <string>
using namespace std;
const char* FILE_NAME = "";
const char* FILE_NAME = "D:\\Games\\Emulator\\PS2\\Games\\Fatal Frame\\Europe\\Debug\\Project Zero 2 Prototype (Feb_6,_2004_prototype)\\SLES_523.elf";
const int NUM_ELEMENTS = 94;
const int NUM_ELEMENTS = 0x118B;
const int OFFSET_ADDRESS = 0x218758;
const int OFFSET_ADDRESS = 0x2DE3D0;
const int ELF_OFFSET_ADDRESS = 0x003dd3d0;
const int OFFSET_DIFF = ELF_OFFSET_ADDRESS - OFFSET_ADDRESS;
struct StructToConvert
{
int a;
int b;
int c;
int d;
char a;
char b;
char c;
char d;
int e;
};
StructToConvert* readFullFile()
char* readFullFile()
{
std::ifstream infile(FILE_NAME, std::ios::binary);
auto fileSize = std::filesystem::file_size(FILE_NAME);
infile.seekg(0, std::ios::beg);
char *buffer = new char[fileSize];
infile.read(buffer, fileSize);
infile.close();
return buffer;
}
StructToConvert* readFileFromOffset()
{
std::ifstream infile(FILE_NAME, std::ios::binary);
@ -37,24 +60,63 @@ StructToConvert* readFullFile()
void printStructCode(const StructToConvert* structToConvert)
{
printf("GPHASE_STRUCT gphase_tbl[%d] = \n{", NUM_ELEMENTS);
//printf("inline Zero2FileInfo filename_dat_us[0x106B] = \n{");
auto fullFile = readFullFile();
int totalFiles = 0;
for(int i = 0; i < NUM_ELEMENTS; i++)
{
printf("\n\t{");
printf("\n\t\t(GPHASE_LAYER) %d,", structToConvert[i].a);
printf("\n\t\t(GPHASE_ID) %d,", structToConvert[i].b);
printf("\n\t\t(GPHASE_ID) %d,", structToConvert[i].c);
printf("\n\t\t(GPHASE_ID) %d", structToConvert[i].d);
printf("\n\t},");
// Since it is a pointer in the elf
char* a = (char*) &fullFile[structToConvert[i].e - OFFSET_DIFF];
std::string b = a;
auto justFilename = b.substr(0, b.find("."));
if (justFilename == "ubi_rogo")
{
printf("\n%s", a);
continue;
}
auto fileLanguage = justFilename.substr(justFilename.size() - 2, 2);
if (b == "snp_tb2_nar_s.pk2" || b == "lang_sl.pk2")
{
}
else if (fileLanguage == "_f" || fileLanguage == "_g" || fileLanguage == "_s" || fileLanguage == "_i")
{
printf("\n%s", a);
continue;
}
auto fileRegion = justFilename.substr(justFilename.size() - 3, 3);
if (fileRegion == "PAL")
{
printf("\n%s", a);
continue;
}
totalFiles += 1;
//printf("\n\t{");
//printf("\n\t\t%d,", structToConvert[i].a);
//printf("\n\t\t%d,", structToConvert[i].b);
//printf("\n\t\t%d,", structToConvert[i].c);
//printf("\n\t\t%d,", structToConvert[i].d);
//printf("\n\t\t(char*) \"%s\"", a);
//printf("\n\t},");
}
printf("\n};");
//printf("\n};");
printf("\n%d", totalFiles);
}
int main(int argc, char *argv[])
{
StructToConvert* structToConvert = readFullFile();
StructToConvert* structToConvert = readFileFromOffset();
printStructCode(structToConvert);

View File

@ -4,4 +4,6 @@ project(Extractor CXX)
set(CMAKE_CXX_STANDARD 20)
add_executable(Extractor extractor.h extractor.cpp deless.h deless.cpp)
include_directories(../argparse)
add_executable(Extractor extractor.h extractor.cpp deless.h deless.cpp ../argparse/argparse.hpp)

View File

@ -1,6 +1,11 @@
#include "extractor.h"
#include <fstream>
#include "deless.h"
#include <fstream>
int NUM_FILES;
int FILE_TABLE_ADDRESS;
std::string REGION;
bool EXTRACT_FILE_NAME;
char *ReadFullFile(const char *filename)
{
@ -35,10 +40,10 @@ char *ReadRangeFile(const char *filename, int startAddress, int readLength)
return buffer;
}
void DecompressFile(int file, const std::filesystem::path outputFolder)
void DecompressFile(std::string file)
{
std::string initialFile = outputFolder.string() + "/" + std::to_string(file) + ".bin";
std::string targetFile = outputFolder.string() + "/" + std::to_string(file) + ".bin" + ".LED";
std::string initialFile = file;
std::string targetFile = file + ".LED";
Decompress(initialFile.c_str(), targetFile.c_str());
@ -47,7 +52,8 @@ void DecompressFile(int file, const std::filesystem::path outputFolder)
std::filesystem::rename(targetFile, initialFile);
}
void ExtractZero2GameFiles(const char *imgBdFile, const char *elf, const std::filesystem::path outputFolder)
void ExtractZero2GameFiles(const char *imgBdFile, const char *elf,
const std::filesystem::path outputFolder)
{
if (!std::filesystem::exists(outputFolder))
{
@ -55,21 +61,26 @@ void ExtractZero2GameFiles(const char *imgBdFile, const char *elf, const std::fi
}
std::ifstream fileDataBank(imgBdFile, std::ios::binary);
Zero2File *fileHd = (Zero2File *)ReadRangeFile(elf, FILE_TABLE_ADDRESS_US_ZERO2, NUM_FILES_US_JP_ZERO2 * sizeof(Zero2File));
Zero2File *fileHd = (Zero2File *) ReadRangeFile(
elf, FILE_TABLE_ADDRESS, NUM_FILES * sizeof(Zero2File));
char fileBuffer[PS2_SECTOR_SIZE];
for (int i = 0; i < NUM_FILES_US_JP_ZERO2; i++)
for (int i = 0; i < NUM_FILES; i++)
{
printf("Extracting file %d/%d done\n", i, NUM_FILES_US_JP_ZERO2);
std::string outputFile = GetFilenameWithPath(i, outputFolder);
printf("Extracting %d/%d %s\n", i, NUM_FILES - 1, outputFile.c_str());
FileType fileStatus = (FileType) (fileHd[i].info & 0b00000011);
// Some files index are bugged and have a type File but with a size of 0 bytes
if (fileStatus == NoFile ||
(fileStatus == FileNotCompressed && fileHd[i].size == 0) ||
(fileStatus == FileCompressed && fileHd[i].sizeCompressed == 0))
if (fileStatus == NoFile
|| (fileStatus == FileNotCompressed && fileHd[i].size == 0)
|| (fileStatus == FileCompressed && fileHd[i].sizeCompressed == 0))
{
printf("Ignored\n");
continue;
}
@ -77,9 +88,9 @@ void ExtractZero2GameFiles(const char *imgBdFile, const char *elf, const std::fi
fileDataBank.seekg(startAddress, std::ios::beg);
int size = fileStatus == FileNotCompressed ? fileHd[i].size : fileHd[i].sizeCompressed;
int size = fileStatus == FileNotCompressed ? fileHd[i].size
: fileHd[i].sizeCompressed;
std::string outputFile = outputFolder.string() + "/" + std::to_string(i) + ".bin";
FILE *pFile = fopen(outputFile.c_str(), "wb+");
for (int k = 0; k <= size / PS2_SECTOR_SIZE; k++)
@ -92,7 +103,7 @@ void ExtractZero2GameFiles(const char *imgBdFile, const char *elf, const std::fi
if (fileStatus == FileCompressed)
{
DecompressFile(i, outputFolder);
DecompressFile(outputFile);
}
}
@ -100,7 +111,32 @@ void ExtractZero2GameFiles(const char *imgBdFile, const char *elf, const std::fi
delete[] fileHd;
}
void ExtractGameFilesFromBank(const char *imgHdFile, const char *imgBdFile, std::filesystem::path outputFolder)
std::string GetFilenameWithPath(int fileId, std::filesystem::path outputFolder)
{
if (!EXTRACT_FILE_NAME)
{
return outputFolder.string() + std::to_string(fileId) + ".bin";
}
auto fileInfo =
REGION == REGION_EU ? filename_dat[fileId] : filename_dat_us[fileId];
auto filename = fileInfo.name;
auto directory = filename_path[fileInfo.directory];
auto fullDirectory = outputFolder.string() + "/" + directory;
if (!std::filesystem::exists(fullDirectory))
{
std::filesystem::create_directories(fullDirectory);
}
return fullDirectory + filename;
}
void ExtractGameFilesFromBank(const char *imgHdFile, const char *imgBdFile,
std::filesystem::path outputFolder)
{
ZeroFile *fileHd = (ZeroFile *) ReadFullFile(imgHdFile);
@ -108,7 +144,7 @@ void ExtractGameFilesFromBank(const char *imgHdFile, const char *imgBdFile, std:
char fileBuffer[PS2_SECTOR_SIZE];
for (int i = 0; i < NUM_FILES_US_ZERO; i++)
for (int i = 0; i < NUM_FILES; i++)
{
unsigned long startAddress = fileHd[i].address * PS2_SECTOR_SIZE;
@ -119,7 +155,8 @@ void ExtractGameFilesFromBank(const char *imgHdFile, const char *imgBdFile, std:
continue;
}
std::string outputFile = outputFolder.string() + "/" + std::to_string(i) + ".bin";
std::string outputFile = GetFilenameWithPath(i, outputFolder);
FILE *pFile = fopen(outputFile.c_str(), "wb+");
for (int k = 0; k <= fileHd[i].size / PS2_SECTOR_SIZE; k++)
@ -135,15 +172,79 @@ void ExtractGameFilesFromBank(const char *imgHdFile, const char *imgBdFile, std:
delete[] fileHd;
}
void Extractor(argparse::ArgumentParser args)
{
REGION = args.get("region");
EXTRACT_FILE_NAME = args["--name"] == true;
if (REGION == REGION_US)
{
NUM_FILES = NUM_FILES_US_JP_ZERO2;
FILE_TABLE_ADDRESS = FILE_TABLE_ADDRESS_US_ZERO2;
}
else if (REGION == REGION_JP)
{
NUM_FILES = NUM_FILES_US_JP_ZERO2;
FILE_TABLE_ADDRESS = FILE_TABLE_ADDRESS_JP_ZERO2;
}
else
{
NUM_FILES = NUM_FILES_EU_ZERO2;
FILE_TABLE_ADDRESS = FILE_TABLE_ADDRESS_EU_ZERO2;
}
ExtractZero2GameFiles(args.get("bin").c_str(), args.get("elf").c_str(),
args.get("output").c_str());
}
int main(int argc, char *argv[])
{
if (argc < 4)
argparse::ArgumentParser program("Mikompilation Extractor");
program.add_argument("bin")
.help("Absolute path with file to the game's IMG_BD.BIN")
.required();
program.add_argument("elf")
.help("Absolute path with file to the game's elf (US: SLUS_207.66)")
.required();
program.add_argument("-o", "--output")
.help("Output folder where all files will be extracted")
.default_value(std::filesystem::current_path().string());
program.add_argument("-n", "--name")
.help("Will extract the files' name and directory")
.default_value(false)
.implicit_value(true);
program.add_argument("-r", "--region")
.default_value("us")
.action([](const std::string &value) {
static const std::vector<std::string> choices = {
REGION_US, REGION_EU, REGION_JP
};
if (std::find(choices.begin(), choices.end(), value) != choices.end())
{
return value;
}
return std::string {REGION_US};
});
try
{
printf("ERROR NOT ENOUGH ARGUMENTS\n To use: <full path to IMG_BD.BIN> <full path to SLUS_207.66> <Your output folder>");
return -1;
program.parse_args(argc, argv);
}
ExtractZero2GameFiles(argv[1], argv[2], argv[3]);
catch (const std::runtime_error &err)
{
std::cerr << err.what() << std::endl;
std::cerr << program;
std::exit(1);
}
Extractor(program);
return 0;
}

File diff suppressed because it is too large Load Diff

1174
tools/argparse/argparse.hpp Normal file

File diff suppressed because it is too large Load Diff