Modules/cellGem: Implement pos, quat and handle_pos in Gemstate for mouse.

Modules/cellGem: Fix name for gem_image_state.
Modules/cellGem: Implement projectiion(x/y) in gem_image_State for mouse.
Modules/cellGem: Add cross, triangle, circle and start with use middle click for mouse.
Modules/cellGem: Refactor global code.
Modules/cellGem: fix some warning with initializing value.
This commit is contained in:
Zangetsu38 2018-07-23 19:57:40 +02:00 committed by Megamouse
parent ac2b0c9752
commit af8ebc76e2
5 changed files with 179 additions and 121 deletions

View file

@ -7,6 +7,7 @@
#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/PPUModule.h"
#include "pad_thread.h" #include "pad_thread.h"
#include "Emu/Io/MouseHandler.h" #include "Emu/Io/MouseHandler.h"
#include "Emu/RSX/GSRender.h"
#include "Utilities/Timer.h" #include "Utilities/Timer.h"
LOG_CHANNEL(cellGem); LOG_CHANNEL(cellGem);
@ -80,31 +81,27 @@ struct gem_config
struct gem_controller struct gem_controller
{ {
u32 status; // connection status (CELL_GEM_STATUS_DISCONNECTED or CELL_GEM_STATUS_READY) u32 status = CELL_GEM_STATUS_DISCONNECTED; // Connection status (CELL_GEM_STATUS_DISCONNECTED or CELL_GEM_STATUS_READY)
u32 ext_status; // external port connection status u32 ext_status = CELL_GEM_NO_EXTERNAL_PORT_DEVICE; // External port connection status
u32 port; // assigned port u32 port = 0; // Assigned port
bool enabled_magnetometer; // whether the magnetometer is enabled (probably used for additional rotational precision) bool enabled_magnetometer = false; // Whether the magnetometer is enabled (probably used for additional rotational precision)
bool calibrated_magnetometer; // whether the magnetometer is calibrated bool calibrated_magnetometer = false; // Whether the magnetometer is calibrated
bool enabled_filtering; // whether filtering is enabled bool enabled_filtering = false; // Whether filtering is enabled
bool enabled_tracking; // whether tracking is enabled bool enabled_tracking = false; // Whether tracking is enabled
bool enabled_LED; // whether the LED is enabled bool enabled_LED = false; // Whether the LED is enabled
u8 rumble; // rumble intensity u8 rumble = 0; // Rumble intensity
gem_color sphere_rgb; // RGB color of the sphere LED gem_color sphere_rgb = {}; // RGB color of the sphere LED
u32 hue; // tracking hue of the motion controller u32 hue = 0; // Tracking hue of the motion controller
gem_controller() :
status(CELL_GEM_STATUS_DISCONNECTED),
enabled_filtering(false), rumble(0), sphere_rgb() {}
}; };
CellGemAttribute attribute; CellGemAttribute attribute = {};
CellGemVideoConvertAttribute vc_attribute; CellGemVideoConvertAttribute vc_attribute = {};
u64 status_flags; u64 status_flags = CELL_GEM_NOT_CALIBRATED;
bool enable_pitch_correction; bool enable_pitch_correction = false;
u32 inertial_counter; u32 inertial_counter = 0;
std::array<gem_controller, CELL_GEM_MAX_NUM> controllers; std::array<gem_controller, CELL_GEM_MAX_NUM> controllers;
u32 connected_controllers; u32 connected_controllers = 0;
bool update_started{}; bool update_started{};
u32 camera_frame{}; u32 camera_frame{};
u32 memory_ptr{}; u32 memory_ptr{};
@ -123,34 +120,21 @@ struct gem_config
{ {
switch (g_cfg.io.move) switch (g_cfg.io.move)
{ {
default: case move_handler::fake:
case move_handler::null: case move_handler::mouse:
{ {
connected_controllers = 0; connected_controllers = 1;
controllers[gem_num].status = CELL_GEM_STATUS_DISCONNECTED;
controllers[gem_num].port = 0;
break; break;
} }
default: break;
}
case move_handler::fake: // Assign status and port number
{
// fake one connected controller
connected_controllers = 1;
if (gem_num < connected_controllers) if (gem_num < connected_controllers)
{ {
controllers[gem_num].status = CELL_GEM_STATUS_READY; controllers[gem_num].status = CELL_GEM_STATUS_READY;
controllers[gem_num].port = 7u - gem_num; controllers[gem_num].port = 7u - gem_num;
} }
else
{
controllers[gem_num].status = CELL_GEM_STATUS_DISCONNECTED;
controllers[gem_num].port = 0;
}
break;
}
}
} }
}; };
@ -167,6 +151,7 @@ void fmt_class_string<move_handler>::format(std::string& out, u64 arg)
{ {
case move_handler::null: return "Null"; case move_handler::null: return "Null";
case move_handler::fake: return "Fake"; case move_handler::fake: return "Fake";
case move_handler::mouse: return "Mouse";
} }
return unknown; return unknown;
@ -306,40 +291,113 @@ static bool ds3_input_to_ext(const u32 port_no, CellGemExtPortData& ext)
} }
/** /**
* \brief Maps Move controller data (digital buttons, and analog Trigger data) to mouse input. * \brief Maps Move controller data (digital buttons, and analog Trigger data) to mouse input.
* Move Button: Mouse1 * Move Button: Mouse1
* Trigger: Mouse2 * Trigger: Mouse2
* \param mouse_no Mouse index number to use * \param mouse_no Mouse index number to use
* \param digital_buttons Bitmask filled with CELL_GEM_CTRL_* values * \param digital_buttons Bitmask filled with CELL_GEM_CTRL_* values
* \param analog_t Analog value of Move's Trigger. * \param analog_t Analog value of Move's Trigger.
* \return true on success, false if mouse mouse_no is invalid * \return true on success, false if mouse mouse_no is invalid
*/ */
static bool map_to_mouse_input(const u32 mouse_no, be_t<u16>& digital_buttons, be_t<u16>& analog_t) static bool mouse_input_to_pad(const u32 mouse_no, be_t<u16>& digital_buttons, be_t<u16>& analog_t)
{ {
const auto handler = g_fxo->get<MouseHandlerBase>(); const auto handler = g_fxo->get<MouseHandlerBase>();
if (handler->GetInfo().status[mouse_no] != CELL_MOUSE_STATUS_CONNECTED) std::scoped_lock lock(handler->mutex);
if (!handler || mouse_no >= handler->GetMice().size())
{ {
return false; return false;
} }
MouseDataList& mouse_data_list = handler->GetDataList(mouse_no); memset(&digital_buttons, 0, sizeof(digital_buttons));
if (mouse_data_list.size()) const auto& mouse_data = handler->GetMice().at(0);
{
const MouseData& mouse_data = mouse_data_list.front();
if (mouse_data.buttons & CELL_MOUSE_BUTTON_1)
digital_buttons |= CELL_GEM_CTRL_T;
if ((mouse_data.buttons & CELL_MOUSE_BUTTON_1) && (mouse_data.buttons & CELL_MOUSE_BUTTON_2))
digital_buttons |= CELL_GEM_CTRL_CIRCLE;
if (mouse_data.buttons & CELL_MOUSE_BUTTON_3)
digital_buttons |= CELL_GEM_CTRL_CROSS;
if (mouse_data.buttons & CELL_MOUSE_BUTTON_2) if (mouse_data.buttons & CELL_MOUSE_BUTTON_2)
digital_buttons |= CELL_GEM_CTRL_MOVE; digital_buttons |= CELL_GEM_CTRL_MOVE;
if ((mouse_data.buttons & CELL_MOUSE_BUTTON_1) && (mouse_data.buttons & CELL_MOUSE_BUTTON_3))
digital_buttons |= CELL_GEM_CTRL_START;
if (mouse_data.buttons & CELL_MOUSE_BUTTON_1)
digital_buttons |= CELL_GEM_CTRL_T;
if ((mouse_data.buttons & CELL_MOUSE_BUTTON_2) && (mouse_data.buttons & CELL_MOUSE_BUTTON_3))
digital_buttons |= CELL_GEM_CTRL_TRIANGLE;
analog_t = mouse_data.buttons & CELL_MOUSE_BUTTON_1 ? 0xFFFF : 0; analog_t = mouse_data.buttons & (CELL_MOUSE_BUTTON_1 ? 0xFFFF : 0);
mouse_data_list.pop_front(); return true;
}
static bool mouse_pos_to_gem_image_state(const u32 mouse_no, vm::ptr<CellGemImageState>& gem_image_state)
{
const auto handler = g_fxo->get<MouseHandlerBase>();
std::scoped_lock lock(handler->mutex);
if (!gem_image_state || !handler || mouse_no >= handler->GetMice().size())
{
return false;
} }
const auto& mouse = handler->GetMice().at(0);
const auto renderer = static_cast<GSRender*>(rsx::get_current_renderer());
const auto width = renderer->get_frame()->client_width();
const auto hight = renderer->get_frame()->client_height();
const f32 scaling_width = width / 640.f;
const f32 scaling_hight = hight / 480.f;
const f32 x = static_cast<f32>(mouse.x_pos) / scaling_width;
const f32 y = static_cast<f32>(mouse.y_pos) / scaling_hight;
gem_image_state->u = 133.f + (x / 1.50f);
gem_image_state->v = 160.f + (y / 1.67f);
gem_image_state->projectionx = x - 320.f;
gem_image_state->projectiony = 240.f - y;
return true;
}
static bool mouse_pos_to_gem_state(const u32 mouse_no, vm::ptr<CellGemState>& gem_state)
{
const auto handler = g_fxo->get<MouseHandlerBase>();
std::scoped_lock lock(handler->mutex);
if (!gem_state || !handler || mouse_no >= handler->GetMice().size())
{
return false;
}
const auto& mouse = handler->GetMice().at(0);
const auto renderer = static_cast<GSRender*>(rsx::get_current_renderer());
const auto width = renderer->get_frame()->client_width();
const auto hight = renderer->get_frame()->client_height();
const f32 scaling_width = width / 640.f;
const f32 scaling_hight = hight / 480.f;
const f32 x = static_cast<f32>(mouse.x_pos) / scaling_width;
const f32 y = static_cast<f32>(mouse.y_pos) / scaling_hight;
gem_state->pos[0] = x;
gem_state->pos[1] = -y;
gem_state->pos[2] = 1500.f;
gem_state->pos[3] = 0.f;
gem_state->quat[0] = 320.f - x;
gem_state->quat[1] = (mouse.y_pos / scaling_width) - 180.f;
gem_state->quat[2] = 1200.f;
gem_state->handle_pos[0] = x;
gem_state->handle_pos[1] = y;
gem_state->handle_pos[2] = 1500.f;
gem_state->handle_pos[3] = 0.f;
return true; return true;
} }
@ -365,9 +423,11 @@ error_code cellGemCalibrate(u32 gem_num)
return CELL_GEM_ERROR_INVALID_PARAMETER; return CELL_GEM_ERROR_INVALID_PARAMETER;
} }
if (g_cfg.io.move == move_handler::fake) if (g_cfg.io.move == move_handler::fake || g_cfg.io.move == move_handler::mouse)
{ {
gem->controllers[gem_num].calibrated_magnetometer = true; gem->controllers[gem_num].calibrated_magnetometer = true;
gem->controllers[gem_num].enabled_tracking = true;
gem->controllers[gem_num].hue = 1;
gem->status_flags = CELL_GEM_FLAG_CALIBRATION_OCCURRED | CELL_GEM_FLAG_CALIBRATION_SUCCEEDED; gem->status_flags = CELL_GEM_FLAG_CALIBRATION_OCCURRED | CELL_GEM_FLAG_CALIBRATION_SUCCEEDED;
} }
@ -629,9 +689,9 @@ error_code cellGemGetHuePixels(vm::cptr<void> camera_frame, u32 hue, vm::ptr<u8>
return CELL_OK; return CELL_OK;
} }
error_code cellGemGetImageState(u32 gem_num, vm::ptr<CellGemImageState> image_state) error_code cellGemGetImageState(u32 gem_num, vm::ptr<CellGemImageState> gem_image_state)
{ {
cellGem.todo("cellGemGetImageState(gem_num=%d, image_state=&0x%x)", gem_num, image_state); cellGem.todo("cellGemGetImageState(gem_num=%d, image_state=&0x%x)", gem_num, gem_image_state);
const auto gem = g_fxo->get<gem_config>(); const auto gem = g_fxo->get<gem_config>();
@ -640,40 +700,31 @@ error_code cellGemGetImageState(u32 gem_num, vm::ptr<CellGemImageState> image_st
return CELL_GEM_ERROR_UNINITIALIZED; return CELL_GEM_ERROR_UNINITIALIZED;
} }
if (!check_gem_num(gem_num) || !image_state) if (!check_gem_num(gem_num) || !gem_image_state)
{ {
return CELL_GEM_ERROR_INVALID_PARAMETER; return CELL_GEM_ERROR_INVALID_PARAMETER;
} }
if (g_cfg.io.move == move_handler::fake &&
g_cfg.io.mouse == mouse_handler::basic)
{
auto shared_data = g_fxo->get<gem_camera_shared>(); auto shared_data = g_fxo->get<gem_camera_shared>();
const auto handler = fxm::get<MouseHandlerBase>(); if (g_cfg.io.move == move_handler::fake)
auto& mouse = handler->GetMice().at(0); {
gem_image_state->u = 0;
gem_image_state->v = 0;
gem_image_state->projectionx = 1;
gem_image_state->projectiony = 1;
}
else if (g_cfg.io.move == move_handler::mouse)
mouse_pos_to_gem_image_state(gem_num, gem_image_state);
f32 x_pos = mouse.x_pos; if (g_cfg.io.move == move_handler::fake || g_cfg.io.move == move_handler::mouse)
f32 y_pos = mouse.y_pos; {
gem_image_state->frame_timestamp = shared_data->frame_timestamp.load();
static constexpr auto aspect_ratio = 1.2; gem_image_state->timestamp = gem_image_state->frame_timestamp + 10;
gem_image_state->r = 10;
static constexpr auto screen_offset_x = 400.0; gem_image_state->distance = 2 * 1000; // 2 meters away from camera
static constexpr auto screen_offset_y = screen_offset_x * aspect_ratio; gem_image_state->visible = true;
gem_image_state->r_valid = true;
static constexpr auto screen_scale = 3.0;
image_state->frame_timestamp = shared_data->frame_timestamp.load();
image_state->timestamp = image_state->frame_timestamp + 10; // arbitrarily define 10 usecs of frame processing
image_state->visible = true;
image_state->u = screen_offset_x / screen_scale + x_pos / screen_scale;
image_state->v = screen_offset_y / screen_scale + y_pos / screen_scale * aspect_ratio;
image_state->r = 10;
image_state->r_valid = true;
image_state->distance = 2 * 1000; // 2 meters away from camera
// TODO
image_state->projectionx = 1;
image_state->projectiony = 1;
} }
return CELL_OK; return CELL_OK;
@ -698,19 +749,16 @@ error_code cellGemGetInertialState(u32 gem_num, u32 state_flag, u64 timestamp, v
} }
if (g_cfg.io.move == move_handler::fake) if (g_cfg.io.move == move_handler::fake)
{
ds3_input_to_pad(gem_num, inertial_state->pad.digitalbuttons, inertial_state->pad.analog_T); ds3_input_to_pad(gem_num, inertial_state->pad.digitalbuttons, inertial_state->pad.analog_T);
else if (g_cfg.io.move == move_handler::mouse)
mouse_input_to_pad(gem_num, inertial_state->pad.digitalbuttons, inertial_state->pad.analog_T);
if (g_cfg.io.move == move_handler::fake || g_cfg.io.move == move_handler::mouse)
{
ds3_input_to_ext(gem_num, inertial_state->ext); ds3_input_to_ext(gem_num, inertial_state->ext);
if (g_cfg.io.mouse == mouse_handler::basic)
{
map_to_mouse_input(gem_num, inertial_state->pad.digitalbuttons, inertial_state->pad.analog_T);
}
inertial_state->timestamp = gem->timer.GetElapsedTimeInMicroSec(); inertial_state->timestamp = gem->timer.GetElapsedTimeInMicroSec();
inertial_state->counter = gem->inertial_counter++; inertial_state->counter = gem->inertial_counter++;
inertial_state->accelerometer[0] = 10; inertial_state->accelerometer[0] = 10;
} }
@ -778,7 +826,7 @@ error_code cellGemGetRGB(u32 gem_num, vm::ptr<float> r, vm::ptr<float> g, vm::pt
return CELL_GEM_ERROR_UNINITIALIZED; return CELL_GEM_ERROR_UNINITIALIZED;
} }
if (!check_gem_num(gem_num) || !r || !g || !b ) if (!check_gem_num(gem_num) || !r || !g || !b)
{ {
return CELL_GEM_ERROR_INVALID_PARAMETER; return CELL_GEM_ERROR_INVALID_PARAMETER;
} }
@ -833,19 +881,21 @@ error_code cellGemGetState(u32 gem_num, u32 flag, u64 time_parameter, vm::ptr<Ce
} }
if (g_cfg.io.move == move_handler::fake) if (g_cfg.io.move == move_handler::fake)
{
ds3_input_to_pad(gem_num, gem_state->pad.digitalbuttons, gem_state->pad.analog_T); ds3_input_to_pad(gem_num, gem_state->pad.digitalbuttons, gem_state->pad.analog_T);
ds3_input_to_ext(gem_num, gem_state->ext); else if (g_cfg.io.move == move_handler::mouse)
if (g_cfg.io.mouse == mouse_handler::basic)
{ {
map_to_mouse_input(gem_num, gem_state->pad.digitalbuttons, gem_state->pad.analog_T); mouse_input_to_pad(gem_num, gem_state->pad.digitalbuttons, gem_state->pad.analog_T);
mouse_pos_to_gem_state(gem_num, gem_state);
} }
if (g_cfg.io.move == move_handler::fake || g_cfg.io.move == move_handler::mouse)
{
ds3_input_to_ext(gem_num, gem_state->ext);
gem_state->tracking_flags = CELL_GEM_TRACKING_FLAG_POSITION_TRACKED | CELL_GEM_TRACKING_FLAG_VISIBLE; gem_state->tracking_flags = CELL_GEM_TRACKING_FLAG_POSITION_TRACKED | CELL_GEM_TRACKING_FLAG_VISIBLE;
gem_state->timestamp = gem->timer.GetElapsedTimeInMicroSec(); gem_state->timestamp = gem->timer.GetElapsedTimeInMicroSec();
gem_state->quat[3] = 1.f;
gem_state->quat[3] = 1.0;
return CELL_OK; return CELL_OK;
} }
@ -959,13 +1009,12 @@ error_code cellGemInit(vm::cptr<CellGemAttribute> attribute)
gem->status_flags = 0; gem->status_flags = 0;
gem->attribute = *attribute; gem->attribute = *attribute;
if (g_cfg.io.move == move_handler::fake && if (g_cfg.io.move == move_handler::mouse)
g_cfg.io.mouse == mouse_handler::basic)
{ {
// init mouse handler // init mouse handler
const auto handler = g_fxo->get<MouseHandlerBase>(); const auto handler = g_fxo->get<MouseHandlerBase>();
handler->Init(std::min(attribute->max_connect.value(), static_cast<u32>(CELL_GEM_MAX_NUM))); handler->Init(std::min<u32>(attribute->max_connect, CELL_GEM_MAX_NUM));
} }
for (int gem_num = 0; gem_num < CELL_GEM_MAX_NUM; gem_num++) for (int gem_num = 0; gem_num < CELL_GEM_MAX_NUM; gem_num++)
@ -997,7 +1046,7 @@ error_code cellGemInvalidateCalibration(s32 gem_num)
return CELL_GEM_ERROR_INVALID_PARAMETER; return CELL_GEM_ERROR_INVALID_PARAMETER;
} }
if (g_cfg.io.move == move_handler::fake) if (g_cfg.io.move == move_handler::fake || g_cfg.io.move == move_handler::mouse)
{ {
gem->controllers[gem_num].calibrated_magnetometer = false; gem->controllers[gem_num].calibrated_magnetometer = false;
// TODO: gem->status_flags // TODO: gem->status_flags

View file

@ -126,6 +126,7 @@ enum class move_handler
{ {
null, null,
fake, fake,
mouse,
}; };
enum class microphone_handler enum class microphone_handler

View file

@ -153,7 +153,7 @@
"mouseHandlerBox": "Some games support native mouse input.\nBasic will work in these cases.", "mouseHandlerBox": "Some games support native mouse input.\nBasic will work in these cases.",
"cameraBox": "Camera support is not implemented, leave this on null.", "cameraBox": "Camera support is not implemented, leave this on null.",
"cameraTypeBox": "Camera support is not implemented, leave this on unknown.", "cameraTypeBox": "Camera support is not implemented, leave this on unknown.",
"moveBox": "PlayStation Move support.\nFake: Experimental! This maps Move controls to DS4 controller mappings." "moveBox": "PlayStation Move support.\nFake: Experimental! This maps Move controls to DS3 controller mappings.\nMouse: Emulate PSMove with Mouse handler."
}, },
"network": { "network": {
"netStatusBox": "Leave as disconnected unless you're debugging.\nRPCS3 has no online support." "netStatusBox": "Leave as disconnected unless you're debugging.\nRPCS3 has no online support."

View file

@ -100,7 +100,15 @@ EmuCallbacks main_application::CreateCallbacks()
{ {
case mouse_handler::null: case mouse_handler::null:
{ {
if (g_cfg.io.move == move_handler::mouse)
{
basic_mouse_handler* ret = g_fxo->init<MouseHandlerBase, basic_mouse_handler>();
ret->moveToThread(get_thread());
ret->SetTargetWindow(m_game_window);
}
else
g_fxo->init<MouseHandlerBase, NullMouseHandler>(); g_fxo->init<MouseHandlerBase, NullMouseHandler>();
break; break;
} }
case mouse_handler::basic: case mouse_handler::basic:

View file

@ -419,7 +419,7 @@ void gs_frame::take_screenshot(const std::vector<u8> sshot_data, const u32 sshot
void gs_frame::mouseDoubleClickEvent(QMouseEvent* ev) void gs_frame::mouseDoubleClickEvent(QMouseEvent* ev)
{ {
if (m_disable_mouse) return; if (m_disable_mouse || g_cfg.io.move == move_handler::mouse) return;
if (ev->button() == Qt::LeftButton) if (ev->button() == Qt::LeftButton)
{ {