feat(libretro_binding): build checkpoint

This commit is contained in:
XargonWan 2024-12-10 22:16:41 +09:00
parent 6e8828a5f3
commit 16de6b1d6e
2 changed files with 115 additions and 105 deletions

View file

@ -1,48 +1,20 @@
// libretro_binding.cpp
#include "libretro_binding.h" #include "libretro_binding.h"
#include <dlfcn.h>
#include <godot_cpp/core/class_db.hpp> #include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/variant/utility_functions.hpp> #include <godot_cpp/variant/utility_functions.hpp>
#include <dlfcn.h> #include <fstream>
#include <godot_cpp/variant/packed_byte_array.hpp>
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/classes/input_event.hpp>
using namespace godot; using namespace godot;
// Funzioni richieste dai core libretro bool LibretroCoreBinding::initialize(const String &core_path) {
typedef void (*retro_init_t)(); UtilityFunctions::print("Loading core: ", core_path);
typedef void (*retro_deinit_t)();
typedef bool (*retro_load_game_t)(const char *);
typedef void (*retro_run_t)();
typedef void (*retro_get_system_info_t)(struct retro_system_info *);
typedef void (*retro_get_video_frame_t)(void **frame, unsigned *width, unsigned *height);
class LibretroCoreBinding : public GodotObject {
GDCLASS(LibretroCoreBinding, Object);
private:
void *core_handle = nullptr; // Handle del core caricato
retro_init_t retro_init = nullptr;
retro_deinit_t retro_deinit = nullptr;
retro_load_game_t retro_load_game = nullptr;
retro_run_t retro_run = nullptr;
retro_get_video_frame_t retro_get_video_frame = nullptr;
unsigned frame_width = 0;
unsigned frame_height = 0;
PackedByteArray frame_buffer;
public:
bool initialize(const String &core_path) {
UtilityFunctions::print("Caricamento del core: ", core_path);
core_handle = dlopen(core_path.utf8().get_data(), RTLD_LAZY); core_handle = dlopen(core_path.utf8().get_data(), RTLD_LAZY);
if (!core_handle) { if (!core_handle) {
UtilityFunctions::print("Errore nel caricamento del core: ", dlerror()); UtilityFunctions::print("Error loading core: ", dlerror());
return false; return false;
} }
// Collegamento delle funzioni // Link functions
retro_init = (retro_init_t)dlsym(core_handle, "retro_init"); retro_init = (retro_init_t)dlsym(core_handle, "retro_init");
retro_deinit = (retro_deinit_t)dlsym(core_handle, "retro_deinit"); retro_deinit = (retro_deinit_t)dlsym(core_handle, "retro_deinit");
retro_load_game = (retro_load_game_t)dlsym(core_handle, "retro_load_game"); retro_load_game = (retro_load_game_t)dlsym(core_handle, "retro_load_game");
@ -50,63 +22,72 @@ public:
retro_get_video_frame = (retro_get_video_frame_t)dlsym(core_handle, "retro_get_video_frame"); retro_get_video_frame = (retro_get_video_frame_t)dlsym(core_handle, "retro_get_video_frame");
if (!retro_init || !retro_deinit || !retro_load_game || !retro_run || !retro_get_video_frame) { if (!retro_init || !retro_deinit || !retro_load_game || !retro_run || !retro_get_video_frame) {
UtilityFunctions::print("Errore: funzioni mancanti nel core."); UtilityFunctions::print("Error: Missing functions in core.");
dlclose(core_handle); dlclose(core_handle);
core_handle = nullptr; core_handle = nullptr;
return false; return false;
} }
retro_init(); retro_init();
UtilityFunctions::print("Core inizializzato con successo."); UtilityFunctions::print("Core successfully initialized.");
return true; return true;
} }
bool load_game(const PackedByteArray &rom_data) { bool LibretroCoreBinding::load_game(const PackedByteArray &rom_data) {
if (!core_handle || !retro_load_game) { if (!core_handle) {
UtilityFunctions::print("Errore: Core non inizializzato."); UtilityFunctions::print("Error: Core not loaded.");
return false; return false;
} }
// Salviamo temporaneamente il file ROM // Save ROM to a temporary file
String temp_rom_path = "/tmp/libretro_temp.rom"; std::string temp_rom_path = "/tmp/libretro_temp.rom";
File *temp_file = File::open(temp_rom_path, File::WRITE); std::ofstream temp_file(temp_rom_path, std::ios::binary);
temp_file->store_buffer(rom_data); if (!temp_file.is_open()) {
temp_file->close(); UtilityFunctions::print("Error: Unable to open temporary ROM file.");
memdelete(temp_file); return false;
}
bool result = retro_load_game(temp_rom_path.utf8().get_data()); // Write the ROM data to the file
temp_file.write(reinterpret_cast<const char *>(rom_data.ptr()), rom_data.size());
temp_file.close();
bool result = retro_load_game(temp_rom_path.c_str());
if (result) { if (result) {
UtilityFunctions::print("ROM caricata con successo: ", temp_rom_path); UtilityFunctions::print("ROM successfully loaded: ", temp_rom_path.c_str());
} else { } else {
UtilityFunctions::print("Errore nel caricamento della ROM."); UtilityFunctions::print("Error: Failed to load ROM.");
} }
return result; return result;
} }
void run() { void LibretroCoreBinding::run() {
if (!core_handle || !retro_run) { if (!core_handle || !retro_run) {
UtilityFunctions::print("Errore: Core non inizializzato."); UtilityFunctions::print("Error: Core not initialized.");
return; return;
} }
retro_run(); retro_run();
} }
PackedByteArray get_frame_buffer() { PackedByteArray LibretroCoreBinding::get_frame_buffer() {
if (!core_handle || !retro_get_video_frame) { if (!core_handle || !retro_get_video_frame) {
UtilityFunctions::print("Errore: Core non inizializzato."); UtilityFunctions::print("Error: Core not initialized.");
return PackedByteArray(); return PackedByteArray();
} }
void *frame = nullptr; void *frame = nullptr;
retro_get_video_frame(&frame, &frame_width, &frame_height); retro_get_video_frame(&frame, &frame_width, &frame_height);
frame_buffer.resize(frame_width * frame_height * 4); // Assumiamo formato RGBA frame_buffer.resize(frame_width * frame_height * 4); // Assume RGBA format
memcpy(frame_buffer.ptrw(), frame, frame_buffer.size()); memcpy(frame_buffer.ptrw(), frame, frame_buffer.size());
return frame_buffer; return frame_buffer;
} }
int get_frame_width() const { return frame_width; } int LibretroCoreBinding::get_frame_width() const {
int get_frame_height() const { return frame_height; } return frame_width;
}; }
int LibretroCoreBinding::get_frame_height() const {
return frame_height;
}

