mirror of
https://github.com/RetroDECK/RetroQUEST.git
synced 2025-04-21 01:24:06 +00:00
feat(libretro_binding): build checkpoint
This commit is contained in:
parent
6e8828a5f3
commit
16de6b1d6e
|
@ -1,112 +1,93 @@
|
|||
// libretro_binding.cpp
|
||||
#include "libretro_binding.h"
|
||||
#include <dlfcn.h>
|
||||
#include <godot_cpp/core/class_db.hpp>
|
||||
#include <godot_cpp/variant/utility_functions.hpp>
|
||||
#include <dlfcn.h>
|
||||
#include <godot_cpp/variant/packed_byte_array.hpp>
|
||||
#include <godot_cpp/classes/ref.hpp>
|
||||
#include <godot_cpp/classes/input_event.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
using namespace godot;
|
||||
|
||||
// Funzioni richieste dai core libretro
|
||||
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_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);
|
||||
if (!core_handle) {
|
||||
UtilityFunctions::print("Errore nel caricamento del core: ", dlerror());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Collegamento delle funzioni
|
||||
retro_init = (retro_init_t)dlsym(core_handle, "retro_init");
|
||||
retro_deinit = (retro_deinit_t)dlsym(core_handle, "retro_deinit");
|
||||
retro_load_game = (retro_load_game_t)dlsym(core_handle, "retro_load_game");
|
||||
retro_run = (retro_run_t)dlsym(core_handle, "retro_run");
|
||||
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) {
|
||||
UtilityFunctions::print("Errore: funzioni mancanti nel core.");
|
||||
dlclose(core_handle);
|
||||
core_handle = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
retro_init();
|
||||
UtilityFunctions::print("Core inizializzato con successo.");
|
||||
return true;
|
||||
bool LibretroCoreBinding::initialize(const String &core_path) {
|
||||
UtilityFunctions::print("Loading core: ", core_path);
|
||||
core_handle = dlopen(core_path.utf8().get_data(), RTLD_LAZY);
|
||||
if (!core_handle) {
|
||||
UtilityFunctions::print("Error loading core: ", dlerror());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool load_game(const PackedByteArray &rom_data) {
|
||||
if (!core_handle || !retro_load_game) {
|
||||
UtilityFunctions::print("Errore: Core non inizializzato.");
|
||||
return false;
|
||||
}
|
||||
// Link functions
|
||||
retro_init = (retro_init_t)dlsym(core_handle, "retro_init");
|
||||
retro_deinit = (retro_deinit_t)dlsym(core_handle, "retro_deinit");
|
||||
retro_load_game = (retro_load_game_t)dlsym(core_handle, "retro_load_game");
|
||||
retro_run = (retro_run_t)dlsym(core_handle, "retro_run");
|
||||
retro_get_video_frame = (retro_get_video_frame_t)dlsym(core_handle, "retro_get_video_frame");
|
||||
|
||||
// Salviamo temporaneamente il file ROM
|
||||
String temp_rom_path = "/tmp/libretro_temp.rom";
|
||||
File *temp_file = File::open(temp_rom_path, File::WRITE);
|
||||
temp_file->store_buffer(rom_data);
|
||||
temp_file->close();
|
||||
memdelete(temp_file);
|
||||
|
||||
bool result = retro_load_game(temp_rom_path.utf8().get_data());
|
||||
if (result) {
|
||||
UtilityFunctions::print("ROM caricata con successo: ", temp_rom_path);
|
||||
} else {
|
||||
UtilityFunctions::print("Errore nel caricamento della ROM.");
|
||||
}
|
||||
|
||||
return result;
|
||||
if (!retro_init || !retro_deinit || !retro_load_game || !retro_run || !retro_get_video_frame) {
|
||||
UtilityFunctions::print("Error: Missing functions in core.");
|
||||
dlclose(core_handle);
|
||||
core_handle = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
void run() {
|
||||
if (!core_handle || !retro_run) {
|
||||
UtilityFunctions::print("Errore: Core non inizializzato.");
|
||||
return;
|
||||
}
|
||||
retro_init();
|
||||
UtilityFunctions::print("Core successfully initialized.");
|
||||
return true;
|
||||
}
|
||||
|
||||
retro_run();
|
||||
bool LibretroCoreBinding::load_game(const PackedByteArray &rom_data) {
|
||||
if (!core_handle) {
|
||||
UtilityFunctions::print("Error: Core not loaded.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PackedByteArray get_frame_buffer() {
|
||||
if (!core_handle || !retro_get_video_frame) {
|
||||
UtilityFunctions::print("Errore: Core non inizializzato.");
|
||||
return PackedByteArray();
|
||||
}
|
||||
|
||||
void *frame = nullptr;
|
||||
retro_get_video_frame(&frame, &frame_width, &frame_height);
|
||||
|
||||
frame_buffer.resize(frame_width * frame_height * 4); // Assumiamo formato RGBA
|
||||
memcpy(frame_buffer.ptrw(), frame, frame_buffer.size());
|
||||
return frame_buffer;
|
||||
// Save ROM to a temporary file
|
||||
std::string temp_rom_path = "/tmp/libretro_temp.rom";
|
||||
std::ofstream temp_file(temp_rom_path, std::ios::binary);
|
||||
if (!temp_file.is_open()) {
|
||||
UtilityFunctions::print("Error: Unable to open temporary ROM file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
int get_frame_width() const { return frame_width; }
|
||||
int get_frame_height() const { return frame_height; }
|
||||
};
|
||||
// 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) {
|
||||
UtilityFunctions::print("ROM successfully loaded: ", temp_rom_path.c_str());
|
||||
} else {
|
||||
UtilityFunctions::print("Error: Failed to load ROM.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void LibretroCoreBinding::run() {
|
||||
if (!core_handle || !retro_run) {
|
||||
UtilityFunctions::print("Error: Core not initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
retro_run();
|
||||
}
|
||||
|
||||
PackedByteArray LibretroCoreBinding::get_frame_buffer() {
|
||||
if (!core_handle || !retro_get_video_frame) {
|
||||
UtilityFunctions::print("Error: Core not initialized.");
|
||||
return PackedByteArray();
|
||||
}
|
||||
|
||||
void *frame = nullptr;
|
||||
retro_get_video_frame(&frame, &frame_width, &frame_height);
|
||||
|
||||
frame_buffer.resize(frame_width * frame_height * 4); // Assume RGBA format
|
||||
memcpy(frame_buffer.ptrw(), frame, frame_buffer.size());
|
||||
return frame_buffer;
|
||||
}
|
||||
|
||||
int LibretroCoreBinding::get_frame_width() const {
|
||||
return frame_width;
|
||||
}
|
||||
|
||||
int LibretroCoreBinding::get_frame_height() const {
|
||||
return frame_height;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,41 @@
|
|||
// libretro_binding.h
|
||||
class LibretroCoreBinding : public GodotObject {
|
||||
#ifndef LIBRETRO_CORE_BINDING_H
|
||||
#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:
|
||||
// Metodi da esporre a GDScript
|
||||
bool initialize();
|
||||
bool load_game(const PackedByteArray& rom_data);
|
||||
bool initialize(const godot::String &core_path);
|
||||
bool load_game(const godot::PackedByteArray &rom_data);
|
||||
void run();
|
||||
PackedByteArray get_frame_buffer();
|
||||
int get_frame_width();
|
||||
int get_frame_height();
|
||||
void handle_input(const Ref<InputEvent>& event);
|
||||
godot::PackedByteArray get_frame_buffer();
|
||||
int get_frame_width() const;
|
||||
int get_frame_height() const;
|
||||
};
|
||||
|
||||
#endif // LIBRETRO_CORE_BINDING_H
|
||||
|
|
Loading…
Reference in a new issue