Cleans up Controllers

Renames VirtualController to DummyController.
Makes controller axis treated the same as buttons.
Made Controller class members private or protected
Made Controller class treat deadzones, sensitivities, and press thresholds consistently.
This commit is contained in:
Kenix3 2022-08-11 00:06:58 -04:00
parent 791f7774a5
commit 094388187f
13 changed files with 413 additions and 362 deletions

View File

@ -2,7 +2,7 @@
#include "Window.h" #include "Window.h"
#include "Controller.h" #include "Controller.h"
#include "VirtualController.h" #include "DummyController.h"
#include "KeyboardController.h" #include "KeyboardController.h"
#include "SDLController.h" #include "SDLController.h"
#include <Utils/StringHelper.h> #include <Utils/StringHelper.h>
@ -28,9 +28,9 @@ namespace Ship {
} }
} }
physicalDevices.push_back(std::make_shared<VirtualController>("Auto", "Auto", true)); physicalDevices.push_back(std::make_shared<DummyController>("Auto", "Auto", true));
physicalDevices.push_back(std::make_shared<KeyboardController>()); physicalDevices.push_back(std::make_shared<KeyboardController>());
physicalDevices.push_back(std::make_shared<VirtualController>("Disconnected", "None", false)); physicalDevices.push_back(std::make_shared<DummyController>("Disconnected", "None", false));
for (const auto& device : physicalDevices) { for (const auto& device : physicalDevices) {
for (int i = 0; i < MAXCONTROLLERS; i++) { for (int i = 0; i < MAXCONTROLLERS; i++) {
@ -77,7 +77,7 @@ namespace Ship {
} }
} }
#define NESTED(key, ...) StringHelper::Sprintf("Controllers.%s.Slot_%d." key, device->GetGuid().c_str(), slot, __VA_ARGS__) #define NESTED(key, ...) StringHelper::Sprintf("Controllers.%s.Slot_%d." key, device->GetGuid().c_str(), virtualSlot, __VA_ARGS__)
void ControlDeck::LoadControllerSettings() { void ControlDeck::LoadControllerSettings() {
std::shared_ptr<Mercury> Config = GlobalCtx2::GetInstance()->GetConfig(); std::shared_ptr<Mercury> Config = GlobalCtx2::GetInstance()->GetConfig();
@ -102,25 +102,40 @@ namespace Ship {
std::string guid = device->GetGuid(); std::string guid = device->GetGuid();
for (int slot = 0; slot < MAXCONTROLLERS; slot++) { for (int32_t virtualSlot = 0; virtualSlot < MAXCONTROLLERS; virtualSlot++) {
if (!(Config->rjson["Controllers"].contains(guid) && Config->rjson["Controllers"][guid].contains(StringHelper::Sprintf("Slot_%d", slot)))) continue; if (!(Config->rjson["Controllers"].contains(guid) && Config->rjson["Controllers"][guid].contains(StringHelper::Sprintf("Slot_%d", virtualSlot)))) continue;
auto& profile = device->profiles[slot]; auto profile = device->getProfile(virtualSlot);
auto rawProfile = Config->rjson["Controllers"][guid][StringHelper::Sprintf("Slot_%d", slot)]; auto rawProfile = Config->rjson["Controllers"][guid][StringHelper::Sprintf("Slot_%d", virtualSlot)];
profile.Mappings.clear(); profile->Mappings.clear();
profile.Thresholds.clear(); profile->AxisDeadzones.clear();
profile.UseRumble = Config->getBool(NESTED("Rumble.Enabled", "")); profile->AxisSensitivities.clear();
profile.RumbleStrength = Config->getFloat(NESTED("Rumble.Strength", "")); profile->GyroData.clear();
profile.UseGyro = Config->getBool(NESTED("Gyro.Enabled", "")); profile->Version = Config->getInt(NESTED("Version", ""));
profile->UseRumble = Config->getBool(NESTED("Rumble.Enabled", ""));
profile->RumbleStrength = Config->getFloat(NESTED("Rumble.Strength", ""));
profile->UseGyro = Config->getBool(NESTED("Gyro.Enabled", ""));
for (auto const& val : rawProfile["Thresholds"].items()) { for (auto const& val : rawProfile["AxisDeadzones"].items()) {
profile.Thresholds[static_cast<ControllerThresholds>(std::stoi(val.key()))] = val.value(); profile->AxisDeadzones[std::stoi(val.key())] = val.value();
}
for (auto const& val : rawProfile["AxisSensitivities"].items()) {
profile->AxisSensitivities[std::stoi(val.key())] = val.value();
}
for (auto const& val : rawProfile["AxisMinimumPress"].items()) {
profile->AxisMinimumPress[std::stoi(val.key())] = val.value();
}
for (auto const& val : rawProfile["GyroData"].items()) {
profile->GyroData[std::stoi(val.key())] = val.value();
} }
for (auto const& val : rawProfile["Mappings"].items()) { for (auto const& val : rawProfile["Mappings"].items()) {
device->SetButtonMapping(slot, std::stoi(val.key().substr(4)), val.value()); device->SetButtonMapping(virtualSlot, std::stoi(val.key().substr(4)), val.value());
} }
} }
} }
@ -136,31 +151,45 @@ namespace Ship {
for (const auto& device : physicalDevices) { for (const auto& device : physicalDevices) {
int slot = 0; int32_t virtualSlot = 0;
std::string guid = device->GetGuid(); std::string guid = device->GetGuid();
for (const auto& profile : device->profiles) { for (int32_t virtualSlot = 0; virtualSlot < MAXCONTROLLERS; virtualSlot++) {
auto profile = device->getProfile(virtualSlot);
if (!device->Connected()) continue; if (!device->Connected()) continue;
auto rawProfile = Config->rjson["Controllers"][guid][StringHelper::Sprintf("Slot_%d", slot)]; auto rawProfile = Config->rjson["Controllers"][guid][StringHelper::Sprintf("Slot_%d", virtualSlot)];
Config->setBool(NESTED("Rumble.Enabled", ""), profile.UseRumble); Config->setInt(NESTED("Version", ""), profile->Version);
Config->setFloat(NESTED("Rumble.Strength", ""), profile.RumbleStrength); Config->setBool(NESTED("Rumble.Enabled", ""), profile->UseRumble);
Config->setBool(NESTED("Gyro.Enabled", ""), profile.UseGyro); Config->setFloat(NESTED("Rumble.Strength", ""), profile->RumbleStrength);
Config->setBool(NESTED("Gyro.Enabled", ""), profile->UseGyro);
for (auto const& val : rawProfile["Mappings"].items()) { for (auto const& val : rawProfile["Mappings"].items()) {
Config->setInt(NESTED("Mappings.%s", val.key().c_str()), -1); Config->setInt(NESTED("Mappings.%s", val.key().c_str()), -1);
} }
for (auto const& [key, val] : profile.Thresholds) { for (auto const& [key, val] : profile->AxisDeadzones) {
Config->setFloat(NESTED("Thresholds.%d", key), val); Config->setFloat(NESTED("AxisDeadzones.%d", key), val);
} }
for (auto const& [key, val] : profile.Mappings) { for (auto const& [key, val] : profile->AxisSensitivities) {
Config->setFloat(NESTED("AxisSensitivities.%d", key), val);
}
for (auto const& [key, val] : profile->AxisMinimumPress) {
Config->setFloat(NESTED("AxisMinimumPress.%d", key), val);
}
for (auto const& [key, val] : profile->GyroData) {
Config->setFloat(NESTED("GyroData.%d", key), val);
}
for (auto const& [key, val] : profile->Mappings) {
Config->setInt(NESTED("Mappings.BTN_%d", val), key); Config->setInt(NESTED("Mappings.BTN_%d", val), key);
} }
slot++; virtualSlot++;
} }
} }

View File

@ -9,72 +9,105 @@
namespace Ship { namespace Ship {
Controller::Controller() : isRumbling(false), wStickX(0), wStickY(0), wGyroX(0), wGyroY(0), wCamX(0), wCamY(0), dwPressedButtons(0){ Controller::Controller() : isRumbling(false) {
Attachment = nullptr; Attachment = nullptr;
profiles.resize(MAXCONTROLLERS);
for(int slot = 0; slot < MAXCONTROLLERS; slot++) { for(int virtualSlot = 0; virtualSlot < MAXCONTROLLERS; virtualSlot++) {
dwPressedButtons.push_back(0); profiles[virtualSlot] = std::make_shared<DeviceProfileV0>();
ButtonData[virtualSlot] = std::make_shared<Buttons>();
} }
} }
void Controller::Read(OSContPad* pad, int32_t slot) { void Controller::Read(OSContPad* pad, int32_t virtualSlot) {
ReadFromSource(slot); ReadFromSource(virtualSlot);
SDL_PumpEvents(); SDL_PumpEvents();
// Button Inputs // Button Inputs
pad->button |= dwPressedButtons[slot] & 0xFFFF; pad->button |= getPressedButtons(virtualSlot) & 0xFFFF;
// Stick Inputs // Stick Inputs
if (wStickX == 0) { if (getLeftStickX(virtualSlot) == 0) {
if (dwPressedButtons[slot] & BTN_STICKLEFT) { if (getPressedButtons(virtualSlot) & BTN_STICKLEFT) {
pad->stick_x = -128; pad->stick_x = -128;
} else if (dwPressedButtons[slot] & BTN_STICKRIGHT) { } else if (getPressedButtons(virtualSlot) & BTN_STICKRIGHT) {
pad->stick_x = 127; pad->stick_x = 127;
} }
} else { } else {
pad->stick_x = wStickX; pad->stick_x = getLeftStickX(virtualSlot);
} }
if (wStickY == 0) { if (getLeftStickY(virtualSlot) == 0) {
if (dwPressedButtons[slot] & BTN_STICKDOWN) { if (getPressedButtons(virtualSlot) & BTN_STICKDOWN) {
pad->stick_y = -128; pad->stick_y = -128;
} else if (dwPressedButtons[slot] & BTN_STICKUP) { } else if (getPressedButtons(virtualSlot) & BTN_STICKUP) {
pad->stick_y = 127; pad->stick_y = 127;
} }
} else { } else {
pad->stick_y = wStickY; pad->stick_y = getLeftStickY(virtualSlot);
} }
// Stick Inputs // Stick Inputs
if (wCamX == 0) { if (getRightStickX(virtualSlot) == 0) {
if (dwPressedButtons[slot] & BTN_VSTICKLEFT) { if (getPressedButtons(virtualSlot) & BTN_VSTICKLEFT) {
pad->cam_x = -128 * 10.0f; pad->right_stick_x = -128;
} else if (dwPressedButtons[slot] & BTN_VSTICKRIGHT) { } else if (getPressedButtons(virtualSlot) & BTN_VSTICKRIGHT) {
pad->cam_x = 127 * 10.0f; pad->right_stick_x = 127;
} }
} else { } else {
pad->cam_x = wCamX; pad->right_stick_x = getRightStickX(virtualSlot);
} }
if (wCamY == 0) { if (getRightStickY(virtualSlot) == 0) {
if (dwPressedButtons[slot] & BTN_VSTICKDOWN) { if (getPressedButtons(virtualSlot) & BTN_VSTICKDOWN) {
pad->cam_y = -128 * 10.0f; pad->right_stick_y = -128;
} else if (dwPressedButtons[slot] & BTN_VSTICKUP) { } else if (getPressedButtons(virtualSlot) & BTN_VSTICKUP) {
pad->cam_y = 127 * 10.0f; pad->right_stick_y = 127;
} }
} else { } else {
pad->cam_y = wCamY; pad->right_stick_y = getRightStickY(virtualSlot);
} }
// Gyro // Gyro
pad->gyro_x = wGyroX; pad->gyro_x = getGyroX(virtualSlot);
pad->gyro_y = wGyroY; pad->gyro_y = getGyroY(virtualSlot);
} }
void Controller::SetButtonMapping(int slot, int32_t n64Button, int32_t dwScancode) { void Controller::SetButtonMapping(int32_t virtualSlot, int32_t n64Button, int32_t dwScancode) {
std::map<int32_t, int32_t>& Mappings = profiles[slot].Mappings; std::map<int32_t, int32_t>& Mappings = getProfile(virtualSlot)->Mappings;
std::erase_if(Mappings, [n64Button](const std::pair<int32_t, int32_t>& bin) { return bin.second == n64Button; }); std::erase_if(Mappings, [n64Button](const std::pair<int32_t, int32_t>& bin) { return bin.second == n64Button; });
Mappings[dwScancode] = n64Button; Mappings[dwScancode] = n64Button;
} }
int8_t& Controller::getLeftStickX(int32_t virtualSlot) {
return ButtonData[virtualSlot]->leftStickX;
}
int8_t& Controller::getLeftStickY(int32_t virtualSlot) {
return ButtonData[virtualSlot]->leftStickY;
}
int8_t& Controller::getRightStickX(int32_t virtualSlot) {
return ButtonData[virtualSlot]->rightStickX;
}
int8_t& Controller::getRightStickY(int32_t virtualSlot) {
return ButtonData[virtualSlot]->rightStickY;
}
int32_t& Controller::getPressedButtons(int32_t virtualSlot) {
return ButtonData[virtualSlot]->pressedButtons;
}
float& Controller::getGyroX(int32_t virtualSlot) {
return ButtonData[virtualSlot]->gyroX;
}
float& Controller::getGyroY(int32_t virtualSlot) {
return ButtonData[virtualSlot]->gyroY;
}
std::shared_ptr<DeviceProfileV0> Controller::getProfile(int32_t virtualSlot) {
return profiles[virtualSlot];
}
} }

View File

@ -3,10 +3,9 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include "stdint.h" #include <cstdint>
#include "UltraController.h" #include "UltraController.h"
#include "ControllerAttachment.h" #include "ControllerAttachment.h"
#include <vector>
#include <unordered_map> #include <unordered_map>
#define EXTENDED_SCANCODE_BIT (1 << 8) #define EXTENDED_SCANCODE_BIT (1 << 8)
@ -14,68 +13,73 @@
namespace Ship { namespace Ship {
enum ControllerThresholds {
LEFT_STICK = 1,
RIGHT_STICK = 2, enum GyroDataV0 {
LEFT_TRIGGER = 3, DRIFT_X,
RIGHT_TRIGGER = 4, DRIFT_Y,
DRIFT_X = 5, GYRO_SENSITIVITY
DRIFT_Y = 6,
SENSITIVITY = 7,
GYRO_SENSITIVITY = 8
}; };
struct DeviceProfile { struct DeviceProfileV0 {
int32_t Version = 0;
bool UseRumble = false; bool UseRumble = false;
bool UseGyro = false; bool UseGyro = false;
float RumbleStrength = 1.0f; float RumbleStrength = 1.0f;
std::unordered_map<ControllerThresholds, float> Thresholds; std::unordered_map<int32_t, float> AxisDeadzones;
std::unordered_map<int32_t, float> AxisMinimumPress;
std::unordered_map<int32_t, float> AxisSensitivities;
std::unordered_map<int32_t, float> GyroData;
std::map<int32_t, int32_t> Mappings; std::map<int32_t, int32_t> Mappings;
}; };
class Controller { class Controller {
public: public:
virtual ~Controller() = default; virtual ~Controller() = default;
Controller(); Controller();
void Read(OSContPad* pad, int32_t slot); void Read(OSContPad* pad, int32_t virtualSlot);
virtual void ReadFromSource(int32_t slot) = 0; virtual void ReadFromSource(int32_t virtualSlot) = 0;
virtual void WriteToSource(int32_t slot, ControllerCallback* controller) = 0; virtual void WriteToSource(int32_t virtualSlot, ControllerCallback* controller) = 0;
virtual bool Connected() const = 0; virtual bool Connected() const = 0;
virtual bool CanRumble() const = 0; virtual bool CanRumble() const = 0;
virtual bool CanGyro() const = 0; virtual bool CanGyro() const = 0;
virtual void CreateDefaultBinding(int32_t slot) = 0; virtual void CreateDefaultBinding(int32_t virtualSlot) = 0;
bool isRumbling; virtual void ClearRawPress() = 0;
std::vector<DeviceProfile> profiles; virtual int32_t ReadRawPress() = 0;
void SetButtonMapping(int32_t virtualSlot, int32_t n64Button, int32_t dwScancode);
virtual void ClearRawPress() = 0; std::shared_ptr<ControllerAttachment> GetAttachment() { return Attachment; }
virtual int32_t ReadRawPress() = 0; int8_t& getLeftStickX(int32_t virtualSlot);
void SetButtonMapping(int slot, int32_t n64Button, int32_t dwScancode); int8_t& getLeftStickY(int32_t virtualSlot);
std::shared_ptr<ControllerAttachment> GetAttachment() { return Attachment; } int8_t& getRightStickX(int32_t virtualSlot);
int8_t& getRightStickY(int32_t virtualSlot);
std::string GetGuid() { return GUID; } int32_t& getPressedButtons(int32_t virtualSlot);
virtual const char* GetButtonName(int slot, int n64Button) = 0; float& getGyroX(int32_t virtualSlot);
virtual const char* GetControllerName() = 0; float& getGyroY(int32_t virtualSlot);
std::shared_ptr<DeviceProfileV0> getProfile(int32_t virtualSlot);
int8_t wStickX; bool IsRumbling() { return isRumbling; }
int8_t wStickY; std::string GetGuid() { return GUID; }
float wGyroX; virtual const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) = 0;
float wGyroY; virtual const std::string GetControllerName() = 0;
float wCamX;
float wCamY;
protected: protected:
std::vector<int32_t> dwPressedButtons; std::shared_ptr<ControllerAttachment> Attachment;
std::string GUID; std::string GUID;
bool isRumbling;
void LoadBinding(); void LoadBinding();
private: private:
std::shared_ptr<ControllerAttachment> Attachment; struct Buttons {
}; int32_t pressedButtons = 0;
int8_t leftStickX = 0;
int8_t leftStickY = 0;
int8_t rightStickX = 0;
int8_t rightStickY = 0;
float gyroX = 0.0f;
float gyroY = 0.0f;
};
struct ControllerEntry { std::unordered_map<int32_t, std::shared_ptr<DeviceProfileV0>> profiles;
uint8_t* controllerBits; std::unordered_map<int32_t, std::shared_ptr<Buttons>> ButtonData = {};
Controller* entryIO;
}; };
} }

View File

@ -5,9 +5,9 @@
#include "Controller.h" #include "Controller.h"
namespace Ship { namespace Ship {
class VirtualController final : public Controller { class DummyController final : public Controller {
public: public:
VirtualController(const std::string& CUID, const std::string& KeyName, bool Connected) { DummyController(const std::string& CUID, const std::string& KeyName, bool Connected) {
GUID = CUID; GUID = CUID;
isConnected = Connected; isConnected = Connected;
ButtonName = KeyName; ButtonName = KeyName;
@ -15,8 +15,8 @@ namespace Ship {
std::map<std::vector<std::string>, int32_t> ReadButtonPress(); std::map<std::vector<std::string>, int32_t> ReadButtonPress();
void ReadFromSource(int32_t slot) override {} void ReadFromSource(int32_t slot) override {}
const char* GetControllerName() override { return GUID.c_str(); } const std::string GetControllerName() override { return GUID; }
const char* GetButtonName(int slot, int n64Button) override { return ButtonName.c_str(); } const std::string GetButtonName(int slot, int n64Button) override { return ButtonName; }
void WriteToSource(int32_t slot, ControllerCallback* controller) override { } void WriteToSource(int32_t slot, ControllerCallback* controller) override { }
bool Connected() const override { return isConnected; } bool Connected() const override { return isConnected; }
bool CanRumble() const override { return false; } bool CanRumble() const override { return false; }

View File

@ -48,9 +48,9 @@ namespace Ship {
} }
} }
const char* BtnName = backend->GetButtonName(CurrentPort, n64Btn); const std::string BtnName = backend->GetButtonName(CurrentPort, n64Btn);
if (ImGui::Button(StringHelper::Sprintf("%s##HBTNID_%d", readingMode ? "Press a Key..." : BtnName, n64Btn).c_str())) { if (ImGui::Button(StringHelper::Sprintf("%s##HBTNID_%d", readingMode ? "Press a Key..." : BtnName.c_str(), n64Btn).c_str())) {
BtnReading = n64Btn; BtnReading = n64Btn;
backend->ClearRawPress(); backend->ClearRawPress();
} }
@ -84,18 +84,16 @@ namespace Ship {
void InputEditor::DrawControllerSchema() { void InputEditor::DrawControllerSchema() {
auto controlDeck = Ship::GlobalCtx2::GetInstance()->GetWindow()->GetControlDeck(); auto controlDeck = Ship::GlobalCtx2::GetInstance()->GetWindow()->GetControlDeck();
auto Backend = controlDeck->GetPhysicalDeviceFromVirtualSlot(CurrentPort); auto Backend = controlDeck->GetPhysicalDeviceFromVirtualSlot(CurrentPort);
DeviceProfile& profile = Backend->profiles[CurrentPort]; auto profile = Backend->getProfile(CurrentPort);
float sensitivity = profile.Thresholds[SENSITIVITY];
bool IsKeyboard = Backend->GetGuid() == "Keyboard" || Backend->GetGuid() == "Auto" || !Backend->Connected(); bool IsKeyboard = Backend->GetGuid() == "Keyboard" || Backend->GetGuid() == "Auto" || !Backend->Connected();
const char* ControllerName = Backend->GetControllerName(); std::string ControllerName = Backend->GetControllerName();
if (ControllerName != nullptr && ImGui::BeginCombo("##ControllerEntries", ControllerName)) { if (ImGui::BeginCombo("##ControllerEntries", ControllerName.c_str())) {
for (uint8_t i = 0; i < controlDeck->GetNumPhysicalDevices(); i++) { for (uint8_t i = 0; i < controlDeck->GetNumPhysicalDevices(); i++) {
std::string DeviceName = controlDeck->GetPhysicalDevice(i)->GetControllerName(); if (ControllerName != "Keyboard" && ControllerName != "Auto") {
if (DeviceName != "Keyboard" && DeviceName != "Auto") { ControllerName += "##"+std::to_string(i);
DeviceName+="##"+std::to_string(i);
} }
if (ImGui::Selectable(DeviceName.c_str(), i == controlDeck->GetVirtualDevice(CurrentPort))) { if (ImGui::Selectable(ControllerName.c_str(), i == controlDeck->GetVirtualDevice(CurrentPort))) {
controlDeck->SetPhysicalDevice(CurrentPort, i); controlDeck->SetPhysicalDevice(CurrentPort, i);
} }
} }
@ -142,7 +140,7 @@ namespace Ship {
if (!IsKeyboard) { if (!IsKeyboard) {
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8);
DrawVirtualStick("##MainVirtualStick", ImVec2(Backend->wStickX, Backend->wStickY)); DrawVirtualStick("##MainVirtualStick", ImVec2(Backend->getLeftStickX(CurrentPort), Backend->getLeftStickY(CurrentPort)));
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
@ -150,7 +148,7 @@ namespace Ship {
ImGui::BeginChild("##MSInput", ImVec2(90, 50), false); ImGui::BeginChild("##MSInput", ImVec2(90, 50), false);
ImGui::Text("Deadzone"); ImGui::Text("Deadzone");
ImGui::PushItemWidth(80); ImGui::PushItemWidth(80);
ImGui::InputFloat("##MDZone", &profile.Thresholds[LEFT_STICK], 1.0f, 0.0f, "%.0f"); ImGui::InputFloat("##MDZone", &profile->AxisDeadzones[0] /* This is the SDL value for left stick X axis */, 1.0f, 0.0f, "%.0f");
ImGui::PopItemWidth(); ImGui::PopItemWidth();
ImGui::EndChild(); ImGui::EndChild();
} else { } else {
@ -172,18 +170,20 @@ namespace Ship {
DrawButton("Right", BTN_VSTICKRIGHT); DrawButton("Right", BTN_VSTICKRIGHT);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8);
DrawVirtualStick("##CameraVirtualStick", ImVec2(Backend->wCamX / sensitivity, Backend->wCamY / sensitivity)); // 2 is the SDL value for right stick X axis
// 3 is the SDL value for right stick Y axis.
DrawVirtualStick("##CameraVirtualStick", ImVec2(Backend->getRightStickX(CurrentPort) / profile->AxisSensitivities[2], Backend->getRightStickY(CurrentPort) / profile->AxisSensitivities[3]));
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::BeginChild("##CSInput", ImVec2(90, 85), false); ImGui::BeginChild("##CSInput", ImVec2(90, 85), false);
ImGui::Text("Deadzone"); ImGui::Text("Deadzone");
ImGui::PushItemWidth(80); ImGui::PushItemWidth(80);
ImGui::InputFloat("##MDZone", &profile.Thresholds[RIGHT_STICK], 1.0f, 0.0f, "%.0f"); ImGui::InputFloat("##MDZone", &profile->AxisDeadzones[2] /* This is the SDL value for left stick X axis */, 1.0f, 0.0f, "%.0f");
ImGui::PopItemWidth(); ImGui::PopItemWidth();
ImGui::Text("Sensitivity"); ImGui::Text("Sensitivity");
ImGui::PushItemWidth(80); ImGui::PushItemWidth(80);
ImGui::InputFloat("##MSensitivity", &profile.Thresholds[SENSITIVITY], 1.0f, 0.0f, "%.0f"); ImGui::InputFloat("##MSensitivity", &profile->AxisSensitivities[2] /* This is the SDL value for right stick X axis */, 1.0f, 0.0f, "%.0f");
ImGui::PopItemWidth(); ImGui::PopItemWidth();
ImGui::EndChild(); ImGui::EndChild();
#ifdef __SWITCH__ #ifdef __SWITCH__
@ -199,32 +199,32 @@ namespace Ship {
SohImGui::BeginGroupPanel("Gyro Options", ImVec2(175, 20)); SohImGui::BeginGroupPanel("Gyro Options", ImVec2(175, 20));
float cursorX = ImGui::GetCursorPosX() + 5; float cursorX = ImGui::GetCursorPosX() + 5;
ImGui::SetCursorPosX(cursorX); ImGui::SetCursorPosX(cursorX);
ImGui::Checkbox("Enable Gyro", &profile.UseGyro); ImGui::Checkbox("Enable Gyro", &profile->UseGyro);
ImGui::SetCursorPosX(cursorX); ImGui::SetCursorPosX(cursorX);
ImGui::Text("Gyro Sensitivity: %d%%", static_cast<int>(100.0f * profile.Thresholds[GYRO_SENSITIVITY])); ImGui::Text("Gyro Sensitivity: %d%%", static_cast<int>(100.0f * profile->GyroData[GYRO_SENSITIVITY]));
ImGui::PushItemWidth(135.0f); ImGui::PushItemWidth(135.0f);
ImGui::SetCursorPosX(cursorX); ImGui::SetCursorPosX(cursorX);
ImGui::SliderFloat("##GSensitivity", &profile.Thresholds[GYRO_SENSITIVITY], 0.0f, 1.0f, ""); ImGui::SliderFloat("##GSensitivity", &profile->GyroData[GYRO_SENSITIVITY], 0.0f, 1.0f, "");
ImGui::PopItemWidth(); ImGui::PopItemWidth();
ImGui::Dummy(ImVec2(0, 1)); ImGui::Dummy(ImVec2(0, 1));
ImGui::SetCursorPosX(cursorX); ImGui::SetCursorPosX(cursorX);
if (ImGui::Button("Recalibrate Gyro##RGyro")) { if (ImGui::Button("Recalibrate Gyro##RGyro")) {
profile.Thresholds[DRIFT_X] = 0.0f; profile->GyroData[DRIFT_X] = 0.0f;
profile.Thresholds[DRIFT_Y] = 0.0f; profile->GyroData[DRIFT_Y] = 0.0f;
} }
ImGui::SetCursorPosX(cursorX); ImGui::SetCursorPosX(cursorX);
DrawVirtualStick("##GyroPreview", ImVec2(-10.0f * Backend->wGyroY, 10.0f * Backend->wGyroX)); DrawVirtualStick("##GyroPreview", ImVec2(-10.0f * Backend->getGyroY(CurrentPort), 10.0f * Backend->getGyroX(CurrentPort)));
ImGui::SameLine(); ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::BeginChild("##GyInput", ImVec2(90, 85), false); ImGui::BeginChild("##GyInput", ImVec2(90, 85), false);
ImGui::Text("Drift X"); ImGui::Text("Drift X");
ImGui::PushItemWidth(80); ImGui::PushItemWidth(80);
ImGui::InputFloat("##GDriftX", &profile.Thresholds[DRIFT_X], 1.0f, 0.0f, "%.1f"); ImGui::InputFloat("##GDriftX", &profile->GyroData[DRIFT_X], 1.0f, 0.0f, "%.1f");
ImGui::PopItemWidth(); ImGui::PopItemWidth();
ImGui::Text("Drift Y"); ImGui::Text("Drift Y");
ImGui::PushItemWidth(80); ImGui::PushItemWidth(80);
ImGui::InputFloat("##GDriftY", &profile.Thresholds[DRIFT_Y], 1.0f, 0.0f, "%.1f"); ImGui::InputFloat("##GDriftY", &profile->GyroData[DRIFT_Y], 1.0f, 0.0f, "%.1f");
ImGui::PopItemWidth(); ImGui::PopItemWidth();
ImGui::EndChild(); ImGui::EndChild();
#ifdef __SWITCH__ #ifdef __SWITCH__
@ -255,13 +255,13 @@ namespace Ship {
SohImGui::BeginGroupPanel("Options", ImVec2(158, 20)); SohImGui::BeginGroupPanel("Options", ImVec2(158, 20));
float cursorX = ImGui::GetCursorPosX() + 5; float cursorX = ImGui::GetCursorPosX() + 5;
ImGui::SetCursorPosX(cursorX); ImGui::SetCursorPosX(cursorX);
ImGui::Checkbox("Rumble Enabled", &profile.UseRumble); ImGui::Checkbox("Rumble Enabled", &profile->UseRumble);
if (Backend->CanRumble()) { if (Backend->CanRumble()) {
ImGui::SetCursorPosX(cursorX); ImGui::SetCursorPosX(cursorX);
ImGui::Text("Rumble Force: %d%%", static_cast<int>(100.0f * profile.RumbleStrength)); ImGui::Text("Rumble Force: %d%%", static_cast<int>(100.0f * profile->RumbleStrength));
ImGui::SetCursorPosX(cursorX); ImGui::SetCursorPosX(cursorX);
ImGui::PushItemWidth(135.0f); ImGui::PushItemWidth(135.0f);
ImGui::SliderFloat("##RStrength", &profile.RumbleStrength, 0.0f, 1.0f, ""); ImGui::SliderFloat("##RStrength", &profile->RumbleStrength, 0.0f, 1.0f, "");
ImGui::PopItemWidth(); ImGui::PopItemWidth();
} }
ImGui::Dummy(ImVec2(0, 5)); ImGui::Dummy(ImVec2(0, 5));

View File

@ -17,13 +17,12 @@ namespace Ship {
} }
bool KeyboardController::PressButton(int32_t dwScancode) { bool KeyboardController::PressButton(int32_t dwScancode) {
lastKey = dwScancode; lastKey = dwScancode;
for (int slot = 0; slot < MAXCONTROLLERS; slot++) { for (int32_t virtualSlot = 0; virtualSlot < MAXCONTROLLERS; virtualSlot++) {
if (profiles[slot].Mappings.contains(dwScancode)) { if (getProfile(virtualSlot)->Mappings.contains(dwScancode)) {
dwPressedButtons[slot] |= profiles[slot].Mappings[dwScancode]; getPressedButtons(virtualSlot) |= getProfile(virtualSlot)->Mappings[dwScancode];
return true; return true;
} }
} }
@ -32,9 +31,9 @@ namespace Ship {
} }
bool KeyboardController::ReleaseButton(int32_t dwScancode) { bool KeyboardController::ReleaseButton(int32_t dwScancode) {
for (int slot = 0; slot < MAXCONTROLLERS; slot++) { for (int32_t virtualSlot = 0; virtualSlot < MAXCONTROLLERS; virtualSlot++) {
if (profiles[slot].Mappings.contains(dwScancode)) { if (getProfile(virtualSlot)->Mappings.contains(dwScancode)) {
dwPressedButtons[slot] &= ~profiles[slot].Mappings[dwScancode]; getPressedButtons(virtualSlot) &= ~getProfile(virtualSlot)->Mappings[dwScancode];
return true; return true;
} }
} }
@ -43,16 +42,16 @@ namespace Ship {
} }
void KeyboardController::ReleaseAllButtons() { void KeyboardController::ReleaseAllButtons() {
for(int slot = 0; slot < MAXCONTROLLERS; slot++) { for(int32_t virtualSlot = 0; virtualSlot < MAXCONTROLLERS; virtualSlot++) {
dwPressedButtons[slot] = 0; getPressedButtons(virtualSlot) = 0;
} }
} }
void KeyboardController::ReadFromSource(int32_t slot) { void KeyboardController::ReadFromSource(int32_t virtualSlot) {
wStickX = 0; getLeftStickX(virtualSlot) = 0;
wStickY = 0; getLeftStickY(virtualSlot) = 0;
wCamX = 0; getRightStickX(virtualSlot) = 0;
wCamY = 0; getRightStickY(virtualSlot) = 0;
} }
int32_t KeyboardController::ReadRawPress() { int32_t KeyboardController::ReadRawPress() {
@ -60,13 +59,12 @@ namespace Ship {
} }
void KeyboardController::WriteToSource(int32_t slot, ControllerCallback* controller) void KeyboardController::WriteToSource(int32_t virtualSlot, ControllerCallback* controller) {
{
} }
const char* KeyboardController::GetButtonName(int slot, int n64Button) { const std::string KeyboardController::GetButtonName(int32_t virtualSlot, int32_t n64Button) {
std::map<int32_t, int32_t>& Mappings = profiles[slot].Mappings; std::map<int32_t, int32_t>& Mappings = getProfile(virtualSlot)->Mappings;
const auto find = std::find_if(Mappings.begin(), Mappings.end(), [n64Button](const std::pair<int32_t, int32_t>& pair) { const auto find = std::find_if(Mappings.begin(), Mappings.end(), [n64Button](const std::pair<int32_t, int32_t>& pair) {
return pair.second == n64Button; return pair.second == n64Button;
}); });
@ -77,29 +75,29 @@ namespace Ship {
} }
void KeyboardController::CreateDefaultBinding(int32_t slot) { void KeyboardController::CreateDefaultBinding(int32_t virtualSlot) {
DeviceProfile& profile = profiles[slot]; auto profile = getProfile(virtualSlot);
profile.Mappings[0x14D] = BTN_CRIGHT; profile->Mappings[0x14D] = BTN_CRIGHT;
profile.Mappings[0x14B] = BTN_CLEFT; profile->Mappings[0x14B] = BTN_CLEFT;
profile.Mappings[0x150] = BTN_CDOWN; profile->Mappings[0x150] = BTN_CDOWN;
profile.Mappings[0x148] = BTN_CUP; profile->Mappings[0x148] = BTN_CUP;
profile.Mappings[0x13] = BTN_R; profile->Mappings[0x13] = BTN_R;
profile.Mappings[0x12] = BTN_L; profile->Mappings[0x12] = BTN_L;
profile.Mappings[0x023] = BTN_DRIGHT; profile->Mappings[0x023] = BTN_DRIGHT;
profile.Mappings[0x021] = BTN_DLEFT; profile->Mappings[0x021] = BTN_DLEFT;
profile.Mappings[0x022] = BTN_DDOWN; profile->Mappings[0x022] = BTN_DDOWN;
profile.Mappings[0x014] = BTN_DUP; profile->Mappings[0x014] = BTN_DUP;
profile.Mappings[0x039] = BTN_START; profile->Mappings[0x039] = BTN_START;
profile.Mappings[0x02C] = BTN_Z; profile->Mappings[0x02C] = BTN_Z;
profile.Mappings[0x02E] = BTN_B; profile->Mappings[0x02E] = BTN_B;
profile.Mappings[0x02D] = BTN_A; profile->Mappings[0x02D] = BTN_A;
profile.Mappings[0x020] = BTN_STICKRIGHT; profile->Mappings[0x020] = BTN_STICKRIGHT;
profile.Mappings[0x01E] = BTN_STICKLEFT; profile->Mappings[0x01E] = BTN_STICKLEFT;
profile.Mappings[0x01F] = BTN_STICKDOWN; profile->Mappings[0x01F] = BTN_STICKDOWN;
profile.Mappings[0x011] = BTN_STICKUP; profile->Mappings[0x011] = BTN_STICKUP;
} }
const char* KeyboardController::GetControllerName() { const std::string KeyboardController::GetControllerName() {
return "Keyboard"; return "Keyboard";
} }
} }

View File

@ -7,13 +7,13 @@ namespace Ship {
public: public:
KeyboardController(); KeyboardController();
void ReadFromSource(int32_t slot) override; void ReadFromSource(int32_t virtualSlot) override;
void WriteToSource(int32_t slot, ControllerCallback* controller) override; void WriteToSource(int32_t virtualSlot, ControllerCallback* controller) override;
bool Connected() const override { return true; } bool Connected() const override { return true; }
bool CanRumble() const override { return false; } bool CanRumble() const override { return false; }
bool CanGyro() const override { return false; } bool CanGyro() const override { return false; }
const char* GetControllerName() override; const std::string GetControllerName() override;
const char* GetButtonName(int slot, int n64Button) override; const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) override;
bool PressButton(int32_t dwScancode); bool PressButton(int32_t dwScancode);
bool ReleaseButton(int32_t dwScancode); bool ReleaseButton(int32_t dwScancode);
@ -29,7 +29,7 @@ namespace Ship {
} }
int32_t GetLastScancode() { return lastScancode; } int32_t GetLastScancode() { return lastScancode; }
void CreateDefaultBinding(int32_t slot) override; void CreateDefaultBinding(int32_t virtualSlot) override;
protected: protected:
int32_t lastScancode; int32_t lastScancode;

View File

@ -13,7 +13,6 @@ extern "C" uint8_t __osMaxControllers;
namespace Ship { namespace Ship {
bool SDLController::Open() { bool SDLController::Open() {
const auto NewCont = SDL_GameControllerOpen(physicalSlot); const auto NewCont = SDL_GameControllerOpen(physicalSlot);
// We failed to load the controller. Go to next. // We failed to load the controller. Go to next.
@ -30,8 +29,7 @@ namespace Ship {
char GuidBuf[33]; char GuidBuf[33];
SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(physicalSlot), GuidBuf, sizeof(GuidBuf)); SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(physicalSlot), GuidBuf, sizeof(GuidBuf));
Cont = NewCont; Cont = NewCont;
wCamX = 0;
wCamY = 0;
#ifdef __SWITCH__ #ifdef __SWITCH__
GUID = StringHelper::Sprintf("%s:%d", GuidBuf, physicalSlot); GUID = StringHelper::Sprintf("%s:%d", GuidBuf, physicalSlot);
ControllerName = StringHelper::Sprintf("%s #%d", SDL_GameControllerNameForIndex(physicalSlot), physicalSlot + 1); ControllerName = StringHelper::Sprintf("%s #%d", SDL_GameControllerNameForIndex(physicalSlot), physicalSlot + 1);
@ -50,54 +48,58 @@ namespace Ship {
SDL_GameControllerClose(Cont); SDL_GameControllerClose(Cont);
} }
Cont = nullptr; Cont = nullptr;
wStickX = 0;
wStickY = 0;
return true; return true;
} }
void SDLController::NormalizeStickAxis(SDL_GameControllerAxis axisX, SDL_GameControllerAxis axisY, int16_t axisThreshold, int32_t virtualSlot) {
auto profile = getProfile(virtualSlot);
const auto axisValueX = SDL_GameControllerGetAxis(Cont, axisX);
const auto axisValueY = SDL_GameControllerGetAxis(Cont, axisY);
void SDLController::NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold, bool isRightStick, float sensitivity) {
//scale {-32768 ... +32767} to {-84 ... +84} //scale {-32768 ... +32767} to {-84 ... +84}
auto ax = wAxisValueX * 85.0 / 32767.0; auto ax = axisValueX * 85.0f / 32767.0f;
auto ay = wAxisValueY * 85.0 / 32767.0; auto ay = axisValueY * 85.0f / 32767.0f;
//create scaled circular dead-zone in range {-15 ... +15} //create scaled circular dead-zone in range {-15 ... +15}
auto len = sqrt(ax * ax + ay * ay); auto len = sqrt(ax * ax + ay * ay);
if (len < wAxisThreshold) { if (len < axisThreshold) {
len = 0; len = 0.0f;
} }
else if (len > 85.0) { else if (len > 85.0) {
len = 85.0 / len; len = 85.0f / len;
} }
else { else {
len = (len - wAxisThreshold) * 85.0 / (85.0 - wAxisThreshold) / len; len = (len - axisThreshold) * 85.0f / (85.0f - axisThreshold) / len;
} }
ax *= len; ax *= len;
ay *= len; ay *= len;
//bound diagonals to an octagonal range {-68 ... +68} //bound diagonals to an octagonal range {-68 ... +68}
if (ax != 0.0 && ay != 0.0) { if (ax != 0.0f && ay != 0.0f) {
auto slope = ay / ax; auto slope = ay / ax;
auto edgex = copysign(85.0 / (abs(slope) + 16.0 / 69.0), ax); auto edgex = copysign(85.0f / (abs(slope) + 16.0f / 69.0f), ax);
auto edgey = copysign(std::min(abs(edgex * slope), 85.0 / (1.0 / abs(slope) + 16.0 / 69.0)), ay); auto edgey = copysign(std::min(abs(edgex * slope), 85.0f / (1.0f / abs(slope) + 16.0f / 69.0f)), ay);
edgex = edgey / slope; edgex = edgey / slope;
auto scale = sqrt(edgex * edgex + edgey * edgey) / 85.0; auto scale = sqrt(edgex * edgex + edgey * edgey) / 85.0f;
ax *= scale; ax *= scale;
ay *= scale; ay *= scale;
} }
if (!isRightStick) { ax *= profile->AxisSensitivities[axisX];
wStickX = +ax; ay *= profile->AxisSensitivities[axisY];
wStickY = -ay;
} else { if (axisX == SDL_CONTROLLER_AXIS_LEFTX) {
wCamX = +ax * sensitivity; getLeftStickX(virtualSlot) = +ax;
wCamY = -ay * sensitivity; getLeftStickY(virtualSlot) = -ay;
} else if (axisX == SDL_CONTROLLER_AXIS_RIGHTX) {
getRightStickX(virtualSlot) = +ax;
getRightStickY(virtualSlot) = -ay;
} }
} }
int32_t SDLController::ReadRawPress() { int32_t SDLController::ReadRawPress() {
SDL_GameControllerUpdate(); SDL_GameControllerUpdate();
@ -123,24 +125,8 @@ namespace Ship {
return -1; return -1;
} }
ControllerThresholds SDLAxisToThreshold( uint32_t axis ){ void SDLController::ReadFromSource(int32_t virtualSlot) {
switch(axis){ auto profile = getProfile(virtualSlot);
case SDL_CONTROLLER_AXIS_LEFTX:
case SDL_CONTROLLER_AXIS_LEFTY:
return LEFT_STICK;
case SDL_CONTROLLER_AXIS_RIGHTX:
case SDL_CONTROLLER_AXIS_RIGHTY:
return RIGHT_STICK;
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
return LEFT_TRIGGER;
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
return RIGHT_TRIGGER;
default: return DRIFT_X;
}
}
void SDLController::ReadFromSource(int32_t slot) {
DeviceProfile& profile = profiles[slot];
SDL_GameControllerUpdate(); SDL_GameControllerUpdate();
@ -157,14 +143,14 @@ namespace Ship {
} }
} }
if (supportsGyro && profile.UseGyro) { if (supportsGyro && profile->UseGyro) {
float gyroData[3]; float gyroData[3];
SDL_GameControllerGetSensorData(Cont, SDL_SENSOR_GYRO, gyroData, 3); SDL_GameControllerGetSensorData(Cont, SDL_SENSOR_GYRO, gyroData, 3);
float gyro_drift_x = profile.Thresholds[DRIFT_X] / 100.0f; float gyro_drift_x = profile->GyroData[DRIFT_X] / 100.0f;
float gyro_drift_y = profile.Thresholds[DRIFT_Y] / 100.0f; float gyro_drift_y = profile->GyroData[DRIFT_Y] / 100.0f;
const float gyro_sensitivity = profile.Thresholds[GYRO_SENSITIVITY]; const float gyro_sensitivity = profile->GyroData[GYRO_SENSITIVITY];
if (gyro_drift_x == 0) { if (gyro_drift_x == 0) {
gyro_drift_x = gyroData[0]; gyro_drift_x = gyroData[0];
@ -174,25 +160,25 @@ namespace Ship {
gyro_drift_y = gyroData[1]; gyro_drift_y = gyroData[1];
} }
profile.Thresholds[DRIFT_X] = gyro_drift_x * 100.0f; profile->GyroData[DRIFT_X] = gyro_drift_x * 100.0f;
profile.Thresholds[DRIFT_Y] = gyro_drift_y * 100.0f; profile->GyroData[DRIFT_Y] = gyro_drift_y * 100.0f;
wGyroX = gyroData[0] - gyro_drift_x; getGyroX(virtualSlot) = gyroData[0] - gyro_drift_x;
wGyroY = gyroData[1] - gyro_drift_y; getGyroY(virtualSlot) = gyroData[1] - gyro_drift_y;
wGyroX *= gyro_sensitivity; getGyroX(virtualSlot) *= gyro_sensitivity;
wGyroY *= gyro_sensitivity; getGyroY(virtualSlot) *= gyro_sensitivity;
} }
dwPressedButtons[slot] = 0; getPressedButtons(virtualSlot) = 0;
for (int32_t i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) { for (int32_t i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) {
if (profile.Mappings.contains(i)) { if (profile->Mappings.contains(i)) {
if (SDL_GameControllerGetButton(Cont, static_cast<SDL_GameControllerButton>(i))) { if (SDL_GameControllerGetButton(Cont, static_cast<SDL_GameControllerButton>(i))) {
dwPressedButtons[slot] |= profile.Mappings[i]; getPressedButtons(virtualSlot) |= profile->Mappings[i];
} }
else { else {
dwPressedButtons[slot] &= ~profile.Mappings[i]; getPressedButtons(virtualSlot) &= ~profile->Mappings[i];
} }
} }
} }
@ -209,9 +195,10 @@ namespace Ship {
const auto Axis = static_cast<SDL_GameControllerAxis>(i); const auto Axis = static_cast<SDL_GameControllerAxis>(i);
const auto PosScancode = i + AXIS_SCANCODE_BIT; const auto PosScancode = i + AXIS_SCANCODE_BIT;
const auto NegScancode = -PosScancode; const auto NegScancode = -PosScancode;
const auto AxisThreshold = static_cast<int>(profile.Thresholds[SDLAxisToThreshold(i)]); const auto AxisDeadzone = profile->AxisDeadzones[i];
const auto PosButton = profile.Mappings[PosScancode]; const auto AxisMinimumPress = profile->AxisMinimumPress[i];
const auto NegButton = profile.Mappings[NegScancode]; const auto PosButton = profile->Mappings[PosScancode];
const auto NegButton = profile->Mappings[NegScancode];
const auto AxisValue = SDL_GameControllerGetAxis(Cont, Axis); const auto AxisValue = SDL_GameControllerGetAxis(Cont, Axis);
#ifdef TARGET_WEB #ifdef TARGET_WEB
@ -231,17 +218,17 @@ namespace Ship {
NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT || NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT ||
NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN)) { NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN)) {
if (AxisValue > 0x1E00) { if (AxisValue > AxisMinimumPress) {
dwPressedButtons[slot] |= PosButton; getPressedButtons(virtualSlot) |= PosButton;
dwPressedButtons[slot] &= ~NegButton; getPressedButtons(virtualSlot) &= ~NegButton;
} }
else if (AxisValue < -0x1E00) { else if (AxisValue < -AxisMinimumPress) {
dwPressedButtons[slot] &= ~PosButton; getPressedButtons(virtualSlot) &= ~PosButton;
dwPressedButtons[slot] |= NegButton; getPressedButtons(virtualSlot) |= NegButton;
} }
else { else {
dwPressedButtons[slot] &= ~PosButton; getPressedButtons(virtualSlot) &= ~PosButton;
dwPressedButtons[slot] &= ~NegButton; getPressedButtons(virtualSlot) &= ~NegButton;
} }
} }
else { else {
@ -250,11 +237,11 @@ namespace Ship {
SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", LStickAxisX, Axis); SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", LStickAxisX, Axis);
} }
if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) { if (LStickDeadzone != 0 && LStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", LStickDeadzone, AxisThreshold); SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", LStickDeadzone, AxisDeadzone);
} }
LStickDeadzone = AxisThreshold; LStickDeadzone = AxisDeadzone;
LStickAxisX = Axis; LStickAxisX = Axis;
} }
@ -263,11 +250,11 @@ namespace Ship {
SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", LStickAxisY, Axis); SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", LStickAxisY, Axis);
} }
if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) { if (LStickDeadzone != 0 && LStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold); SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisDeadzone);
} }
LStickDeadzone = AxisThreshold; LStickDeadzone = AxisDeadzone;
LStickAxisY = Axis; LStickAxisY = Axis;
} }
@ -276,11 +263,11 @@ namespace Ship {
SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", LStickAxisX, Axis); SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", LStickAxisX, Axis);
} }
if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) { if (LStickDeadzone != 0 && LStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold); SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisDeadzone);
} }
LStickDeadzone = AxisThreshold; LStickDeadzone = AxisDeadzone;
LStickAxisX = Axis; LStickAxisX = Axis;
} }
@ -289,21 +276,15 @@ namespace Ship {
SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", LStickAxisY, Axis); SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", LStickAxisY, Axis);
} }
if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) { if (LStickDeadzone != 0 && LStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold); SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisDeadzone);
} }
LStickDeadzone = AxisThreshold; LStickDeadzone = AxisDeadzone;
LStickAxisY = Axis; LStickAxisY = Axis;
} }
} }
if (LStickAxisX != SDL_CONTROLLER_AXIS_INVALID && LStickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
const auto AxisValueX = SDL_GameControllerGetAxis(Cont, LStickAxisX);
const auto AxisValueY = SDL_GameControllerGetAxis(Cont, LStickAxisY);
NormalizeStickAxis(AxisValueX, AxisValueY, LStickDeadzone, false, profile.Thresholds[SENSITIVITY]);
}
// Right Stick // Right Stick
// If the axis is NOT mapped to the control stick. // If the axis is NOT mapped to the control stick.
if (!( if (!(
@ -312,17 +293,17 @@ namespace Ship {
NegButton == BTN_VSTICKLEFT || NegButton == BTN_VSTICKRIGHT || NegButton == BTN_VSTICKLEFT || NegButton == BTN_VSTICKRIGHT ||
NegButton == BTN_VSTICKUP || NegButton == BTN_VSTICKDOWN)) { NegButton == BTN_VSTICKUP || NegButton == BTN_VSTICKDOWN)) {
if (AxisValue > 0x1E00) { if (AxisValue > AxisMinimumPress) {
dwPressedButtons[slot] |= PosButton; getPressedButtons(virtualSlot) |= PosButton;
dwPressedButtons[slot] &= ~NegButton; getPressedButtons(virtualSlot) &= ~NegButton;
} }
else if (AxisValue < -0x1E00) { else if (AxisValue < -AxisMinimumPress) {
dwPressedButtons[slot] &= ~PosButton; getPressedButtons(virtualSlot) &= ~PosButton;
dwPressedButtons[slot] |= NegButton; getPressedButtons(virtualSlot) |= NegButton;
} }
else { else {
dwPressedButtons[slot] &= ~PosButton; getPressedButtons(virtualSlot) &= ~PosButton;
dwPressedButtons[slot] &= ~NegButton; getPressedButtons(virtualSlot) &= ~NegButton;
} }
} else { } else {
@ -331,11 +312,11 @@ namespace Ship {
SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", RStickAxisX, Axis); SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", RStickAxisX, Axis);
} }
if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) { if (RStickDeadzone != 0 && RStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", RStickDeadzone, AxisThreshold); SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", RStickDeadzone, AxisDeadzone);
} }
RStickDeadzone = AxisThreshold; RStickDeadzone = AxisDeadzone;
RStickAxisX = Axis; RStickAxisX = Axis;
} }
@ -344,11 +325,11 @@ namespace Ship {
SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", RStickAxisY, Axis); SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", RStickAxisY, Axis);
} }
if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) { if (RStickDeadzone != 0 && RStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisThreshold); SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisDeadzone);
} }
RStickDeadzone = AxisThreshold; RStickDeadzone = AxisDeadzone;
RStickAxisY = Axis; RStickAxisY = Axis;
} }
@ -357,11 +338,11 @@ namespace Ship {
SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", RStickAxisX, Axis); SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", RStickAxisX, Axis);
} }
if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) { if (RStickDeadzone != 0 && RStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisThreshold); SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisDeadzone);
} }
RStickDeadzone = AxisThreshold; RStickDeadzone = AxisDeadzone;
RStickAxisX = Axis; RStickAxisX = Axis;
} }
@ -370,28 +351,30 @@ namespace Ship {
SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", RStickAxisY, Axis); SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", RStickAxisY, Axis);
} }
if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) { if (RStickDeadzone != 0 && RStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisThreshold); SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisDeadzone);
} }
RStickDeadzone = AxisThreshold; RStickDeadzone = AxisDeadzone;
RStickAxisY = Axis; RStickAxisY = Axis;
} }
}
if (RStickAxisX != SDL_CONTROLLER_AXIS_INVALID && RStickAxisY != SDL_CONTROLLER_AXIS_INVALID) { if (LStickAxisX != SDL_CONTROLLER_AXIS_INVALID && LStickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
const auto AxisValueX = SDL_GameControllerGetAxis(Cont, RStickAxisX); NormalizeStickAxis(LStickAxisX, LStickAxisY, LStickDeadzone, virtualSlot);
const auto AxisValueY = SDL_GameControllerGetAxis(Cont, RStickAxisY); }
NormalizeStickAxis(AxisValueX, AxisValueY, RStickDeadzone, true, profile.Thresholds[SENSITIVITY]);
if (RStickAxisX != SDL_CONTROLLER_AXIS_INVALID && RStickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
NormalizeStickAxis(RStickAxisX, RStickAxisY, RStickDeadzone, virtualSlot);
}
} }
} }
} }
void SDLController::WriteToSource(int32_t slot, ControllerCallback* controller) void SDLController::WriteToSource(int32_t virtualSlot, ControllerCallback* controller)
{ {
if (CanRumble() && profiles[slot].UseRumble) { if (CanRumble() && getProfile(virtualSlot)->UseRumble) {
if (controller->rumble > 0) { if (controller->rumble > 0) {
float rumble_strength = profiles[slot].RumbleStrength; float rumble_strength = getProfile(virtualSlot)->RumbleStrength;
SDL_GameControllerRumble(Cont, 0xFFFF * rumble_strength, 0xFFFF * rumble_strength, 0); SDL_GameControllerRumble(Cont, 0xFFFF * rumble_strength, 0xFFFF * rumble_strength, 0);
} }
else { else {
@ -416,20 +399,11 @@ namespace Ship {
} }
} }
} }
const std::string SDLController::GetButtonName(int32_t virtualSlot, int32_t n64Button) {
char buffer[50];
std::map<int32_t, int32_t>& Mappings = getProfile(virtualSlot)->Mappings;
const char* AxisNames[] = {
"Left Stick X",
"Left Stick Y",
"Right Stick X",
"Right Stick Y",
"Left Trigger",
"Right Trigger",
"Start Button"
};
char buffer[50];
const char* SDLController::GetButtonName(int slot, int n64Button) {
std::map<int32_t, int32_t>& Mappings = profiles[slot].Mappings;
const auto find = std::find_if(Mappings.begin(), Mappings.end(), [n64Button](const std::pair<int32_t, int32_t>& pair) { const auto find = std::find_if(Mappings.begin(), Mappings.end(), [n64Button](const std::pair<int32_t, int32_t>& pair) {
return pair.second == n64Button; return pair.second == n64Button;
}); });
@ -449,42 +423,45 @@ namespace Ship {
return buffer; return buffer;
} }
const char* SDLController::GetControllerName() { const std::string SDLController::GetControllerName() {
return strdup(ControllerName.c_str()); return ControllerName;
} }
void SDLController::CreateDefaultBinding(int32_t slot) { void SDLController::CreateDefaultBinding(int32_t virtualSlot) {
DeviceProfile& profile = profiles[slot]; auto profile = getProfile(virtualSlot);
profile.Mappings.clear(); profile->Mappings.clear();
profile.UseRumble = true; profile->UseRumble = true;
profile.RumbleStrength = 1.0f; profile->RumbleStrength = 1.0f;
profile.UseGyro = false; profile->UseGyro = false;
profile.Mappings[ SDL_CONTROLLER_AXIS_RIGHTX | AXIS_SCANCODE_BIT] = BTN_CRIGHT;
profile.Mappings[-(SDL_CONTROLLER_AXIS_RIGHTX | AXIS_SCANCODE_BIT)] = BTN_CLEFT; profile->Mappings[SDL_CONTROLLER_AXIS_RIGHTX | AXIS_SCANCODE_BIT] = BTN_CRIGHT;
profile.Mappings[ SDL_CONTROLLER_AXIS_RIGHTY | AXIS_SCANCODE_BIT] = BTN_CDOWN; profile->Mappings[-(SDL_CONTROLLER_AXIS_RIGHTX | AXIS_SCANCODE_BIT)] = BTN_CLEFT;
profile.Mappings[-(SDL_CONTROLLER_AXIS_RIGHTY | AXIS_SCANCODE_BIT)] = BTN_CUP; profile->Mappings[SDL_CONTROLLER_AXIS_RIGHTY | AXIS_SCANCODE_BIT] = BTN_CDOWN;
profile.Mappings[SDL_CONTROLLER_AXIS_TRIGGERRIGHT + AXIS_SCANCODE_BIT] = BTN_R; profile->Mappings[-(SDL_CONTROLLER_AXIS_RIGHTY | AXIS_SCANCODE_BIT)] = BTN_CUP;
profile.Mappings[SDL_CONTROLLER_BUTTON_LEFTSHOULDER] = BTN_L; profile->Mappings[SDL_CONTROLLER_AXIS_LEFTX | AXIS_SCANCODE_BIT] = BTN_STICKRIGHT;
profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_RIGHT] = BTN_DRIGHT; profile->Mappings[-(SDL_CONTROLLER_AXIS_LEFTX | AXIS_SCANCODE_BIT)] = BTN_STICKLEFT;
profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_LEFT] = BTN_DLEFT; profile->Mappings[SDL_CONTROLLER_AXIS_LEFTY | AXIS_SCANCODE_BIT] = BTN_STICKDOWN;
profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_DOWN] = BTN_DDOWN; profile->Mappings[-(SDL_CONTROLLER_AXIS_LEFTY | AXIS_SCANCODE_BIT)] = BTN_STICKUP;
profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_UP] = BTN_DUP; profile->Mappings[SDL_CONTROLLER_AXIS_TRIGGERRIGHT | AXIS_SCANCODE_BIT] = BTN_R;
profile.Mappings[SDL_CONTROLLER_BUTTON_START] = BTN_START; profile->Mappings[SDL_CONTROLLER_AXIS_TRIGGERLEFT | AXIS_SCANCODE_BIT] = BTN_Z;
profile.Mappings[SDL_CONTROLLER_AXIS_TRIGGERLEFT + AXIS_SCANCODE_BIT] = BTN_Z; profile->Mappings[SDL_CONTROLLER_BUTTON_LEFTSHOULDER] = BTN_L;
profile.Mappings[SDL_CONTROLLER_BUTTON_B] = BTN_B; profile->Mappings[SDL_CONTROLLER_BUTTON_DPAD_RIGHT] = BTN_DRIGHT;
profile.Mappings[SDL_CONTROLLER_BUTTON_A] = BTN_A; profile->Mappings[SDL_CONTROLLER_BUTTON_DPAD_LEFT] = BTN_DLEFT;
profile.Mappings[(SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT)] = BTN_STICKRIGHT; profile->Mappings[SDL_CONTROLLER_BUTTON_DPAD_DOWN] = BTN_DDOWN;
profile.Mappings[-(SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT)] = BTN_STICKLEFT; profile->Mappings[SDL_CONTROLLER_BUTTON_DPAD_UP] = BTN_DUP;
profile.Mappings[SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT] = BTN_STICKDOWN; profile->Mappings[SDL_CONTROLLER_BUTTON_START] = BTN_START;
profile.Mappings[-(SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT)] = BTN_STICKUP; profile->Mappings[SDL_CONTROLLER_BUTTON_B] = BTN_B;
profile.Thresholds[LEFT_STICK] = 16.0f; profile->Mappings[SDL_CONTROLLER_BUTTON_A] = BTN_A;
profile.Thresholds[RIGHT_STICK] = 16.0f;
profile.Thresholds[LEFT_TRIGGER] = 0x1E00; for (int32_t i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) {
profile.Thresholds[RIGHT_TRIGGER] = 0x1E00; profile->AxisSensitivities[i] = 1.0f;
profile.Thresholds[DRIFT_X] = 0.0f; profile->AxisDeadzones[i] = 16.0f;
profile.Thresholds[DRIFT_Y] = 0.0f; profile->AxisMinimumPress[i] = 7680.0f;
profile.Thresholds[SENSITIVITY] = 16.0f; }
profile.Thresholds[GYRO_SENSITIVITY] = 1.0f;
profile->GyroData[DRIFT_X] = 0.0f;
profile->GyroData[DRIFT_Y] = 0.0f;
profile->GyroData[GYRO_SENSITIVITY] = 1.0f;
} }
} }

