diff --git a/.gitmodules b/.gitmodules index e79738aba1..50cdb67ab6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -100,3 +100,7 @@ path = 3rdparty/opencv/opencv url = ../../Megamouse/opencv_minimal.git ignore = dirty +[submodule "3rdparty/fusion/fusion"] + path = 3rdparty/fusion/fusion + url = ../../xioTechnologies/Fusion.git + ignore = dirty diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index 57a45d7be5..434b870b52 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -346,6 +346,9 @@ add_subdirectory(rtmidi EXCLUDE_FROM_ALL) # OPENCV add_subdirectory(opencv EXCLUDE_FROM_ALL) +# FUSION +add_subdirectory(fusion EXCLUDE_FROM_ALL) + # add nice ALIAS targets for ease of use if(USE_SYSTEM_LIBUSB) add_library(3rdparty::libusb ALIAS usb-1.0-shared) @@ -377,3 +380,4 @@ add_library(3rdparty::sdl2 ALIAS ${SDL2_TARGET}) add_library(3rdparty::miniupnpc ALIAS libminiupnpc-static) add_library(3rdparty::rtmidi ALIAS rtmidi) add_library(3rdparty::opencv ALIAS ${OPENCV_TARGET}) +add_library(3rdparty::fusion ALIAS Fusion) diff --git a/3rdparty/fusion/CMakeLists.txt b/3rdparty/fusion/CMakeLists.txt new file mode 100644 index 0000000000..099056a8de --- /dev/null +++ b/3rdparty/fusion/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(fusion EXCLUDE_FROM_ALL) diff --git a/3rdparty/fusion/fusion b/3rdparty/fusion/fusion new file mode 160000 index 0000000000..fecf2f0af3 --- /dev/null +++ b/3rdparty/fusion/fusion @@ -0,0 +1 @@ +Subproject commit fecf2f0af3bd23cbba553ceedc2bc6c1cd410fc1 diff --git a/3rdparty/fusion/fusion.vcxproj b/3rdparty/fusion/fusion.vcxproj new file mode 100644 index 0000000000..71e669be00 --- /dev/null +++ b/3rdparty/fusion/fusion.vcxproj @@ -0,0 +1,75 @@ + + + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + Fusion + {3C67A2FF-4710-402A-BE3E-31B0CB0576DF} + + + + + + StaticLibrary + Unicode + + + + x64 + + + $(SolutionDir)build\lib\$(Configuration)-$(Platform)\ + $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\ + + + $(SolutionDir)build\lib\$(Configuration)-$(Platform)\ + $(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\ + + + + + + + + + + + + + + + + + + + Sync + MaxSpeed + + + + + + \ No newline at end of file diff --git a/3rdparty/fusion/fusion.vcxproj.filters b/3rdparty/fusion/fusion.vcxproj.filters new file mode 100644 index 0000000000..85764a4f97 --- /dev/null +++ b/3rdparty/fusion/fusion.vcxproj.filters @@ -0,0 +1,29 @@ + + + + + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + + + + + + + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/rpcs3.sln b/rpcs3.sln index 9ca661550b..26bc66179b 100644 --- a/rpcs3.sln +++ b/rpcs3.sln @@ -7,6 +7,7 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "emucore", "rpcs3\emucore.vcxproj", "{C4A10229-4712-4BD2-B63E-50D93C67A038}" ProjectSection(ProjectDependencies) = postProject {2C902C67-985C-4BE0-94A3-E0FE2EB929A3} = {2C902C67-985C-4BE0-94A3-E0FE2EB929A3} + {3C67A2FF-4710-402A-BE3E-31B0CB0576DF} = {3C67A2FF-4710-402A-BE3E-31B0CB0576DF} {5228F863-E0DD-4DE7-AA7B-5C52B14CD4D0} = {5228F863-E0DD-4DE7-AA7B-5C52B14CD4D0} {8846A9AA-5539-4C91-8301-F54260E1A07A} = {8846A9AA-5539-4C91-8301-F54260E1A07A} {939FE206-1182-ABC3-1234-FEAB88E98404} = {939FE206-1182-ABC3-1234-FEAB88E98404} @@ -46,6 +47,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxpro {2C902C67-985C-4BE0-94A3-E0FE2EB929A3} = {2C902C67-985C-4BE0-94A3-E0FE2EB929A3} {3384223A-6D97-4799-9862-359F85312892} = {3384223A-6D97-4799-9862-359F85312892} {349EE8F9-7D25-4909-AAF5-FF3FADE72187} = {349EE8F9-7D25-4909-AAF5-FF3FADE72187} + {3C67A2FF-4710-402A-BE3E-31B0CB0576DF} = {3C67A2FF-4710-402A-BE3E-31B0CB0576DF} {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D} = {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D} {508C291A-3D18-49F5-B25D-F7C8DB92CB21} = {508C291A-3D18-49F5-B25D-F7C8DB92CB21} {5B146DEA-9ACE-4D32-A7FD-3F42464DD69C} = {5B146DEA-9ACE-4D32-A7FD-3F42464DD69C} @@ -103,6 +105,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "7zip", "3rdparty\7zip\7zip. EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openal-soft", "3rdparty\openal\openal-soft.vcxproj", "{8846A9AA-5539-4C91-8301-F54260E1A07A}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fusion", "3rdparty\fusion\fusion.vcxproj", "{3C67A2FF-4710-402A-BE3E-31B0CB0576DF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -211,6 +215,10 @@ Global {8846A9AA-5539-4C91-8301-F54260E1A07A}.Debug|x64.Build.0 = Debug|x64 {8846A9AA-5539-4C91-8301-F54260E1A07A}.Release|x64.ActiveCfg = Release|x64 {8846A9AA-5539-4C91-8301-F54260E1A07A}.Release|x64.Build.0 = Release|x64 + {3C67A2FF-4710-402A-BE3E-31B0CB0576DF}.Debug|x64.ActiveCfg = Debug|x64 + {3C67A2FF-4710-402A-BE3E-31B0CB0576DF}.Debug|x64.Build.0 = Debug|x64 + {3C67A2FF-4710-402A-BE3E-31B0CB0576DF}.Release|x64.ActiveCfg = Release|x64 + {3C67A2FF-4710-402A-BE3E-31B0CB0576DF}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -243,6 +251,7 @@ Global {4E52A41A-F33B-4C7A-8C36-A1A6B4F4277C} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8} {5B146DEA-9ACE-4D32-A7FD-3F42464DD69C} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8} {8846A9AA-5539-4C91-8301-F54260E1A07A} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8} + {3C67A2FF-4710-402A-BE3E-31B0CB0576DF} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {06CC7920-E085-4B81-9582-8DE8AAD42510} diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index 04a928fa72..059d0a4dbf 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -82,6 +82,7 @@ target_sources(rpcs3 Input/mm_joystick_handler.cpp Input/pad_thread.cpp Input/product_info.cpp + Input/ps_move_calibration.cpp Input/ps_move_config.cpp Input/ps_move_handler.cpp Input/ps_move_tracker.cpp @@ -110,6 +111,7 @@ target_link_libraries(rpcs3 3rdparty::libcurl 3rdparty::zlib 3rdparty::opencv + 3rdparty::fusion ${ADDITIONAL_LIBS}) # Unix display manager diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index d94c4dbd70..7e1e95ae61 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -903,7 +903,7 @@ static inline void pos_to_gem_image_state(u32 gem_num, const gem_config::gem_con } } -static inline void pos_to_gem_state(u32 gem_num, const gem_config::gem_controller& controller, vm::ptr& gem_state, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max) +static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& controller, vm::ptr& gem_state, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max, const ps_move_data& move_data) { const auto& shared_data = g_fxo->get(); @@ -932,16 +932,28 @@ static inline void pos_to_gem_state(u32 gem_num, const gem_config::gem_controlle gem_state->pos[2] = controller.distance_mm; gem_state->pos[3] = 0.f; - gem_state->quat[0] = 320.f - image_x; - gem_state->quat[1] = (y_pos / scaling_width) - 180.f; - gem_state->quat[2] = 1200.f; - // TODO: calculate handle position based on our world coordinate and the angles gem_state->handle_pos[0] = camera_x; gem_state->handle_pos[1] = camera_y; gem_state->handle_pos[2] = controller.distance_mm + 10.0f; gem_state->handle_pos[3] = 0.f; + // Calculate orientation + if (g_cfg.io.move == move_handler::real) + { + gem_state->quat[0] = move_data.quaternion[1]; // x + gem_state->quat[1] = move_data.quaternion[2]; // y + gem_state->quat[2] = move_data.quaternion[3]; // z + gem_state->quat[3] = move_data.quaternion[0]; // w + } + else + { + gem_state->quat[0] = 320.f - image_x; + gem_state->quat[1] = (y_pos / scaling_width) - 180.f; + gem_state->quat[2] = 1200.f; + gem_state->quat[3] = 1.f; + } + if (g_cfg.io.show_move_cursor) { draw_overlay_cursor(gem_num, controller, x_pos, y_pos, x_max, y_max); @@ -1056,7 +1068,7 @@ static inline void ds3_get_stick_values(u32 gem_num, const std::shared_ptr& } template -static void ds3_pos_to_gem_state(u32 gem_num, const gem_config::gem_controller& controller, T& gem_state) +static void ds3_pos_to_gem_state(u32 gem_num, gem_config::gem_controller& controller, T& gem_state) { if (!gem_state || !is_input_allowed()) { @@ -1078,7 +1090,7 @@ static void ds3_pos_to_gem_state(u32 gem_num, const gem_config::gem_controller& if constexpr (std::is_same_v>) { - pos_to_gem_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y); + pos_to_gem_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y, {}); } else if constexpr (std::is_same_v>) { @@ -1087,7 +1099,7 @@ static void ds3_pos_to_gem_state(u32 gem_num, const gem_config::gem_controller& } template -static void ps_move_pos_to_gem_state(u32 gem_num, const gem_config::gem_controller& controller, T& gem_state) +static void ps_move_pos_to_gem_state(u32 gem_num, gem_config::gem_controller& controller, T& gem_state) { if (!gem_state || !is_input_allowed()) { @@ -1114,7 +1126,7 @@ static void ps_move_pos_to_gem_state(u32 gem_num, const gem_config::gem_controll gem_state->accel[1] = pad->move_data.accelerometer_y * 1000; // linear velocity in mm/s² gem_state->accel[2] = pad->move_data.accelerometer_z * 1000; // linear velocity in mm/s² - pos_to_gem_state(gem_num, controller, gem_state, info.x_pos, info.y_pos, info.x_max, info.y_max); + pos_to_gem_state(gem_num, controller, gem_state, info.x_pos, info.y_pos, info.x_max, info.y_max, pad->move_data); } else if constexpr (std::is_same_v>) { @@ -1272,7 +1284,7 @@ static bool mouse_input_to_pad(u32 mouse_no, be_t& digital_buttons, be_t -static void mouse_pos_to_gem_state(u32 mouse_no, const gem_config::gem_controller& controller, T& gem_state) +static void mouse_pos_to_gem_state(u32 mouse_no, gem_config::gem_controller& controller, T& gem_state) { if (!gem_state || !is_input_allowed()) { @@ -1295,7 +1307,7 @@ static void mouse_pos_to_gem_state(u32 mouse_no, const gem_config::gem_controlle if constexpr (std::is_same_v>) { - pos_to_gem_state(mouse_no, controller, gem_state, mouse.x_pos, mouse.y_pos, mouse.x_max, mouse.y_max); + pos_to_gem_state(mouse_no, controller, gem_state, mouse.x_pos, mouse.y_pos, mouse.x_max, mouse.y_max, {}); } else if constexpr (std::is_same_v>) { @@ -1345,7 +1357,7 @@ static bool gun_input_to_pad(u32 gem_no, be_t& digital_buttons, be_t& } template -static void gun_pos_to_gem_state(u32 gem_no, const gem_config::gem_controller& controller, T& gem_state) +static void gun_pos_to_gem_state(u32 gem_no, gem_config::gem_controller& controller, T& gem_state) { if (!gem_state || !is_input_allowed()) return; @@ -1363,7 +1375,7 @@ static void gun_pos_to_gem_state(u32 gem_no, const gem_config::gem_controller& c if constexpr (std::is_same_v>) { - pos_to_gem_state(gem_no, controller, gem_state, x_pos, y_pos, x_max, y_max); + pos_to_gem_state(gem_no, controller, gem_state, x_pos, y_pos, x_max, y_max, {}); } else if constexpr (std::is_same_v>) { @@ -1800,7 +1812,7 @@ error_code cellGemGetImageState(u32 gem_num, vm::ptr gem_imag if (g_cfg.io.move != move_handler::null) { auto& shared_data = g_fxo->get(); - const auto& controller = gem.controllers[gem_num]; + auto& controller = gem.controllers[gem_num]; gem_image_state->frame_timestamp = shared_data.frame_timestamp_us.load(); gem_image_state->timestamp = gem_image_state->frame_timestamp + 10; @@ -2130,7 +2142,6 @@ error_code cellGemGetState(u32 gem_num, u32 flag, u64 time_parameter, vm::ptrtimestamp = (get_guest_system_time() - gem.start_timestamp_us); gem_state->camera_pitch_angle = 0.f; - gem_state->quat[3] = 1.f; switch (g_cfg.io.move) { diff --git a/rpcs3/Emu/Io/pad_types.h b/rpcs3/Emu/Io/pad_types.h index 631e9d6c4e..77d56fdf59 100644 --- a/rpcs3/Emu/Io/pad_types.h +++ b/rpcs3/Emu/Io/pad_types.h @@ -466,12 +466,13 @@ struct ps_move_data bool external_device_read_requested = false; bool external_device_write_requested = false; + std::array quaternion { 1.0f, 0.0f, 0.0f, 0.0f }; // quaternion orientation (x,y,z,w) of controller relative to default (facing the camera with buttons up) f32 accelerometer_x = 0; // linear velocity in m/s² f32 accelerometer_y = 0; // linear velocity in m/s² f32 accelerometer_z = 0; // linear velocity in m/s² - f32 gyro_x = 0; // linear velocity in m/s² - f32 gyro_y = 0; // linear velocity in m/s² - f32 gyro_z = 0; // linear velocity in m/s² + f32 gyro_x = 0; // angular velocity in rad/s + f32 gyro_y = 0; // angular velocity in rad/s + f32 gyro_z = 0; // angular velocity in rad/s s16 temperature = 0; }; diff --git a/rpcs3/Input/ps_move_calibration.cpp b/rpcs3/Input/ps_move_calibration.cpp new file mode 100644 index 0000000000..aaadc2b89a --- /dev/null +++ b/rpcs3/Input/ps_move_calibration.cpp @@ -0,0 +1,240 @@ +#include "stdafx.h" +#include "ps_move_calibration.h" + +LOG_CHANNEL(move_log, "Move"); + +// This is basically the same as in ps move api + +static inline s32 psmove_calibration_decode_16bit_unsigned(const u8* data, u32 offset) +{ + const u8 low = data[offset] & 0xFF; + const u8 high = (data[offset + 1]) & 0xFF; + return (low | (high << 8)) - zero_shift; +} + +static inline s16 psmove_calibration_decode_16bit_signed(const u8* data, u32 offset) +{ + const u16 low = data[offset] & 0xFF; + const u16 high = (data[offset + 1]) & 0xFF; + return static_cast(low | (high << 8)); +} + +static inline u32 psmove_calibration_decode_12bits(const u8* data, u32 offset) +{ + const u8 low = data[offset] & 0xFF; + const u8 high = (data[offset + 1]) & 0xFF; + return low | (high << 8); +} + +static inline f32 psmove_calibration_decode_float(const u8* data, u32 offset) +{ + union + { + uint32_t u32; + float f; + } v { + .u32 = static_cast( (data[offset] & 0xFF) | + ((data[offset + 1] & 0xFF) << 8) | + ((data[offset + 2] & 0xFF) << 16) | + ((data[offset + 3] & 0xFF) << 24)) + }; + + return v.f; +} + +static void psmove_dump_calibration(const reports::ps_move_calibration_blob& calibration, const ps_move_device& device) +{ + int t, x, y, z; + float fx, fy, fz; + + const u8* data = calibration.data.data(); + + switch (device.model) + { + case ps_move_model::ZCM1: + t = psmove_calibration_decode_12bits(data, 0x02); + move_log.error("Temperature: 0x%04X", t); + for (int orientation = 0; orientation < 6; orientation++) + { + x = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * orientation); + y = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * orientation + 2); + z = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * orientation + 4); + move_log.error("Orientation #%d: (%5d | %5d | %5d)", orientation, x, y, z); + } + + t = psmove_calibration_decode_12bits(data, 0x42); + move_log.error("Temperature: 0x%04X", t); + for (int orientation = 0; orientation < 3; orientation++) + { + x = psmove_calibration_decode_16bit_unsigned(data, 0x46 + 8 * orientation); + y = psmove_calibration_decode_16bit_unsigned(data, 0x46 + 8 * orientation + 2); + z = psmove_calibration_decode_16bit_unsigned(data, 0x46 + 8 * orientation + 4); + move_log.error("Gyro %c, 80 rpm: (%5d | %5d | %5d)", "XYZ"[orientation], x, y, z); + } + + t = psmove_calibration_decode_12bits(data, 0x28); + x = psmove_calibration_decode_16bit_unsigned(data, 0x2a); + y = psmove_calibration_decode_16bit_unsigned(data, 0x2a + 2); + z = psmove_calibration_decode_16bit_unsigned(data, 0x2a + 4); + move_log.error("Temperature: 0x%04X", t); + move_log.error("Gyro, 0 rpm (@0x2a): (%5d | %5d | %5d)", x, y, z); + + t = psmove_calibration_decode_12bits(data, 0x30); + x = psmove_calibration_decode_16bit_unsigned(data, 0x32); + y = psmove_calibration_decode_16bit_unsigned(data, 0x32 + 2); + z = psmove_calibration_decode_16bit_unsigned(data, 0x32 + 4); + move_log.error("Temperature: 0x%04X", t); + move_log.error("Gyro, 0 rpm (@0x32): (%5d | %5d | %5d)", x, y, z); + + t = psmove_calibration_decode_12bits(data, 0x5c); + fx = psmove_calibration_decode_float(data, 0x5e); + fy = psmove_calibration_decode_float(data, 0x5e + 4); + fz = psmove_calibration_decode_float(data, 0x5e + 8); + move_log.error("Temperature: 0x%04X", t); + move_log.error("Vector @0x5e: (%f | %f | %f)", fx, fy, fz); + + fx = psmove_calibration_decode_float(data, 0x6a); + fy = psmove_calibration_decode_float(data, 0x6a + 4); + fz = psmove_calibration_decode_float(data, 0x6a + 8); + move_log.error("Vector @0x6a: (%f | %f | %f)", fx, fy, fz); + + move_log.error("byte @0x3f: 0x%02x", static_cast(data[0x3f])); + move_log.error("float @0x76: %f", psmove_calibration_decode_float(data, 0x76)); + move_log.error("float @0x7a: %f", psmove_calibration_decode_float(data, 0x7a)); + break; + case ps_move_model::ZCM2: + for (int orientation = 0; orientation < 6; orientation++) + { + x = psmove_calibration_decode_16bit_signed(data, 0x04 + 6 * orientation); + y = psmove_calibration_decode_16bit_signed(data, 0x04 + 6 * orientation + 2); + z = psmove_calibration_decode_16bit_signed(data, 0x04 + 6 * orientation + 4); + move_log.error("Orientation #%d: (%5d | %5d | %5d)", orientation, x, y, z); + } + + x = psmove_calibration_decode_16bit_signed(data, 0x26); + y = psmove_calibration_decode_16bit_signed(data, 0x26 + 2); + z = psmove_calibration_decode_16bit_signed(data, 0x26 + 4); + move_log.error("Gyro Bias?, 0 rpm (@0x26): (%5d | %5d | %5d)", x, y, z); + + for (int orientation = 0; orientation < 6; orientation++) + { + x = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * orientation); + y = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * orientation + 2); + z = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * orientation + 4); + move_log.error("Gyro %c, 90 rpm: (%5d | %5d | %5d)", "XYZXYZ"[orientation], x, y, z); + } + break; + } +} + +void psmove_calibration_get_usb_accel_values(const reports::ps_move_calibration_blob& calibration, ps_move_device& device) +{ + const u8* data = calibration.data.data(); + + int x1 = 0, x2 = 0, y1 = 0, y2 = 0, z1 = 0, z2 = 0; + + switch (device.model) + { + case ps_move_model::ZCM1: + // Minimum (negative) value of each axis + x1 = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * 1); + y1 = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * 5 + 2); + z1 = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * 2 + 4); + + // Maximum (positive) value of each axis + x2 = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * 3); + y2 = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * 4 + 2); + z2 = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * 0 + 4); + break; + case ps_move_model::ZCM2: + // Minimum (negative) value of each axis + x1 = psmove_calibration_decode_16bit_signed(data, 0x02 + 6 * 1); + y1 = psmove_calibration_decode_16bit_signed(data, 0x02 + 6 * 3 + 2); + z1 = psmove_calibration_decode_16bit_signed(data, 0x02 + 6 * 5 + 4); + + // Maximum (positive) value of each axis + x2 = psmove_calibration_decode_16bit_signed(data, 0x02 + 6 * 0); + y2 = psmove_calibration_decode_16bit_signed(data, 0x02 + 6 * 2 + 2); + z2 = psmove_calibration_decode_16bit_signed(data, 0x02 + 6 * 4 + 4); + break; + } + + device.calibration.accel_x_factor = 2.0f / static_cast(x2 - x1); + device.calibration.accel_y_factor = 2.0f / static_cast(y2 - y1); + device.calibration.accel_z_factor = 2.0f / static_cast(z2 - z1); + + device.calibration.accel_x_offset = -(device.calibration.accel_x_factor * static_cast(x1)) - 1.0f; + device.calibration.accel_y_offset = -(device.calibration.accel_y_factor * static_cast(x1)) - 1.0f; + device.calibration.accel_z_offset = -(device.calibration.accel_z_factor * static_cast(x1)) - 1.0f; +} + +void psmove_calibration_get_usb_gyro_values(const reports::ps_move_calibration_blob& calibration, ps_move_device& device) +{ + const u8* data = calibration.data.data(); + + constexpr f32 PI = 3.14159265f; + constexpr f32 rpm_to_rad_per_sec = (2.0f * PI) / 60.0f; + + switch (device.model) + { + case ps_move_model::ZCM1: + { + const int bx = psmove_calibration_decode_16bit_unsigned(data, 0x2a); + const int by = psmove_calibration_decode_16bit_unsigned(data, 0x2a + 2); + const int bz = psmove_calibration_decode_16bit_unsigned(data, 0x2a + 4); + + const int x = psmove_calibration_decode_16bit_unsigned(data, 0x46 + 8 * 0) - bx; + const int y = psmove_calibration_decode_16bit_unsigned(data, 0x46 + 8 * 1 + 2) - by; + const int z = psmove_calibration_decode_16bit_unsigned(data, 0x46 + 8 * 2 + 4) - bz; + + constexpr f32 calibration_rpm = 80.0f; + constexpr f32 factor = calibration_rpm * rpm_to_rad_per_sec; + + // Per frame drift taken into account using adjusted gain values + device.calibration.gyro_x_gain = factor / static_cast(x); + device.calibration.gyro_y_gain = factor / static_cast(y); + device.calibration.gyro_z_gain = factor / static_cast(z); + device.calibration.gyro_x_offset = 0; + device.calibration.gyro_y_offset = 0; + device.calibration.gyro_z_offset = 0; + break; + } + case ps_move_model::ZCM2: + { + // Minimum (negative) value of each axis + const int x1 = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * 3); + const int y1 = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * 4 + 2); + const int z1 = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * 5 + 4); + + // Maximum (positive) values of each axis + const int x2 = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * 0); + const int y2 = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * 1 + 2); + const int z2 = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * 2 + 4); + + const int dx = psmove_calibration_decode_16bit_signed(data, 0x26); + const int dy = psmove_calibration_decode_16bit_signed(data, 0x26 + 2); + const int dz = psmove_calibration_decode_16bit_signed(data, 0x26 + 4); + + constexpr f32 calibration_rpm = 90.0f; + constexpr f32 calibration_hi = calibration_rpm * rpm_to_rad_per_sec; + constexpr f32 calibration_low = -calibration_rpm * rpm_to_rad_per_sec; + constexpr f32 factor = calibration_hi - calibration_low; + + // Compute the gain value (the slope of the gyro reading/angular speed line) + device.calibration.gyro_x_gain = factor / static_cast(x2 - x1); + device.calibration.gyro_y_gain = factor / static_cast(y2 - y1); + device.calibration.gyro_z_gain = factor / static_cast(z2 - z1); + device.calibration.gyro_x_offset = static_cast(dx); + device.calibration.gyro_y_offset = static_cast(dy); + device.calibration.gyro_z_offset = static_cast(dz); + break; + } + } +} + +void psmove_parse_calibration(const reports::ps_move_calibration_blob& calibration, ps_move_device& device) +{ + psmove_dump_calibration(calibration, device); + psmove_calibration_get_usb_accel_values(calibration, device); + psmove_calibration_get_usb_gyro_values(calibration, device); +} diff --git a/rpcs3/Input/ps_move_calibration.h b/rpcs3/Input/ps_move_calibration.h new file mode 100644 index 0000000000..a1e362fa9f --- /dev/null +++ b/rpcs3/Input/ps_move_calibration.h @@ -0,0 +1,5 @@ +#pragma once + +#include "ps_move_handler.h" + +void psmove_parse_calibration(const reports::ps_move_calibration_blob& calibration, ps_move_device& device); diff --git a/rpcs3/Input/ps_move_handler.cpp b/rpcs3/Input/ps_move_handler.cpp index cee24d208f..38dd3d6551 100644 --- a/rpcs3/Input/ps_move_handler.cpp +++ b/rpcs3/Input/ps_move_handler.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "ps_move_handler.h" +#include "ps_move_calibration.h" #include "Emu/Io/pad_config.h" #include "Emu/System.h" #include "Emu/system_config.h" @@ -57,11 +58,6 @@ namespace usb_charging = 0xEE, usb_charged = 0xEF, }; - - enum - { - zero_shift = 0x8000, - }; } const ps_move_input_report_common& ps_move_device::input_report_common() const @@ -223,7 +219,7 @@ hid_device* ps_move_handler::connect_move_device(ps_move_device* device, std::st if (hid_set_nonblocking(device->bt_device, 1) == -1) { - move_log.error("check_add_device: hid_set_nonblocking failed! Reason: %s", hid_error(device->bt_device)); + move_log.error("connect_move_device: hid_set_nonblocking failed! Reason: %s", hid_error(device->bt_device)); device->close(); return nullptr; } @@ -239,7 +235,7 @@ hid_device* ps_move_handler::connect_move_device(ps_move_device* device, std::st if (hid_set_nonblocking(device->hidDevice, 1) == -1) { - move_log.error("check_add_device: hid_set_nonblocking failed! Reason: %s", hid_error(device->hidDevice)); + move_log.error("connect_move_device: hid_set_nonblocking failed! Reason: %s", hid_error(device->hidDevice)); device->close(); return nullptr; } @@ -315,6 +311,60 @@ void ps_move_handler::check_add_device(hid_device* hidDevice, std::string_view p device->hidDevice = hidDevice; device->path = path; + // Get calibration + device->calibration.is_valid = true; + + ps_move_calibration_blob calibration {}; + + for (int i = 0; i < 2; i++) + { + std::array cal {}; + cal[0] = 0x10; + const int res = hid_get_feature_report(device->hidDevice, cal.data(), cal.size()); + if (res < 0) + { + move_log.error("connect_move_device: hid_get_feature_report 0x10 (calibration) failed! result=%d, error=%s", res, hid_error(device->hidDevice)); + device->calibration.is_valid = false; + break; + } + + int src_offset = 0; + int dest_offset = 0; + + if ((cal[1] == 0x01 && device->model == ps_move_model::ZCM1) || + (cal[1] == 0x81 && device->model == ps_move_model::ZCM2)) + { + // This is the second block + dest_offset = PSMOVE_CALIBRATION_SIZE; + src_offset = 2; + } + else if (cal[1] == 0x82 && device->model == ps_move_model::ZCM1) + { + // This is the third block + dest_offset = 2 * PSMOVE_CALIBRATION_SIZE - 2; + src_offset = 2; + } + else if (cal[1] != 0x00) // Check if this is the first block (offsets stay 0) + { + move_log.error("connect_move_device: Failed to read calibration: cal=0x%x'", cal[1]); + device->calibration.is_valid = false; + break; + } + + std::memcpy(&calibration.data[dest_offset], &cal[src_offset], cal.size() - src_offset); + } + + if (device->calibration.is_valid) + { + psmove_parse_calibration(calibration, *device); + } + + // Initialize Fusion + FusionAhrsInitialise(&device->ahrs); + device->ahrs.settings.convention = FusionConvention::FusionConventionEnu; + FusionAhrsSetSettings(&device->ahrs, &device->ahrs.settings); + FusionAhrsReset(&device->ahrs); + // Activate if (send_output_report(device) == -1) { @@ -620,34 +670,48 @@ void ps_move_handler::get_extended_info(const pad_ensemble& binding) const ps_move_input_report_common& input = dev->input_report_common(); - constexpr f32 MOVE_ONE_G = 4096.0f; // This is just a rough estimate and probably depends on the device - // The default position is flat on the ground, pointing forward. // The accelerometers constantly measure G forces. // The gyros measure changes in orientation and will reset when the device isn't moved anymore. - s16 accel_x = input.accel_x_2; // Increases if the device is rolled to the left - s16 accel_y = input.accel_y_2; // Increases if the device is pitched upwards - s16 accel_z = input.accel_z_2; // Increases if the device is moved upwards - s16 gyro_x = input.gyro_x_2; // Increases if the device is pitched upwards - s16 gyro_y = input.gyro_y_2; // Increases if the device is rolled to the right - s16 gyro_z = input.gyro_z_2; // Increases if the device is yawed to the left + s16 accel_x = input.accel_x_1; // Increases if the device is rolled to the left + s16 accel_y = input.accel_y_1; // Increases if the device is pitched upwards + s16 accel_z = input.accel_z_1; // Increases if the device is moved upwards + s16 gyro_x = input.gyro_x_1; // Increases if the device is pitched upwards + s16 gyro_y = input.gyro_y_1; // Increases if the device is rolled to the right + s16 gyro_z = input.gyro_z_1; // Increases if the device is yawed to the left if (dev->model == ps_move_model::ZCM1) { - accel_x -= zero_shift; - accel_y -= zero_shift; - accel_z -= zero_shift; - gyro_x -= zero_shift; - gyro_y -= zero_shift; - gyro_z -= zero_shift; + accel_x = (input.accel_x_1 + input.accel_x_2) / 2 - zero_shift; + accel_y = (input.accel_y_1 + input.accel_y_2) / 2 - zero_shift; + accel_z = (input.accel_z_1 + input.accel_z_2) / 2 - zero_shift; + gyro_x = (input.gyro_x_1 + input.gyro_x_2) / 2 - zero_shift; + gyro_y = (input.gyro_y_1 + input.gyro_y_2) / 2 - zero_shift; + gyro_z = (input.gyro_z_1 + input.gyro_z_2) / 2 - zero_shift; + } + + // Apply calibration + if (dev->calibration.is_valid) + { + pad->move_data.accelerometer_x = accel_x * dev->calibration.accel_x_factor + dev->calibration.accel_x_offset; + pad->move_data.accelerometer_y = accel_y * dev->calibration.accel_y_factor + dev->calibration.accel_y_offset; + pad->move_data.accelerometer_z = accel_z * dev->calibration.accel_z_factor + dev->calibration.accel_z_offset; + pad->move_data.gyro_x = (gyro_x - dev->calibration.gyro_x_offset) * dev->calibration.gyro_x_gain; + pad->move_data.gyro_y = (gyro_y - dev->calibration.gyro_y_offset) * dev->calibration.gyro_y_gain; + pad->move_data.gyro_z = (gyro_z - dev->calibration.gyro_z_offset) * dev->calibration.gyro_z_gain; + } + else + { + constexpr f32 MOVE_ONE_G = 4096.0f; // This is just a rough estimate and probably depends on the device + + pad->move_data.accelerometer_x = accel_x / MOVE_ONE_G; + pad->move_data.accelerometer_y = accel_y / MOVE_ONE_G; + pad->move_data.accelerometer_z = accel_z / MOVE_ONE_G; + pad->move_data.gyro_x = gyro_x / MOVE_ONE_G; + pad->move_data.gyro_y = gyro_y / MOVE_ONE_G; + pad->move_data.gyro_z = gyro_z / MOVE_ONE_G; } - pad->move_data.accelerometer_x = accel_x / MOVE_ONE_G; - pad->move_data.accelerometer_y = accel_y / MOVE_ONE_G; - pad->move_data.accelerometer_z = accel_z / MOVE_ONE_G; - pad->move_data.gyro_x = accel_x / MOVE_ONE_G; - pad->move_data.gyro_y = accel_y / MOVE_ONE_G; - pad->move_data.gyro_z = accel_z / MOVE_ONE_G; pad->move_data.temperature = ((input.temperature << 4) | ((input.magnetometer_x & 0xF0) >> 4)); pad->m_sensors[0].m_value = Clamp0To1023(512.0f + (MOTION_ONE_G * pad->move_data.accelerometer_x * -1.0f)); @@ -655,6 +719,58 @@ void ps_move_handler::get_extended_info(const pad_ensemble& binding) pad->m_sensors[2].m_value = Clamp0To1023(512.0f + (MOTION_ONE_G * pad->move_data.accelerometer_z)); pad->m_sensors[3].m_value = Clamp0To1023(512.0f + (MOTION_ONE_G * pad->move_data.gyro_z * -1.0f)); + // Get elapsed time since last update + const u64 now_us = get_system_time(); + const float elapsed_sec = (dev->last_ahrs_update_time_us == 0) ? 0.0f : ((now_us - dev->last_ahrs_update_time_us) / 1'000'000.0f); + dev->last_ahrs_update_time_us = now_us; + + // The ps move handler's axis may differ from the Fusion axis, so we have to map them correctly. + // Don't ask how the axis work. It's basically been trial and error. + ensure(dev->ahrs.settings.convention == FusionConvention::FusionConventionEnu); // East-North-Up + + const FusionVector accelerometer{ + .axis { + .x = -pad->move_data.accelerometer_x, + .y = +pad->move_data.accelerometer_y, + .z = +pad->move_data.accelerometer_z + } + }; + + static constexpr f32 PI = 3.14159265f; + const auto rad_to_degree = [](f32 radians) -> f32 { return radians * 180.0f / PI; }; + const FusionVector gyroscope{ + .axis { + .x = +rad_to_degree(pad->move_data.gyro_x), + .y = +rad_to_degree(pad->move_data.gyro_z), + .z = -rad_to_degree(pad->move_data.gyro_y) + } + }; + + FusionVector magnetometer {}; + + // TODO: use magnetometer if possible + //if (dev->model == ps_move_model::ZCM1) + //{ + // const ps_move_input_report_ZCM1& input = dev->input_report_ZCM1; + // magnetometer = FusionVector{ + // .axis { + // .x = input.magnetometer_x2, + // .y = input.magnetometer_y, + // .z = input.magnetometer_z + // } + // }; + //} + + // Update Fusion + FusionAhrsUpdate(&dev->ahrs, gyroscope, accelerometer, magnetometer, elapsed_sec); + + // Get quaternion + const FusionQuaternion quaternion = FusionAhrsGetQuaternion(&dev->ahrs); + pad->move_data.quaternion[0] = quaternion.array[0]; + pad->move_data.quaternion[1] = quaternion.array[1]; + pad->move_data.quaternion[2] = quaternion.array[2]; + pad->move_data.quaternion[3] = quaternion.array[3]; + handle_external_device(binding); } diff --git a/rpcs3/Input/ps_move_handler.h b/rpcs3/Input/ps_move_handler.h index edf377e044..434a3c81a2 100644 --- a/rpcs3/Input/ps_move_handler.h +++ b/rpcs3/Input/ps_move_handler.h @@ -2,6 +2,15 @@ #include "hid_pad_handler.h" +#ifndef _MSC_VER +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wold-style-cast" +#endif +#include "3rdparty/fusion/fusion/Fusion/Fusion.h" +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif + #include namespace reports @@ -80,14 +89,50 @@ namespace reports { std::array data{}; // TODO }; + + // Buffer size for calibration data + constexpr u32 PSMOVE_CALIBRATION_SIZE = 49; + + // Three blocks, minus header (2 bytes) for blocks 2,3 + constexpr u32 PSMOVE_ZCM1_CALIBRATION_BLOB_SIZE = PSMOVE_CALIBRATION_SIZE * 3 - 2 * 2; + + // Three blocks, minus header (2 bytes) for block 2 + constexpr u32 PSMOVE_ZCM2_CALIBRATION_BLOB_SIZE = PSMOVE_CALIBRATION_SIZE * 2 - 2 * 1; + + struct ps_move_calibration_blob + { + std::array data{}; + }; } +enum +{ + zero_shift = 0x8000, +}; + enum class ps_move_model { ZCM1, // PS3 ZCM2, // PS4 }; +struct ps_move_calibration +{ + bool is_valid = false; + f32 accel_x_factor = 1.0f; + f32 accel_y_factor = 1.0f; + f32 accel_z_factor = 1.0f; + f32 accel_x_offset = 0.0f; + f32 accel_y_offset = 0.0f; + f32 accel_z_offset = 0.0f; + f32 gyro_x_gain = 1.0f; + f32 gyro_y_gain = 1.0f; + f32 gyro_z_gain = 1.0f; + f32 gyro_x_offset = 0.0f; + f32 gyro_y_offset = 0.0f; + f32 gyro_z_offset = 0.0f; +}; + class ps_move_device : public HidDevice { public: @@ -98,6 +143,10 @@ public: reports::ps_move_output_report last_output_report{}; steady_clock::time_point last_output_report_time; u32 external_device_id = 0; + ps_move_calibration calibration{}; + + FusionAhrs ahrs {}; // Used to calculate quaternions from sensor data + u64 last_ahrs_update_time_us = 0; // Last ahrs update const reports::ps_move_input_report_common& input_report_common() const; }; diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 8c3566dca5..9a196dd8af 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -40,7 +40,7 @@ Use - ..\3rdparty\miniupnp\miniupnp\miniupnpc\include;..\3rdparty\wolfssl\wolfssl;..\3rdparty\flatbuffers\include;..\3rdparty\libusb\libusb\libusb;..\3rdparty\yaml-cpp\yaml-cpp\include;..\3rdparty\SoundTouch\soundtouch\include;..\3rdparty\rtmidi\rtmidi;..\3rdparty\zlib\zlib;$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build\include;$(SolutionDir)build\lib_ext\$(Configuration)-$(Platform)\llvm_build\include;$(SolutionDir)build\lib_ext\$(Configuration)-$(Platform)\llvm\include;$(VULKAN_SDK)\Include;..\3rdparty\zstd\zstd\lib + ..\3rdparty\miniupnp\miniupnp\miniupnpc\include;..\3rdparty\wolfssl\wolfssl;..\3rdparty\flatbuffers\include;..\3rdparty\libusb\libusb\libusb;..\3rdparty\yaml-cpp\yaml-cpp\include;..\3rdparty\SoundTouch\soundtouch\include;..\3rdparty\rtmidi\rtmidi;..\3rdparty\zlib\zlib;$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build\include;$(SolutionDir)build\lib_ext\$(Configuration)-$(Platform)\llvm_build\include;$(SolutionDir)build\lib_ext\$(Configuration)-$(Platform)\llvm\include;$(VULKAN_SDK)\Include;..\3rdparty\zstd\zstd\lib;$(SolutionDir)3rdparty\fusion\fusion\Fusion MaxSpeed AL_LIBTYPE_STATIC;MINIUPNP_STATICLIB;HAVE_VULKAN;HAVE_SDL2;ZLIB_CONST;%(PreprocessorDefinitions) AL_LIBTYPE_STATIC;MINIUPNP_STATICLIB;HAVE_VULKAN;HAVE_SDL2;ZLIB_CONST;%(PreprocessorDefinitions) diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 6f5dafcc08..1973831ab3 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -62,12 +62,12 @@ true - $(SolutionDir)3rdparty\7zip\7zip\C;$(SolutionDir)3rdparty\hidapi\hidapi\hidapi;.\;$(SolutionDir);$(SolutionDir)3rdparty\asmjit\asmjit\src;$(SolutionDir)3rdparty\yaml-cpp\yaml-cpp\include;$(SolutionDir)3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)3rdparty\libpng\libpng;$(SolutionDir)3rdparty\GL;$(SolutionDir)3rdparty\stblib\stb;$(SolutionDir)3rdparty\openal\openal-soft\include\AL;$(SolutionDir)3rdparty\pugixml\src;$(SolutionDir)3rdparty\Optional;$(SolutionDir)3rdparty\discord-rpc\include;$(SolutionDir)3rdparty\zlib\zlib;$(SolutionDir)3rdparty\libsdl-org\SDL\include + $(SolutionDir)3rdparty\7zip\7zip\C;$(SolutionDir)3rdparty\hidapi\hidapi\hidapi;.\;$(SolutionDir);$(SolutionDir)3rdparty\asmjit\asmjit\src;$(SolutionDir)3rdparty\yaml-cpp\yaml-cpp\include;$(SolutionDir)3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)3rdparty\libpng\libpng;$(SolutionDir)3rdparty\GL;$(SolutionDir)3rdparty\stblib\stb;$(SolutionDir)3rdparty\openal\openal-soft\include\AL;$(SolutionDir)3rdparty\pugixml\src;$(SolutionDir)3rdparty\Optional;$(SolutionDir)3rdparty\discord-rpc\include;$(SolutionDir)3rdparty\zlib\zlib;$(SolutionDir)3rdparty\libsdl-org\SDL\include;$(SolutionDir)3rdparty\fusion\fusion\Fusion $(SolutionDir)build\lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath) $(SolutionDir)build\lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath) - $(SolutionDir)3rdparty\7zip\7zip\C;$(SolutionDir)3rdparty\hidapi\hidapi\hidapi;.\;$(SolutionDir);$(SolutionDir)3rdparty\asmjit\asmjit\src;$(SolutionDir)3rdparty\yaml-cpp\yaml-cpp\include;$(SolutionDir)3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)3rdparty\libpng\libpng;$(SolutionDir)3rdparty\GL;$(SolutionDir)3rdparty\stblib\stb;$(SolutionDir)3rdparty\openal\openal-soft\include\AL;$(SolutionDir)3rdparty\pugixml\src;$(SolutionDir)3rdparty\Optional;$(SolutionDir)3rdparty\discord-rpc\include;$(SolutionDir)3rdparty\zlib\zlib;$(SolutionDir)3rdparty\libsdl-org\SDL\include + $(SolutionDir)3rdparty\7zip\7zip\C;$(SolutionDir)3rdparty\hidapi\hidapi\hidapi;.\;$(SolutionDir);$(SolutionDir)3rdparty\asmjit\asmjit\src;$(SolutionDir)3rdparty\yaml-cpp\yaml-cpp\include;$(SolutionDir)3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)3rdparty\libpng\libpng;$(SolutionDir)3rdparty\GL;$(SolutionDir)3rdparty\stblib\stb;$(SolutionDir)3rdparty\openal\openal-soft\include\AL;$(SolutionDir)3rdparty\pugixml\src;$(SolutionDir)3rdparty\Optional;$(SolutionDir)3rdparty\discord-rpc\include;$(SolutionDir)3rdparty\zlib\zlib;$(SolutionDir)3rdparty\libsdl-org\SDL\include;$(SolutionDir)3rdparty\fusion\fusion\Fusion @@ -89,7 +89,7 @@ TurnOffAllWarnings - opencv_world4100.lib;DbgHelp.lib;Ole32.lib;gdi32.lib;hidapi.lib;libusb-1.0.lib;winmm.lib;miniupnpc_static.lib;rtmidi.lib;imm32.lib;ksuser.lib;version.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslang.lib;OSDependent.lib;OGLCompiler.lib;SPIRV.lib;MachineIndependent.lib;GenericCodeGen.lib;Advapi32.lib;user32.lib;zlib.lib;zstd.lib;libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;shell32.lib;Qt6Core.lib;Qt6Gui.lib;Qt6Widgets.lib;Qt6Concurrent.lib;Qt6Multimedia.lib;Qt6MultimediaWidgets.lib;Qt6Svg.lib;Qt6SvgWidgets.lib;7zip.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;SDL.lib;%(AdditionalDependencies) + opencv_world4100.lib;DbgHelp.lib;Ole32.lib;gdi32.lib;hidapi.lib;libusb-1.0.lib;winmm.lib;miniupnpc_static.lib;rtmidi.lib;imm32.lib;ksuser.lib;version.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslang.lib;OSDependent.lib;OGLCompiler.lib;SPIRV.lib;MachineIndependent.lib;GenericCodeGen.lib;Advapi32.lib;user32.lib;zlib.lib;zstd.lib;libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;shell32.lib;Qt6Core.lib;Qt6Gui.lib;Qt6Widgets.lib;Qt6Concurrent.lib;Qt6Multimedia.lib;Qt6MultimediaWidgets.lib;Qt6Svg.lib;Qt6SvgWidgets.lib;7zip.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;SDL.lib;fusion.lib;%(AdditionalDependencies) $(SolutionDir)3rdparty\opencv\opencv\opencv410\build\x64\lib;$(SolutionDir)build\lib\$(Configuration)-$(Platform)\glslang;$(SolutionDir)build\lib_ext\$(CONFIGURATION)-$(PLATFORM);$(SolutionDir)3rdparty\discord-rpc\lib;$(QTDIR)\lib;$(VULKAN_SDK)\Lib;%(AdditionalLibraryDirectories) "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) true @@ -141,7 +141,7 @@ $(IntDir)vc$(PlatformToolsetVersion).pdb - opencv_world4100.lib;DbgHelp.lib;Ole32.lib;gdi32.lib;hidapi.lib;libusb-1.0.lib;winmm.lib;miniupnpc_static.lib;rtmidi.lib;imm32.lib;ksuser.lib;version.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslangd.lib;OSDependentd.lib;OGLCompilerd.lib;SPIRVd.lib;MachineIndependentd.lib;GenericCodeGend.lib;Advapi32.lib;user32.lib;zlib.lib;zstd.lib;libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;shell32.lib;Qt6Cored.lib;Qt6Guid.lib;Qt6Widgetsd.lib;Qt6Concurrentd.lib;Qt6Multimediad.lib;Qt6MultimediaWidgetsd.lib;Qt6Svgd.lib;Qt6SvgWidgetsd.lib;7zip.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;SDL.lib;%(AdditionalDependencies) + opencv_world4100.lib;DbgHelp.lib;Ole32.lib;gdi32.lib;hidapi.lib;libusb-1.0.lib;winmm.lib;miniupnpc_static.lib;rtmidi.lib;imm32.lib;ksuser.lib;version.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslangd.lib;OSDependentd.lib;OGLCompilerd.lib;SPIRVd.lib;MachineIndependentd.lib;GenericCodeGend.lib;Advapi32.lib;user32.lib;zlib.lib;zstd.lib;libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;shell32.lib;Qt6Cored.lib;Qt6Guid.lib;Qt6Widgetsd.lib;Qt6Concurrentd.lib;Qt6Multimediad.lib;Qt6MultimediaWidgetsd.lib;Qt6Svgd.lib;Qt6SvgWidgetsd.lib;7zip.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;SDL.lib;fusion.lib;%(AdditionalDependencies) $(SolutionDir)3rdparty\opencv\opencv\opencv410\build\x64\lib;$(SolutionDir)build\lib\$(Configuration)-$(Platform)\glslang;$(SolutionDir)3rdparty\discord-rpc\lib;$(SolutionDir)build\lib\$(CONFIGURATION)-$(PLATFORM);$(QTDIR)\lib;$(VULKAN_SDK)\Lib;%(AdditionalLibraryDirectories) "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" /VERBOSE %(AdditionalOptions) true @@ -179,6 +179,7 @@ + @@ -971,6 +972,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath) $(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath) + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index b7e277ca51..0e2eae3a00 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -1143,6 +1143,9 @@ Io\Move + + Io\Move + @@ -1343,6 +1346,9 @@ Io\Move + + Io\Move + diff --git a/rpcs3/rpcs3qt/CMakeLists.txt b/rpcs3/rpcs3qt/CMakeLists.txt index 2629da0880..e3e3c0a264 100644 --- a/rpcs3/rpcs3qt/CMakeLists.txt +++ b/rpcs3/rpcs3qt/CMakeLists.txt @@ -160,4 +160,5 @@ target_link_libraries(rpcs3_ui 3rdparty::wolfssl 3rdparty::libcurl 3rdparty::opencv + 3rdparty::fusion 3rdparty::rtmidi)