Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ else ()
endif ()

option(CUBEB_ENABLED "Enable the cubeb audio backend" ON)
option(SDL_ENABLED "Enable building SDL files" ON)
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
if (TARGET_ARCHS MATCHES "arm64")
option(HYPERVISOR_ENABLED "Enable the Hypervisor CPU backend" ON)
Expand All @@ -29,6 +30,10 @@ else ()
set(FRONTEND "SDL3")
endif ()

if (FRONTEND STREQUAL "SDL3")
set(SDL_ENABLED ON)
endif ()

if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
option(MACOS_BUNDLE "Build a macOS app bundle" OFF)
elseif (CMAKE_SYSTEM_NAME STREQUAL "iOS")
Expand Down Expand Up @@ -161,6 +166,12 @@ else ()
add_compile_definitions(HYDRA_CUBEB_ENABLED=0)
endif ()

if (SDL_ENABLED)
add_compile_definitions(HYDRA_SDL_ENABLED=1)
else ()
add_compile_definitions(HYDRA_SDL_ENABLED=0)
endif ()

if (APPLE)
set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC NO)
endif ()
Expand Down
17 changes: 14 additions & 3 deletions src/common/config.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include "common/config.hpp"

#include "common/log.hpp"
#include "common/platform.hpp"
#include "common/toml_helper.hpp"

TOML11_DEFINE_CONVERSION_ENUM(hydra::InputBackend, Sdl, "SDL",
AppleGameController, "Apple GameController")
TOML11_DEFINE_CONVERSION_ENUM(hydra::CpuBackend, AppleHypervisor,
"Apple Hypervisor", Dynarmic, "dynarmic")
TOML11_DEFINE_CONVERSION_ENUM(hydra::GpuRenderer, Metal, "Metal")
Expand All @@ -12,7 +12,7 @@ TOML11_DEFINE_CONVERSION_ENUM(hydra::Resolution, Auto, "auto", _720p, "720p",
_1080p, "1080p", _1440p, "1440p", _2160p, "2160p",
_4320p, "4320p", AutoExact, "Auto exact", Custom,
"custom")
TOML11_DEFINE_CONVERSION_ENUM(hydra::AudioBackend, Null, "Null", Cubeb, "Cubeb")
TOML11_DEFINE_CONVERSION_ENUM(hydra::AudioBackend, Null, "null", Cubeb, "Cubeb")
TOML11_DEFINE_CONVERSION_ENUM(hydra::LogOutput, None, "none", StdOut, "stdout",
File, "file")