View File

@ -5,18 +5,28 @@
namespace Ship { namespace Ship {
class SDLController : public Controller { class SDLController : public Controller {
public: public:
SDLController(int slot) : Controller(), Cont(nullptr), physicalSlot(slot) { } inline static const char* AxisNames[] = {
void ReadFromSource(int32_t slot) override; "Left Stick X",
const char* GetControllerName() override; "Left Stick Y",
const char* GetButtonName(int slot, int n64Button) override; "Right Stick X",
void WriteToSource(int32_t slot, ControllerCallback* controller) override; "Right Stick Y",
"Left Trigger",
"Right Trigger",
"Start Button"
};
SDLController(int32_t physicalSlot) : Controller(), Cont(nullptr), physicalSlot(physicalSlot) { }
void ReadFromSource(int32_t virtualSlot) override;
const std::string GetControllerName() override;
const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) override;
void WriteToSource(int32_t virtualSlot, ControllerCallback* controller) override;
bool Connected() const override { return Cont != nullptr; } bool Connected() const override { return Cont != nullptr; }
bool CanGyro() const override { return supportsGyro; } bool CanGyro() const override { return supportsGyro; }
bool CanRumble() const override { bool CanRumble() const override {
#if SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2,0,18) #if SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2,0,18)
return SDL_GameControllerHasRumble(Cont); return SDL_GameControllerHasRumble(Cont);
#endif #endif
return true; return false;
} }
bool Open(); bool Open();
@ -24,14 +34,14 @@ namespace Ship {
int32_t ReadRawPress() override; int32_t ReadRawPress() override;
protected: protected:
void CreateDefaultBinding(int32_t slot) override; void CreateDefaultBinding(int32_t virtualSlot) override;
private: private:
std::string ControllerName = "Unknown"; std::string ControllerName = "Unknown";
SDL_GameController* Cont; SDL_GameController* Cont;
int physicalSlot; int32_t physicalSlot;
bool supportsGyro; bool supportsGyro;
void NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold, bool isRightStick, float sensitivity); void NormalizeStickAxis(SDL_GameControllerAxis axisX, SDL_GameControllerAxis axisY, int16_t axisThreshold, int32_t virtualSlot);
bool Close(); bool Close();
}; };
} }

