mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-11-26 03:12:18 -05:00
Controllers (#3378)
* lay some groundwork * use custom window (which is currently identical to the LUS window) * start making it shippy * start moving stuff out of gamecontroleditor * clean up shouldrumble * include the other way * wii u * latest lus main * notch snap angle buttons * buttons on all the sliders * just use a hidden id * handle debug for port 2 and rename tabs so everything fits * button line buttons look better * padding fixed * clang format * bump to latest LUS main * big buttons * just default the analog stick options to open for now * fix wii u build * bonus: make it all scale-aware * clang format * fix horizontal scrolling * fix all +/- buttons * keyboard set defaults * axis threshold helper text * bonus: test rumble button * clang format * fix otrexporter submodule * bump to latest lus main
This commit is contained in:
parent
34556e40d6
commit
76e90c0928
@ -1 +1 @@
|
||||
Subproject commit f717dd265aff2eff359de26915d8ad4e498ffdaf
|
||||
Subproject commit 1b41afa9eaedb19a9073f5dd1eca2cda4dea59c8
|
@ -14,6 +14,8 @@
|
||||
#include <Utils/StringHelper.h>
|
||||
#include <libultraship/libultraship.h>
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
#include "../../UIWidgets.hpp"
|
||||
|
||||
namespace GameControlEditor {
|
||||
@ -214,16 +216,6 @@ namespace GameControlEditor {
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
// CurrentPort is indexed started at 1 here due to the Generic tab, instead of 0 like in InputEditorWindow
|
||||
// Therefore CurrentPort - 1 must always be used inside this function instead of CurrentPort
|
||||
void DrawCustomButtons() {
|
||||
auto inputEditorWindow = std::reinterpret_pointer_cast<LUS::InputEditorWindow>(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Input Editor"));
|
||||
inputEditorWindow->DrawControllerSelect(CurrentPort - 1);
|
||||
|
||||
inputEditorWindow->DrawButton("Modifier 1", BTN_MODIFIER1, CurrentPort - 1, &BtnReading);
|
||||
inputEditorWindow->DrawButton("Modifier 2", BTN_MODIFIER2, CurrentPort - 1, &BtnReading);
|
||||
}
|
||||
|
||||
void DrawCameraControlPanel(GameControlEditorWindow* window) {
|
||||
if (!ImGui::CollapsingHeader("Camera Controls")) {
|
||||
return;
|
||||
@ -329,70 +321,14 @@ namespace GameControlEditor {
|
||||
window->EndGroupPanelPublic(0);
|
||||
}
|
||||
|
||||
void DrawLEDControlPanel(GameControlEditorWindow* window) {
|
||||
window->BeginGroupPanelPublic("LED Colors", ImGui::GetContentRegionAvail());
|
||||
static const char* ledSources[] = { "Original Tunic Colors", "Cosmetics Tunic Colors", "Health Colors",
|
||||
"Original Navi Targeting Colors", "Cosmetics Navi Targeting Colors", "Custom" };
|
||||
UIWidgets::PaddedText("Source");
|
||||
UIWidgets::EnhancementCombobox("gLedColorSource", ledSources, LED_SOURCE_TUNIC_ORIGINAL);
|
||||
DrawHelpIcon("Health\n- Red when health critical (13-20% depending on max health)\n- Yellow when health < 40%. Green otherwise.\n\n" \
|
||||
"Tunics: colors will mirror currently equipped tunic, whether original or the current values in Cosmetics Editor.\n\n" \
|
||||
"Custom: single, solid color");
|
||||
if (CVarGetInteger("gLedColorSource", 1) == LED_SOURCE_CUSTOM) {
|
||||
UIWidgets::Spacer(3);
|
||||
auto port1Color = CVarGetColor24("gLedPort1Color", { 255, 255, 255 });
|
||||
ImVec4 colorVec = { port1Color.r / 255.0f, port1Color.g / 255.0f, port1Color.b / 255.0f, 1.0f };
|
||||
if (ImGui::ColorEdit3("", (float*)&colorVec, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel)) {
|
||||
Color_RGB8 color;
|
||||
color.r = colorVec.x * 255.0;
|
||||
color.g = colorVec.y * 255.0;
|
||||
color.b = colorVec.z * 255.0;
|
||||
|
||||
CVarSetColor24("gLedPort1Color", color);
|
||||
LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("Custom Color");
|
||||
}
|
||||
UIWidgets::PaddedEnhancementSliderFloat("Brightness: %d%%", "##LED_Brightness", "gLedBrightness",
|
||||
0.0f, 1.0f, "", 1.0f, true, true);
|
||||
DrawHelpIcon("Sets the brightness of controller LEDs. 0% brightness = LEDs off.");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Critical Health Override", "gLedCriticalOverride", true, true,
|
||||
CVarGetInteger("gLedColorSource", LED_SOURCE_TUNIC_ORIGINAL) == LED_SOURCE_HEALTH, "Override redundant for health source.",
|
||||
UIWidgets::CheckboxGraphics::Cross, true);
|
||||
DrawHelpIcon("Shows red color when health is critical, otherwise displays according to color source.");
|
||||
window->EndGroupPanelPublic(0);
|
||||
}
|
||||
|
||||
void GameControlEditorWindow::DrawElement() {
|
||||
ImGui::SetNextWindowSize(ImVec2(465, 430), ImGuiCond_FirstUseEver);
|
||||
if (ImGui::Begin("Game Controls Configuration", &mIsVisible)) {
|
||||
ImGui::BeginTabBar("##CustomControllers");
|
||||
if (ImGui::BeginTabItem("Generic")) {
|
||||
CurrentPort = 0;
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
for (int i = 1; i <= 4; i++) {
|
||||
if (ImGui::BeginTabItem(StringHelper::Sprintf("Port %d", i).c_str())) {
|
||||
CurrentPort = i;
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
|
||||
if (CurrentPort == 0) {
|
||||
DrawOcarinaControlPanel(this);
|
||||
DrawCameraControlPanel(this);
|
||||
DrawDpadControlPanel(this);
|
||||
DrawMiscControlPanel(this);
|
||||
} else {
|
||||
DrawCustomButtons();
|
||||
if (CurrentPort == 1 && LUS::Context::GetInstance()->GetControlDeck()->GetDeviceFromPortIndex(0)->CanSetLed()) {
|
||||
DrawLEDControlPanel(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
1902
soh/soh/Enhancements/controls/SohInputEditorWindow.cpp
Normal file
1902
soh/soh/Enhancements/controls/SohInputEditorWindow.cpp
Normal file
File diff suppressed because it is too large
Load Diff
86
soh/soh/Enhancements/controls/SohInputEditorWindow.h
Normal file
86
soh/soh/Enhancements/controls/SohInputEditorWindow.h
Normal file
@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include "stdint.h"
|
||||
#include <libultraship/libultraship.h>
|
||||
#include <ImGui/imgui.h>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
class SohInputEditorWindow : public LUS::GuiWindow {
|
||||
public:
|
||||
using GuiWindow::GuiWindow;
|
||||
~SohInputEditorWindow();
|
||||
|
||||
void DrawButton(const char* label, int32_t n64Btn, int32_t currentPort, int32_t* btnReading);
|
||||
|
||||
void DrawInputChip(const char* buttonName, ImVec4 color);
|
||||
void DrawAnalogPreview(const char* label, ImVec2 stick, float deadzone = 0, bool gyro = false);
|
||||
void DrawControllerSchema();
|
||||
bool TestingRumble();
|
||||
|
||||
protected:
|
||||
void InitElement() override;
|
||||
void DrawElement() override;
|
||||
void UpdateElement() override;
|
||||
|
||||
private:
|
||||
void DrawStickDirectionLine(const char* axisDirectionName, uint8_t port, uint8_t stick, LUS::Direction direction,
|
||||
ImVec4 color);
|
||||
void DrawButtonLine(const char* buttonName, uint8_t port, uint16_t bitmask, ImVec4 color);
|
||||
void DrawButtonLineEditMappingButton(uint8_t port, uint16_t bitmask, std::string id);
|
||||
void DrawButtonLineAddMappingButton(uint8_t port, uint16_t bitmask);
|
||||
|
||||
void DrawStickDirectionLineEditMappingButton(uint8_t port, uint8_t stick, LUS::Direction direction, std::string id);
|
||||
void DrawStickDirectionLineAddMappingButton(uint8_t port, uint8_t stick, LUS::Direction direction);
|
||||
void DrawStickSection(uint8_t port, uint8_t stick, int32_t id, ImVec4 color);
|
||||
|
||||
void DrawRumbleSection(uint8_t port);
|
||||
void DrawRemoveRumbleMappingButton(uint8_t port, std::string id);
|
||||
void DrawAddRumbleMappingButton(uint8_t port);
|
||||
|
||||
void DrawLEDSection(uint8_t port);
|
||||
void DrawRemoveLEDMappingButton(uint8_t port, std::string id);
|
||||
void DrawAddLEDMappingButton(uint8_t port);
|
||||
|
||||
void DrawGyroSection(uint8_t port);
|
||||
void DrawRemoveGyroMappingButton(uint8_t port, std::string id);
|
||||
void DrawAddGyroMappingButton(uint8_t port);
|
||||
|
||||
int32_t mGameInputBlockTimer;
|
||||
int32_t mMappingInputBlockTimer;
|
||||
int32_t mRumbleTimer;
|
||||
std::shared_ptr<LUS::ControllerRumbleMapping> mRumbleMappingToTest;
|
||||
|
||||
// mBitmaskToMappingIds[port][bitmask] = { id0, id1, ... }
|
||||
std::unordered_map<uint8_t, std::unordered_map<uint16_t, std::vector<std::string>>> mBitmaskToMappingIds;
|
||||
|
||||
// mStickDirectionToMappingIds[port][stick][direction] = { id0, id1, ... }
|
||||
std::unordered_map<uint8_t,
|
||||
std::unordered_map<uint8_t, std::unordered_map<LUS::Direction, std::vector<std::string>>>>
|
||||
mStickDirectionToMappingIds;
|
||||
|
||||
void UpdateBitmaskToMappingIds(uint8_t port);
|
||||
void UpdateStickDirectionToMappingIds(uint8_t port);
|
||||
|
||||
void GetButtonColorsForLUSDeviceIndex(LUS::LUSDeviceIndex lusIndex, ImVec4& buttonColor,
|
||||
ImVec4& buttonHoveredColor);
|
||||
void DrawLinkTab();
|
||||
void DrawIvanTab();
|
||||
void DrawDebugPortTab(uint8_t portIndex, std::string customName = "");
|
||||
void DrawDevicesTab();
|
||||
std::set<uint16_t> mButtonsBitmasks;
|
||||
std::set<uint16_t> mDpadBitmasks;
|
||||
std::set<uint16_t> mModifierButtonsBitmasks;
|
||||
void DrawButtonDeviceIcons(uint8_t portIndex, std::set<uint16_t> bitmasks);
|
||||
void DrawAnalogStickDeviceIcons(uint8_t portIndex, LUS::Stick stick);
|
||||
void DrawRumbleDeviceIcons(uint8_t portIndex);
|
||||
void DrawGyroDeviceIcons(uint8_t portIndex);
|
||||
void DrawLEDDeviceIcons(uint8_t portIndex);
|
||||
bool mInputEditorPopupOpen;
|
||||
void DrawSetDefaultsButton(uint8_t portIndex);
|
||||
void DrawClearAllButton(uint8_t portIndex);
|
||||
|
||||
void DrawHelpIcon(const std::string& helptext);
|
||||
};
|
@ -30,6 +30,7 @@
|
||||
#include <AudioPlayer.h>
|
||||
#include "Enhancements/speechsynthesizer/SpeechSynthesizer.h"
|
||||
#include "Enhancements/controls/GameControlEditor.h"
|
||||
#include "Enhancements/controls/SohInputEditorWindow.h"
|
||||
#include "Enhancements/cosmetics/CosmeticsEditor.h"
|
||||
#include "Enhancements/audio/AudioCollection.h"
|
||||
#include "Enhancements/audio/AudioEditor.h"
|
||||
@ -279,8 +280,25 @@ OTRGlobals::OTRGlobals() {
|
||||
OOT_PAL_GC_DBG1,
|
||||
OOT_PAL_GC_DBG2
|
||||
};
|
||||
|
||||
context = LUS::Context::CreateUninitializedInstance("Ship of Harkinian", appShortName, "shipofharkinian.json");
|
||||
|
||||
context->InitLogging();
|
||||
context->InitConfiguration();
|
||||
context->InitConsoleVariables();
|
||||
|
||||
// tell LUS to reserve 3 SoH specific threads (Game, Audio, Save)
|
||||
context = LUS::Context::CreateInstance("Ship of Harkinian", appShortName, "shipofharkinian.json", OTRFiles, {}, 3);
|
||||
context->InitResourceManager(OTRFiles, {}, 3);
|
||||
|
||||
context->InitControlDeck({BTN_MODIFIER1, BTN_MODIFIER2});
|
||||
context->GetControlDeck()->SetSinglePlayerMappingMode(true);
|
||||
|
||||
context->InitCrashHandler();
|
||||
context->InitConsole();
|
||||
|
||||
auto sohInputEditorWindow = std::make_shared<SohInputEditorWindow>("gControllerConfigurationEnabled", "Input Editor");
|
||||
context->InitWindow(sohInputEditorWindow);
|
||||
context->InitAudio();
|
||||
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Animation, "Animation", std::make_shared<LUS::AnimationFactory>());
|
||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_PlayerAnimation, "PlayerAnimation", std::make_shared<LUS::PlayerAnimationFactory>());
|
||||
@ -2065,15 +2083,22 @@ Color_RGB8 GetColorForControllerLED() {
|
||||
}
|
||||
|
||||
extern "C" void OTRControllerCallback(uint8_t rumble) {
|
||||
auto physicalDevice = LUS::Context::GetInstance()->GetControlDeck()->GetDeviceFromPortIndex(0);
|
||||
|
||||
if (physicalDevice->CanSetLed()) {
|
||||
// We call this every tick, SDL accounts for this use and prevents driver spam
|
||||
// https://github.com/libsdl-org/SDL/blob/f17058b562c8a1090c0c996b42982721ace90903/src/joystick/SDL_joystick.c#L1114-L1144
|
||||
physicalDevice->SetLedColor(0, GetColorForControllerLED());
|
||||
LUS::Context::GetInstance()->GetControlDeck()->GetControllerByPort(0)->GetLED()->SetLEDColor(GetColorForControllerLED());
|
||||
|
||||
static std::shared_ptr<SohInputEditorWindow> controllerConfigWindow = nullptr;
|
||||
if (controllerConfigWindow == nullptr) {
|
||||
controllerConfigWindow = std::dynamic_pointer_cast<SohInputEditorWindow>(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Input Editor"));
|
||||
} else if (controllerConfigWindow->TestingRumble()) {
|
||||
return;
|
||||
}
|
||||
|
||||
physicalDevice->SetRumble(0, rumble);
|
||||
if (rumble) {
|
||||
LUS::Context::GetInstance()->GetControlDeck()->GetControllerByPort(0)->GetRumble()->StartRumble();
|
||||
} else {
|
||||
LUS::Context::GetInstance()->GetControlDeck()->GetControllerByPort(0)->GetRumble()->StopRumble();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" float OTRGetAspectRatio() {
|
||||
@ -2112,12 +2137,12 @@ extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len) {
|
||||
}
|
||||
|
||||
extern "C" int Controller_ShouldRumble(size_t slot) {
|
||||
auto controlDeck = LUS::Context::GetInstance()->GetControlDeck();
|
||||
|
||||
if (slot < controlDeck->GetNumConnectedPorts()) {
|
||||
auto physicalDevice = controlDeck->GetDeviceFromPortIndex(slot);
|
||||
|
||||
if (physicalDevice->GetProfile(slot)->UseRumble && physicalDevice->CanRumble()) {
|
||||
for (auto [id, mapping] : LUS::Context::GetInstance()
|
||||
->GetControlDeck()
|
||||
->GetControllerByPort(static_cast<uint8_t>(slot))
|
||||
->GetRumble()
|
||||
->GetAllRumbleMappings()) {
|
||||
if (mapping->PhysicalDeviceIsConnected()) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,9 @@
|
||||
#define GAME_PLATFORM_N64 0
|
||||
#define GAME_PLATFORM_GC 1
|
||||
|
||||
#define BTN_MODIFIER1 0x00040
|
||||
#define BTN_MODIFIER2 0x00080
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <Context.h>
|
||||
#include "Enhancements/savestates.h"
|
||||
|
Loading…
Reference in New Issue
Block a user