Merge branch 'main' into 26-03-27-better-mapping

This commit is contained in:
PJB3005
2026-04-10 03:50:32 +02:00
404 changed files with 14458 additions and 3069 deletions
+244 -88
View File
@@ -1,57 +1,102 @@
#include "fmt/format.h"
#include "imgui.h"
#include "aurora/gfx.h"
#include "ImGuiConsole.hpp"
#include "ImGuiMenuGame.hpp"
#include "ImGuiConfig.hpp"
#include <imgui_internal.h>
#include "JSystem/JUtility/JUTGamePad.h"
#include "dusk/audio/DuskAudioSystem.h"
#include "dusk/audio/DuskDsp.hpp"
#include "dusk/dusk.h"
#include "dusk/hotkeys.h"
#include "dusk/settings.h"
#include "m_Do/m_Do_controller_pad.h"
#include "m_Do/m_Do_audio.h"
#include "m_Do/m_Do_graphic.h"
#include <aurora/gfx.h>
#include <SDL3/SDL_gamepad.h>
namespace dusk {
void ImGuiMenuGame::ToggleFullscreen() {
getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen);
VISetWindowFullscreen(getSettings().video.enableFullscreen);
config::Save();
}
ImGuiMenuGame::ImGuiMenuGame() {}
void ImGuiMenuGame::draw() {
if (ImGui::BeginMenu("Game")) {
if (ImGui::MenuItem("Reset", "Ctrl+R")) {
if (ImGui::MenuItem("Reset", hotkeys::DO_RESET)) {
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
}
ImGui::Separator();
if (ImGui::BeginMenu("Graphics")) {
ImGui::Checkbox("Native Bloom", &m_graphicsSettings.m_enableBloom);
ImGui::Checkbox("Water Projection Offset", &m_graphicsSettings.m_waterProjectionOffset);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Adds GC-specific -0.01 transS offset\n"
"that causes ~6px ghost artifacts in water reflections");
if (ImGui::MenuItem("Toggle Fullscreen", hotkeys::TOGGLE_FULLSCREEN)) {
ToggleFullscreen();
}
if (ImGui::MenuItem("Default Window Size")) {
getSettings().video.enableFullscreen.setValue(false);
VISetWindowFullscreen(false);
VISetWindowSize(FB_WIDTH * 2, FB_HEIGHT * 2);
VICenterWindow();
}
bool vsync = getSettings().video.enableVsync;
if (ImGui::Checkbox("Enable Vsync", &vsync)) {
getSettings().video.enableVsync.setValue(vsync);
aurora_enable_vsync(vsync);
config::Save();
}
bool lockAspect = getSettings().video.lockAspectRatio;
if (ImGui::Checkbox("Force 4:3 Aspect Ratio", &lockAspect)) {
getSettings().video.lockAspectRatio.setValue(lockAspect);
if (lockAspect) {
VILockAspectRatio(defaultAspectRatioW, defaultAspectRatioH);
} else {
VIUnlockAspectRatio();
}
config::Save();
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Audio")) {
ImGui::Text("Master Volume");
ImGui::SliderFloat("##m_masterVolume", &m_audioSettings.m_masterVolume, 0.0f, 1.0f, "");
if (config::ImGuiSliderInt("##masterVolume", getSettings().audio.masterVolume, 0, 100)) {
dusk::audio::SetMasterVolume(getSettings().audio.masterVolume / 100.0f);
}
if (config::ImGuiCheckbox("Enable Reverb", getSettings().audio.enableReverb)) {
dusk::audio::SetEnableReverb(getSettings().audio.enableReverb);
}
/*
// TODO: Implement additional settings
ImGui::Text("Main Music Volume");
ImGui::SliderFloat("##m_mainMusicVolume", &m_audioSettings.m_mainMusicVolume, 0.0f, 1.0f, "");
ImGui::SliderFloat("##mainMusicVolume", &getSettings().audio.mainMusicVolume, 0, 100);
ImGui::Text("Sub Music Volume");
ImGui::SliderFloat("##m_subMusicVolume", &m_audioSettings.m_subMusicVolume, 0.0f, 1.0f, "");
ImGui::SliderFloat("##subMusicVolume", &getSettings().audio.subMusicVolume, 0, 100);
ImGui::Text("Sound Effects Volume");
ImGui::SliderFloat("##m_soundEffectsVolume", &m_audioSettings.m_soundEffectsVolume, 0.0f, 1.0f, "");
ImGui::SliderFloat("##soundEffectsVolume", &getSettings().audio.soundEffectsVolume, 0, 100);
ImGui::Text("Fanfare Volume");
ImGui::SliderFloat("##m_fanfareVolume", &m_audioSettings.m_fanfareVolume, 0.0f, 1.0f, "");
ImGui::SliderFloat("##fanfareVolume", &getSettings().audio.fanfareVolume, 0, 100);
Z2AudioMgr* audioMgr = Z2AudioMgr::getInterface();
if (audioMgr != nullptr) {
// TODO: actually apply volume settings
}
*/
ImGui::EndMenu();
}
@@ -68,20 +113,17 @@ namespace dusk {
windowInputViewer();
windowControllerConfig();
if ((ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) && ImGui::IsKeyPressed(ImGuiKey_R)) {
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
}
}
static void drawVirtualStick(const char* id, const ImVec2& stick) {
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 5, ImGui::GetCursorPos().y));
float scale = ImGuiScale();
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 45 * scale, ImGui::GetCursorPos().y + 10));
ImGui::BeginChild(id, ImVec2(80, 80));
ImGui::BeginChild(id, ImVec2(80 * scale, 80 * scale), 0, ImGuiWindowFlags_NoBackground);
ImDrawList* dl = ImGui::GetWindowDrawList();
ImVec2 p = ImGui::GetCursorScreenPos();
float radius = ImGui::GetCurrentContext()->CurrentDpiScale * 30.0f;
float radius = 30.0f * scale;
ImVec2 pos = ImVec2(p.x + radius, p.y + radius);
constexpr ImU32 stickGray = IM_COL32(150, 150, 150, 255);
@@ -89,7 +131,7 @@ namespace dusk {
constexpr ImU32 red = IM_COL32(230, 0, 0, 255);
dl->AddCircleFilled(pos, radius, stickGray, 8);
dl->AddCircleFilled(ImVec2(pos.x + stick.x * (radius), pos.y + -stick.y * (radius)), 3, red);
dl->AddCircleFilled(ImVec2(pos.x + stick.x * (radius), pos.y + -stick.y * (radius)), 3 * scale, red);
ImGui::EndChild();
}
@@ -155,6 +197,10 @@ namespace dusk {
// clang-format on
static const char* GetNameForGamepadButton(SDL_Gamepad* gamepad, u32 buttonUntyped) {
if (buttonUntyped == PAD_NATIVE_BUTTON_INVALID) {
return "Not bound";
}
auto button = static_cast<SDL_GamepadButton>(buttonUntyped);
auto label = SDL_GetGamepadButtonLabel(gamepad, button);
@@ -210,23 +256,44 @@ namespace dusk {
return;
}
// if pending for an input mapping, check to set new input
if (m_controllerConfig.m_pendingMapping != nullptr) {
// if pending for a button mapping, check to set new input
if (m_controllerConfig.m_pendingButtonMapping != nullptr) {
s32 nativeButton = PADGetNativeButtonPressed(m_controllerConfig.m_pendingPort);
if (nativeButton != -1) {
m_controllerConfig.m_pendingMapping->nativeButton = nativeButton;
m_controllerConfig.m_pendingMapping = nullptr;
m_controllerConfig.m_pendingButtonMapping->nativeButton = nativeButton;
m_controllerConfig.m_pendingButtonMapping = nullptr;
m_controllerConfig.m_pendingPort = -1;
PADBlockInput(false);
}
}
// if pending for an axis mapping, check to set new input
if (m_controllerConfig.m_pendingAxisMapping != nullptr) {
auto nativeAxis = PADGetNativeAxisPulled(m_controllerConfig.m_pendingPort);
if (nativeAxis.nativeAxis != -1) {
m_controllerConfig.m_pendingAxisMapping->nativeAxis = nativeAxis;
m_controllerConfig.m_pendingAxisMapping->nativeButton = -1;
m_controllerConfig.m_pendingAxisMapping = nullptr;
m_controllerConfig.m_pendingPort = -1;
PADBlockInput(false);
} else {
auto nativeButton = PADGetNativeButtonPressed(m_controllerConfig.m_pendingPort);
if (nativeButton != -1) {
m_controllerConfig.m_pendingAxisMapping->nativeAxis = {-1, AXIS_SIGN_POSITIVE};
m_controllerConfig.m_pendingAxisMapping->nativeButton = nativeButton;
m_controllerConfig.m_pendingAxisMapping = nullptr;
m_controllerConfig.m_pendingPort = -1;
PADBlockInput(false);
}
}
}
float scale = ImGuiScale();
ImGuiWindowFlags windowFlags =
ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_AlwaysAutoResize;
ImGui::SetNextWindowBgAlpha(0.65f);
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 400), ImVec2(850, 400));
if (!ImGui::Begin("Controller Config", &m_showControllerConfig, windowFlags)) {
ImGui::End();
@@ -244,10 +311,12 @@ namespace dusk {
ImGui::EndTabBar();
// if tab is changed while waiting for input, cancel pending
if (m_controllerConfig.m_pendingMapping != nullptr &&
if ((m_controllerConfig.m_pendingButtonMapping != nullptr ||
m_controllerConfig.m_pendingAxisMapping != nullptr) &&
m_controllerConfig.m_pendingPort != m_controllerConfig.m_selectedPort)
{
m_controllerConfig.m_pendingMapping = nullptr;
m_controllerConfig.m_pendingButtonMapping = nullptr;
m_controllerConfig.m_pendingAxisMapping = nullptr;
m_controllerConfig.m_pendingPort = -1;
PADBlockInput(false);
}
@@ -270,6 +339,7 @@ namespace dusk {
// controller selection combo box
bool changedController = false;
int changedControllerIndex = 0;
ImGui::SetNextItemWidth(400.0f * scale);
if (ImGui::BeginCombo("##ControllerDeviceList", currentName.c_str())) {
for (int i = 0; const auto& name : controllerList) {
if (ImGui::Selectable(name.c_str(), currentName == name)) {
@@ -305,35 +375,39 @@ namespace dusk {
}
// buttons panel
constexpr float buttonSize = 40;
const float uiButtonSize = 40 * scale;
ImGuiBeginGroupPanel("Buttons", ImVec2(150, 20));
ImGuiBeginGroupPanel("Buttons", ImVec2(150 * scale, 20 * scale));
SDL_Gamepad* gamepad = PADGetSDLGamepadForIndex(PADGetIndexForPort(m_controllerConfig.m_selectedPort));
u32 buttonCount;
PADButtonMapping* mappingList = PADGetButtonMappings(m_controllerConfig.m_selectedPort, &buttonCount);
if (mappingList != nullptr) {
PADButtonMapping* btnMappingList = PADGetButtonMappings(m_controllerConfig.m_selectedPort, &buttonCount);
if (btnMappingList != nullptr) {
for (int i = 0; i < buttonCount; i++) {
const char* btnName = PADGetButtonName(mappingList[i].padButton);
const char* btnName = PADGetButtonName(btnMappingList[i].padButton);
ImVec2 len = ImGui::CalcTextSize(btnName);
ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetCursorPosY(pos.y + len.y / 4);
ImGui::SetCursorPosX(pos.x + abs(len.x - buttonSize));
ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize));
ImGui::Text("%s", btnName);
ImGui::SameLine();
ImGui::SetCursorPosY(pos.y);
bool pressed = ImGui::Button(m_controllerConfig.m_isReading && m_controllerConfig.m_pendingMapping == &mappingList[i]
? fmt::format("Press a Key...##{}", btnName).c_str()
: fmt::format("{0}##-{1}", GetNameForGamepadButton(gamepad, mappingList[i].nativeButton), i).c_str(),
ImVec2(100.0f, 20.0f));
std::string dispName;
if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingButtonMapping == &btnMappingList[i]) {
dispName = fmt::format("Press a Key...##{}", btnName);
} else {
dispName = fmt::format("{0}##-{1}", GetNameForGamepadButton(gamepad, btnMappingList[i].nativeButton), i);
}
bool pressed = ImGui::Button(dispName.c_str(),
ImVec2(100.0f * scale, 20.0f * scale));
if (pressed) {
m_controllerConfig.m_isReading = true;
m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort;
m_controllerConfig.m_pendingMapping = &mappingList[i];
m_controllerConfig.m_pendingButtonMapping = &btnMappingList[i];
PADBlockInput(true);
}
}
@@ -342,39 +416,120 @@ namespace dusk {
ImGuiEndGroupPanel();
ImGui::SameLine();
int port = m_controllerConfig.m_selectedPort;
uint32_t axisCount;
PADAxisMapping* axisMappingList = PADGetAxisMappings(m_controllerConfig.m_selectedPort, &axisCount);
const char* stickDirections[] = {
"Up",
"Down",
"Left",
"Right",
};
ImGuiBeginGroupPanel("Analog Triggers", ImVec2(150 * scale, 20 * scale));
PADAxis triggers[] = {PAD_AXIS_TRIGGER_L, PAD_AXIS_TRIGGER_R};
if (axisMappingList != nullptr) {
for (PADAxis trigger : triggers) {
const char* axisName = PADGetAxisName(axisMappingList[trigger].padAxis);
ImVec2 len = ImGui::CalcTextSize(axisName);
ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetCursorPosY(pos.y + len.y / 4);
ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize));
ImGui::Text("%s", axisName);
ImGui::SameLine();
ImGui::SetCursorPosY(pos.y);
std::string dispName;
if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[trigger]) {
dispName = fmt::format("Press a Key...##{}", axisName);
} else {
dispName = fmt::format("{0}##-{1}", PADGetNativeAxisName(axisMappingList[trigger].nativeAxis), trigger);
}
bool pressed = ImGui::Button(dispName.c_str(),
ImVec2(100.0f * scale, 20.0f * scale));
if (pressed) {
m_controllerConfig.m_isReading = true;
m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort;
m_controllerConfig.m_pendingAxisMapping = &axisMappingList[trigger];
PADBlockInput(true);
}
}
}
int port = m_controllerConfig.m_selectedPort;
PADDeadZones* deadZones = PADGetDeadZones(port);
if (deadZones != nullptr) {
ImGui::Text("L Threshold");
ImGui::SameLine();
{
float tmp = static_cast<float>(deadZones->leftTriggerActivationZone * 100.f) / 32767.f;
if (ImGui::DragFloat("##LThreshold", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
deadZones->leftTriggerActivationZone = static_cast<u16>((tmp / 100.f) * 32767);
}
}
}
if (deadZones != nullptr) {
ImGui::Text("R Threshold");
ImGui::SameLine();
{
float tmp = static_cast<float>(deadZones->rightTriggerActivationZone * 100.f) / 32767.f;
if (ImGui::DragFloat("##RThreshold", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
deadZones->rightTriggerActivationZone = static_cast<u16>((tmp / 100.f) * 32767);
}
}
}
ImGuiEndGroupPanel();
ImGui::SameLine();
// main stick panel
ImGuiBeginGroupPanel("Control Stick", ImVec2(150, 20));
ImGuiBeginGroupPanel("Control Stick", ImVec2(150 * scale, 20 * scale));
drawVirtualStick("##mainStick", ImVec2{ mDoCPd_c::getStickX(port), mDoCPd_c::getStickY(port) });
{
for (int i = 0; i < 4; i++) {
const char* label = stickDirections[i];
if (axisMappingList != nullptr) {
const PADAxis lStickAxes[] = {PAD_AXIS_LEFT_Y_POS, PAD_AXIS_LEFT_Y_NEG, PAD_AXIS_LEFT_X_NEG, PAD_AXIS_LEFT_X_POS};
for (auto axis : lStickAxes) {
const char* label = PADGetAxisDirectionLabel(axis);
ImVec2 len = ImGui::CalcTextSize(label);
ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetCursorPosY(pos.y + len.y / 4);
ImGui::SetCursorPosX(pos.x + abs(len.x - buttonSize));
ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize));
ImGui::Text("%s", label);
ImGui::SameLine();
ImGui::SetCursorPosY(pos.y);
bool pressed = ImGui::Button(fmt::format("Temp##{}", label).c_str(), ImVec2(100.0f, 20.0f));
std::string dispName;
if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[axis]) {
dispName = fmt::format("Press a Key...##{}", label);
} else {
if (axisMappingList[axis].nativeAxis.nativeAxis != -1) {
const char* signStr;
if (axis == PAD_AXIS_TRIGGER_L || axis == PAD_AXIS_TRIGGER_R) {
signStr = "";
} else if (axisMappingList[axis].nativeAxis.sign == AXIS_SIGN_POSITIVE) {
signStr = "+";
} else {
signStr = "-";
}
dispName = fmt::format("{0}{1}##-{2}", PADGetNativeAxisName(axisMappingList[axis].nativeAxis), signStr, axis);
} else {
assert(axisMappingList[axis].nativeButton != -1);
dispName = fmt::format("{0}##-{1}", PADGetNativeButtonName(axisMappingList[axis].nativeButton), axis);
}
}
bool pressed = ImGui::Button(dispName.c_str(), ImVec2(100.0f * scale, 20.0f * scale));
if (pressed) {
m_controllerConfig.m_isReading = true;
m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort;
m_controllerConfig.m_pendingAxisMapping = &axisMappingList[axis];
PADBlockInput(true);
}
}
}
PADDeadZones* deadZones = PADGetDeadZones(port);
if (deadZones != nullptr) {
ImGui::Text("Dead Zone");
{
@@ -389,24 +544,51 @@ namespace dusk {
ImGui::SameLine();
// sub stick panel
ImGuiBeginGroupPanel("C Stick", ImVec2(150, 20));
ImGuiBeginGroupPanel("C Stick", ImVec2(150 * scale, 20 * scale));
drawVirtualStick("##subStick", ImVec2{ mDoCPd_c::getSubStickX(port), mDoCPd_c::getSubStickY(port) });
{
for (int i = 0; i < 4; i++) {
const char* label = stickDirections[i];
if (axisMappingList != nullptr) {
const PADAxis rStickAxes[] = {PAD_AXIS_RIGHT_Y_POS, PAD_AXIS_RIGHT_Y_NEG, PAD_AXIS_RIGHT_X_NEG, PAD_AXIS_RIGHT_X_POS};
for (auto axis : rStickAxes) {
const char* label = PADGetAxisDirectionLabel(axisMappingList[axis].padAxis);
ImVec2 len = ImGui::CalcTextSize(label);
ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetCursorPosY(pos.y + len.y / 4);
ImGui::SetCursorPosX(pos.x + abs(len.x - buttonSize));
ImGui::SetCursorPosX(pos.x + abs(len.x - uiButtonSize));
ImGui::Text("%s", label);
ImGui::SameLine();
ImGui::SetCursorPosY(pos.y);
bool pressed = ImGui::Button(fmt::format("Temp##sub{}", label).c_str(), ImVec2(100.0f, 20.0f));
std::string dispName;
if (m_controllerConfig.m_isReading && m_controllerConfig.m_pendingAxisMapping == &axisMappingList[axis]) {
dispName = fmt::format("Press a Key...##sub{}", label);
} else {
if (axisMappingList[axis].nativeAxis.nativeAxis != -1) {
const char* signStr;
if (axis == PAD_AXIS_TRIGGER_L || axis == PAD_AXIS_TRIGGER_R) {
signStr = "";
} else if (axisMappingList[axis].nativeAxis.sign == AXIS_SIGN_POSITIVE) {
signStr = "+";
} else {
signStr = "-";
}
dispName = fmt::format("{0}{1}##-{2}", PADGetNativeAxisName(axisMappingList[axis].nativeAxis), signStr, axis);
} else {
assert(axisMappingList[axis].nativeButton != -1);
dispName = fmt::format("{0}##-{1}", PADGetNativeButtonName(axisMappingList[axis].nativeButton), axis);
}
}
bool pressed = ImGui::Button(fmt::format("{0}##sub{1}", dispName, label).c_str(), ImVec2(100.0f * scale, 20.0f * scale));
if (pressed) {
m_controllerConfig.m_isReading = true;
m_controllerConfig.m_pendingPort = m_controllerConfig.m_selectedPort;
m_controllerConfig.m_pendingAxisMapping = &axisMappingList[axis];
PADBlockInput(true);
}
}
}
@@ -423,34 +605,8 @@ namespace dusk {
ImGuiEndGroupPanel();
ImGui::SameLine();
// Triggers Panel
ImGuiBeginGroupPanel("Triggers", ImVec2(150, 20));
if (deadZones != nullptr) {
ImGui::Text("L Threshold");
{
float tmp = static_cast<float>(deadZones->leftTriggerActivationZone * 100.f) / 32767.f;
if (ImGui::DragFloat("##LThreshold", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
deadZones->leftTriggerActivationZone = static_cast<u16>((tmp / 100.f) * 32767);
}
}
}
if (deadZones != nullptr) {
ImGui::Text("R Threshold");
{
float tmp = static_cast<float>(deadZones->rightTriggerActivationZone * 100.f) / 32767.f;
if (ImGui::DragFloat("##RThreshold", &tmp, 0.5f, 0.f, 100.f, "%.3f%%")) {
deadZones->rightTriggerActivationZone = static_cast<u16>((tmp / 100.f) * 32767);
}
}
}
ImGuiEndGroupPanel();
ImGui::SameLine();
// Options panel
ImGuiBeginGroupPanel("Options", ImVec2(150, 20));
ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, 20 * scale));
if (deadZones != nullptr) {
ImGui::Checkbox("Enable Dead Zones", &deadZones->useDeadzones);