View File

@ -124,8 +124,8 @@ typedef struct {
/* 0x04 */ uint8_t err_no; /* 0x04 */ uint8_t err_no;
/* 0x05 */ float gyro_x; /* 0x05 */ float gyro_x;
/* 0x09 */ float gyro_y; /* 0x09 */ float gyro_y;
/* 0x1C */ float cam_x; /* 0x1C */ int8_t right_stick_x;
/* 0x20 */ float cam_y; /* 0x20 */ int8_t right_stick_y;
} OSContPad; // size = 0x24 } OSContPad; // size = 0x24
typedef struct { typedef struct {

View File

@ -61,8 +61,8 @@ extern "C" {
pad->button = 0; pad->button = 0;
pad->stick_x = 0; pad->stick_x = 0;
pad->stick_y = 0; pad->stick_y = 0;
pad->cam_x = 0; pad->right_stick_x = 0;
pad->cam_y = 0; pad->right_stick_y = 0;
pad->err_no = 0; pad->err_no = 0;
pad->gyro_x = 0; pad->gyro_x = 0;
pad->gyro_y = 0; pad->gyro_y = 0;

View File

@ -1410,8 +1410,8 @@ s32 Camera_Noop(Camera* camera) {
} }
s32 SetCameraManual(Camera* camera) { s32 SetCameraManual(Camera* camera) {
f32 newCamX = -D_8015BD7C->state.input[0].cur.cam_x; f32 newCamX = -D_8015BD7C->state.input[0].cur.cam_x * 10.0f;
f32 newCamY = D_8015BD7C->state.input[0].cur.cam_y; f32 newCamY = D_8015BD7C->state.input[0].cur.cam_y * 10.0f;
if ((fabsf(newCamX) >= 15.0f || fabsf(newCamY) >= 15.0f) && camera->globalCtx->manualCamera == false) { if ((fabsf(newCamX) >= 15.0f || fabsf(newCamY) >= 15.0f) && camera->globalCtx->manualCamera == false) {
camera->globalCtx->manualCamera = true; camera->globalCtx->manualCamera = true;
@ -1479,8 +1479,8 @@ s32 Camera_Free(Camera* camera) {
camera->animState = 1; camera->animState = 1;
f32 newCamX = -D_8015BD7C->state.input[0].cur.cam_x; f32 newCamX = -D_8015BD7C->state.input[0].cur.cam_x * 10.0f;
f32 newCamY = D_8015BD7C->state.input[0].cur.cam_y; f32 newCamY = D_8015BD7C->state.input[0].cur.cam_y * 10.0f;
camera->globalCtx->camX += newCamX; camera->globalCtx->camX += newCamX;
camera->globalCtx->camY += newCamY; camera->globalCtx->camY += newCamY;

View File

@ -128,8 +128,8 @@ void KaleidoScope_DrawPlayerWork(GlobalContext* globalCtx) {
} else if ((AllowDPadRotation && CHECK_BTN_ALL(input->cur.button, BTN_DRIGHT)) || } else if ((AllowDPadRotation && CHECK_BTN_ALL(input->cur.button, BTN_DRIGHT)) ||
(AllowCRotation && CHECK_BTN_ALL(input->cur.button, BTN_CRIGHT))) { (AllowCRotation && CHECK_BTN_ALL(input->cur.button, BTN_CRIGHT))) {
link_kaleido_rot.y = link_kaleido_rot.y + RotationSpeed; link_kaleido_rot.y = link_kaleido_rot.y + RotationSpeed;
} else if(AllowStickRotation && input->cur.cam_x != 0){ } else if(AllowStickRotation && input->cur.cam_x*10.0f != 0){
link_kaleido_rot.y = link_kaleido_rot.y + (input->cur.cam_x*(((f32)RotationSpeed)/600.0f)); link_kaleido_rot.y = link_kaleido_rot.y + (input->cur.cam_x*10.0f*(((f32)RotationSpeed)/600.0f));
} }
if ((AllowDPadRotation && CHECK_BTN_ALL(input->press.button, BTN_DUP)) || // reset rotation if ((AllowDPadRotation && CHECK_BTN_ALL(input->press.button, BTN_DUP)) || // reset rotation
@ -138,13 +138,13 @@ void KaleidoScope_DrawPlayerWork(GlobalContext* globalCtx) {
} else if ((AllowCRotation && CHECK_BTN_ALL(input->press.button, BTN_CUP)) || } else if ((AllowCRotation && CHECK_BTN_ALL(input->press.button, BTN_CUP)) ||
(AllowCRotation && CHECK_BTN_ALL(input->press.button, BTN_CDOWN))) { (AllowCRotation && CHECK_BTN_ALL(input->press.button, BTN_CDOWN))) {
link_kaleido_rot.y = 32300; link_kaleido_rot.y = 32300;
} else if (AllowStickRotation && input->cur.cam_y < -1200) { } else if (AllowStickRotation && input->cur.cam_y * 10.0f < -1200) {
link_kaleido_rot.y = 32300; link_kaleido_rot.y = 32300;
} }
if (AllowStickRotation && input->cur.cam_y>0) { // Zoom in if (AllowStickRotation && input->cur.cam_y * 10.0f > 0) { // Zoom in
scale = scale + input->cur.cam_y*.00005; scale = scale + input->cur.cam_y*10.0f*.00005f;
pos.y = pos.y - input->cur.cam_y*.25; pos.y = pos.y - input->cur.cam_y*10.0f*0.25f;
} }