mirror of https://github.com/AxioDL/metaforce.git
Initial port configuration (needs cleanup)
This commit is contained in:
parent
f8d9207aaa
commit
10d4bbf297
|
@ -89,6 +89,7 @@ set(RUNTIME_SOURCES_B
|
||||||
Streams/ContainerReaders.hpp
|
Streams/ContainerReaders.hpp
|
||||||
Streams/CTextInStream.hpp Streams/CTextInStream.cpp
|
Streams/CTextInStream.hpp Streams/CTextInStream.cpp
|
||||||
Streams/CTextOutStream.hpp Streams/CTextOutStream.cpp
|
Streams/CTextOutStream.hpp Streams/CTextOutStream.cpp
|
||||||
|
Streams/CFileOutStream.hpp Streams/CFileOutStream.cpp
|
||||||
CGameAllocator.hpp CGameAllocator.cpp
|
CGameAllocator.hpp CGameAllocator.cpp
|
||||||
CMemoryCardSys.hpp CMemoryCardSys.cpp
|
CMemoryCardSys.hpp CMemoryCardSys.cpp
|
||||||
CScannableObjectInfo.hpp CScannableObjectInfo.cpp
|
CScannableObjectInfo.hpp CScannableObjectInfo.cpp
|
||||||
|
|
|
@ -1,15 +1,64 @@
|
||||||
#include "Runtime/ImGuiControllerConfig.hpp"
|
#include "Runtime/ImGuiControllerConfig.hpp"
|
||||||
|
|
||||||
|
#include "Runtime/Streams/CFileOutStream.hpp"
|
||||||
|
#include "Runtime/Streams/ContainerReaders.hpp"
|
||||||
|
#include "Runtime/Streams/ContainerWriters.hpp"
|
||||||
|
|
||||||
#include "aurora/pad.hpp"
|
#include "aurora/pad.hpp"
|
||||||
|
#include "aurora/aurora.hpp"
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
namespace metaforce {
|
namespace metaforce {
|
||||||
|
ImGuiControllerConfig::Button::Button(CInputStream& in)
|
||||||
|
: button(in.Get<s32>())
|
||||||
|
, uvX(in.Get<u32>())
|
||||||
|
, uvY(in.Get<u32>())
|
||||||
|
, width(in.Get<u32>())
|
||||||
|
, height(in.Get<u32>())
|
||||||
|
, offX(in.Get<float>())
|
||||||
|
, offY(in.Get<float>()) {}
|
||||||
|
|
||||||
|
void ImGuiControllerConfig::Button::PutTo(COutputStream& out) const {
|
||||||
|
out.Put(button);
|
||||||
|
out.Put(uvX);
|
||||||
|
out.Put(uvY);
|
||||||
|
out.Put(width);
|
||||||
|
out.Put(height);
|
||||||
|
out.Put(offX);
|
||||||
|
out.Put(offY);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiControllerConfig::ControllerAtlas::ControllerAtlas(CInputStream& in) : name(in.Get<std::string>()) {
|
||||||
|
u32 vidPidCount = in.Get<u32>();
|
||||||
|
vidPids.reserve(vidPidCount);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < vidPidCount; ++i) {
|
||||||
|
u16 vid = static_cast<u16>(in.Get<s16>());
|
||||||
|
u16 pid = static_cast<u16>(in.Get<s16>());
|
||||||
|
vidPids.emplace_back(vid, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
atlasFile = in.Get<std::string>();
|
||||||
|
read_vector(buttons, in);
|
||||||
|
};
|
||||||
|
|
||||||
|
void ImGuiControllerConfig::ControllerAtlas::PutTo(COutputStream& out) const {
|
||||||
|
out.Put(name);
|
||||||
|
out.Put(static_cast<u32>(vidPids.size()));
|
||||||
|
for (const auto& vidPid : vidPids) {
|
||||||
|
out.Put(vidPid.first);
|
||||||
|
out.Put(vidPid.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_vector(buttons, out);
|
||||||
|
}
|
||||||
|
|
||||||
void ImGuiControllerConfig::show(bool& visible) {
|
void ImGuiControllerConfig::show(bool& visible) {
|
||||||
|
|
||||||
/** TODO:
|
/** TODO:
|
||||||
* - Implement multiple controllers
|
* - Implement multiple controllers
|
||||||
* - Implement setting controller ports
|
* - Implement setting controller ports (except for the GameCube adapter, which is hard coded)
|
||||||
* - Implement fancy graphical UI
|
* - Implement fancy graphical UI
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -18,57 +67,128 @@ void ImGuiControllerConfig::show(bool& visible) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_pendingMapping != nullptr) {
|
if (m_pendingMapping != nullptr) {
|
||||||
s32 nativeButton = PADGetNativeButtonPressed(0);
|
s32 nativeButton = PADGetNativeButtonPressed(m_pendingPort);
|
||||||
if (nativeButton != -1) {
|
if (nativeButton != -1) {
|
||||||
m_pendingMapping->nativeButton = nativeButton;
|
m_pendingMapping->nativeButton = nativeButton;
|
||||||
m_pendingMapping = nullptr;
|
m_pendingMapping = nullptr;
|
||||||
|
m_pendingPort = -1;
|
||||||
PADBlockInput(false);
|
PADBlockInput(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> controllers;
|
||||||
|
controllers.push_back("None");
|
||||||
|
for (u32 i = 0; i < PADCount(); ++i) {
|
||||||
|
controllers.push_back(fmt::format(FMT_STRING("{}-{}"), PADGetNameForControllerIndex(i), i));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pendingValid = false;
|
||||||
if (ImGui::Begin("Controller Config", &visible)) {
|
if (ImGui::Begin("Controller Config", &visible)) {
|
||||||
ImGui::Text("%s", PADGetName(0));
|
if (ImGui::CollapsingHeader("Ports")) {
|
||||||
|
for (u32 i = 0; i < 4; ++i) {
|
||||||
|
ImGui::PushID(fmt::format(FMT_STRING("PortConf-{}"), i).c_str());
|
||||||
|
s32 index = PADGetIndexForPort(i);
|
||||||
|
int sel = 0;
|
||||||
|
std::string name = "None";
|
||||||
|
const char* tmpName = PADGetName(i);
|
||||||
|
bool changed = false;
|
||||||
|
if (tmpName != nullptr) {
|
||||||
|
name = fmt::format(FMT_STRING("{}-{}"), tmpName, index);
|
||||||
|
}
|
||||||
|
if (ImGui::BeginCombo(fmt::format(FMT_STRING("Port {}"), i + 1).c_str(), name.c_str())) {
|
||||||
|
for (u32 j = 0; const auto& s : controllers) {
|
||||||
|
if (ImGui::Selectable(s.c_str(), name == s)) {
|
||||||
|
sel = j;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
++j;
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
if (sel > 0) {
|
||||||
|
PADSetPortForIndex(sel - 1, i);
|
||||||
|
} else if (sel == 0) {
|
||||||
|
PADClearPort(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ImGui::BeginTabBar("Controllers")) {
|
||||||
|
for (u32 i = 0; i < 4; ++i) {
|
||||||
|
if (ImGui::BeginTabItem(fmt::format(FMT_STRING("Port {}"), i + 1).c_str())) {
|
||||||
|
ImGui::PushID(fmt::format(FMT_STRING("Port_{}"), i + 1).c_str());
|
||||||
|
/* If the tab is changed while pending for input, cancel the pending port */
|
||||||
|
if (m_pendingMapping != nullptr && m_pendingPort != i) {
|
||||||
|
m_pendingMapping = nullptr;
|
||||||
|
m_pendingValid = false;
|
||||||
|
m_pendingPort = -1;
|
||||||
|
}
|
||||||
|
u32 vid, pid;
|
||||||
|
PADGetVidPid(i, &vid, &pid);
|
||||||
|
if (vid == 0 && pid == 0) {
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
ImGui::PopID();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ImGui::Text("%s", PADGetName(i));
|
||||||
u32 buttonCount = 0;
|
u32 buttonCount = 0;
|
||||||
PADButtonMapping* mapping = PADGetButtonMappings(0, &buttonCount);
|
PADButtonMapping* mapping = PADGetButtonMappings(i, &buttonCount);
|
||||||
if (mapping != nullptr) {
|
if (mapping != nullptr) {
|
||||||
for (u32 i = 0; i < buttonCount; ++i) {
|
for (u32 m = 0; m < buttonCount; ++m) {
|
||||||
bool pressed = ImGui::Button(PADGetButtonName(mapping[i].padButton));
|
const char* padName = PADGetButtonName(mapping[m].padButton);
|
||||||
|
if (padName == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ImGui::PushID(padName);
|
||||||
|
bool pressed = ImGui::Button(padName);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text("%s", PADGetNativeButtonName(mapping[i].nativeButton));
|
ImGui::Text("%s", PADGetNativeButtonName(mapping[m].nativeButton));
|
||||||
|
|
||||||
if (pressed && m_pendingMapping == nullptr) {
|
if (pressed && m_pendingMapping == nullptr) {
|
||||||
m_pendingMapping = &mapping[i];
|
m_pendingMapping = &mapping[m];
|
||||||
|
m_pendingPort = i;
|
||||||
PADBlockInput(true);
|
PADBlockInput(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_pendingMapping == &mapping[i]) {
|
if (m_pendingMapping == &mapping[m]) {
|
||||||
|
m_pendingValid = true;
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text(" - Waiting for button...");
|
ImGui::Text(" - Waiting for button...");
|
||||||
}
|
}
|
||||||
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::CollapsingHeader("Dead-zones")) {
|
if (ImGui::CollapsingHeader("Dead-zones")) {
|
||||||
PADDeadZones* deadZones = PADGetDeadZones(0);
|
PADDeadZones* deadZones = PADGetDeadZones(i);
|
||||||
ImGui::Checkbox("Use Dead-zones", &deadZones->useDeadzones);
|
ImGui::Checkbox("Use Dead-zones", &deadZones->useDeadzones);
|
||||||
s32 tmp = deadZones->stickDeadZone;
|
float tmp = static_cast<float>(deadZones->stickDeadZone * 100.f) / 32767.f;
|
||||||
if (ImGui::DragInt("Left Stick", &tmp)) {
|
if (ImGui::DragFloat("Left Stick", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
|
||||||
deadZones->stickDeadZone = tmp;
|
deadZones->stickDeadZone = static_cast<u16>((tmp / 100.f) * 32767);
|
||||||
}
|
}
|
||||||
tmp = deadZones->substickDeadZone;
|
tmp = static_cast<float>(deadZones->substickDeadZone * 100.f) / 32767.f;
|
||||||
if (ImGui::DragInt("Right Stick", &tmp)) {
|
if (ImGui::DragFloat("Right Stick", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
|
||||||
deadZones->substickDeadZone = tmp;
|
deadZones->substickDeadZone = static_cast<u16>((tmp / 100.f) * 32767);
|
||||||
}
|
}
|
||||||
ImGui::Checkbox("Emulate Triggers", &deadZones->emulateTriggers);
|
ImGui::Checkbox("Emulate Triggers", &deadZones->emulateTriggers);
|
||||||
tmp = deadZones->leftTriggerActivationZone;
|
tmp = static_cast<float>(deadZones->leftTriggerActivationZone * 100.f) / 32767.f;
|
||||||
if (ImGui::DragInt("Left Trigger Activation", &tmp)) {
|
if (ImGui::DragFloat("Left Trigger Activation", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
|
||||||
deadZones->leftTriggerActivationZone = tmp;
|
deadZones->leftTriggerActivationZone = static_cast<u16>((tmp / 100.f) * 32767);
|
||||||
}
|
}
|
||||||
tmp = deadZones->rightTriggerActivationZone;
|
tmp = static_cast<float>(deadZones->rightTriggerActivationZone * 100.f) / 32767.f;
|
||||||
if (ImGui::DragInt("Right Trigger Activation", &tmp)) {
|
if (ImGui::DragFloat("Right Trigger Activation", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
|
||||||
deadZones->rightTriggerActivationZone = tmp;
|
deadZones->rightTriggerActivationZone = static_cast<u16>((tmp / 100.f) * 32767);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndTabBar();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
if (ImGui::Button("Display Editor")) {
|
if (ImGui::Button("Display Editor")) {
|
||||||
|
@ -96,6 +216,23 @@ void ImGuiControllerConfig::showEditor(bool& visible) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Begin("Controller Atlas Editor", &visible)) {
|
if (ImGui::Begin("Controller Atlas Editor", &visible)) {
|
||||||
|
/* TODO: Atlas editor */
|
||||||
|
ImGui::Separator();
|
||||||
|
if (ImGui::Button("Save Controller Database")) {
|
||||||
|
CFileOutStream out("ControllerAtlases.ctrdb");
|
||||||
|
out.WriteUint32(SLITTLE('CTDB'));
|
||||||
|
out.WriteUint32(1); // Version
|
||||||
|
write_vector(m_controllerAtlases, out);
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Export") && m_currentAtlas != nullptr) {
|
||||||
|
CFileOutStream out("test.ctratlas");
|
||||||
|
out.Put(SLITTLE('CTRA'));
|
||||||
|
out.Put(1); // Version
|
||||||
|
out.Put(*m_currentAtlas);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Import logic */
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Runtime/GCNTypes.hpp"
|
#include "Runtime/GCNTypes.hpp"
|
||||||
|
#include "Runtime/Streams/CInputStream.hpp"
|
||||||
|
#include "Runtime/Streams/COutputStream.hpp"
|
||||||
#include "aurora/pad.hpp"
|
#include "aurora/pad.hpp"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
@ -11,20 +13,28 @@
|
||||||
namespace metaforce {
|
namespace metaforce {
|
||||||
class ImGuiControllerConfig {
|
class ImGuiControllerConfig {
|
||||||
struct Button {
|
struct Button {
|
||||||
u32 button; // the SDL button this entry corresponds to
|
s32 button = -1; // the SDL button this entry corresponds to
|
||||||
u32 uvX; // Offset if icon image in atlas from left (in pixels)
|
u32 uvX = 0; // Offset if icon image in atlas from left (in pixels)
|
||||||
u32 uvY; // Offset if icon image in atlas from top (in pixels)
|
u32 uvY = 0; // Offset if icon image in atlas from top (in pixels)
|
||||||
u32 width; // Width of button image (in pixels)
|
u32 width = 32; // Width of button image (in pixels)
|
||||||
u32 height; // Height of button image (in pixels)
|
u32 height = 32; // Height of button image (in pixels)
|
||||||
float offX; // Offset from left of config window
|
float offX = 0.f; // Offset from left of config window
|
||||||
float offY; // Offset from top of config window
|
float offY = 0.f; // Offset from top of config window
|
||||||
|
|
||||||
|
Button() = default;
|
||||||
|
explicit Button(CInputStream& in);
|
||||||
|
void PutTo(COutputStream& in) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ControllerMapping {
|
struct ControllerAtlas {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::pair<u32, u32> vidPid;
|
std::vector<std::pair<u16, u16>> vidPids;
|
||||||
std::string atlasFile; // Path to atlas relative to controller definition
|
std::string atlasFile; // Path to atlas relative to controller definition
|
||||||
std::vector<Button> buttons;
|
std::vector<Button> buttons;
|
||||||
|
|
||||||
|
ControllerAtlas() = default;
|
||||||
|
explicit ControllerAtlas(CInputStream& in);
|
||||||
|
void PutTo(COutputStream& out) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -34,9 +44,12 @@ private:
|
||||||
void showEditor(bool& visible);
|
void showEditor(bool& visible);
|
||||||
|
|
||||||
PADButtonMapping* m_pendingMapping = nullptr;
|
PADButtonMapping* m_pendingMapping = nullptr;
|
||||||
|
s32 m_pendingPort = 0;
|
||||||
|
bool m_pendingValid = false;
|
||||||
bool m_editorVisible = false;
|
bool m_editorVisible = false;
|
||||||
|
|
||||||
std::array<ControllerMapping*, 4> m_controllers;
|
|
||||||
std::vector<ControllerMapping> m_mappings;
|
ControllerAtlas* m_currentAtlas = nullptr;
|
||||||
|
std::vector<ControllerAtlas> m_controllerAtlases;
|
||||||
};
|
};
|
||||||
} // namespace metaforce
|
} // namespace metaforce
|
|
@ -30,8 +30,11 @@ void CInputGenerator::Update(float dt, CArchitectureQueue& queue) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
firstController = true;
|
firstController = true;
|
||||||
}
|
}
|
||||||
m_lastInput = CFinalInput(i, dt, cont, xc_leftDiv, x10_rightDiv);
|
auto tmp = CFinalInput(i, dt, cont, xc_leftDiv, x10_rightDiv);
|
||||||
queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, m_lastInput));
|
if (i == 0) {
|
||||||
|
m_lastInput = tmp;
|
||||||
|
}
|
||||||
|
queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, tmp));
|
||||||
++availSlot;
|
++availSlot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include "Runtime/Streams/CFileOutStream.hpp"
|
||||||
|
|
||||||
|
namespace metaforce {
|
||||||
|
CFileOutStream::CFileOutStream(std::string_view name, u32 blockLen) : COutputStream(blockLen) {
|
||||||
|
m_file = fopen(name.data(), "wbe");
|
||||||
|
}
|
||||||
|
|
||||||
|
CFileOutStream::~CFileOutStream() {
|
||||||
|
Flush();
|
||||||
|
if (m_file) {
|
||||||
|
fclose(m_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFileOutStream::Write(const u8* ptr, u32 len) {
|
||||||
|
if (!m_file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fwrite(ptr, 1, len, m_file);
|
||||||
|
}
|
||||||
|
} // namespace metaforce
|
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Runtime/Streams/COutputStream.hpp"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
namespace metaforce {
|
||||||
|
class CFileOutStream final : public COutputStream {
|
||||||
|
FILE* m_file;
|
||||||
|
public:
|
||||||
|
explicit CFileOutStream(std::string_view name, u32 blockLen = 4096);
|
||||||
|
virtual ~CFileOutStream();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void Write(const u8* ptr, u32 len);
|
||||||
|
};
|
||||||
|
} // namespace metaforce
|
|
@ -97,9 +97,15 @@ struct PADButtonMapping {
|
||||||
PAD::BUTTON padButton;
|
PAD::BUTTON padButton;
|
||||||
};
|
};
|
||||||
|
|
||||||
s32 PADGetCount();
|
/* Returns the total number of controllers */
|
||||||
void PADGetVidPid(u32 idx, u32* vid, u32* pid);
|
u32 PADCount();
|
||||||
const char* PADGetName(u32 idx);
|
/* Returns the controller name for the given index into the controller map */
|
||||||
|
const char* PADGetNameForControllerIndex(u32 idx);
|
||||||
|
void PADSetPortForIndex(u32 index, s32 port);
|
||||||
|
s32 PADGetIndexForPort(u32 port);
|
||||||
|
void PADGetVidPid(u32 port, u32* vid, u32* pid);
|
||||||
|
void PADClearPort(u32 port);
|
||||||
|
const char* PADGetName(u32 port);
|
||||||
void PADSetButtonMapping(u32 port, PADButtonMapping mapping);
|
void PADSetButtonMapping(u32 port, PADButtonMapping mapping);
|
||||||
void PADSetAllButtonMappings(u32 port, PADButtonMapping buttons[12]);
|
void PADSetAllButtonMappings(u32 port, PADButtonMapping buttons[12]);
|
||||||
PADButtonMapping* PADGetButtonMappings(u32 port, u32* buttonCount);
|
PADButtonMapping* PADGetButtonMappings(u32 port, u32* buttonCount);
|
||||||
|
|
|
@ -22,7 +22,7 @@ struct GameController {
|
||||||
PADDeadZones m_deadZones;
|
PADDeadZones m_deadZones;
|
||||||
u16 m_vid = 0;
|
u16 m_vid = 0;
|
||||||
u16 m_pid = 0;
|
u16 m_pid = 0;
|
||||||
std::array<PADButtonMapping, 12> m_mapping;
|
std::array<PADButtonMapping, 12> m_mapping{};
|
||||||
bool m_mappingLoaded = false;
|
bool m_mappingLoaded = false;
|
||||||
constexpr bool operator==(const GameController& other) const {
|
constexpr bool operator==(const GameController& other) const {
|
||||||
return m_controller == other.m_controller && m_index == other.m_index;
|
return m_controller == other.m_controller && m_index == other.m_index;
|
||||||
|
@ -37,20 +37,24 @@ GameController* get_controller_for_player(u32 player) noexcept {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
/* If we don't have a controller assigned to this port use the first unassigned controller */
|
/* If we don't have a controller assigned to this port use the first unassigned controller */
|
||||||
if (!g_GameControllers.empty()) {
|
if (!g_GameControllers.empty()) {
|
||||||
int32_t availIndex = -1;
|
int32_t availIndex = -1;
|
||||||
for (const auto& controller : g_GameControllers) {
|
GameController* ct = nullptr;
|
||||||
if (player_index(controller.second.m_index) == -1) {
|
for (auto& controller : g_GameControllers) {
|
||||||
availIndex = controller.second.m_index;
|
if (player_index(controller.first) == -1) {
|
||||||
|
availIndex = controller.first;
|
||||||
|
ct = &controller.second;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (availIndex != -1) {
|
if (availIndex != -1) {
|
||||||
set_player_index(g_GameControllers.begin()->second.m_index, player);
|
set_player_index(availIndex, player);
|
||||||
return get_controller_for_player(player);
|
return ct;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,6 +393,71 @@ static const std::array<PADButtonMapping, 12> mDefaultButtons{{
|
||||||
void PADSetSpec(s32 spec) {}
|
void PADSetSpec(s32 spec) {}
|
||||||
void PADInit() {}
|
void PADInit() {}
|
||||||
|
|
||||||
|
aurora::input::GameController* __PADGetControllerForIndex(u32 idx) {
|
||||||
|
if (idx >= aurora::input::g_GameControllers.size()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 tmp = 0;
|
||||||
|
auto iter = aurora::input::g_GameControllers.begin();
|
||||||
|
while (tmp < idx) {
|
||||||
|
++iter;
|
||||||
|
++tmp;
|
||||||
|
}
|
||||||
|
if (iter == aurora::input::g_GameControllers.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &iter->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 PADCount() { return aurora::input::g_GameControllers.size(); }
|
||||||
|
|
||||||
|
const char* PADGetNameForControllerIndex(u32 idx) {
|
||||||
|
auto* ctrl = __PADGetControllerForIndex(idx);
|
||||||
|
if (ctrl == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SDL_GameControllerName(ctrl->m_controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PADSetPortForIndex(u32 idx, s32 port) {
|
||||||
|
auto* ctrl = __PADGetControllerForIndex(idx);
|
||||||
|
auto* dest = aurora::input::get_controller_for_player(port);
|
||||||
|
if (ctrl == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dest != nullptr) {
|
||||||
|
SDL_GameControllerSetPlayerIndex(dest->m_controller, -1);
|
||||||
|
}
|
||||||
|
SDL_GameControllerSetPlayerIndex(ctrl->m_controller, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 PADGetIndexForPort(u32 port) {
|
||||||
|
auto* ctrl = aurora::input::get_controller_for_player(port);
|
||||||
|
if (ctrl == nullptr) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
s32 index = 0;
|
||||||
|
for (auto iter = aurora::input::g_GameControllers.begin(); iter != aurora::input::g_GameControllers.end();
|
||||||
|
++iter, ++index) {
|
||||||
|
if (&iter->second == ctrl) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PADClearPort(u32 port) {
|
||||||
|
auto* ctrl = aurora::input::get_controller_for_player(port);
|
||||||
|
if (ctrl == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SDL_GameControllerSetPlayerIndex(ctrl->m_controller, -1);
|
||||||
|
}
|
||||||
|
|
||||||
void __PADLoadMapping(aurora::input::GameController* controller) {
|
void __PADLoadMapping(aurora::input::GameController* controller) {
|
||||||
s32 playerIndex = SDL_GameControllerGetPlayerIndex(controller->m_controller);
|
s32 playerIndex = SDL_GameControllerGetPlayerIndex(controller->m_controller);
|
||||||
if (playerIndex == -1) {
|
if (playerIndex == -1) {
|
||||||
|
@ -402,11 +471,9 @@ void __PADLoadMapping(aurora::input::GameController* controller) {
|
||||||
|
|
||||||
controller->m_mappingLoaded = true;
|
controller->m_mappingLoaded = true;
|
||||||
|
|
||||||
FILE* file =
|
auto path = fmt::format(FMT_STRING("{}/{}_{:04X}_{:04X}.controller"), basePath, PADGetName(playerIndex),
|
||||||
fopen(fmt::format(FMT_STRING("{}/{}_{:04X}_{:04X}.controller"), basePath,
|
controller->m_vid, controller->m_pid);
|
||||||
aurora::input::controller_name(controller->m_index), controller->m_vid, controller->m_pid)
|
FILE* file = fopen(path.c_str(), "rbe");
|
||||||
.c_str(),
|
|
||||||
"rbe");
|
|
||||||
if (file == nullptr) {
|
if (file == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -434,7 +501,7 @@ void __PADLoadMapping(aurora::input::GameController* controller) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fread(&controller->m_deadZones, 1, sizeof(PADDeadZones), file);
|
fread(&controller->m_deadZones, 1, sizeof(PADDeadZones), file);
|
||||||
fread(&controller->m_mapping, 1, sizeof(PADButtonMapping), file);
|
fread(&controller->m_mapping, 1, sizeof(PADButtonMapping) * controller->m_mapping.size(), file);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,9 +522,6 @@ u32 PADRead(PAD::Status* status) {
|
||||||
|
|
||||||
if (!controller->m_mappingLoaded) {
|
if (!controller->m_mappingLoaded) {
|
||||||
__PADLoadMapping(controller);
|
__PADLoadMapping(controller);
|
||||||
#ifndef NDEBUG
|
|
||||||
PADSerializeMappings();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
status[i].xa_err = PAD::ERR_NONE;
|
status[i].xa_err = PAD::ERR_NONE;
|
||||||
std::for_each(controller->m_mapping.begin(), controller->m_mapping.end(),
|
std::for_each(controller->m_mapping.begin(), controller->m_mapping.end(),
|
||||||
|
@ -563,7 +627,7 @@ void PADControlAllMotors(const u32* commands) {
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 SIProbe(s32 chan) {
|
u32 SIProbe(s32 chan) {
|
||||||
auto *const controller = aurora::input::get_controller_for_player(chan);
|
auto* const controller = aurora::input::get_controller_for_player(chan);
|
||||||
if (controller == nullptr) {
|
if (controller == nullptr) {
|
||||||
return SI::ERROR_NO_RESPONSE;
|
return SI::ERROR_NO_RESPONSE;
|
||||||
}
|
}
|
||||||
|
@ -735,26 +799,10 @@ void PADClampCircle(PAD::Status* status) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PADGetCount() { return aurora::input::g_GameControllers.size(); }
|
void PADGetVidPid(u32 port, u32* vid, u32* pid) {
|
||||||
|
|
||||||
aurora::input::GameController* __PADGetController(s32 idx) {
|
|
||||||
auto iter = aurora::input::g_GameControllers.begin();
|
|
||||||
s32 i = 0;
|
|
||||||
for (; aurora::input::g_GameControllers.begin() != aurora::input::g_GameControllers.end() && i < idx; ++iter, ++i) {}
|
|
||||||
if (iter == aurora::input::g_GameControllers.end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return &iter->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PADGetVidPid(u32 idx, u32* vid, u32* pid) {
|
|
||||||
*vid = 0;
|
*vid = 0;
|
||||||
*pid = 0;
|
*pid = 0;
|
||||||
if (idx < 0 || idx >= aurora::input::g_GameControllers.size()) {
|
auto* controller = aurora::input::get_controller_for_player(port);
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto* controller = __PADGetController(idx);
|
|
||||||
if (controller == nullptr) {
|
if (controller == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -763,8 +811,8 @@ void PADGetVidPid(u32 idx, u32* vid, u32* pid) {
|
||||||
*pid = controller->m_pid;
|
*pid = controller->m_pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* PADGetName(u32 idx) {
|
const char* PADGetName(u32 port) {
|
||||||
auto* controller = __PADGetController(idx);
|
auto* controller = aurora::input::get_controller_for_player(port);
|
||||||
if (controller == nullptr) {
|
if (controller == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -916,6 +964,4 @@ void PADRestoreDefaultMapping(u32 port) {
|
||||||
controller->m_mapping = mDefaultButtons;
|
controller->m_mapping = mDefaultButtons;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PADBlockInput(bool block) {
|
void PADBlockInput(bool block) { gBlockPAD = block; }
|
||||||
gBlockPAD = block;
|
|
||||||
}
|
|
Loading…
Reference in New Issue