mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-11-22 17:32:19 -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 <Utils/StringHelper.h>
|
||||||
#include <libultraship/libultraship.h>
|
#include <libultraship/libultraship.h>
|
||||||
|
|
||||||
|
#include "macros.h"
|
||||||
|
|
||||||
#include "../../UIWidgets.hpp"
|
#include "../../UIWidgets.hpp"
|
||||||
|
|
||||||
namespace GameControlEditor {
|
namespace GameControlEditor {
|
||||||
@ -214,16 +216,6 @@ namespace GameControlEditor {
|
|||||||
ImGui::EndTable();
|
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) {
|
void DrawCameraControlPanel(GameControlEditorWindow* window) {
|
||||||
if (!ImGui::CollapsingHeader("Camera Controls")) {
|
if (!ImGui::CollapsingHeader("Camera Controls")) {
|
||||||
return;
|
return;
|
||||||
@ -329,70 +321,14 @@ namespace GameControlEditor {
|
|||||||
window->EndGroupPanelPublic(0);
|
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() {
|
void GameControlEditorWindow::DrawElement() {
|
||||||
ImGui::SetNextWindowSize(ImVec2(465, 430), ImGuiCond_FirstUseEver);
|
ImGui::SetNextWindowSize(ImVec2(465, 430), ImGuiCond_FirstUseEver);
|
||||||
if (ImGui::Begin("Game Controls Configuration", &mIsVisible)) {
|
if (ImGui::Begin("Game Controls Configuration", &mIsVisible)) {
|
||||||
ImGui::BeginTabBar("##CustomControllers");
|
DrawOcarinaControlPanel(this);
|
||||||
if (ImGui::BeginTabItem("Generic")) {
|
DrawCameraControlPanel(this);
|
||||||
CurrentPort = 0;
|
DrawDpadControlPanel(this);
|
||||||
ImGui::EndTabItem();
|
DrawMiscControlPanel(this);
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
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 <AudioPlayer.h>
|
||||||
#include "Enhancements/speechsynthesizer/SpeechSynthesizer.h"
|
#include "Enhancements/speechsynthesizer/SpeechSynthesizer.h"
|
||||||
#include "Enhancements/controls/GameControlEditor.h"
|
#include "Enhancements/controls/GameControlEditor.h"
|
||||||
|
#include "Enhancements/controls/SohInputEditorWindow.h"
|
||||||
#include "Enhancements/cosmetics/CosmeticsEditor.h"
|
#include "Enhancements/cosmetics/CosmeticsEditor.h"
|
||||||
#include "Enhancements/audio/AudioCollection.h"
|
#include "Enhancements/audio/AudioCollection.h"
|
||||||
#include "Enhancements/audio/AudioEditor.h"
|
#include "Enhancements/audio/AudioEditor.h"
|
||||||
@ -279,9 +280,26 @@ OTRGlobals::OTRGlobals() {
|
|||||||
OOT_PAL_GC_DBG1,
|
OOT_PAL_GC_DBG1,
|
||||||
OOT_PAL_GC_DBG2
|
OOT_PAL_GC_DBG2
|
||||||
};
|
};
|
||||||
// tell LUS to reserve 3 SoH specific threads (Game, Audio, Save)
|
|
||||||
context = LUS::Context::CreateInstance("Ship of Harkinian", appShortName, "shipofharkinian.json", OTRFiles, {}, 3);
|
|
||||||
|
|
||||||
|
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->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_Animation, "Animation", std::make_shared<LUS::AnimationFactory>());
|
||||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_PlayerAnimation, "PlayerAnimation", std::make_shared<LUS::PlayerAnimationFactory>());
|
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_PlayerAnimation, "PlayerAnimation", std::make_shared<LUS::PlayerAnimationFactory>());
|
||||||
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Room, "Room", std::make_shared<LUS::SceneFactory>()); // Is room scene? maybe?
|
context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Room, "Room", std::make_shared<LUS::SceneFactory>()); // Is room scene? maybe?
|
||||||
@ -2065,15 +2083,22 @@ Color_RGB8 GetColorForControllerLED() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void OTRControllerCallback(uint8_t rumble) {
|
extern "C" void OTRControllerCallback(uint8_t rumble) {
|
||||||
auto physicalDevice = LUS::Context::GetInstance()->GetControlDeck()->GetDeviceFromPortIndex(0);
|
// 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
|
||||||
|
LUS::Context::GetInstance()->GetControlDeck()->GetControllerByPort(0)->GetLED()->SetLEDColor(GetColorForControllerLED());
|
||||||
|
|
||||||
if (physicalDevice->CanSetLed()) {
|
static std::shared_ptr<SohInputEditorWindow> controllerConfigWindow = nullptr;
|
||||||
// We call this every tick, SDL accounts for this use and prevents driver spam
|
if (controllerConfigWindow == nullptr) {
|
||||||
// https://github.com/libsdl-org/SDL/blob/f17058b562c8a1090c0c996b42982721ace90903/src/joystick/SDL_joystick.c#L1114-L1144
|
controllerConfigWindow = std::dynamic_pointer_cast<SohInputEditorWindow>(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Input Editor"));
|
||||||
physicalDevice->SetLedColor(0, GetColorForControllerLED());
|
} 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() {
|
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) {
|
extern "C" int Controller_ShouldRumble(size_t slot) {
|
||||||
auto controlDeck = LUS::Context::GetInstance()->GetControlDeck();
|
for (auto [id, mapping] : LUS::Context::GetInstance()
|
||||||
|
->GetControlDeck()
|
||||||
if (slot < controlDeck->GetNumConnectedPorts()) {
|
->GetControllerByPort(static_cast<uint8_t>(slot))
|
||||||
auto physicalDevice = controlDeck->GetDeviceFromPortIndex(slot);
|
->GetRumble()
|
||||||
|
->GetAllRumbleMappings()) {
|
||||||
if (physicalDevice->GetProfile(slot)->UseRumble && physicalDevice->CanRumble()) {
|
if (mapping->PhysicalDeviceIsConnected()) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
#define GAME_PLATFORM_N64 0
|
#define GAME_PLATFORM_N64 0
|
||||||
#define GAME_PLATFORM_GC 1
|
#define GAME_PLATFORM_GC 1
|
||||||
|
|
||||||
|
#define BTN_MODIFIER1 0x00040
|
||||||
|
#define BTN_MODIFIER2 0x00080
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#include <Context.h>
|
#include <Context.h>
|
||||||
#include "Enhancements/savestates.h"
|
#include "Enhancements/savestates.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user