View file

@ -1,12 +1,41 @@
// libretro_binding.h #ifndef LIBRETRO_CORE_BINDING_H
class LibretroCoreBinding : public GodotObject { #define LIBRETRO_CORE_BINDING_H
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
#include <godot_cpp/variant/packed_byte_array.hpp>
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/classes/object.hpp> // Correct base class
// Typedefs for libretro core functions
typedef void (*retro_init_t)();
typedef void (*retro_deinit_t)();
typedef bool (*retro_load_game_t)(const char *);
typedef void (*retro_run_t)();
typedef void (*retro_get_video_frame_t)(void **, unsigned *, unsigned *);
class LibretroCoreBinding : public godot::Object {
GDCLASS(LibretroCoreBinding, godot::Object);
private:
void *core_handle = nullptr;
retro_init_t retro_init = nullptr;
retro_deinit_t retro_deinit = nullptr;
retro_load_game_t retro_load_game = nullptr;
retro_run_t retro_run = nullptr;
retro_get_video_frame_t retro_get_video_frame = nullptr;
unsigned frame_width = 0;
unsigned frame_height = 0;
godot::PackedByteArray frame_buffer;
public: public:
// Metodi da esporre a GDScript bool initialize(const godot::String &core_path);
bool initialize(); bool load_game(const godot::PackedByteArray &rom_data);
bool load_game(const PackedByteArray& rom_data);
void run(); void run();
PackedByteArray get_frame_buffer(); godot::PackedByteArray get_frame_buffer();
int get_frame_width(); int get_frame_width() const;
int get_frame_height(); int get_frame_height() const;
void handle_input(const Ref<InputEvent>& event);
}; };
#endif // LIBRETRO_CORE_BINDING_H