Bump LUS and OTRExporter pt.3 (#984)

* Bump LUS and OTRExporter pt.3

* Remove outdated controller disclaimer
This commit is contained in:
Archez 2025-02-04 10:28:18 -05:00 committed by GitHub
parent eeed3ad367
commit 7896a0f648
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 305 additions and 471 deletions

2
.gitmodules vendored
View File

@ -3,7 +3,7 @@
url = https://github.com/kenix3/libultraship.git
[submodule "OTRExporter"]
path = OTRExporter
url = https://github.com/louist103/OTRExporter.git
url = https://github.com/HarbourMasters/OTRExporter.git
[submodule "ZAPDTR"]
path = ZAPDTR
url = https://github.com/louist103/ZAPDTR.git

@ -1 +1 @@
Subproject commit d2fd3202b47e6d46367bd43a72b3c20b69935be6
Subproject commit e9667ee75f6a1676b206192d4bba18005f4f6dff

@ -1 +1 @@
Subproject commit 4810a17e66a6827b522053aadf60632fef8c49d6
Subproject commit e641b3777cbefb18a9cf4b95353d650b3a2abf65

View File

@ -2,7 +2,6 @@
#include <spdlog/spdlog.h>
#include <imgui.h>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui_internal.h>
#include <libultraship/libultraship.h>
#include <Fast3D/gfx_pc.h>
@ -34,6 +33,7 @@ std::shared_ptr<BenMenuBar> mBenMenuBar;
std::shared_ptr<Ship::GuiWindow> mConsoleWindow;
std::shared_ptr<Ship::GuiWindow> mStatsWindow;
std::shared_ptr<Ship::GuiWindow> mGfxDebuggerWindow;
std::shared_ptr<Ship::GuiWindow> mInputEditorWindow;
std::shared_ptr<SaveEditorWindow> mSaveEditorWindow;
std::shared_ptr<HudEditorWindow> mHudEditorWindow;
@ -42,7 +42,6 @@ std::shared_ptr<ActorViewerWindow> mActorViewerWindow;
std::shared_ptr<CollisionViewerWindow> mCollisionViewerWindow;
std::shared_ptr<EventLogWindow> mEventLogWindow;
std::shared_ptr<BenMenu> mBenMenu;
std::shared_ptr<BenInputEditorWindow> mBenInputEditorWindow;
std::shared_ptr<Notification::Window> mNotificationWindow;
std::shared_ptr<ItemTrackerWindow> mItemTrackerWindow;
std::shared_ptr<ItemTrackerSettingsWindow> mItemTrackerSettingsWindow;
@ -84,8 +83,10 @@ void SetupGuiElements() {
SPDLOG_ERROR("Could not find input GfxDebuggerWindow");
}
mBenInputEditorWindow = std::make_shared<BenInputEditorWindow>("gWindows.BenInputEditor", "2S2H Input Editor");
gui->AddGuiWindow(mBenInputEditorWindow);
mInputEditorWindow = gui->GetGuiWindow("2S2H Input Editor");
if (mInputEditorWindow == nullptr) {
SPDLOG_ERROR("Could not find input editor window");
}
mSaveEditorWindow = std::make_shared<SaveEditorWindow>("gWindows.SaveEditor", "Save Editor", ImVec2(480, 600));
gui->AddGuiWindow(mSaveEditorWindow);
@ -127,8 +128,8 @@ void Destroy() {
mBenMenu = nullptr;
mStatsWindow = nullptr;
mConsoleWindow = nullptr;
mBenInputEditorWindow = nullptr;
mGfxDebuggerWindow = nullptr;
mInputEditorWindow = nullptr;
mCollisionViewerWindow = nullptr;
mEventLogWindow = nullptr;
mNotificationWindow = nullptr;

View File

@ -1,14 +1,12 @@
#include "BenInputEditorWindow.h"
#include "Context.h"
#include "Gui.h"
#include "utils/StringHelper.h"
#include "public/bridge/consolevariablebridge.h"
#ifndef __WIIU__
#include "controller/controldevice/controller/mapping/sdl/SDLAxisDirectionToButtonMapping.h"
#endif
#define SCALE_IMGUI_SIZE(value) ((value / 13.0f) * ImGui::GetFontSize())
BenInputEditorWindow::~BenInputEditorWindow() {
SPDLOG_TRACE("destruct input editor window");
}
void BenInputEditorWindow::InitElement() {
@ -21,12 +19,21 @@ void BenInputEditorWindow::InitElement() {
mButtonsBitmasks = { BTN_A, BTN_B, BTN_START, BTN_L, BTN_R, BTN_Z, BTN_CUP, BTN_CDOWN, BTN_CLEFT, BTN_CRIGHT };
mDpadBitmasks = { BTN_DUP, BTN_DDOWN, BTN_DLEFT, BTN_DRIGHT };
mDeviceIndexVisiblity.clear();
mDeviceIndexVisiblity[Ship::ShipDeviceIndex::Keyboard] = true;
mDeviceIndexVisiblity[Ship::ShipDeviceIndex::Blue] = true;
for (auto index = 1; index < Ship::ShipDeviceIndex::Max; index++) {
mDeviceIndexVisiblity[static_cast<Ship::ShipDeviceIndex>(index)] = false;
}
addButtonName(BTN_A, "A");
addButtonName(BTN_B, "B");
addButtonName(BTN_CUP, "C Up");
addButtonName(BTN_CDOWN, "C Down");
addButtonName(BTN_CLEFT, "C Left");
addButtonName(BTN_CRIGHT, "C Right");
addButtonName(BTN_L, "L");
addButtonName(BTN_Z, "Z");
addButtonName(BTN_R, "R");
addButtonName(BTN_START, "Start");
addButtonName(BTN_DUP, "D-pad up");
addButtonName(BTN_DDOWN, "D-pad down");
addButtonName(BTN_DLEFT, "D-pad left");
addButtonName(BTN_DRIGHT, "D-pad right");
addButtonName(0, "None");
}
#define INPUT_EDITOR_WINDOW_GAME_INPUT_BLOCK_ID 95237929
@ -150,6 +157,9 @@ void BenInputEditorWindow::DrawAnalogPreview(const char* label, ImVec2 stick, fl
#define BUTTON_COLOR_KEYBOARD_BEIGE ImVec4(0.651f, 0.482f, 0.357f, 0.5f)
#define BUTTON_COLOR_KEYBOARD_BEIGE_HOVERED ImVec4(0.651f, 0.482f, 0.357f, 1.0f)
#define BUTTON_COLOR_MOUSE_BEIGE ImVec4(0.5f, 0.5f, 0.5f, 0.5f)
#define BUTTON_COLOR_MOUSE_BEIGE_HOVERED ImVec4(0.5f, 0.5f, 0.5f, 1.0f)
#define BUTTON_COLOR_GAMEPAD_BLUE ImVec4(0.0f, 0.255f, 0.976f, 0.5f)
#define BUTTON_COLOR_GAMEPAD_BLUE_HOVERED ImVec4(0.0f, 0.255f, 0.976f, 1.0f)
@ -165,29 +175,21 @@ void BenInputEditorWindow::DrawAnalogPreview(const char* label, ImVec2 stick, fl
#define BUTTON_COLOR_GAMEPAD_PURPLE ImVec4(0.431f, 0.369f, 0.706f, 0.5f)
#define BUTTON_COLOR_GAMEPAD_PURPLE_HOVERED ImVec4(0.431f, 0.369f, 0.706f, 1.0f)
void BenInputEditorWindow::GetButtonColorsForShipDeviceIndex(Ship::ShipDeviceIndex lusIndex, ImVec4& buttonColor,
ImVec4& buttonHoveredColor) {
void BenInputEditorWindow::GetButtonColorsForDeviceType(Ship::PhysicalDeviceType lusIndex, ImVec4& buttonColor,
ImVec4& buttonHoveredColor) {
switch (lusIndex) {
case Ship::ShipDeviceIndex::Keyboard:
case Ship::PhysicalDeviceType::Keyboard:
buttonColor = BUTTON_COLOR_KEYBOARD_BEIGE;
buttonHoveredColor = BUTTON_COLOR_KEYBOARD_BEIGE_HOVERED;
break;
case Ship::ShipDeviceIndex::Blue:
case Ship::PhysicalDeviceType::Mouse:
buttonColor = BUTTON_COLOR_MOUSE_BEIGE;
buttonHoveredColor = BUTTON_COLOR_MOUSE_BEIGE_HOVERED;
break;
case Ship::PhysicalDeviceType::SDLGamepad:
buttonColor = BUTTON_COLOR_GAMEPAD_BLUE;
buttonHoveredColor = BUTTON_COLOR_GAMEPAD_BLUE_HOVERED;
break;
case Ship::ShipDeviceIndex::Red:
buttonColor = BUTTON_COLOR_GAMEPAD_RED;
buttonHoveredColor = BUTTON_COLOR_GAMEPAD_RED_HOVERED;
break;
case Ship::ShipDeviceIndex::Orange:
buttonColor = BUTTON_COLOR_GAMEPAD_ORANGE;
buttonHoveredColor = BUTTON_COLOR_GAMEPAD_ORANGE_HOVERED;
break;
case Ship::ShipDeviceIndex::Green:
buttonColor = BUTTON_COLOR_GAMEPAD_GREEN;
buttonHoveredColor = BUTTON_COLOR_GAMEPAD_GREEN_HOVERED;
break;
default:
buttonColor = BUTTON_COLOR_GAMEPAD_PURPLE;
buttonHoveredColor = BUTTON_COLOR_GAMEPAD_PURPLE_HOVERED;
@ -202,7 +204,7 @@ void BenInputEditorWindow::DrawInputChip(const char* buttonName, ImVec4 color =
ImGui::EndDisabled();
}
void BenInputEditorWindow::DrawButtonLineAddMappingButton(uint8_t port, CONTROLLERBUTTONS_T bitmask) {
void BenInputEditorWindow::DrawButtonLineAddMappingButton(uint8_t port, N64ButtonMask bitmask) {
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(1.0f, 0.5f));
auto popupId = StringHelper::Sprintf("addButtonMappingPopup##%d-%d", port, bitmask);
if (ImGui::Button(StringHelper::Sprintf("%s###addButtonMappingButton%d-%d", ICON_FA_PLUS, port, bitmask).c_str(),
@ -231,7 +233,7 @@ void BenInputEditorWindow::DrawButtonLineAddMappingButton(uint8_t port, CONTROLL
}
}
void BenInputEditorWindow::DrawButtonLineEditMappingButton(uint8_t port, CONTROLLERBUTTONS_T bitmask, std::string id) {
void BenInputEditorWindow::DrawButtonLineEditMappingButton(uint8_t port, N64ButtonMask bitmask, std::string id) {
auto mapping = Ship::Context::GetInstance()
->GetControlDeck()
->GetControllerByPort(port)
@ -240,9 +242,6 @@ void BenInputEditorWindow::DrawButtonLineEditMappingButton(uint8_t port, CONTROL
if (mapping == nullptr) {
return;
}
if (!mDeviceIndexVisiblity[mapping->GetShipDeviceIndex()]) {
return;
}
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f));
std::string icon = "";
@ -261,7 +260,7 @@ void BenInputEditorWindow::DrawButtonLineEditMappingButton(uint8_t port, CONTROL
auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
auto physicalInputDisplayName =
StringHelper::Sprintf("%s %s", icon.c_str(), mapping->GetPhysicalInputName().c_str());
GetButtonColorsForShipDeviceIndex(mapping->GetShipDeviceIndex(), buttonColor, buttonHoveredColor);
GetButtonColorsForDeviceType(mapping->GetPhysicalDeviceType(), buttonColor, buttonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_Button, buttonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor);
auto popupId = StringHelper::Sprintf("editButtonMappingPopup##%s", id.c_str());
@ -299,17 +298,11 @@ void BenInputEditorWindow::DrawButtonLineEditMappingButton(uint8_t port, CONTROL
ImGui::SameLine(0, 0);
auto sdlAxisDirectionToButtonMapping = std::dynamic_pointer_cast<Ship::SDLAxisDirectionToButtonMapping>(mapping);
auto indexMapping = Ship::Context::GetInstance()
->GetControlDeck()
->GetDeviceIndexMappingManager()
->GetDeviceIndexMappingFromShipDeviceIndex(mapping->GetShipDeviceIndex());
auto sdlIndexMapping = std::dynamic_pointer_cast<Ship::ShipDeviceIndexToSDLDeviceIndexMapping>(indexMapping);
if (sdlIndexMapping != nullptr && sdlAxisDirectionToButtonMapping != nullptr) {
if (sdlAxisDirectionToButtonMapping != nullptr) {
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f));
auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button);
auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
GetButtonColorsForShipDeviceIndex(mapping->GetShipDeviceIndex(), buttonColor, buttonHoveredColor);
GetButtonColorsForDeviceType(mapping->GetPhysicalDeviceType(), buttonColor, buttonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_Button, buttonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor);
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(1.0f, 0.5f));
@ -330,17 +323,19 @@ void BenInputEditorWindow::DrawButtonLineEditMappingButton(uint8_t port, CONTROL
ImGui::Text("Axis Threshold\n\nThe extent to which the joystick\nmust be moved or the trigger\npressed to "
"initiate the assigned\nbutton action.\n\n");
auto globalSettings = Ship::Context::GetInstance()->GetControlDeck()->GetGlobalSDLDeviceSettings();
if (sdlAxisDirectionToButtonMapping->AxisIsStick()) {
ImGui::Text("Stick axis threshold:");
int32_t stickAxisThreshold = sdlIndexMapping->GetStickAxisThresholdPercentage();
int32_t stickAxisThreshold = globalSettings->GetStickAxisThresholdPercentage();
if (stickAxisThreshold == 0) {
ImGui::BeginDisabled();
}
ImGui::PushButtonRepeat(true);
if (ImGui::Button(StringHelper::Sprintf("-##Stick Axis Threshold%s", id.c_str()).c_str())) {
sdlIndexMapping->SetStickAxisThresholdPercentage(stickAxisThreshold - 1);
sdlIndexMapping->SaveToConfig();
globalSettings->SetStickAxisThresholdPercentage(stickAxisThreshold - 1);
globalSettings->SaveToConfig();
}
ImGui::PopButtonRepeat();
if (stickAxisThreshold == 0) {
@ -350,8 +345,8 @@ void BenInputEditorWindow::DrawButtonLineEditMappingButton(uint8_t port, CONTROL
ImGui::SetNextItemWidth(SCALE_IMGUI_SIZE(160.0f));
if (ImGui::SliderInt(StringHelper::Sprintf("##Stick Axis Threshold%s", id.c_str()).c_str(),
&stickAxisThreshold, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp)) {
sdlIndexMapping->SetStickAxisThresholdPercentage(stickAxisThreshold);
sdlIndexMapping->SaveToConfig();
globalSettings->SetStickAxisThresholdPercentage(stickAxisThreshold);
globalSettings->SaveToConfig();
}
ImGui::SameLine(0.0f, 0.0f);
if (stickAxisThreshold == 100) {
@ -359,8 +354,8 @@ void BenInputEditorWindow::DrawButtonLineEditMappingButton(uint8_t port, CONTROL
}
ImGui::PushButtonRepeat(true);
if (ImGui::Button(StringHelper::Sprintf("+##Stick Axis Threshold%s", id.c_str()).c_str())) {
sdlIndexMapping->SetStickAxisThresholdPercentage(stickAxisThreshold + 1);
sdlIndexMapping->SaveToConfig();
globalSettings->SetStickAxisThresholdPercentage(stickAxisThreshold + 1);
globalSettings->SaveToConfig();
}
ImGui::PopButtonRepeat();
if (stickAxisThreshold == 100) {
@ -371,14 +366,14 @@ void BenInputEditorWindow::DrawButtonLineEditMappingButton(uint8_t port, CONTROL
if (sdlAxisDirectionToButtonMapping->AxisIsTrigger()) {
ImGui::Text("Trigger axis threshold:");
int32_t triggerAxisThreshold = sdlIndexMapping->GetTriggerAxisThresholdPercentage();
int32_t triggerAxisThreshold = globalSettings->GetTriggerAxisThresholdPercentage();
if (triggerAxisThreshold == 0) {
ImGui::BeginDisabled();
}
ImGui::PushButtonRepeat(true);
if (ImGui::Button(StringHelper::Sprintf("-##Trigger Axis Threshold%s", id.c_str()).c_str())) {
sdlIndexMapping->SetTriggerAxisThresholdPercentage(triggerAxisThreshold - 1);
sdlIndexMapping->SaveToConfig();
globalSettings->SetTriggerAxisThresholdPercentage(triggerAxisThreshold - 1);
globalSettings->SaveToConfig();
}
ImGui::PopButtonRepeat();
if (triggerAxisThreshold == 0) {
@ -388,8 +383,8 @@ void BenInputEditorWindow::DrawButtonLineEditMappingButton(uint8_t port, CONTROL
ImGui::SetNextItemWidth(SCALE_IMGUI_SIZE(160.0f));
if (ImGui::SliderInt(StringHelper::Sprintf("##Trigger Axis Threshold%s", id.c_str()).c_str(),
&triggerAxisThreshold, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp)) {
sdlIndexMapping->SetTriggerAxisThresholdPercentage(triggerAxisThreshold);
sdlIndexMapping->SaveToConfig();
globalSettings->SetTriggerAxisThresholdPercentage(triggerAxisThreshold);
globalSettings->SaveToConfig();
}
ImGui::SameLine(0.0f, 0.0f);
if (triggerAxisThreshold == 100) {
@ -397,8 +392,8 @@ void BenInputEditorWindow::DrawButtonLineEditMappingButton(uint8_t port, CONTROL
}
ImGui::PushButtonRepeat(true);
if (ImGui::Button(StringHelper::Sprintf("+##Trigger Axis Threshold%s", id.c_str()).c_str())) {
sdlIndexMapping->SetTriggerAxisThresholdPercentage(triggerAxisThreshold + 1);
sdlIndexMapping->SaveToConfig();
globalSettings->SetTriggerAxisThresholdPercentage(triggerAxisThreshold + 1);
globalSettings->SaveToConfig();
}
ImGui::PopButtonRepeat();
if (triggerAxisThreshold == 100) {
@ -436,7 +431,7 @@ void BenInputEditorWindow::DrawButtonLineEditMappingButton(uint8_t port, CONTROL
ImGui::SameLine(0, SCALE_IMGUI_SIZE(4.0f));
}
void BenInputEditorWindow::DrawButtonLine(const char* buttonName, uint8_t port, CONTROLLERBUTTONS_T bitmask,
void BenInputEditorWindow::DrawButtonLine(const char* buttonName, uint8_t port, N64ButtonMask bitmask,
ImVec4 color = CHIP_COLOR_N64_GREY) {
ImGui::NewLine();
ImGui::SameLine(SCALE_IMGUI_SIZE(32.0f));
@ -511,9 +506,6 @@ void BenInputEditorWindow::DrawStickDirectionLineEditMappingButton(uint8_t port,
if (mapping == nullptr) {
return;
}
if (!mDeviceIndexVisiblity[mapping->GetShipDeviceIndex()]) {
return;
}
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f));
std::string icon = "";
@ -532,7 +524,7 @@ void BenInputEditorWindow::DrawStickDirectionLineEditMappingButton(uint8_t port,
auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
auto physicalInputDisplayName =
StringHelper::Sprintf("%s %s", icon.c_str(), mapping->GetPhysicalInputName().c_str());
GetButtonColorsForShipDeviceIndex(mapping->GetShipDeviceIndex(), buttonColor, buttonHoveredColor);
GetButtonColorsForDeviceType(mapping->GetPhysicalDeviceType(), buttonColor, buttonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_Button, buttonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor);
auto popupId = StringHelper::Sprintf("editStickDirectionMappingPopup##%s", id.c_str());
@ -857,7 +849,7 @@ void BenInputEditorWindow::DrawRumbleSection(uint8_t port) {
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button);
auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
GetButtonColorsForShipDeviceIndex(mapping->GetShipDeviceIndex(), buttonColor, buttonHoveredColor);
GetButtonColorsForDeviceType(mapping->GetPhysicalDeviceType(), buttonColor, buttonHoveredColor);
// begin hackaround https://github.com/ocornut/imgui/issues/282#issuecomment-123763192
// spaces to have background color for text in a tree node
std::string spaces = "";
@ -1189,267 +1181,123 @@ void BenInputEditorWindow::DrawGyroSection(uint8_t port) {
}
}
void BenInputEditorWindow::DrawButtonDeviceIcons(uint8_t portIndex, std::set<CONTROLLERBUTTONS_T> bitmasks) {
std::set<Ship::ShipDeviceIndex> allLusDeviceIndices;
allLusDeviceIndices.insert(Ship::ShipDeviceIndex::Keyboard);
for (auto [lusIndex, mapping] : Ship::Context::GetInstance()
->GetControlDeck()
->GetDeviceIndexMappingManager()
->GetAllDeviceIndexMappingsFromConfig()) {
allLusDeviceIndices.insert(lusIndex);
const ImGuiTableFlags PANEL_TABLE_FLAGS = ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV;
const ImGuiTableColumnFlags PANEL_TABLE_COLUMN_FLAGS =
ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_NoSort;
namespace TableHelper {
void InitHeader(bool has_header = true) {
if (has_header) {
ImGui::TableHeadersRow();
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding(); // This is to adjust Vertical pos of item in a cell to be normlized.
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
}
void NextCol() {
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
}
void NextLine() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
}
} // namespace TableHelper
void BenInputEditorWindow::addButtonName(N64ButtonMask mask, const char* name) {
buttons.push_back(std::make_pair(mask, name));
buttonNames[mask] = std::prev(buttons.end());
}
// Draw a button mapping setting consisting of a padded label and button dropdown.
// excludedButtons indicates which buttons are unavailable to choose from.
void BenInputEditorWindow::DrawMapping(CustomButtonMap& mapping, float labelWidth, N64ButtonMask excludedButtons) {
N64ButtonMask currentButton = CVarGetInteger(mapping.cVarName, mapping.defaultBtn);
const char* preview;
if (buttonNames.contains(currentButton)) {
preview = buttonNames[currentButton]->second;
} else {
preview = "Unknown";
}
std::vector<std::pair<Ship::ShipDeviceIndex, bool>> lusDeviceIndiciesWithMappings;
for (auto lusIndex : allLusDeviceIndices) {
for (auto [bitmask, button] :
Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->GetAllButtons()) {
if (!bitmasks.contains(bitmask)) {
ImGui::Dummy(ImVec2(0.0f, 0.0f));
ImVec2 cursorPos = ImGui::GetCursorPos();
ImVec2 textSize = ImGui::CalcTextSize(mapping.label);
ImGui::SetCursorPosY(cursorPos.y + textSize.y / 4);
ImGui::SetCursorPosX(cursorPos.x + abs(textSize.x - labelWidth));
ImGui::Text("%s", mapping.label);
ImGui::SameLine();
ImGui::SetCursorPosY(cursorPos.y);
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
if (ImGui::BeginCombo(StringHelper::Sprintf("##%s", mapping.cVarName).c_str(), preview)) {
for (auto i = buttons.begin(); i != buttons.end(); i++) {
if ((i->first & excludedButtons) != 0) {
continue;
}
if (button->HasMappingsForShipDeviceIndex(lusIndex)) {
for (auto [id, mapping] : button->GetAllButtonMappings()) {
if (mapping->GetShipDeviceIndex() == lusIndex) {
lusDeviceIndiciesWithMappings.push_back(
std::pair<Ship::ShipDeviceIndex, bool>(lusIndex, mapping->PhysicalDeviceIsConnected()));
break;
}
}
break;
if (ImGui::Selectable(i->second, i->first == currentButton)) {
CVarSetInteger(mapping.cVarName, i->first);
Ship::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesNextFrame();
}
}
ImGui::EndCombo();
}
for (auto [lusIndex, connected] : lusDeviceIndiciesWithMappings) {
auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button);
auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
GetButtonColorsForShipDeviceIndex(lusIndex, buttonColor, buttonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_Button, buttonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor);
ImGui::SameLine();
if (lusIndex == Ship::ShipDeviceIndex::Keyboard) {
ImGui::SmallButton(ICON_FA_KEYBOARD_O);
} else {
ImGui::SmallButton(connected ? ICON_FA_GAMEPAD : ICON_FA_CHAIN_BROKEN);
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
}
ImGui::Dummy(ImVec2(0.0f, 0.0f));
}
void BenInputEditorWindow::DrawAnalogStickDeviceIcons(uint8_t portIndex, Ship::Stick stick) {
std::set<Ship::ShipDeviceIndex> allLusDeviceIndices;
allLusDeviceIndices.insert(Ship::ShipDeviceIndex::Keyboard);
for (auto [lusIndex, mapping] : Ship::Context::GetInstance()
->GetControlDeck()
->GetDeviceIndexMappingManager()
->GetAllDeviceIndexMappingsFromConfig()) {
allLusDeviceIndices.insert(lusIndex);
}
std::vector<std::pair<Ship::ShipDeviceIndex, bool>> lusDeviceIndiciesWithMappings;
for (auto lusIndex : allLusDeviceIndices) {
auto controllerStick =
stick == Ship::Stick::LEFT_STICK
? Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->GetLeftStick()
: Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->GetRightStick();
if (controllerStick->HasMappingsForShipDeviceIndex(lusIndex)) {
for (auto [direction, mappings] : controllerStick->GetAllAxisDirectionMappings()) {
bool foundMapping = false;
for (auto [id, mapping] : mappings) {
if (mapping->GetShipDeviceIndex() == lusIndex) {
foundMapping = true;
lusDeviceIndiciesWithMappings.push_back(
std::pair<Ship::ShipDeviceIndex, bool>(lusIndex, mapping->PhysicalDeviceIsConnected()));
break;
}
}
if (foundMapping) {
break;
}
}
}
}
for (auto [lusIndex, connected] : lusDeviceIndiciesWithMappings) {
auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button);
auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
GetButtonColorsForShipDeviceIndex(lusIndex, buttonColor, buttonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_Button, buttonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor);
ImGui::SameLine();
if (lusIndex == Ship::ShipDeviceIndex::Keyboard) {
ImGui::SmallButton(ICON_FA_KEYBOARD_O);
} else {
ImGui::SmallButton(connected ? ICON_FA_GAMEPAD : ICON_FA_CHAIN_BROKEN);
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
}
}
void BenInputEditorWindow::DrawRumbleDeviceIcons(uint8_t portIndex) {
std::set<Ship::ShipDeviceIndex> allLusDeviceIndices;
for (auto [lusIndex, mapping] : Ship::Context::GetInstance()
->GetControlDeck()
->GetDeviceIndexMappingManager()
->GetAllDeviceIndexMappingsFromConfig()) {
allLusDeviceIndices.insert(lusIndex);
}
std::vector<std::pair<Ship::ShipDeviceIndex, bool>> lusDeviceIndiciesWithMappings;
for (auto lusIndex : allLusDeviceIndices) {
if (Ship::Context::GetInstance()
->GetControlDeck()
->GetControllerByPort(portIndex)
->GetRumble()
->HasMappingsForShipDeviceIndex(lusIndex)) {
for (auto [id, mapping] : Ship::Context::GetInstance()
->GetControlDeck()
->GetControllerByPort(portIndex)
->GetRumble()
->GetAllRumbleMappings()) {
if (mapping->GetShipDeviceIndex() == lusIndex) {
lusDeviceIndiciesWithMappings.push_back(
std::pair<Ship::ShipDeviceIndex, bool>(lusIndex, mapping->PhysicalDeviceIsConnected()));
break;
}
}
}
}
for (auto [lusIndex, connected] : lusDeviceIndiciesWithMappings) {
auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button);
auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
GetButtonColorsForShipDeviceIndex(lusIndex, buttonColor, buttonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_Button, buttonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor);
ImGui::SameLine();
ImGui::SmallButton(connected ? ICON_FA_GAMEPAD : ICON_FA_CHAIN_BROKEN);
ImGui::PopStyleColor();
ImGui::PopStyleColor();
}
}
void BenInputEditorWindow::DrawGyroDeviceIcons(uint8_t portIndex) {
auto mapping =
Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->GetGyro()->GetGyroMapping();
if (mapping == nullptr) {
return;
}
auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button);
auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
GetButtonColorsForShipDeviceIndex(mapping->GetShipDeviceIndex(), buttonColor, buttonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_Button, buttonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor);
ImGui::SameLine();
ImGui::SmallButton(mapping->PhysicalDeviceIsConnected() ? ICON_FA_GAMEPAD : ICON_FA_CHAIN_BROKEN);
ImGui::PopStyleColor();
ImGui::PopStyleColor();
}
void BenInputEditorWindow::DrawLEDDeviceIcons(uint8_t portIndex) {
std::set<Ship::ShipDeviceIndex> allLusDeviceIndices;
for (auto [lusIndex, mapping] : Ship::Context::GetInstance()
->GetControlDeck()
->GetDeviceIndexMappingManager()
->GetAllDeviceIndexMappingsFromConfig()) {
allLusDeviceIndices.insert(lusIndex);
}
std::vector<std::pair<Ship::ShipDeviceIndex, bool>> lusDeviceIndiciesWithMappings;
for (auto lusIndex : allLusDeviceIndices) {
if (Ship::Context::GetInstance()
->GetControlDeck()
->GetControllerByPort(portIndex)
->GetRumble()
->HasMappingsForShipDeviceIndex(lusIndex)) {
for (auto [id, mapping] : Ship::Context::GetInstance()
->GetControlDeck()
->GetControllerByPort(portIndex)
->GetLED()
->GetAllLEDMappings()) {
if (mapping->GetShipDeviceIndex() == lusIndex) {
lusDeviceIndiciesWithMappings.push_back(
std::pair<Ship::ShipDeviceIndex, bool>(lusIndex, mapping->PhysicalDeviceIsConnected()));
break;
}
}
}
}
for (auto [lusIndex, connected] : lusDeviceIndiciesWithMappings) {
auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button);
auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
GetButtonColorsForShipDeviceIndex(lusIndex, buttonColor, buttonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_Button, buttonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor);
ImGui::SameLine();
ImGui::SmallButton(connected ? ICON_FA_GAMEPAD : ICON_FA_CHAIN_BROKEN);
ImGui::PopStyleColor();
ImGui::PopStyleColor();
}
}
void BenInputEditorWindow::DrawDeviceVisibilityButtons() {
std::map<Ship::ShipDeviceIndex, std::pair<std::string, int32_t>> indexMappings;
for (auto [lusIndex, mapping] : Ship::Context::GetInstance()
->GetControlDeck()
->GetDeviceIndexMappingManager()
->GetAllDeviceIndexMappingsFromConfig()) {
auto sdlIndexMapping = std::static_pointer_cast<Ship::ShipDeviceIndexToSDLDeviceIndexMapping>(mapping);
if (sdlIndexMapping == nullptr) {
continue;
}
indexMappings[lusIndex] = { sdlIndexMapping->GetSDLControllerName(), -1 };
}
for (auto [lusIndex, mapping] :
Ship::Context::GetInstance()->GetControlDeck()->GetDeviceIndexMappingManager()->GetAllDeviceIndexMappings()) {
auto sdlIndexMapping = std::static_pointer_cast<Ship::ShipDeviceIndexToSDLDeviceIndexMapping>(mapping);
if (sdlIndexMapping == nullptr) {
continue;
}
indexMappings[lusIndex] = { sdlIndexMapping->GetSDLControllerName(), sdlIndexMapping->GetSDLDeviceIndex() };
}
void BenInputEditorWindow::DrawDeviceToggles(uint8_t portIndex) {
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
auto keyboardButtonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button);
auto keyboardButtonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
GetButtonColorsForShipDeviceIndex(Ship::ShipDeviceIndex::Keyboard, keyboardButtonColor, keyboardButtonHoveredColor);
GetButtonColorsForDeviceType(Ship::PhysicalDeviceType::Keyboard, keyboardButtonColor, keyboardButtonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_Button, keyboardButtonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, keyboardButtonHoveredColor);
bool keyboardVisible = mDeviceIndexVisiblity[Ship::ShipDeviceIndex::Keyboard];
if (ImGui::Button(StringHelper::Sprintf("%s %s Keyboard", keyboardVisible ? ICON_FA_EYE : ICON_FA_EYE_SLASH,
ICON_FA_KEYBOARD_O)
.c_str())) {
mDeviceIndexVisiblity[Ship::ShipDeviceIndex::Keyboard] = !keyboardVisible;
}
ImGui::Button(StringHelper::Sprintf("%s Keyboard", ICON_FA_KEYBOARD_O).c_str());
ImGui::PopStyleColor();
ImGui::PopStyleColor();
for (auto [lusIndex, info] : indexMappings) {
auto [name, sdlIndex] = info;
bool connected = sdlIndex != -1;
auto mouseButtonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button);
auto mouseButtonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
GetButtonColorsForDeviceType(Ship::PhysicalDeviceType::Mouse, mouseButtonColor, mouseButtonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_Button, mouseButtonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, mouseButtonHoveredColor);
ImGui::Button(StringHelper::Sprintf("%s Mouse", ICON_FA_KEYBOARD_O).c_str());
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopItemFlag();
auto connectedDeviceManager = Ship::Context::GetInstance()->GetControlDeck()->GetConnectedPhysicalDeviceManager();
for (const auto& [instanceId, name] : connectedDeviceManager->GetConnectedSDLGamepadNames()) {
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button);
auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
GetButtonColorsForShipDeviceIndex(lusIndex, buttonColor, buttonHoveredColor);
GetButtonColorsForDeviceType(Ship::PhysicalDeviceType::SDLGamepad, buttonColor, buttonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_Button, buttonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor);
bool visible = mDeviceIndexVisiblity[lusIndex];
if (ImGui::Button(
StringHelper::Sprintf("%s %s %s (%s)", visible ? ICON_FA_EYE : ICON_FA_EYE_SLASH,
connected ? ICON_FA_GAMEPAD : ICON_FA_CHAIN_BROKEN, name.c_str(),
connected ? StringHelper::Sprintf("SDL %d", sdlIndex).c_str() : "Disconnected")
.c_str())) {
mDeviceIndexVisiblity[lusIndex] = !visible;
}
auto notIgnored = !connectedDeviceManager->PortIsIgnoringInstanceId(portIndex, instanceId);
ImGui::PopItemFlag();
if (ImGui::Checkbox(StringHelper::Sprintf("###instanceId_%d", instanceId).c_str(), &notIgnored)) {
if (notIgnored) {
connectedDeviceManager->UnignoreInstanceIdForPort(portIndex, instanceId);
} else {
connectedDeviceManager->IgnoreInstanceIdForPort(portIndex, instanceId);
}
};
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
ImGui::SameLine();
ImGui::Button(StringHelper::Sprintf("%s %s (SDL)", ICON_FA_GAMEPAD, name.c_str()).c_str());
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopItemFlag();
}
}
@ -1480,13 +1328,7 @@ void BenInputEditorWindow::DrawPortTab(uint8_t portIndex) {
void BenInputEditorWindow::DrawPortTabContents(uint8_t portIndex) {
DrawClearAllButton(portIndex);
DrawSetDefaultsButton(portIndex);
if (!Ship::Context::GetInstance()->GetControlDeck()->IsSinglePlayerMappingMode()) {
ImGui::SameLine();
if (ImGui::Button("Reorder controllers")) {
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Controller Reordering")->Show();
}
}
DrawDeviceVisibilityButtons();
DrawDeviceToggles(portIndex);
UpdateBitmaskToMappingIds(portIndex);
UpdateStickDirectionToMappingIds(portIndex);
@ -1496,7 +1338,6 @@ void BenInputEditorWindow::DrawPortTabContents(uint8_t portIndex) {
ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
if (ImGui::CollapsingHeader("Buttons", NULL, ImGuiTreeNodeFlags_DefaultOpen)) {
DrawButtonDeviceIcons(portIndex, mButtonsBitmasks);
DrawButtonLine("A", portIndex, BTN_A, CHIP_COLOR_N64_BLUE);
DrawButtonLine("B", portIndex, BTN_B, CHIP_COLOR_N64_GREEN);
DrawButtonLine("Start", portIndex, BTN_START, CHIP_COLOR_N64_RED);
@ -1511,53 +1352,33 @@ void BenInputEditorWindow::DrawPortTabContents(uint8_t portIndex) {
CHIP_COLOR_N64_YELLOW);
DrawButtonLine(StringHelper::Sprintf("C %s", ICON_FA_ARROW_RIGHT).c_str(), portIndex, BTN_CRIGHT,
CHIP_COLOR_N64_YELLOW);
} else {
DrawButtonDeviceIcons(portIndex, mButtonsBitmasks);
}
if (ImGui::CollapsingHeader("D-Pad", NULL, ImGuiTreeNodeFlags_DefaultOpen)) {
DrawButtonDeviceIcons(portIndex, mDpadBitmasks);
DrawButtonLine(StringHelper::Sprintf("%s", ICON_FA_ARROW_UP).c_str(), portIndex, BTN_DUP);
DrawButtonLine(StringHelper::Sprintf("%s", ICON_FA_ARROW_DOWN).c_str(), portIndex, BTN_DDOWN);
DrawButtonLine(StringHelper::Sprintf("%s", ICON_FA_ARROW_LEFT).c_str(), portIndex, BTN_DLEFT);
DrawButtonLine(StringHelper::Sprintf("%s", ICON_FA_ARROW_RIGHT).c_str(), portIndex, BTN_DRIGHT);
} else {
DrawButtonDeviceIcons(portIndex, mDpadBitmasks);
}
if (ImGui::CollapsingHeader("Analog Stick", NULL, ImGuiTreeNodeFlags_DefaultOpen)) {
DrawAnalogStickDeviceIcons(portIndex, Ship::LEFT_STICK);
DrawStickSection(portIndex, Ship::LEFT, 0);
} else {
DrawAnalogStickDeviceIcons(portIndex, Ship::LEFT_STICK);
}
if (ImGui::CollapsingHeader("Additional (\"Right\") Stick")) {
DrawAnalogStickDeviceIcons(portIndex, Ship::RIGHT_STICK);
DrawStickSection(portIndex, Ship::RIGHT, 1, CHIP_COLOR_N64_YELLOW);
} else {
DrawAnalogStickDeviceIcons(portIndex, Ship::RIGHT_STICK);
}
if (ImGui::CollapsingHeader("Rumble")) {
DrawRumbleDeviceIcons(portIndex);
DrawRumbleSection(portIndex);
} else {
DrawRumbleDeviceIcons(portIndex);
}
if (ImGui::CollapsingHeader("Gyro")) {
DrawGyroDeviceIcons(portIndex);
DrawGyroSection(portIndex);
} else {
DrawGyroDeviceIcons(portIndex);
}
if (ImGui::CollapsingHeader("LEDs")) {
DrawLEDDeviceIcons(portIndex);
DrawLEDSection(portIndex);
} else {
DrawLEDDeviceIcons(portIndex);
}
ImGui::PopStyleColor();
@ -1574,19 +1395,6 @@ void BenInputEditorWindow::DrawSetDefaultsButton(uint8_t portIndex) {
}
if (ImGui::BeginPopup(popupId.c_str())) {
std::map<Ship::ShipDeviceIndex, std::pair<std::string, int32_t>> indexMappings;
for (auto [lusIndex, mapping] : Ship::Context::GetInstance()
->GetControlDeck()
->GetDeviceIndexMappingManager()
->GetAllDeviceIndexMappings()) {
auto sdlIndexMapping = std::static_pointer_cast<Ship::ShipDeviceIndexToSDLDeviceIndexMapping>(mapping);
if (sdlIndexMapping == nullptr) {
continue;
}
indexMappings[lusIndex] = { sdlIndexMapping->GetSDLControllerName(), sdlIndexMapping->GetSDLDeviceIndex() };
}
bool shouldClose = false;
ImGui::PushStyleColor(ImGuiCol_Button, BUTTON_COLOR_KEYBOARD_BEIGE);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, BUTTON_COLOR_KEYBOARD_BEIGE_HOVERED);
@ -1605,49 +1413,43 @@ void BenInputEditorWindow::DrawSetDefaultsButton(uint8_t portIndex) {
Ship::Context::GetInstance()
->GetControlDeck()
->GetControllerByPort(portIndex)
->ClearAllMappingsForDevice(Ship::ShipDeviceIndex::Keyboard);
->ClearAllMappingsForDeviceType(Ship::PhysicalDeviceType::Keyboard);
Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->AddDefaultMappings(
Ship::ShipDeviceIndex::Keyboard);
Ship::PhysicalDeviceType::Keyboard);
shouldClose = true;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
for (auto [lusIndex, info] : indexMappings) {
auto [name, sdlIndex] = info;
auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button);
auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
GetButtonColorsForShipDeviceIndex(lusIndex, buttonColor, buttonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_Button, buttonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor);
if (ImGui::Button(StringHelper::Sprintf("%s %s (%s)", ICON_FA_GAMEPAD, name.c_str(),
StringHelper::Sprintf("SDL %d", sdlIndex).c_str())
.c_str())) {
ImGui::OpenPopup(StringHelper::Sprintf("Set Defaults for %s", name.c_str()).c_str());
auto buttonColor = ImGui::GetStyleColorVec4(ImGuiCol_Button);
auto buttonHoveredColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
GetButtonColorsForDeviceType(Ship::PhysicalDeviceType::SDLGamepad, buttonColor, buttonHoveredColor);
ImGui::PushStyleColor(ImGuiCol_Button, buttonColor);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, buttonHoveredColor);
if (ImGui::Button(StringHelper::Sprintf("%s %s", ICON_FA_GAMEPAD, "Gamepad (SDL)").c_str())) {
ImGui::OpenPopup("Set Defaults for Gamepad (SDL)");
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
if (ImGui::BeginPopupModal("Set Defaults for Gamepad (SDL)", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("This will clear all existing mappings for\nGamepad (SDL) on port %d.\n\nContinue?",
portIndex + 1);
if (ImGui::Button("Cancel")) {
shouldClose = true;
ImGui::CloseCurrentPopup();
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
if (ImGui::BeginPopupModal(StringHelper::Sprintf("Set Defaults for %s", name.c_str()).c_str(), NULL,
ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("This will clear all existing mappings for\n%s (SDL %d) on port %d.\n\nContinue?",
name.c_str(), sdlIndex, portIndex + 1);
if (ImGui::Button("Cancel")) {
shouldClose = true;
ImGui::CloseCurrentPopup();
}
if (ImGui::Button("Set defaults")) {
Ship::Context::GetInstance()
->GetControlDeck()
->GetControllerByPort(portIndex)
->ClearAllMappingsForDevice(lusIndex);
Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->AddDefaultMappings(
lusIndex);
shouldClose = true;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
if (ImGui::Button("Set defaults")) {
Ship::Context::GetInstance()
->GetControlDeck()
->GetControllerByPort(portIndex)
->ClearAllMappingsForDeviceType(Ship::PhysicalDeviceType::SDLGamepad);
Ship::Context::GetInstance()->GetControlDeck()->GetControllerByPort(portIndex)->AddDefaultMappings(
Ship::PhysicalDeviceType::SDLGamepad);
shouldClose = true;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
if (ImGui::Button("Cancel") || shouldClose) {

View File

@ -1,20 +1,25 @@
#pragma once
#include "stdint.h"
#include "window/gui/GuiWindow.h"
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include <libultraship/libultraship.h>
#include <imgui.h>
#include <unordered_map>
#include <string>
#include <vector>
#include <set>
#include "controller/controldevice/controller/Controller.h"
#include <list>
typedef CONTROLLERBUTTONS_T N64ButtonMask;
typedef struct {
const char* label;
const char* cVarName;
N64ButtonMask defaultBtn;
} CustomButtonMap;
class BenInputEditorWindow : public Ship::GuiWindow {
public:
using Ship::GuiWindow::GuiWindow;
using GuiWindow::GuiWindow;
~BenInputEditorWindow();
void DrawButton(const char* label, int32_t n64Btn, int32_t currentPort, int32_t* btnReading);
@ -34,9 +39,9 @@ class BenInputEditorWindow : public Ship::GuiWindow {
private:
void DrawStickDirectionLine(const char* axisDirectionName, uint8_t port, uint8_t stick, Ship::Direction direction,
ImVec4 color);
void DrawButtonLine(const char* buttonName, uint8_t port, CONTROLLERBUTTONS_T bitmask, ImVec4 color);
void DrawButtonLineEditMappingButton(uint8_t port, CONTROLLERBUTTONS_T bitmask, std::string id);
void DrawButtonLineAddMappingButton(uint8_t port, CONTROLLERBUTTONS_T bitmask);
void DrawButtonLine(const char* buttonName, uint8_t port, N64ButtonMask bitmask, ImVec4 color);
void DrawButtonLineEditMappingButton(uint8_t port, N64ButtonMask bitmask, std::string id);
void DrawButtonLineAddMappingButton(uint8_t port, N64ButtonMask bitmask);
void DrawStickDirectionLineEditMappingButton(uint8_t port, uint8_t stick, Ship::Direction direction,
std::string id);
@ -55,13 +60,20 @@ class BenInputEditorWindow : public Ship::GuiWindow {
void DrawRemoveGyroMappingButton(uint8_t port, std::string id);
void DrawAddGyroMappingButton(uint8_t port);
// Used together for an incomplete linked hash map implementation in order to
// map button masks to their names and original mapping on N64
std::list<std::pair<N64ButtonMask, const char*>> buttons;
std::unordered_map<N64ButtonMask, decltype(buttons)::iterator> buttonNames;
void addButtonName(N64ButtonMask mask, const char* name);
void DrawMapping(CustomButtonMap& mapping, float labelWidth, N64ButtonMask excludedButtons);
int32_t mGameInputBlockTimer;
int32_t mMappingInputBlockTimer;
int32_t mRumbleTimer;
std::shared_ptr<Ship::ControllerRumbleMapping> mRumbleMappingToTest;
// mBitmaskToMappingIds[port][bitmask] = { id0, id1, ... }
std::unordered_map<uint8_t, std::unordered_map<CONTROLLERBUTTONS_T, std::vector<std::string>>> mBitmaskToMappingIds;
std::unordered_map<uint8_t, std::unordered_map<N64ButtonMask, std::vector<std::string>>> mBitmaskToMappingIds;
// mStickDirectionToMappingIds[port][stick][direction] = { id0, id1, ... }
std::unordered_map<uint8_t,
@ -71,20 +83,14 @@ class BenInputEditorWindow : public Ship::GuiWindow {
void UpdateBitmaskToMappingIds(uint8_t port);
void UpdateStickDirectionToMappingIds(uint8_t port);
void GetButtonColorsForShipDeviceIndex(Ship::ShipDeviceIndex lusIndex, ImVec4& buttonColor,
ImVec4& buttonHoveredColor);
void GetButtonColorsForDeviceType(Ship::PhysicalDeviceType lusIndex, ImVec4& buttonColor,
ImVec4& buttonHoveredColor);
void DrawPortTab(uint8_t portIndex);
std::set<CONTROLLERBUTTONS_T> mButtonsBitmasks;
std::set<CONTROLLERBUTTONS_T> mDpadBitmasks;
void DrawButtonDeviceIcons(uint8_t portIndex, std::set<CONTROLLERBUTTONS_T> bitmasks);
void DrawAnalogStickDeviceIcons(uint8_t portIndex, Ship::Stick stick);
void DrawRumbleDeviceIcons(uint8_t portIndex);
void DrawGyroDeviceIcons(uint8_t portIndex);
void DrawLEDDeviceIcons(uint8_t portIndex);
std::set<N64ButtonMask> mButtonsBitmasks;
std::set<N64ButtonMask> mDpadBitmasks;
bool mInputEditorPopupOpen;
void DrawSetDefaultsButton(uint8_t portIndex);
void DrawClearAllButton(uint8_t portIndex);
std::map<Ship::ShipDeviceIndex, bool> mDeviceIndexVisiblity;
void DrawDeviceVisibilityButtons();
void DrawDeviceToggles(uint8_t portIndex);
};

View File

@ -335,21 +335,6 @@ void BenMenu::AddSettings() {
path.sidebarName = "Controls";
AddSidebarEntry("Settings", "Controls", 1);
AddWidget(path,
"This interface can be a little daunting. Please bear with us as we work to improve the experience "
"and address some known issues.\n"
"\n"
"At first glance, you may notice several input devices displayed below the 'Clear All' button. "
"Some of these might be other controllers connected to your computer, while others may be "
"duplicated controllers (a known issue). We recommend clicking on the box with the " ICON_FA_EYE
" icon and the name of any disconnected or unused controllers to hide their inputs. Make sure the "
"target controller remains visible.\n"
"\n"
"If you encounter issues connecting your controller or registering inputs, try closing Steam or "
"any other external input software. Alternatively, test a different controller to determine if "
"it's a compatibility issue.\n",
WIDGET_TEXT);
AddWidget(path, "Bindings", WIDGET_SEPARATOR_TEXT);
AddWidget(path, "Popout Bindings Window", WIDGET_WINDOW_BUTTON)
.CVar("gWindows.BenInputEditor")
.WindowName("2S2H Input Editor")

View File

@ -1,5 +1,4 @@
#include "UIWidgets.hpp"
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui_internal.h>
#include <sstream>
#include <libultraship/libultraship.h>
@ -264,7 +263,7 @@ bool Checkbox(const char* _label, bool* value, const CheckboxOptions& options) {
: ImGuiCol_FrameBg),
true, style.FrameRounding);
ImU32 check_col = ImGui::GetColorU32(ImGuiCol_CheckMark);
bool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0;
bool mixed_value = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) != 0;
if (mixed_value) {
// Undocumented tristate/mixed/indeterminate checkbox (#2644)
// This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all

View File

@ -5,7 +5,6 @@
#include <vector>
#include <span>
#include <stdint.h>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui.h>
#include <libultraship/libultraship.h>
#include <unordered_map>

View File

@ -162,16 +162,29 @@ OTRGlobals::OTRGlobals() {
std::unordered_set<uint32_t> validHashes = { MM_NTSC_US_10, MM_NTSC_US_GC };
context = Ship::Context::CreateUninitializedInstance("2 Ship 2 Harkinian", appShortName, "2ship2harkinian.json");
context->InitLogging();
context->InitGfxDebugger();
context->InitConfiguration();
context->InitConsoleVariables();
// tell LUS to reserve 3 SoH specific threads (Game, Audio, Save)
context =
Ship::Context::CreateInstance("2 Ship 2 Harkinian", appShortName, "2ship2harkinian.json", archiveFiles, {}, 3,
{ .SampleRate = 32000, .SampleLength = 1024, .DesiredBuffered = 1680 });
SPDLOG_INFO("Starting 2 Ship 2 Harkinian version {}", (char*)gBuildVersion);
context->InitResourceManager(archiveFiles, {}, 3);
prevAltAssets = CVarGetInteger("gEnhancements.Mods.AlternateAssets", 0);
context->GetResourceManager()->SetAltAssetsEnabled(prevAltAssets);
auto controlDeck = std::make_shared<LUS::ControlDeck>(std::vector<CONTROLLERBUTTONS_T>({}));
context->InitControlDeck(controlDeck);
context->InitCrashHandler();
context->InitConsole();
auto benInputEditorWindow = std::make_shared<BenInputEditorWindow>("gWindows.BenInputEditor", "2S2H Input Editor");
auto benFast3dWindow =
std::make_shared<Fast::Fast3dWindow>(std::vector<std::shared_ptr<Ship::GuiWindow>>({ benInputEditorWindow }));
context->InitWindow(benFast3dWindow);
// Override LUS defaults
Ship::Context::GetInstance()->GetLogger()->set_level(
(spdlog::level::level_enum)CVarGetInteger("gDeveloperTools.LogLevel", 1));
@ -182,23 +195,28 @@ OTRGlobals::OTRGlobals() {
overlay->LoadFont("Fipps", 32.0f, "fonts/Fipps-Regular.otf");
overlay->SetCurrentFont(CVarGetString(CVAR_GAME_OVERLAY_FONT, "Press Start 2P"));
context->InitAudio({ .SampleRate = 32000, .SampleLength = 1024, .DesiredBuffered = 1680 });
SPDLOG_INFO("Starting 2 Ship 2 Harkinian version {}", (char*)gBuildVersion);
auto loader = context->GetResourceManager()->GetResourceLoader();
loader->RegisterResourceFactory(std::make_shared<LUS::ResourceFactoryBinaryTextureV0>(), RESOURCE_FORMAT_BINARY,
"Texture", static_cast<uint32_t>(LUS::ResourceType::Texture), 0);
loader->RegisterResourceFactory(std::make_shared<LUS::ResourceFactoryBinaryTextureV1>(), RESOURCE_FORMAT_BINARY,
"Texture", static_cast<uint32_t>(LUS::ResourceType::Texture), 1);
loader->RegisterResourceFactory(std::make_shared<LUS::ResourceFactoryBinaryVertexV0>(), RESOURCE_FORMAT_BINARY,
"Vertex", static_cast<uint32_t>(LUS::ResourceType::Vertex), 0);
loader->RegisterResourceFactory(std::make_shared<LUS::ResourceFactoryXMLVertexV0>(), RESOURCE_FORMAT_XML, "Vertex",
static_cast<uint32_t>(LUS::ResourceType::Vertex), 0);
loader->RegisterResourceFactory(std::make_shared<LUS::ResourceFactoryBinaryDisplayListV0>(), RESOURCE_FORMAT_BINARY,
"DisplayList", static_cast<uint32_t>(LUS::ResourceType::DisplayList), 0);
loader->RegisterResourceFactory(std::make_shared<LUS::ResourceFactoryXMLDisplayListV0>(), RESOURCE_FORMAT_XML,
"DisplayList", static_cast<uint32_t>(LUS::ResourceType::DisplayList), 0);
loader->RegisterResourceFactory(std::make_shared<LUS::ResourceFactoryBinaryMatrixV0>(), RESOURCE_FORMAT_BINARY,
"Matrix", static_cast<uint32_t>(LUS::ResourceType::Matrix), 0);
loader->RegisterResourceFactory(std::make_shared<LUS::ResourceFactoryBinaryBlobV0>(), RESOURCE_FORMAT_BINARY,
"Blob", static_cast<uint32_t>(LUS::ResourceType::Blob), 0);
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryBinaryTextureV0>(), RESOURCE_FORMAT_BINARY,
"Texture", static_cast<uint32_t>(Fast::ResourceType::Texture), 0);
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryBinaryTextureV1>(), RESOURCE_FORMAT_BINARY,
"Texture", static_cast<uint32_t>(Fast::ResourceType::Texture), 1);
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryBinaryVertexV0>(), RESOURCE_FORMAT_BINARY,
"Vertex", static_cast<uint32_t>(Fast::ResourceType::Vertex), 0);
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryXMLVertexV0>(), RESOURCE_FORMAT_XML, "Vertex",
static_cast<uint32_t>(Fast::ResourceType::Vertex), 0);
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryBinaryDisplayListV0>(),
RESOURCE_FORMAT_BINARY, "DisplayList",
static_cast<uint32_t>(Fast::ResourceType::DisplayList), 0);
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryXMLDisplayListV0>(), RESOURCE_FORMAT_XML,
"DisplayList", static_cast<uint32_t>(Fast::ResourceType::DisplayList), 0);
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryBinaryMatrixV0>(), RESOURCE_FORMAT_BINARY,
"Matrix", static_cast<uint32_t>(Fast::ResourceType::Matrix), 0);
loader->RegisterResourceFactory(std::make_shared<Ship::ResourceFactoryBinaryBlobV0>(), RESOURCE_FORMAT_BINARY,
"Blob", static_cast<uint32_t>(Ship::ResourceType::Blob), 0);
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryArrayV0>(), RESOURCE_FORMAT_BINARY,
"Array", static_cast<uint32_t>(SOH::ResourceType::SOH_Array), 0);
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryAnimationV0>(), RESOURCE_FORMAT_BINARY,
@ -239,7 +257,6 @@ OTRGlobals::OTRGlobals() {
"KeyFrameAnim", static_cast<uint32_t>(SOH::ResourceType::TSH_CKeyFrameAnim), 0);
loader->RegisterResourceFactory(std::make_shared<SOH::ResourceFactoryBinaryKeyFrameSkel>(), RESOURCE_FORMAT_BINARY,
"KeyFrameSkel", static_cast<uint32_t>(SOH::ResourceType::TSH_CKeyFrameSkel), 0);
context->GetControlDeck()->SetSinglePlayerMappingMode(true);
// gSaveStateMgr = std::make_shared<SaveStateMgr>();
// gRandomizer = std::make_shared<Randomizer>();
@ -310,7 +327,7 @@ ImFont* OTRGlobals::CreateFontWithSize(float size, std::string fontPath) {
initData->ResourceVersion = 0;
initData->Path = fontPath;
std::shared_ptr<Ship::Font> fontData = std::static_pointer_cast<Ship::Font>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResource(fontPath, 0, false, initData));
Ship::Context::GetInstance()->GetResourceManager()->LoadResource(fontPath, false, initData));
font = mImGuiIo->Fonts->AddFontFromMemoryTTF(fontData->Data, fontData->DataSize, size);
}
// FontAwesome fonts need to have their sizes reduced by 2.0f/3.0f in order to align correctly
@ -840,14 +857,20 @@ extern "C" void Graph_StartFrame() {
CVarClear(CVAR_NEW_FILE_DROPPED);
CVarClear(CVAR_DROPPED_FILE);
}
OTRGlobals::Instance->context->GetWindow()->StartFrame();
}
void RunCommands(Gfx* Commands, const std::vector<std::unordered_map<Mtx*, MtxF>>& mtx_replacements) {
auto wnd = std::dynamic_pointer_cast<Fast::Fast3dWindow>(OTRGlobals::Instance->context->GetWindow());
if (wnd == nullptr) {
return;
}
// Process window events for resize, mouse, keyboard events
wnd->HandleEvents();
for (const auto& m : mtx_replacements) {
gfx_run(Commands, m);
gfx_end_frame();
wnd->DrawAndRunGraphicsCommands(Commands, m);
}
}
@ -993,10 +1016,10 @@ extern "C" uint32_t ResourceMgr_GetGameRegion(int index) {
}
extern "C" void ResourceMgr_LoadDirectory(const char* resName) {
Ship::Context::GetInstance()->GetResourceManager()->LoadDirectory(resName);
Ship::Context::GetInstance()->GetResourceManager()->LoadResources(resName);
}
extern "C" void ResourceMgr_DirtyDirectory(const char* resName) {
Ship::Context::GetInstance()->GetResourceManager()->DirtyDirectory(resName);
Ship::Context::GetInstance()->GetResourceManager()->DirtyResources(resName);
}
// OTRTODO: There is probably a more elegant way to go about this...
@ -1096,8 +1119,8 @@ extern "C" uint16_t ResourceMgr_LoadTexHeightByName(char* texPath);
extern "C" char* ResourceMgr_LoadTexOrDListByName(const char* filePath) {
auto res = GetResourceByName(filePath);
if (res->GetInitData()->Type == static_cast<uint32_t>(LUS::ResourceType::DisplayList))
return (char*)&((std::static_pointer_cast<LUS::DisplayList>(res))->Instructions[0]);
if (res->GetInitData()->Type == static_cast<uint32_t>(Fast::ResourceType::DisplayList))
return (char*)&((std::static_pointer_cast<Fast::DisplayList>(res))->Instructions[0]);
else if (res->GetInitData()->Type == static_cast<uint32_t>(SOH::ResourceType::SOH_Array))
return (char*)(std::static_pointer_cast<SOH::Array>(res))->Vertices.data();
else {
@ -1108,8 +1131,8 @@ extern "C" char* ResourceMgr_LoadTexOrDListByName(const char* filePath) {
extern "C" char* ResourceMgr_LoadIfDListByName(const char* filePath) {
auto res = GetResourceByName(filePath);
if (res->GetInitData()->Type == static_cast<uint32_t>(LUS::ResourceType::DisplayList))
return (char*)&((std::static_pointer_cast<LUS::DisplayList>(res))->Instructions[0]);
if (res->GetInitData()->Type == static_cast<uint32_t>(Fast::ResourceType::DisplayList))
return (char*)&((std::static_pointer_cast<Fast::DisplayList>(res))->Instructions[0]);
return nullptr;
}
@ -1129,7 +1152,7 @@ extern "C" void ResourceMgr_PushCurrentDirectory(char* path) {
}
extern "C" Gfx* ResourceMgr_LoadGfxByName(const char* path) {
auto res = std::static_pointer_cast<LUS::DisplayList>(GetResourceByName(path));
auto res = std::static_pointer_cast<Fast::DisplayList>(GetResourceByName(path));
return (Gfx*)&res->Instructions[0];
}
@ -1143,7 +1166,7 @@ std::unordered_map<std::string, std::unordered_map<std::string, GfxPatch>> origi
// Attention! This is primarily for cosmetics & bug fixes. For things like mods and model replacement you should be
// using OTRs instead (When that is available). Index can be found using the commented out section below.
extern "C" void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction) {
auto res = std::static_pointer_cast<LUS::DisplayList>(
auto res = std::static_pointer_cast<Fast::DisplayList>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResource(path));
// Leaving this here for people attempting to find the correct Dlist index to patch
@ -1181,7 +1204,7 @@ extern "C" void ResourceMgr_PatchGfxByName(const char* path, const char* patchNa
extern "C" void ResourceMgr_PatchGfxCopyCommandByName(const char* path, const char* patchName, int destinationIndex,
int sourceIndex) {
auto res = std::static_pointer_cast<LUS::DisplayList>(
auto res = std::static_pointer_cast<Fast::DisplayList>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResource(path));
// Do not patch custom assets as they most likely do not have the same instructions as authentic assets
@ -1201,7 +1224,7 @@ extern "C" void ResourceMgr_PatchGfxCopyCommandByName(const char* path, const ch
extern "C" void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName) {
if (originalGfx.contains(path) && originalGfx[path].contains(patchName)) {
auto res = std::static_pointer_cast<LUS::DisplayList>(
auto res = std::static_pointer_cast<Fast::DisplayList>(
Ship::Context::GetInstance()->GetResourceManager()->LoadResource(path));
Gfx* gfx = (Gfx*)&res->Instructions[originalGfx[path][patchName].index];
@ -1752,17 +1775,27 @@ extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len) {
}
extern "C" int Controller_ShouldRumble(size_t slot) {
for (auto [id, mapping] : Ship::Context::GetInstance()
->GetControlDeck()
->GetControllerByPort(static_cast<uint8_t>(slot))
->GetRumble()
->GetAllRumbleMappings()) {
if (mapping->PhysicalDeviceIsConnected()) {
return 1;
}
// don't rumble if we don't have rumble mappings
if (Ship::Context::GetInstance()
->GetControlDeck()
->GetControllerByPort(static_cast<uint8_t>(slot))
->GetRumble()
->GetAllRumbleMappings()
.empty()) {
return 0;
}
return 0;
// don't rumble if we don't have connected gamepads
if (Ship::Context::GetInstance()
->GetControlDeck()
->GetConnectedPhysicalDeviceManager()
->GetConnectedSDLGamepadsForPort(slot)
.empty()) {
return 0;
}
// rumble
return 1;
}
// Helper to redirect the user to the boot screen in place of known console crash scenarios, and emits a notification

View File

@ -734,8 +734,13 @@ void DrawSlot(InventorySlot slot) {
(const char*)gItemIcons[currentItemId]);
}
if (ImGui::ImageButton(textureId, ImVec2(INV_GRID_ICON_SIZE, INV_GRID_ICON_SIZE), ImVec2(0, 0), ImVec2(1, 1), 0,
ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, currentItemId == ITEM_NONE ? 0.4f : 1.0f))) {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
bool buttonPressed =
ImGui::ImageButton((const char*)gItemIcons[safeItemsForInventorySlot[slot][0]], textureId,
ImVec2(INV_GRID_ICON_SIZE, INV_GRID_ICON_SIZE), ImVec2(0, 0), ImVec2(1, 1),
ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, currentItemId == ITEM_NONE ? 0.4f : 1.0f));
ImGui::PopStyleVar();
if (buttonPressed) {
if (safeMode && safeItemsForInventorySlot[slot].size() < 2) {
NextItemInSlot(slot);
} else {
@ -765,9 +770,13 @@ void DrawSlot(InventorySlot slot) {
}
ItemId id = safeMode ? safeItemsForInventorySlot[selectedInventorySlot][pickerIndex]
: static_cast<ItemId>(pickerIndex);
if (ImGui::ImageButton(
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName((const char*)gItemIcons[id]),
ImVec2(INV_GRID_ICON_SIZE, INV_GRID_ICON_SIZE), ImVec2(0, 0), ImVec2(1, 1), 0)) {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
bool buttonPressed = ImGui::ImageButton(
(const char*)gItemIcons[id],
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName((const char*)gItemIcons[id]),
ImVec2(INV_GRID_ICON_SIZE, INV_GRID_ICON_SIZE));
ImGui::PopStyleVar();
if (buttonPressed) {
gSaveContext.save.saveInfo.inventory.items[selectedInventorySlot] = id;
ImGui::CloseCurrentPopup();
}