From 81639410032c55c0fcef2597467dc3e4220caee9 Mon Sep 17 00:00:00 2001 From: XargonWan Date: Fri, 27 Dec 2024 12:02:35 +0900 Subject: [PATCH] Deleted prompt.md --- prompt.md | 1060 ----------------------------------------------------- 1 file changed, 1060 deletions(-) delete mode 100644 prompt.md diff --git a/prompt.md b/prompt.md deleted file mode 100644 index 1ed46ae..0000000 --- a/prompt.md +++ /dev/null @@ -1,1060 +0,0 @@ -RetroQUEST is an application mainly written for Meta Quest 3 with Linux non-VR support in Godot 4.3. -In the future will be added supporto for Widnows, Mac and other VRs as well. -The app is working mainly with VR controls but can be used even with desktop controls (mouse, keyboard, controllers). -The app is Quest Native and not PCVR. -The scope of this application is to emulate games and render them on a virtual CRT TV in the VR space, more features will be added later. -The first iteration will be to be able to run the rom roms/megadrive/Sonic -For this scope I am using gdlibretro (https://github.com/gabrielmedici/gdlibretro) with some modifications to make it work on Linux and Android. -Here is my directory structure -. -├── addons -│   ├── godot-xr-tools -│   ├── libLibRetroHost-d.so -│   ├── LibRetroHost.gdextension -│   └── xr-simulator -├── assets -│   ├── Brick Wall Texture.jpg -│   ├── Brick Wall Texture.jpg.import -│   ├── consoles -│   ├── kenney_furniture-kit -│   ├── kenney_mini-arcade -│   ├── kenney_prototype-kit -│   ├── textures -│   └── tv -├── build_gdlibretro.sh -├── cores -> /home/jay/retrodeck_ro_user/share/libretro/cores -├── functions -│   └── run_core.gd -├── gdlibretro -│   ├── addons -│   ├── cmake -│   ├── CMakeCache.txt -│   ├── CMakeFiles -│   ├── cmake_install.cmake -│   ├── CMakeLists.txt -│   ├── CMakePresets.json -│   ├── compile_commands.json -│   ├── demo -│   ├── extern -│   ├── gen -│   ├── LibRetroHost -│   ├── Makefile -│   ├── README.md -│   ├── src -│   └── template -├── icon.svg -├── icon.svg.import -├── main.gd -├── main.tscn -├── openxr_action_map.tres -├── project.godot -├── prompt.md -├── prompt.sh -├── README.md -├── roms -> /home/jay/retrodeck/roms -├── SConstruct -├── scripts -│   ├── emulate.gd.old -│   └── libretro_loader.gd -└── xr_origin_3d.tscn - -24 directories, 27 files -Now I will cat you the main files for you to understand better the project. ---- project.godot --- -; Engine configuration file. -; It's best edited using the editor UI and not directly, -; since the parameters that go here are not all obvious. -; -; Format: -; [section] ; section goes between [] -; param=value ; assign values to parameters - -config_version=5 - -[application] - -config/name="RetroQUEST" -run/main_scene="res://main.tscn" -config/features=PackedStringArray("4.3", "GL Compatibility") -config/icon="res://icon.svg" - -[autoload] - -XRToolsUserSettings="*res://addons/godot-xr-tools/user_settings/user_settings.gd" -XRToolsRumbleManager="*res://addons/godot-xr-tools/rumble/rumble_manager.gd" -XrSimulator="*res://addons/xr-simulator/XRSimulator.tscn" - -[editor_plugins] - -enabled=PackedStringArray("res://addons/godot-xr-tools/plugin.cfg") - -[gd_extension] - -extensions=PackedStringArray("res://addons/LibRetroHost.gdextension") - -[rendering] - -renderer/rendering_method="gl_compatibility" -renderer/rendering_method.mobile="gl_compatibility" - -[xr] - -openxr/enabled=true -shaders/enabled=true ---- end of project.godot --- - ---- main.tscn --- -[gd_scene load_steps=22 format=3 uid="uid://8roky2tr13v8"] - -[ext_resource type="Script" path="res://main.gd" id="1_36sr1"] -[ext_resource type="ArrayMesh" uid="uid://bggt7a5musnhs" path="res://assets/kenney_furniture-kit/Models/OBJ format/cabinetTelevision.obj" id="2_h1lnb"] -[ext_resource type="Texture2D" uid="uid://rpfpax3cx88g" path="res://assets/textures/close-up-wooden-texture_23-2147625744.jpg" id="2_hgnca"] -[ext_resource type="PackedScene" uid="uid://bkt5sw3j026sx" path="res://xr_origin_3d.tscn" id="2_jdtaa"] -[ext_resource type="PackedScene" uid="uid://diyu06cw06syv" path="res://addons/godot-xr-tools/player/player_body.tscn" id="3_76mo5"] -[ext_resource type="ArrayMesh" uid="uid://12208cv4iusu" path="res://assets/kenney_furniture-kit/Models/OBJ format/bedSingle.obj" id="4_gdp5r"] -[ext_resource type="PackedScene" uid="uid://coocuwjurtlft" path="res://assets/consoles/sega_genesis_model_2__sega_mega_drive.glb" id="5_o8gwv"] -[ext_resource type="PackedScene" uid="uid://c5yymdsb50dia" path="res://assets/tv/crt_tv.glb" id="6_bla35"] -[ext_resource type="Texture2D" uid="uid://cveoss57kakcb" path="res://assets/textures/orange-brick-wall.jpg" id="7_7vxdg"] -[ext_resource type="ArrayMesh" uid="uid://js8c02ef5656" path="res://assets/kenney_furniture-kit/Models/OBJ format/doorway.obj" id="10_b82c5"] -[ext_resource type="ArrayMesh" uid="uid://bqh7jhg02guef" path="res://assets/kenney_furniture-kit/Models/OBJ format/books.obj" id="11_6t3bm"] - -[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_odtcn"] -sky_horizon_color = Color(0.64625, 0.65575, 0.67075, 1) -ground_horizon_color = Color(0.64625, 0.65575, 0.67075, 1) - -[sub_resource type="Sky" id="Sky_d5n34"] -sky_material = SubResource("ProceduralSkyMaterial_odtcn") - -[sub_resource type="Environment" id="Environment_rebsy"] -background_mode = 2 -sky = SubResource("Sky_d5n34") -tonemap_mode = 2 - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_022uh"] -albedo_texture = ExtResource("2_hgnca") -uv1_scale = Vector3(10, 10, 10) - -[sub_resource type="PlaneMesh" id="PlaneMesh_t6a7n"] -material = SubResource("StandardMaterial3D_022uh") -size = Vector2(7, 9) - -[sub_resource type="BoxShape3D" id="BoxShape3D_smmd7"] -size = Vector3(10, 0.1, 10) - -[sub_resource type="ViewportTexture" id="ViewportTexture_0ae1f"] -viewport_path = NodePath("room/SubViewport") - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_p0q3w"] -resource_local_to_scene = true -albedo_texture = SubResource("ViewportTexture_0ae1f") - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_dneyb"] -resource_local_to_scene = true -albedo_texture = ExtResource("7_7vxdg") -uv1_scale = Vector3(3, 3, 3) - -[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_vl1cb"] -albedo_color = Color(1, 0.953959, 0.778434, 1) - -[node name="main" type="Node3D"] -script = ExtResource("1_36sr1") - -[node name="WorldEnvironment" type="WorldEnvironment" parent="."] -environment = SubResource("Environment_rebsy") - -[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."] -transform = Transform3D(-0.866024, -0.433016, 0.250001, 0, 0.499998, 0.866026, -0.500003, 0.749999, -0.43301, 0, 2.75, 0) -directional_shadow_mode = 0 - -[node name="room" type="Node" parent="."] - -[node name="floor" type="StaticBody3D" parent="room"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.05, 0) - -[node name="MeshInstance3D" type="MeshInstance3D" parent="room/floor"] -mesh = SubResource("PlaneMesh_t6a7n") -skeleton = NodePath("../CollisionShape3D") - -[node name="CollisionShape3D" type="CollisionShape3D" parent="room/floor"] -shape = SubResource("BoxShape3D_smmd7") - -[node name="BedSingle" type="MeshInstance3D" parent="room"] -transform = Transform3D(3, 0, 0, 0, 3, 0, 0, 0, 3, 0.141, 0, 0.594707) -mesh = ExtResource("4_gdp5r") -skeleton = NodePath("../..") - -[node name="CabinetTelevision" type="MeshInstance3D" parent="room"] -transform = Transform3D(-1.92921, 0, 2.29743, 0, 3, 0, -2.29743, 0, -1.92921, 0.849805, -0.0571399, -3.42659) -mesh = ExtResource("2_h1lnb") -skeleton = NodePath("../floor/CollisionShape3D") - -[node name="CRTTV" type="CSGBox3D" parent="room"] -transform = Transform3D(0.643068, 0, -0.536066, 0, 0.9, 0, 0.765809, 0, 0.450148, 1.49155, 1.32038, -3.29054) -use_collision = true -material = SubResource("StandardMaterial3D_p0q3w") - -[node name="MegaDrive" parent="room" instance=ExtResource("5_o8gwv")] -transform = Transform3D(0.00064082, 0, -0.000767691, 0, 0.001, 0, 0.000767691, 0, 0.00064082, 2.08216, 0.913985, -2.52858) - -[node name="CRTTV2" parent="room" instance=ExtResource("6_bla35")] -transform = Transform3D(-1.32944, 0, 1.49418, 0, 2, 0, -1.49418, 0, -1.32944, 1.31505, 0.816899, -3.11279) - -[node name="brick wall" type="CSGBox3D" parent="room"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.53021, -4.14194) -use_collision = true -size = Vector3(6.72745, 6.15861, 0.141602) -material = SubResource("StandardMaterial3D_dneyb") - -[node name="wall3" type="CSGBox3D" parent="room"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0828514, 2.48109, 4.14488) -use_collision = true -size = Vector3(6.56174, 6.14909, 0.141602) -material = SubResource("StandardMaterial3D_vl1cb") - -[node name="Doorway" type="MeshInstance3D" parent="room/wall3"] -transform = Transform3D(3, 0, 0, 0, 3, 0, 0, 0, 1, 2.53115, -2.52145, -0.14388) -mesh = ExtResource("10_b82c5") -skeleton = NodePath("../../..") - -[node name="wall2" type="CSGBox3D" parent="room"] -transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, 3.08915, 2.41665, 0.056199) -use_collision = true -size = Vector3(8.52944, 6.14718, 0.141602) -material = SubResource("StandardMaterial3D_vl1cb") - -[node name="wall4" type="CSGBox3D" parent="room"] -transform = Transform3D(-4.37114e-08, 0, 1, 0, 1, 0, -1, 0, -4.37114e-08, -3.03443, 2.56347, -0.053894) -use_collision = true -size = Vector3(8.60897, 5.83376, 0.141602) -material = SubResource("StandardMaterial3D_vl1cb") - -[node name="roof" type="StaticBody3D" parent="room"] -transform = Transform3D(0.906308, 0.422618, 0, 0.422618, -0.906308, -8.74228e-08, -3.69465e-08, 7.92319e-08, -1, 0, 3.8, 0) - -[node name="MeshInstance3D" type="MeshInstance3D" parent="room/roof"] -mesh = SubResource("PlaneMesh_t6a7n") -skeleton = NodePath("../CollisionShape3D") - -[node name="CollisionShape3D" type="CollisionShape3D" parent="room/roof"] -shape = SubResource("BoxShape3D_smmd7") - -[node name="SubViewport" type="SubViewport" parent="room"] -transparent_bg = true -size = Vector2i(640, 480) - -[node name="ColorRect" type="ColorRect" parent="room/SubViewport"] -visible = false -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -color = Color(0.262745, 1, 0, 1) - -[node name="TextureRect" type="TextureRect" parent="room/SubViewport"] -offset_right = 40.0 -offset_bottom = 40.0 - -[node name="XROrigin3D" parent="." instance=ExtResource("2_jdtaa")] - -[node name="PlayerBody" parent="XROrigin3D" instance=ExtResource("3_76mo5")] - -[node name="CollisionShape3D" type="CollisionShape3D" parent="XROrigin3D/PlayerBody"] - -[node name="Books" type="MeshInstance3D" parent="."] -transform = Transform3D(-0.617031, -0.0412188, 2.93557, 0.151763, 2.99525, 0.0739558, -2.93193, 0.163714, -0.613967, 2.30079, 0.879317, -2.22938) -mesh = ExtResource("11_6t3bm") ---- end of main.tscn --- - ---- scripts/libretro_loader.gd --- -extends Node - -@onready var sub_viewport = $room/SubViewport -@onready var texture_rect = $room/SubViewport/TextureRect - -var current_core : Object = null # The emulator core (passed dynamically) -var current_rom : String = "" # Initialize to an empty string - -func start_emulation(core_path: String, rom_path: String) -> bool: - print("Starting emulation with core: ", core_path, ", ROM: ", rom_path) - - if not core_path or not rom_path: - push_error("Core path or ROM path is missing.") - return false - - # Load the core (emulator) - print("Loading core...") - current_core = load(core_path) - if not current_core: - push_error("Failed to load core: " + core_path) - return false - print("Core loaded successfully.") - - current_core.initialize() - - # Load the ROM - print("Checking ROM file...") - if not FileAccess.file_exists(rom_path): - push_error("ROM not found: " + rom_path) - return false - print("ROM file exists.") - - var file = FileAccess.open(rom_path, FileAccess.READ) - if not file: - push_error("Error opening ROM: " + rom_path) - return false - print("ROM file opened successfully.") - - var rom_data = file.get_buffer(file.get_length()) - file.close() - - if not current_core.load_game(rom_data): - push_error("Failed to load ROM: " + rom_path) - return false - print("ROM loaded successfully.") - - current_rom = rom_path - print("Core and ROM loaded successfully.") - - # Wait for SubViewport to render at least one frame - sub_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS - await get_tree().create_timer(0.1).timeout # Delay ensures rendering starts - - # Assign the SubViewport texture - var viewport_texture = sub_viewport.get_texture() - if viewport_texture: - texture_rect.texture = viewport_texture - print("SubViewport texture assigned successfully.") - else: - push_error("Error: SubViewport texture is not ready.") - return false - - return true - -func _process(delta): - """ - Dynamically updates the TextureRect's texture during runtime. - """ - if current_core: - current_core.run() - - var frame_data = current_core.get_frame_buffer() - if frame_data: - var frame_width = current_core.get_frame_width() - var frame_height = current_core.get_frame_height() - - if frame_width > 0 and frame_height > 0: - var image = Image.create_from_data( - frame_width, - frame_height, - false, - Image.FORMAT_RGB8, - frame_data - ) - var texture = ImageTexture.create_from_image(image) - texture_rect.texture = texture - -func _ready(): - """ - Initializes the SubViewport and TextureRect. - """ - if sub_viewport and texture_rect: - print("SubViewport and TextureRect initialized successfully.") - else: - push_error("Error: SubViewport or TextureRect is missing.") - - # Ensure SubViewport always renders - sub_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS ---- end of scripts/libretro_loader.gd --- - ---- addons/LibRetroHost.gdextension --- -[configuration] - -entry_symbol = "GDExtensionInit" -compatibility_minimum = 4.1 - -[libraries] -windows.release.x86_64 = "lib/Windows-AMD64/LibRetroHost-d.dll" -windows.debug.x86_64 = "lib/Windows-AMD64/LibRetroHost-d.dll" -linux.release.x86_64 = "res://addons/libLibRetroHost-d.so" -linux.debug.x86_64 = "res://addons/libLibRetroHost-d.so" ---- end of addons/LibRetroHost.gdextension --- - ---- gdlibretro/src/CoreEnvironment.cpp --- -#include "RetroHost.hpp" -#include "godot_cpp/variant/utility_functions.hpp" -#include // Required for va_start and va_end - -// Logging function for the core -void core_log(enum retro_log_level level, const char *fmt, ...) -{ - char buffer[4096] = {0}; - static const char *levelstr[] = {"DEBUG", "INFO", "WARN", "ERROR"}; - va_list va; - - va_start(va, fmt); - vsnprintf(buffer, sizeof(buffer), fmt, va); - va_end(va); - - godot::UtilityFunctions::print("[RetroHost Loaded CORE][" + - godot::String(levelstr[level - 1]) + "] " + buffer); -} - -// Retrieves a core variable -bool RetroHost::get_variable(retro_variable *variable) -{ - if (!this->core_variables[variable->key].IsDefined()) - { - godot::UtilityFunctions::printerr("[RetroHost] Core variable ", variable->key, " not defined"); - return false; - } - - auto var_value = core_variables[variable->key].as(); - if (var_value.empty()) - { - godot::UtilityFunctions::printerr("[RetroHost] Core variable ", variable->key, " was empty ", var_value.c_str()); - return false; - } - - const std::string::size_type size = var_value.size(); - char *buffer = new char[size + 1]; - memcpy(buffer, var_value.c_str(), size + 1); - - this->please_free_me_str.push_back(buffer); - - variable->value = buffer; - return true; -} - -// Helper function to split strings -std::vector split(std::string s, std::string delimiter) -{ - size_t pos_start = 0, pos_end, delim_len = delimiter.length(); - std::string token; - std::vector res; - - while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) - { - token = s.substr(pos_start, pos_end - pos_start); - pos_start = pos_end + delim_len; - res.push_back(token); - } - - res.push_back(s.substr(pos_start)); - return res; -} - -// Handles various core environment commands -bool RetroHost::core_environment(unsigned command, void *data) -{ - switch (command) - { - case RETRO_ENVIRONMENT_GET_LOG_INTERFACE: - { - godot::UtilityFunctions::print("[RetroHost] Core log interface set."); - struct retro_log_callback *cb = (struct retro_log_callback *)data; - cb->log = core_log; - } - break; - - case RETRO_ENVIRONMENT_GET_CAN_DUPE: - { - godot::UtilityFunctions::print("[RetroHost] Core can dupe set."); - bool *b = (bool *)data; - *b = true; - } - break; - - case RETRO_ENVIRONMENT_GET_VARIABLE: - { - auto var = (retro_variable *)data; - return this->get_variable(var); - } - break; - - case RETRO_ENVIRONMENT_SET_VARIABLES: - { - auto variables = (const struct retro_variable *)data; - while (variables->key) - { - if (!this->core_variables[variables->key].IsDefined()) - { - std::string value = variables->value; - auto possible_values_str = split(value, ";")[1].erase(0, 1); - auto possible_values = split(possible_values_str, "|"); - this->core_variables[variables->key] = possible_values[0]; - - godot::UtilityFunctions::print("[RetroHost] Core variable ", variables->key, - " was not present in the config file, now set to the first possible value: ", - possible_values[0].c_str()); - } - variables++; - } - } - break; - - case RETRO_ENVIRONMENT_GET_VFS_INTERFACE: - { - auto vfs_interface = (struct retro_vfs_interface_info *)data; - godot::UtilityFunctions::print("[RetroHost] Core requested VFS interface"); - if (vfs_interface->required_interface_version > this->vfs.supported_interface_version) - { - godot::UtilityFunctions::printerr("[RetroHost] Core requested VFS interface v", - vfs_interface->required_interface_version, - " we only support up to v", - this->vfs.supported_interface_version); - return false; - } - vfs_interface->iface = &this->vfs.vfs_interface; - return true; - } - break; - - case RETRO_ENVIRONMENT_SET_PIXEL_FORMAT: - { - const enum retro_pixel_format *fmt = (enum retro_pixel_format *)data; - if (*fmt > RETRO_PIXEL_FORMAT_RGB565) - { - return false; - } - - godot::UtilityFunctions::print("[RetroHost] Core setting pixel format"); - return this->core_video_set_pixel_format(*fmt); - } - break; - - case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY: - case RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY: - case RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY: - case RETRO_ENVIRONMENT_GET_LIBRETRO_PATH: - { - godot::UtilityFunctions::print("[RetroHost] Core requested path"); - *(const char **)data = this->cwd.trim_suffix("/").utf8().get_data(); - return true; - } - - case RETRO_ENVIRONMENT_SHUTDOWN: - { - godot::UtilityFunctions::print("[RetroHost] Core shutdown requested"); - break; - } - - default: - { - godot::UtilityFunctions::print("[RetroHost] Core environment command " + - godot::String::num(command) + " not implemented."); - return false; - } - } - - return true; -} ---- end of gdlibretro/src/CoreEnvironment.cpp --- - ---- gdlibretro/src/RetroHost.cpp --- -#include "RetroHost.hpp" -#include "godot_cpp/variant/utility_functions.hpp" -#include -#include -#include - -#include -#include - -// Platform-specific includes -#ifdef _WIN32 -#include -#define PLATFORM_WINDOWS -#elif __linux__ -#include -#define PLATFORM_LINUX -#elif __ANDROID__ -#include -#define PLATFORM_ANDROID -#endif - -// Returns the last error message as a string -std::string GetLastErrorAsStr() -{ -#ifdef PLATFORM_WINDOWS - DWORD errorMessageID = ::GetLastError(); - if (errorMessageID == 0) { - return std::string(); - } - - LPSTR messageBuffer = nullptr; - size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&messageBuffer, 0, NULL); - - std::string message(messageBuffer, size); - LocalFree(messageBuffer); - - return message; -#elif defined(PLATFORM_LINUX) || defined(PLATFORM_ANDROID) - return dlerror(); // Linux and Android use dlerror for error reporting. -#else - return "Error information not available on this platform"; -#endif -} - -RetroHost::RetroHost() -{ - godot::UtilityFunctions::print("[RetroHost] Constructor"); - singleton = this; - this->vfs.init_vfs_interface(); -} - -RetroHost::~RetroHost() -{ - godot::UtilityFunctions::print("[RetroHost] Destructor"); - this->unload_core(); -} - -RetroHost *RetroHost::singleton = nullptr; - -RetroHost *RetroHost::get_singleton() -{ - return singleton; -} - -#define load_symbol_return_false_on_err(handle, dest, sym) \ - godot::UtilityFunctions::print("[RetroHost] Loading core symbol \"", #sym, "\""); \ - dest = (decltype(dest))dlsym(handle, #sym); \ - if (dest == NULL) \ - { \ - godot::UtilityFunctions::printerr("[RetroHost] Could not load symbol \"", #sym, \ - "\": ", dlerror()); \ - return false; \ - } - -bool RetroHost::load_core(godot::String name) { - this->unload_core(); - godot::UtilityFunctions::print("[RetroHost] Loading core \"", name, "\""); - - godot::String lib_path; - if (godot::OS::get_singleton()->has_feature("editor")) { - this->cwd = - godot::ProjectSettings::get_singleton()->globalize_path("res://") + "libretro-cores/"; - lib_path = cwd + name + ".dll"; // Editor path (Windows assumed default) - } else { - this->cwd = godot::OS::get_singleton()->get_executable_path().get_base_dir(); - lib_path = cwd + "/" + name; - } - -#ifdef PLATFORM_WINDOWS - this->core.handle = LoadLibrary(lib_path.utf8().get_data()); - if (this->core.handle == NULL) { - godot::UtilityFunctions::printerr("[RetroHost] Failed to load core \"", lib_path, "\""); - return false; - } -#elif defined(PLATFORM_LINUX) || defined(PLATFORM_ANDROID) - this->core.handle = dlopen(lib_path.utf8().get_data(), RTLD_LAZY); - if (this->core.handle == nullptr) { - godot::UtilityFunctions::printerr("[RetroHost] Failed to load core \"" + - godot::String(lib_path.utf8().get_data()) + - "\": " + - godot::String(GetLastErrorAsStr().c_str())); - return false; - } -#endif - - // Load RetroArch symbols dynamically - load_symbol_return_false_on_err(this->core.handle, this->core.retro_init, retro_init); - load_symbol_return_false_on_err(this->core.handle, this->core.retro_deinit, retro_deinit); - load_symbol_return_false_on_err(this->core.handle, this->core.retro_api_version, retro_api_version); - load_symbol_return_false_on_err(this->core.handle, this->core.retro_get_system_info, retro_get_system_info); - load_symbol_return_false_on_err(this->core.handle, this->core.retro_get_system_av_info, retro_get_system_av_info); - load_symbol_return_false_on_err(this->core.handle, this->core.retro_set_controller_port_device, retro_set_controller_port_device); - load_symbol_return_false_on_err(this->core.handle, this->core.retro_reset, retro_reset); - load_symbol_return_false_on_err(this->core.handle, this->core.retro_run, retro_run); - load_symbol_return_false_on_err(this->core.handle, this->core.retro_load_game, retro_load_game); - load_symbol_return_false_on_err(this->core.handle, this->core.retro_unload_game, retro_unload_game); - - this->core_name = name; - this->load_core_variables(); - - this->core.retro_init(); - this->core.retro_load_game(NULL); - - struct retro_system_av_info av; - this->core.retro_get_system_av_info(&av); - - this->core_video_init(&av.geometry); - this->core_audio_init(av); - - this->core.initialized = true; - return true; -} - -void RetroHost::unload_core() -{ - if (this->core.initialized) - { - this->core.retro_deinit(); - this->core.initialized = false; - } - -#ifdef PLATFORM_WINDOWS - if (this->core.handle != NULL) - { - FreeLibrary(this->core.handle); - this->core.handle = NULL; - } -#elif defined(PLATFORM_LINUX) || defined(PLATFORM_ANDROID) - if (this->core.handle != nullptr) - { - dlclose(this->core.handle); - this->core.handle = nullptr; - } -#endif -} - -void RetroHost::run() -{ - if (!this->core.initialized) - { - godot::UtilityFunctions::printerr("[RetroHost] Core not initialized"); - return; - } - this->core.retro_run(); -} - -void RetroHost::_bind_methods() -{ - godot::ClassDB::bind_method(godot::D_METHOD("load_core", "name"), &RetroHost::load_core); - godot::ClassDB::bind_method(godot::D_METHOD("unload_core"), &RetroHost::unload_core); - godot::ClassDB::bind_method(godot::D_METHOD("run"), &RetroHost::run); -} ---- end of gdlibretro/src/RetroHost.cpp --- - ---- gdlibretro/src/RetroHost.hpp --- -#pragma once - -#include "filesystem" -#include "godot_cpp/classes/image.hpp" -#include "godot_cpp/classes/input_event.hpp" -#include "godot_cpp/classes/object.hpp" -#include "libretro.h" -#include "yaml-cpp/yaml.h" - -// Platform-specific includes -#ifdef _WIN32 -#include -#define PLATFORM_WINDOWS -#elif __linux__ -#include -#define PLATFORM_LINUX -#elif __ANDROID__ -#include -#define PLATFORM_ANDROID -#endif - -class RetroHost : public godot::Object -{ - GDCLASS(RetroHost, godot::Object) - -public: - godot::String cwd; - static RetroHost *get_singleton(); - - RetroHost(); - ~RetroHost(); - - bool load_core(godot::String path); - void unload_core(); - void run(); - void forwarded_input(const godot::Ref &event); - -private: - static RetroHost *singleton; - - godot::Ref frame_buffer; - godot::Ref get_frame_buffer() - { - return frame_buffer; - } - - std::vector please_free_me_str; - - YAML::Node core_variables; - godot::String core_name; - - void load_core_variables(); - void save_core_variables(); - bool get_variable(retro_variable *variable); - - bool core_environment(unsigned cmd, void *data); - - void core_video_init(const struct retro_game_geometry *geometry); - void core_video_refresh(const void *data, unsigned width, unsigned height, size_t pitch); - bool core_video_set_pixel_format(unsigned format); - godot::Image::Format pixel_format; - - void core_input_poll(void); - int16_t core_input_state(unsigned port, unsigned device, unsigned index, unsigned id); - - void core_audio_init(retro_system_av_info av); - void core_audio_sample(int16_t left, int16_t right); - size_t core_audio_sample_batch(const int16_t *data, size_t frames); - - struct VFS - { - uint32_t supported_interface_version = 0; - - void init_vfs_interface(); - struct retro_vfs_interface vfs_interface; - - const char *get_path(retro_vfs_file_handle *stream); - struct retro_vfs_file_handle *open(const char *path, unsigned mode, unsigned hints); - int close(retro_vfs_file_handle *stream); - int64_t size(struct retro_vfs_file_handle *stream); - int64_t tell(struct retro_vfs_file_handle *stream); - int64_t seek(struct retro_vfs_file_handle *stream, int64_t offset, int seek_position); - int64_t read(struct retro_vfs_file_handle *stream, void *s, uint64_t len); - int64_t write(struct retro_vfs_file_handle *stream, const void *s, uint64_t len); - int flush(retro_vfs_file_handle *stream); - int remove(const char *path); - int rename(const char *old_path, const char *new_path); - int64_t truncate(struct retro_vfs_file_handle *stream, int64_t length); - int stat(const char *path, int32_t *size); - int mkdir(const char *dir); - struct retro_vfs_dir_handle *opendir(const char *dir, bool include_hidden_files); - bool read_dir(struct retro_vfs_dir_handle *dir_stream); - const char *dirent_get_name(struct retro_vfs_dir_handle *dir_stream); - bool dirent_is_dir(struct retro_vfs_dir_handle *dir_stream); - int closedir(struct retro_vfs_dir_handle *dir_stream); - } vfs; - - struct - { -#ifdef PLATFORM_WINDOWS - HINSTANCE handle; -#elif defined(PLATFORM_LINUX) || defined(PLATFORM_ANDROID) - void *handle; -#endif - bool initialized = false; - - void (*retro_init)(void); - void (*retro_deinit)(void); - unsigned (*retro_api_version)(void); - void (*retro_get_system_info)(struct retro_system_info *info); - void (*retro_get_system_av_info)(struct retro_system_av_info *info); - void (*retro_set_controller_port_device)(unsigned port, unsigned device); - void (*retro_reset)(void); - void (*retro_run)(void); - bool (*retro_load_game)(const struct retro_game_info *game); - void (*retro_unload_game)(void); - - retro_keyboard_event_t retro_keyboard_event_callback; - } core; - -protected: - static void _bind_methods(); -}; ---- end of gdlibretro/src/RetroHost.hpp --- - ---- gdlibretro/src/Video.cpp --- -#include "RetroHost.hpp" -#include "godot_cpp/classes/image.hpp" -#include "godot_cpp/variant/utility_functions.hpp" - -void RetroHost::core_video_init(const struct retro_game_geometry *geometry) -{ - godot::UtilityFunctions::print("[RetroHost] Video init ", geometry->base_width, " x ", - geometry->base_height); - this->frame_buffer = godot::Image::create(geometry->base_width, geometry->base_height, false, - this->pixel_format); -} - -void RetroHost::core_video_refresh(const void *data, unsigned width, unsigned height, - size_t pitch) -{ - if (!data || frame_buffer.is_null() || !frame_buffer.is_valid()) - { - return; - } - - if ((unsigned)frame_buffer->get_width() != width || - (unsigned)frame_buffer->get_height() != height) - { - godot::UtilityFunctions::print("[RetroHost] Resizing frame buffer to ", width, "x", - height); - auto created_frame_buffer = - godot::Image::create(width, height, false, frame_buffer->get_format()); - if (created_frame_buffer.is_null() || !created_frame_buffer.is_valid()) - { - godot::UtilityFunctions::printerr("[RetroHost] Failed to recreate frame buffer"); - return; - } - frame_buffer = created_frame_buffer; - } - - unsigned buffer_size; - switch (frame_buffer->get_format()) - { - case godot::Image::FORMAT_RGB565: - buffer_size = width * height * 2; - break; - case godot::Image::FORMAT_RGBA8: - { - buffer_size = width * height * 4; - -#if defined(_MSC_VER) // MSVC compiler -#pragma warning(push) -#pragma warning(disable : 4244) -#endif - - uint32_t *data32 = (uint32_t *)data; - for (unsigned i = 0; i < width * height; i++) - { - uint32_t pixel = data32[i]; - uint8_t alpha = (pixel & 0xFF000000) >> 24; - uint8_t red = (pixel & 0x00FF0000) >> 16; - uint8_t green = (pixel & 0x0000FF00) >> 8; - uint8_t blue = (pixel & 0x000000FF); - data32[i] = (alpha << 24) | (blue << 16) | (green << 8) | red; - } - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - } - break; - default: - godot::UtilityFunctions::printerr("[RetroHost] Unhandled pixel format: ", - frame_buffer->get_format()); - return; - } - - godot::PackedByteArray intermediary_buffer; - intermediary_buffer.resize(buffer_size); - memcpy((void *)intermediary_buffer.ptr(), data, buffer_size); - - frame_buffer->set_data(width, height, false, frame_buffer->get_format(), intermediary_buffer); -} - -bool RetroHost::core_video_set_pixel_format(unsigned format) -{ - switch (format) - { - case RETRO_PIXEL_FORMAT_0RGB1555: - godot::UtilityFunctions::print("[RetroHost] Pixel format: 0RGB1555"); - this->pixel_format = godot::Image::Format::FORMAT_RGB565; - return true; - case RETRO_PIXEL_FORMAT_XRGB8888: - godot::UtilityFunctions::print("[RetroHost] Pixel format: XRGB8888"); - this->pixel_format = godot::Image::Format::FORMAT_RGBA8; - return true; - case RETRO_PIXEL_FORMAT_RGB565: - godot::UtilityFunctions::print("[RetroHost] Pixel format: RGB565"); - this->pixel_format = godot::Image::Format::FORMAT_RGB565; - return true; - default: - return false; - } -} ---- end of gdlibretro/src/Video.cpp --- - ---- gdlibretro/src/RegisterExtension.cpp --- -#include "gdextension_interface.h" - -#include "godot_cpp/core/class_db.hpp" -#include "godot_cpp/core/defs.hpp" -#include "godot_cpp/godot.hpp" -#include "godot_cpp/classes/engine.hpp" - -#include "RetroHost.hpp" - -static RetroHost *retro_host_singleton = nullptr; - -namespace { - void initialize_extension(godot::ModuleInitializationLevel p_level) { - if (p_level != godot::MODULE_INITIALIZATION_LEVEL_SCENE) { - return; - } - - godot::ClassDB::register_class(); - - retro_host_singleton = memnew(RetroHost()); - godot::Engine::get_singleton()->register_singleton("RetroHost", RetroHost::get_singleton()); - } - - void uninitialize_extension(godot::ModuleInitializationLevel p_level) { - if (p_level != godot::MODULE_INITIALIZATION_LEVEL_SCENE) { - return; - } - godot::Engine::get_singleton()->unregister_singleton("RetroHost"); - memdelete(retro_host_singleton); - } -} - -extern "C" { - GDExtensionBool GDE_EXPORT GDExtensionInit( - GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, - GDExtensionInitialization *r_initialization) { - godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization); - - init_obj.register_initializer(initialize_extension); - init_obj.register_terminator(uninitialize_extension); - init_obj.set_minimum_library_initialization_level(godot::MODULE_INITIALIZATION_LEVEL_SCENE); - - return init_obj.init(); - } -} ---- end of gdlibretro/src/RegisterExtension.cpp --- - ---- gdlibretro/src/CMakeLists.txt --- -# SPDX-License-Identifier: Unlicense - -# Platform-specific settings -if (ANDROID) - target_link_libraries(${PROJECT_NAME} PUBLIC dl log) - add_definitions(-DPLATFORM_ANDROID) -elseif (UNIX AND NOT APPLE) # Linux - target_link_libraries(${PROJECT_NAME} PUBLIC dl) - add_definitions(-DPLATFORM_LINUX) -elseif (WIN32) - add_definitions(-DPLATFORM_WINDOWS) -endif() - -# Add sources -target_sources(${PROJECT_NAME} - PRIVATE - RegisterExtension.cpp - RetroHost.hpp - RetroHost.cpp - CoreEnvironment.cpp - CoreVariables.cpp - Audio.cpp - Input.cpp - Video.cpp - KeyboardMap.hpp - VFS.cpp -) - -# Include directories -target_include_directories(${PROJECT_NAME} - PRIVATE - "src" -) ---- end of gdlibretro/src/CMakeLists.txt --- - - -My issue now is the following, can you help me to fix it? -Godot says: -[RetroHost] Constructor - core/extension/gdextension.cpp:1011 - No GDExtension library found for current OS and architecture (linux.x86_64) in configuration file: res://gdlibretro/LibRetroHost/LibRetroHost.gdextension - Failed loading resource: res://gdlibretro/LibRetroHost/LibRetroHost.gdextension. Make sure resources have been imported by opening the project in the editor at least once. -Core path: res://cores/genesis_plus_gx_libretro.so -ROM path: res://roms/megadrive/Sonic the Hedgehog.bin -Starting emulation with core: res://cores/genesis_plus_gx_libretro.so, ROM: res://roms/megadrive/Sonic the Hedgehog.bin -Loading core... -Failed to start the game. ---- Debugging process stopped --- - core/extension/gdextension.cpp:1011 - No GDExtension library found for current OS and architecture (linux.x86_64) in configuration file: res://gdlibretro/LibRetroHost/LibRetroHost.gdextension - Failed loading resource: res://gdlibretro/LibRetroHost/LibRetroHost.gdextension. Make sure resources have been imported by opening the project in the editor at least once. - core/extension/gdextension.cpp:1011 - No GDExtension library found for current OS and architecture (linux.x86_64) in configuration file: res://gdlibretro/LibRetroHost/LibRetroHost.gdextension - Failed loading resource: res://gdlibretro/LibRetroHost/LibRetroHost.gdextension. Make sure resources have been imported by opening the project in the editor at least once. -