Expand Down Expand Up @@ -120,6 +120,7 @@ void Config::LoadDefaults() {
game_paths = GetDefaultGamePaths();
loader_plugins = GetDefaultLoaderPlugins();
patch_paths = GetDefaultPatchPaths();
input_backend = GetDefaultInputBackend();
input_profiles = GetDefaultInputProfiles();
cpu_backend = GetDefaultCpuBackend();
gpu_renderer = GetDefaultGpuRenderer();
Expand Down Expand Up @@ -174,6 +175,7 @@ void Config::Serialize() {

{
auto& input = data.at("Input");
input["backend"] = input_backend;
input["profiles"] = input_profiles;
}

Expand Down Expand Up @@ -253,6 +255,8 @@ void Config::Deserialize() {
}
if (data.contains("Input")) {
const auto& input = data.at("Input");
input_backend = toml::find_or<InputBackend>(input, "backend",
GetDefaultInputBackend());
input_profiles = toml::find_or<std::vector<std::string>>(
input, "profiles", GetDefaultInputProfiles());
}
Expand Down Expand Up @@ -315,6 +319,12 @@ void Config::Deserialize() {
}

// Validate
if (input_backend == InputBackend::Invalid) {
input_backend = GetDefaultInputBackend();
LOG_WARN(Other, "Invalid input backend, falling back to {}",
input_backend);
}

if (cpu_backend == CpuBackend::Invalid) {
cpu_backend = GetDefaultCpuBackend();
LOG_WARN(Other, "Invalid CPU backend, falling back to {}", cpu_backend);
Expand Down Expand Up @@ -351,6 +361,7 @@ void Config::Log() {
LOG_INFO(Other, "Game paths: [{}]", fmt::join(game_paths, ", "));
LOG_INFO(Other, "Loader plugins: [{}]", fmt::join(loader_plugins, ", "));
LOG_INFO(Other, "Patch paths: [{}]", fmt::join(patch_paths, ", "));
LOG_INFO(Other, "Input backend: {}", input_backend);
LOG_INFO(Other, "Input profiles: [{}]", fmt::join(input_profiles, ", "));
LOG_INFO(Other, "CPU backend: {}", cpu_backend);
LOG_INFO(Other, "Gpu renderer: {}", gpu_renderer);
Expand Down
20 changes: 20 additions & 0 deletions src/common/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@
#include <fmt/ranges.h>

#include "common/log.hpp"
#include "common/platform.hpp"
#include "common/types.hpp"

#define CONFIG_INSTANCE Config::GetInstance()

namespace hydra {

enum class InputBackend : u32 {
Invalid = 0,

Sdl,
AppleGameController,
};

enum class CpuBackend : u32 {
Invalid = 0,

Expand Down Expand Up @@ -90,6 +98,7 @@ class Config {
std::vector<std::string> game_paths;
std::vector<LoaderPlugin> loader_plugins;
std::vector<std::string> patch_paths;
InputBackend input_backend;
std::vector<std::string> input_profiles;
CpuBackend cpu_backend;
GpuRenderer gpu_renderer;
Expand All @@ -116,6 +125,13 @@ class Config {
std::vector<std::string> GetDefaultGamePaths() const { return {}; }
std::vector<LoaderPlugin> GetDefaultLoaderPlugins() const { return {}; }
std::vector<std::string> GetDefaultPatchPaths() const { return {}; }
InputBackend GetDefaultInputBackend() const {
#ifdef PLATFORM_APPLE
return InputBackend::AppleGameController;
#else
return InputBackend::Sdl;
#endif
}
std::vector<std::string> GetDefaultInputProfiles() const {
return {"Default", "", "", "", "", "", "", "", "", ""};
}
Expand Down Expand Up @@ -164,6 +180,7 @@ class Config {
REF_GETTER(game_paths, GetGamePaths);
REF_GETTER(loader_plugins, GetLoaderPlugins);
REF_GETTER(patch_paths, GetPatchPaths);
REF_GETTER(input_backend, GetInputBackend);
REF_GETTER(input_profiles, GetInputProfiles);
REF_GETTER(cpu_backend, GetCpuBackend);
REF_GETTER(gpu_renderer, GetGpuRenderer);
Expand All @@ -189,6 +206,9 @@ class Config {

} // namespace hydra

ENABLE_ENUM_FORMATTING_AND_CASTING(hydra, InputBackend, input_backend, Sdl,
"SDL", AppleGameController,
"Apple GameController")
ENABLE_ENUM_FORMATTING_AND_CASTING(hydra, CpuBackend, cpu_backend,
AppleHypervisor, "Apple Hypervisor",
Dynarmic, "dynarmic")
Expand Down
17 changes: 17 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,17 @@ if (CUBEB_ENABLED)
)
endif ()

if (SDL_ENABLED)
target_sources(hydra-core PRIVATE
input/sdl/keyboard.cpp
input/sdl/keyboard.hpp
input/sdl/controller.cpp
input/sdl/controller.hpp
input/sdl/device_list.cpp
input/sdl/device_list.hpp
)
endif ()

target_include_directories(hydra-core PRIVATE ${CMAKE_SOURCE_DIR}/externals/libyaz0/include)
# TODO: only link Apple frameworks if Apple
target_link_libraries(hydra-core PRIVATE hydra_warnings "-framework Foundation" "-framework Metal" "-framework QuartzCore" "-framework GameController" dynarmic hatch libyaz0 nx2elf hydra-common)
Expand All @@ -682,6 +693,12 @@ if (CUBEB_ENABLED)
target_link_libraries(hydra-core PRIVATE cubeb)
endif ()

if (SDL_ENABLED)
find_package(SDL3 CONFIG REQUIRED)

target_link_libraries(hydra-core PRIVATE SDL3::SDL3)
endif ()

if (CMAKE_SYSTEM_NAME STREQUAL "iOS")
set_target_properties(hydra-core PROPERTIES
XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET ${IOS_DEPLOYMENT_TARGET}
Expand Down
22 changes: 13 additions & 9 deletions src/core/input/apple_gc/controller.mm
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
namespace hydra::input::apple_gc {

bool Controller::IsPressedImpl(ControllerInput input) {
const auto controller = reinterpret_cast<GCController*>(handle);

#define BUTTON_CASE(input, gc_button) \
case ControllerInput::input: \
gc_button_name = GCInput##gc_button; \
Expand All @@ -18,32 +20,34 @@
BUTTON_CASE(Y, ButtonX)
BUTTON_CASE(StickL, LeftThumbstickButton)
BUTTON_CASE(StickR, RightThumbstickButton)
BUTTON_CASE(L, LeftBumper)
BUTTON_CASE(R, RightBumper)
BUTTON_CASE(L, LeftShoulder)
BUTTON_CASE(R, RightShoulder)
BUTTON_CASE(ZL, LeftTrigger)
BUTTON_CASE(ZR, RightTrigger)
// TODO: implement
case ControllerInput::Plus:
case ControllerInput::Minus:
BUTTON_CASE(Plus, ButtonMenu)
BUTTON_CASE(Minus, ButtonOptions)
case ControllerInput::Left:
return controller.extendedGamepad.dpad.left.isPressed;
case ControllerInput::Up:
return controller.extendedGamepad.dpad.up.isPressed;
case ControllerInput::Right:
return controller.extendedGamepad.dpad.right.isPressed;
case ControllerInput::Down:
return controller.extendedGamepad.dpad.down.isPressed;
// TODO: implement
case ControllerInput::LeftSL:
case ControllerInput::LeftSR:
case ControllerInput::RightSL:
case ControllerInput::RightSR:
break;
return false;
default:
LOG_NOT_IMPLEMENTED(Input, "Controller button {}", input);
return false;
}

#undef BUTTON_CASE

return reinterpret_cast<GCController*>(handle)
.physicalInputProfile.buttons[gc_button_name]
.isPressed;
return controller.physicalInputProfile.buttons[gc_button_name].isPressed;
}

f32 Controller::GetAxisValueImpl(ControllerInput input) {
Expand Down
11 changes: 5 additions & 6 deletions src/core/input/apple_gc/device_list.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@ namespace hydra::input::apple_gc {
class DeviceList : public IDeviceList {
public:
DeviceList();
~DeviceList();
~DeviceList() override;

// For the implementation
void _AddController(id controller);
void _RemoveController(id controller);
void _AddKeyboard(id keyboard);
void _RemoveKeyboard(id keyboard);
void AddController(id controller);
void RemoveController(id controller);
void AddKeyboard(id keyboard);
void RemoveKeyboard(id keyboard);

private:
id impl;
Expand Down
44 changes: 15 additions & 29 deletions src/core/input/apple_gc/device_list.mm
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ - (id)initWithParent:(DeviceList*)parent {
if (@available(macOS 11.0, iOS 14.0, tvOS 14.0, *)) {
GCKeyboard* keyboard = [GCKeyboard coalescedKeyboard];
if (keyboard) {
self.parent->_AddKeyboard(keyboard);
self.parent->AddKeyboard(keyboard);
}
}

// Connected controllers
for (GCController* controller in [GCController controllers]) {
self.parent->_AddController(controller);
self.parent->AddController(controller);
}
}

Expand All @@ -66,23 +66,23 @@ - (void)dealloc {
- (void)controllerConnected:(NSNotification*)notification {
GCController* controller =
reinterpret_cast<GCController*>(notification.object);
_parent->_AddController(controller);
_parent->AddController(controller);
}

- (void)controllerDisconnected:(NSNotification*)notification {
GCController* controller =
reinterpret_cast<GCController*>(notification.object);
_parent->_RemoveController(controller);
_parent->RemoveController(controller);
}

- (void)keyboardConnected:(NSNotification*)notification {
GCKeyboard* keyboard = reinterpret_cast<GCKeyboard*>(notification.object);
_parent->_AddKeyboard(keyboard);
_parent->AddKeyboard(keyboard);
}

- (void)keyboardDisconnected:(NSNotification*)notification {
GCKeyboard* keyboard = reinterpret_cast<GCKeyboard*>(notification.object);
_parent->_RemoveKeyboard(keyboard);
_parent->RemoveKeyboard(keyboard);
}

@end
Expand All @@ -91,7 +91,7 @@ - (void)keyboardDisconnected:(NSNotification*)notification {

namespace {

std::string get_device_name(id device) {
std::string GetDeviceName(id device) {
return [[device vendorName] UTF8String];
}

Expand All @@ -103,34 +103,20 @@ - (void)keyboardDisconnected:(NSNotification*)notification {

DeviceList::~DeviceList() { [impl release]; }

void DeviceList::_AddController(id controller) {
auto name = get_device_name(controller);
LOG_INFO(Input, "Controller connected: {}", name);
devices[name] = new Controller(controller);
void DeviceList::AddController(id controller) {
AddDevice(GetDeviceName(controller), new Controller(controller));
}

void DeviceList::_RemoveController(id controller) {
auto name = get_device_name(controller);
LOG_INFO(Input, "Controller disconnected: {}", name);
auto it = devices.find(name);
ASSERT(it != devices.end(), Input, "Controller not connected");
delete it->second;
devices.erase(it);
void DeviceList::RemoveController(id controller) {
RemoveDevice(GetDeviceName(controller));
}

void DeviceList::_AddKeyboard(id keyboard) {
auto name = get_device_name(keyboard);
LOG_INFO(Input, "Keyboard connected: {}", name);
devices[name] = new Keyboard(keyboard);
void DeviceList::AddKeyboard(id keyboard) {
AddDevice(GetDeviceName(keyboard), new Keyboard(keyboard));
}

void DeviceList::_RemoveKeyboard(id keyboard) {
auto name = get_device_name(keyboard);
LOG_INFO(Input, "Keyboard disconnected: {}", name);
auto it = devices.find(name);
ASSERT(it != devices.end(), Input, "Keyboard not connected");
delete it->second;
devices.erase(it);
void DeviceList::RemoveKeyboard(id keyboard) {
RemoveDevice(GetDeviceName(keyboard));
}

} // namespace hydra::input::apple_gc
Loading