Guillaume Jacquemin
0b2796e94b
From now on, Maps will only be for preprocessor-powered multi-directional mapping fuckery.
769 lines
28 KiB
C++
769 lines
28 KiB
C++
// MassBuilderSaveTool
|
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
#include <Corrade/Containers/ScopeGuard.h>
|
|
#include <Corrade/Utility/Format.h>
|
|
|
|
#include <Magnum/ImGuiIntegration/Integration.h>
|
|
|
|
#include "../Configuration/Configuration.h"
|
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
|
#include "../GameData/Accessories.h"
|
|
#define STYLENAMES_DEFINITION
|
|
#include "../GameData/StyleNames.h"
|
|
#include "../ImportExport/Export.h"
|
|
|
|
#include "Application.h"
|
|
|
|
namespace mbst {
|
|
|
|
void
|
|
Application::drawMassViewer() {
|
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
|
_currentMass = nullptr;
|
|
_currentWeapon = nullptr;
|
|
_uiState = UiState::MainManager;
|
|
_queue.addToast(Toast::Type::Error, "The selected M.A.S.S. isn't valid anymore.");
|
|
return;
|
|
}
|
|
|
|
ImGui::SetNextWindowPos({0.0f, ImGui::GetItemRectSize().y}, ImGuiCond_Always);
|
|
ImGui::SetNextWindowSize(ImVec2{Vector2{float(windowSize().x()), float(windowSize().y()) - ImGui::GetItemRectSize().y} / dpiScaling()},
|
|
ImGuiCond_Always);
|
|
if(!ImGui::Begin("##MassViewer", nullptr,
|
|
ImGuiWindowFlags_NoDecoration|ImGuiWindowFlags_NoMove|
|
|
ImGuiWindowFlags_NoBackground|ImGuiWindowFlags_NoBringToFrontOnFocus))
|
|
{
|
|
ImGui::End();
|
|
return;
|
|
}
|
|
|
|
if(ImGui::BeginChild("##MassInfo",
|
|
{0.0f, 0.0f},
|
|
ImGuiChildFlags_Border, ImGuiWindowFlags_MenuBar))
|
|
{
|
|
if(ImGui::BeginMenuBar()) {
|
|
if(ImGui::BeginTable("##MassViewerMenuTable", 4)) {
|
|
ImGui::TableSetupColumn("##MassName");
|
|
ImGui::TableSetupColumn("##Spacer", ImGuiTableColumnFlags_WidthStretch);
|
|
ImGui::TableSetupColumn("##Updates");
|
|
ImGui::TableSetupColumn("##Close", ImGuiTableColumnFlags_WidthFixed);
|
|
|
|
ImGui::TableNextRow();
|
|
|
|
ImGui::TableSetColumnIndex(0);
|
|
ImGui::Text("M.A.S.S.: %s", _currentMass->name().data());
|
|
drawTooltip(_currentMass->filename());
|
|
|
|
ImGui::TableSetColumnIndex(2);
|
|
if(_currentMass->dirty()) {
|
|
ImGui::TextUnformatted("External changes detected");
|
|
ImGui::SameLine();
|
|
if(ImGui::SmallButton(ICON_FA_SYNC_ALT " Refresh")) {
|
|
_currentMass->refreshValues();
|
|
_currentMass->setDirty(false);
|
|
_jointsDirty = false;
|
|
_stylesDirty = false;
|
|
_eyeFlareDirty = false;
|
|
}
|
|
}
|
|
|
|
ImGui::TableSetColumnIndex(3);
|
|
if(ImGui::SmallButton(ICON_FA_TIMES)) {
|
|
_currentWeapon = nullptr;
|
|
_currentMass = nullptr;
|
|
_uiState = UiState::MainManager;
|
|
_jointsDirty = false;
|
|
_stylesDirty = false;
|
|
_eyeFlareDirty = false;
|
|
_selectedArmourSlot = Containers::NullOpt;
|
|
_selectedArmourDecals = Containers::StaticArray<38, std::int32_t>{ValueInit};
|
|
_selectedArmourAccessories = Containers::StaticArray<38, std::int32_t>{ValueInit};
|
|
_selectedBLPlacement = 0;
|
|
_selectedWeaponPart = 0;
|
|
_selectedWeaponDecal = 0;
|
|
_selectedWeaponAccessory = 0;
|
|
}
|
|
|
|
ImGui::EndTable();
|
|
}
|
|
|
|
ImGui::EndMenuBar();
|
|
}
|
|
|
|
ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE);
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::TextWrapped("WARNING: Colours in this app may look different from in-game colours, due to unavoidable differences in the rendering pipeline.");
|
|
ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE);
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::TextWrapped("Real-time updates are disabled on this screen.");
|
|
|
|
if(_currentMass) {
|
|
if(ImGui::BeginTabBar("##MassTabBar")) {
|
|
if(ImGui::BeginTabItem("Frame")) {
|
|
drawFrameInfo();
|
|
ImGui::EndTabItem();
|
|
}
|
|
|
|
if(ImGui::BeginTabItem("Custom frame styles")) {
|
|
drawCustomFrameStyles();
|
|
ImGui::EndTabItem();
|
|
}
|
|
|
|
if(ImGui::BeginTabItem("Armour")) {
|
|
drawArmour();
|
|
ImGui::EndTabItem();
|
|
}
|
|
|
|
if(_currentMass->bulletLauncherAttachmentStyle() != GameObjects::BulletLauncherAttachmentStyle::NotFound &&
|
|
ImGui::BeginTabItem("Bullet launcher attachment"))
|
|
{
|
|
drawBLAttachment();
|
|
ImGui::EndTabItem();
|
|
}
|
|
|
|
if(ImGui::BeginTabItem("Custom armour styles")) {
|
|
drawCustomArmourStyles();
|
|
ImGui::EndTabItem();
|
|
}
|
|
|
|
if(ImGui::BeginTabItem("Weapons")) {
|
|
drawWeapons();
|
|
ImGui::EndTabItem();
|
|
}
|
|
|
|
if(!_currentMass->globalStyles().isEmpty() && ImGui::BeginTabItem("Global styles")) {
|
|
drawGlobalStyles();
|
|
ImGui::EndTabItem();
|
|
}
|
|
|
|
#ifdef SAVETOOL_DEBUG_BUILD
|
|
if(ImGui::BeginTabItem("Tuning (WIP)")) {
|
|
drawTuning();
|
|
ImGui::EndTabItem();
|
|
}
|
|
#endif
|
|
|
|
ImGui::EndTabBar();
|
|
}
|
|
}
|
|
}
|
|
ImGui::EndChild();
|
|
|
|
ImGui::End();
|
|
}
|
|
|
|
void
|
|
Application::drawGlobalStyles() {
|
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
|
return;
|
|
}
|
|
|
|
if(!ImGui::BeginChild("##GlobalStyles")) {
|
|
ImGui::EndChild();
|
|
return;
|
|
}
|
|
|
|
ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.");
|
|
|
|
for(std::uint32_t i = 0; i < _currentMass->globalStyles().size(); i++) {
|
|
ImGui::PushID(int(i));
|
|
auto result = drawCustomStyle(_currentMass->globalStyles()[i]);
|
|
switch(result) {
|
|
case DCS_ResetStyle:
|
|
_currentMass->getGlobalStyles();
|
|
break;
|
|
case DCS_Save:
|
|
_modifiedBySaveTool = true;
|
|
if(!_currentMass->writeGlobalStyle(i)) {
|
|
_modifiedBySaveTool = false;
|
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
ImGui::PopID();
|
|
}
|
|
|
|
ImGui::EndChild();
|
|
}
|
|
|
|
void
|
|
Application::drawTuning() {
|
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
|
return;
|
|
}
|
|
|
|
if(!ImGui::BeginTable("##TuningTable", 3)) {
|
|
return;
|
|
}
|
|
|
|
ImGui::TableSetupColumn("##EngineColumn");
|
|
ImGui::TableSetupColumn("##OSColumn");
|
|
ImGui::TableSetupColumn("##ArchitectureColumn");
|
|
|
|
ImGui::TableNextRow();
|
|
|
|
ImGui::TableSetColumnIndex(0);
|
|
|
|
if(ImGui::BeginTable("##EngineTable", 1, ImGuiTableFlags_Borders)) {
|
|
ImGui::TableSetupColumn("##Engine");
|
|
|
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
|
ImGui::TableNextColumn();
|
|
ImGui::TextUnformatted("Engine");
|
|
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%i", _currentMass->engine());
|
|
|
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
|
ImGui::TableNextColumn();
|
|
ImGui::TextUnformatted("Gears");
|
|
|
|
for(std::uint32_t i = 0; i < _currentMass->gears().size(); i++) {
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%i", _currentMass->gears()[i]);
|
|
}
|
|
|
|
ImGui::EndTable();
|
|
}
|
|
|
|
ImGui::TableSetColumnIndex(1);
|
|
|
|
if(ImGui::BeginTable("##OSTable", 1, ImGuiTableFlags_Borders)) {
|
|
ImGui::TableSetupColumn("##OS");
|
|
|
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
|
ImGui::TableNextColumn();
|
|
ImGui::TextUnformatted("OS");
|
|
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%i", _currentMass->os());
|
|
|
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
|
ImGui::TableNextColumn();
|
|
ImGui::TextUnformatted("Modules");
|
|
|
|
for(std::uint32_t i = 0; i < _currentMass->modules().size(); i++) {
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%i", _currentMass->modules()[i]);
|
|
}
|
|
|
|
ImGui::EndTable();
|
|
}
|
|
|
|
ImGui::TableSetColumnIndex(2);
|
|
|
|
if(ImGui::BeginTable("##ArchTable", 1, ImGuiTableFlags_Borders)) {
|
|
ImGui::TableSetupColumn("##Arch");
|
|
|
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
|
ImGui::TableNextColumn();
|
|
ImGui::TextUnformatted("Architecture");
|
|
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%i", _currentMass->architecture());
|
|
|
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
|
ImGui::TableNextColumn();
|
|
ImGui::TextUnformatted("Techs");
|
|
|
|
for(std::uint32_t i = 0; i < _currentMass->techs().size(); i++) {
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::Text("%i", _currentMass->techs()[i]);
|
|
}
|
|
|
|
ImGui::EndTable();
|
|
}
|
|
|
|
ImGui::EndTable();
|
|
}
|
|
|
|
Application::DCSResult
|
|
Application::drawCustomStyle(GameObjects::CustomStyle& style) {
|
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
|
return DCS_Fail;
|
|
}
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {8.0f, 0.0f});
|
|
|
|
Containers::ScopeGuard guard{[]{ ImGui::PopStyleVar(); }};
|
|
|
|
DCSResult return_value = DCS_Fail;
|
|
|
|
if(!ImGui::BeginChild("##CustomStyle", {}, ImGuiChildFlags_Border|ImGuiChildFlags_AutoResizeY,
|
|
ImGuiWindowFlags_MenuBar))
|
|
{
|
|
ImGui::EndChild();
|
|
return DCS_Fail;
|
|
}
|
|
|
|
if(ImGui::BeginMenuBar()) {
|
|
ImGui::TextUnformatted(style.name.cbegin(), style.name.cend());
|
|
|
|
static Containers::StaticArray<33, char> name_buf{ValueInit};
|
|
if(ImGui::SmallButton(ICON_FA_EDIT " Rename")) {
|
|
for(auto& c : name_buf) {
|
|
c = '\0';
|
|
}
|
|
std::strncpy(name_buf.data(), style.name.data(), 32);
|
|
ImGui::OpenPopup("name_edit");
|
|
}
|
|
if(drawRenamePopup(name_buf)) {
|
|
style.name = name_buf.data();
|
|
}
|
|
|
|
ImGui::EndMenuBar();
|
|
}
|
|
|
|
if(ImGui::BeginTable("##StyleTable", 2, ImGuiTableFlags_BordersInnerV)) {
|
|
ImGui::TableSetupColumn("##Colour", ImGuiTableColumnFlags_WidthStretch);
|
|
ImGui::TableSetupColumn("##Pattern", ImGuiTableColumnFlags_WidthStretch);
|
|
|
|
ImGui::TableNextRow();
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::BeginGroup();
|
|
drawAlignedText("Colour:");
|
|
drawAlignedText("Metallic:");
|
|
drawAlignedText("Gloss:");
|
|
drawAlignedText("Glow:");
|
|
ImGui::EndGroup();
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::BeginGroup();
|
|
ImGui::ColorEdit3("##Picker", &style.colour.r());
|
|
ImGui::SameLine();
|
|
drawHelpMarker("Right-click for more option, click the coloured square for the full picker.");
|
|
|
|
ImGui::SetNextItemWidth(-FLT_MIN);
|
|
ImGui::SliderFloat("##SliderMetallic", &style.metallic, 0.0f, 1.0f);
|
|
|
|
ImGui::SetNextItemWidth(-FLT_MIN);
|
|
ImGui::SliderFloat("##SliderGloss", &style.gloss,0.0f, 1.0f);
|
|
|
|
ImGui::Checkbox("##Glow", &style.glow);
|
|
ImGui::EndGroup();
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::BeginGroup();
|
|
drawAlignedText("Pattern:");
|
|
drawAlignedText("Opacity:");
|
|
drawAlignedText("X offset:");
|
|
drawAlignedText("Y offset:");
|
|
drawAlignedText("Rotation:");
|
|
drawAlignedText("Scale:");
|
|
ImGui::EndGroup();
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::BeginGroup();
|
|
drawAlignedText("%i", style.patternId);
|
|
ImGui::PushItemWidth(-FLT_MIN);
|
|
ImGui::SliderFloat("##SliderOpacity", &style.opacity, 0.0f, 1.0f);
|
|
ImGui::SliderFloat("##SliderOffsetX", &style.offset.x(), 0.0f, 1.0f);
|
|
ImGui::SliderFloat("##SliderOffsetY", &style.offset.y(), 0.0f, 1.0f);
|
|
ImGui::SliderFloat("##SliderRotation", &style.rotation, 0.0f, 1.0f);
|
|
ImGui::SliderFloat("##SliderScale", &style.scale, 0.0f, 1.0f);
|
|
ImGui::PopItemWidth();
|
|
ImGui::EndGroup();
|
|
|
|
ImGui::EndTable();
|
|
}
|
|
|
|
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
|
return_value = DCS_Save;
|
|
}
|
|
ImGui::SameLine();
|
|
if(ImGui::Button(ICON_FA_UNDO " Reset")) {
|
|
return_value = DCS_ResetStyle;
|
|
}
|
|
|
|
ImGui::EndChild();
|
|
|
|
return return_value;
|
|
}
|
|
|
|
void
|
|
Application::drawDecalEditor(GameObjects::Decal& decal) {
|
|
ImGui::Text("ID: %i", decal.id);
|
|
|
|
if(ImGui::BeginTable("##DecalTable", conf().advancedMode() ? 2 : 1, ImGuiTableFlags_BordersInnerV)) {
|
|
ImGui::TableSetupColumn("##Normal", ImGuiTableColumnFlags_WidthStretch);
|
|
|
|
if(conf().advancedMode()) {
|
|
ImGui::TableSetupColumn("##Advanced", ImGuiTableColumnFlags_WidthStretch);
|
|
}
|
|
|
|
ImGui::TableNextRow();
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::BeginGroup();
|
|
drawAlignedText("Colour:");
|
|
drawAlignedText("Offset:");
|
|
drawAlignedText("Rotation:");
|
|
drawAlignedText("Scale:");
|
|
drawAlignedText("Flip X:");
|
|
drawAlignedText("Surface wrap:");
|
|
ImGui::EndGroup();
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::BeginGroup();
|
|
ImGui::ColorEdit3("##Picker", &decal.colour.r());
|
|
ImGui::SameLine();
|
|
drawHelpMarker("Right-click for more option, click the coloured square for the full picker.");
|
|
|
|
ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth());
|
|
ImGui::SliderFloat("##OffsetX", &decal.offset.x(), 0.0f, 1.0f, "X: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::SliderFloat("##OffsetY", &decal.offset.y(), 0.0f, 1.0f, "Y: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine();
|
|
drawHelpMarker("0.0 = -100 in-game\n1.0 = 100 in-game");
|
|
|
|
ImGui::SliderFloat("##Rotation", &decal.rotation, 0.0f, 1.0f);
|
|
ImGui::SameLine();
|
|
drawHelpMarker("0.0 = 0 in-game\n1.0 = 360 in-game");
|
|
|
|
ImGui::SliderFloat("##Scale", &decal.scale, 0.0f, 1.0f);
|
|
ImGui::SameLine();
|
|
drawHelpMarker("0.0 = 1 in-game\n1.0 = 100 in-game");
|
|
|
|
ImGui::Checkbox("##Flip", &decal.flip);
|
|
|
|
ImGui::Checkbox("##Wrap", &decal.wrap);
|
|
ImGui::EndGroup();
|
|
|
|
if(conf().advancedMode()) {
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE);
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::TextUnformatted("Advanced settings. Touch these at your own risk.");
|
|
|
|
ImGui::BeginGroup();
|
|
drawAlignedText("Position:");
|
|
drawAlignedText("U axis:");
|
|
drawAlignedText("V axis:");
|
|
ImGui::EndGroup();
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::BeginGroup();
|
|
ImGui::PushItemWidth(-1.0f);
|
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
|
ImGui::DragFloat("##PosX", &decal.position.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::DragFloat("##PosY", &decal.position.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::DragFloat("##PosZ", &decal.position.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
|
ImGui::PopItemWidth();
|
|
|
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
|
ImGui::DragFloat("##UX", &decal.uAxis.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::DragFloat("##UY", &decal.uAxis.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::DragFloat("##UZ", &decal.uAxis.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
|
ImGui::PopItemWidth();
|
|
|
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
|
ImGui::DragFloat("##VX", &decal.vAxis.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::DragFloat("##VY", &decal.vAxis.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::DragFloat("##VZ", &decal.vAxis.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::PopItemWidth();
|
|
ImGui::EndGroup();
|
|
}
|
|
|
|
ImGui::EndTable();
|
|
}
|
|
}
|
|
|
|
void
|
|
Application::drawAccessoryEditor(GameObjects::Accessory& accessory, Containers::ArrayView<GameObjects::CustomStyle> style_view) {
|
|
if(accessory.id < 1) {
|
|
ImGui::TextUnformatted("Accessory: <none>");
|
|
}
|
|
else if(GameData::accessories.find(accessory.id) != GameData::accessories.cend()) {
|
|
ImGui::Text("Accessory #%.4i - %s", accessory.id, GameData::accessories.at(accessory.id).name.data());
|
|
}
|
|
else {
|
|
ImGui::Text("Accessory #%i", accessory.id);
|
|
drawTooltip("WARNING: accessory mapping is a WIP.");
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
static std::int32_t tab = 0;
|
|
static Containers::Optional<GameData::Accessory::Size> size = Containers::NullOpt;
|
|
if(ImGui::SmallButton("Change")) {
|
|
ImGui::OpenPopup("##AccessoryPopup");
|
|
if(accessory.id >= 3000) {
|
|
tab = 3;
|
|
}
|
|
else if(accessory.id >= 2000) {
|
|
tab = 2;
|
|
}
|
|
else if(accessory.id >= 1000) {
|
|
tab = 1;
|
|
}
|
|
else {
|
|
tab = 0;
|
|
}
|
|
}
|
|
if(ImGui::BeginPopup("##AccessoryPopup")) {
|
|
static const char* size_labels[] = {
|
|
"S",
|
|
"M",
|
|
"L",
|
|
"XL"
|
|
};
|
|
static const float selectable_width = 90.0f;
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.0f});
|
|
if(ImGui::Selectable("Primitives", tab == 0, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
|
|
tab = 0;
|
|
}
|
|
ImGui::SameLine();
|
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
|
ImGui::SameLine();
|
|
if(ImGui::Selectable("Armours", tab == 1, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
|
|
tab = 1;
|
|
}
|
|
ImGui::SameLine();
|
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
|
ImGui::SameLine();
|
|
if(ImGui::Selectable("Components", tab == 2, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
|
|
tab = 2;
|
|
}
|
|
ImGui::SameLine();
|
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
|
ImGui::SameLine();
|
|
if(ImGui::Selectable("Connectors", tab == 3, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
|
|
tab = 3;
|
|
}
|
|
ImGui::PopStyleVar();
|
|
|
|
ImGui::Separator();
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.0f});
|
|
if(ImGui::Selectable("All", !size, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
|
size = Containers::NullOpt;
|
|
}
|
|
ImGui::SameLine();
|
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
|
ImGui::SameLine();
|
|
if(ImGui::Selectable("S", size && *size == GameData::Accessory::Size::S, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
|
if(!size) {
|
|
size.emplace();
|
|
}
|
|
*size = GameData::Accessory::Size::S;
|
|
}
|
|
ImGui::SameLine();
|
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
|
ImGui::SameLine();
|
|
if(ImGui::Selectable("M", size && *size == GameData::Accessory::Size::M, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
|
if(!size) {
|
|
size.emplace();
|
|
}
|
|
*size = GameData::Accessory::Size::M;
|
|
}
|
|
ImGui::SameLine();
|
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
|
ImGui::SameLine();
|
|
if(ImGui::Selectable("L", size && *size == GameData::Accessory::Size::L, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
|
if(!size) {
|
|
size.emplace();
|
|
}
|
|
*size = GameData::Accessory::Size::L;
|
|
}
|
|
ImGui::SameLine();
|
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
|
ImGui::SameLine();
|
|
if(ImGui::Selectable("XL", size && *size == GameData::Accessory::Size::XL, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
|
if(!size) {
|
|
size.emplace();
|
|
}
|
|
*size = GameData::Accessory::Size::XL;
|
|
}
|
|
ImGui::PopStyleVar();
|
|
|
|
ImGui::Separator();
|
|
|
|
if(ImGui::BeginListBox("##AccessoryListbox", {-1.0f, 0.0f})) {
|
|
for(const auto& acc : GameData::accessories) {
|
|
if(acc.first >= tab * 1000 && acc.first < ((tab + 1) * 1000) && (!size || *size == acc.second.size)) {
|
|
if(ImGui::Selectable(Utility::format("#{:.4d} - {} ({})", acc.first, acc.second.name, size_labels[acc.second.size]).data(),
|
|
acc.first == accessory.id))
|
|
{
|
|
accessory.id = acc.first;
|
|
accessory.attachIndex = 0;
|
|
}
|
|
if(acc.first == accessory.id) {
|
|
ImGui::SetItemDefaultFocus();
|
|
}
|
|
}
|
|
}
|
|
|
|
ImGui::EndListBox();
|
|
}
|
|
|
|
ImGui::EndPopup();
|
|
}
|
|
|
|
if(accessory.id > 0) {
|
|
ImGui::SameLine();
|
|
if(ImGui::SmallButton("Unequip")) {
|
|
accessory.id = 0;
|
|
accessory.attachIndex = -1;
|
|
}
|
|
}
|
|
|
|
ImGui::BeginGroup();
|
|
drawAlignedText("Styles:");
|
|
if(conf().advancedMode()) {
|
|
drawAlignedText("Base position:");
|
|
}
|
|
drawAlignedText("Position offset:");
|
|
if(conf().advancedMode()) {
|
|
drawAlignedText("Base rotation:");
|
|
}
|
|
drawAlignedText("Rotation offset:");
|
|
drawAlignedText("Scale:");
|
|
ImGui::EndGroup();
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::BeginGroup();
|
|
ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth());
|
|
if(ImGui::BeginCombo("##Style1", getStyleName(accessory.styles[0], style_view).data())) {
|
|
for(const auto& style : GameData::builtin_style_names) {
|
|
if(ImGui::Selectable(getStyleName(style.first, style_view).data(), accessory.styles[0] == style.first)) {
|
|
accessory.styles[0] = style.first;
|
|
}
|
|
}
|
|
|
|
ImGui::EndCombo();
|
|
}
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
if(ImGui::BeginCombo("##Style2", getStyleName(accessory.styles[1], style_view).data())) {
|
|
for(const auto& style : GameData::builtin_style_names) {
|
|
if(ImGui::Selectable(getStyleName(style.first, style_view).data(), accessory.styles[1] == style.first)) {
|
|
accessory.styles[1] = style.first;
|
|
}
|
|
}
|
|
|
|
ImGui::EndCombo();
|
|
}
|
|
ImGui::PopItemWidth();
|
|
|
|
if(conf().advancedMode()) {
|
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
|
ImGui::DragFloat("##PosX", &accessory.relativePosition.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::DragFloat("##PosY", &accessory.relativePosition.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::DragFloat("##PosZ", &accessory.relativePosition.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
|
ImGui::PopItemWidth();
|
|
}
|
|
|
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
|
ImGui::SliderFloat("##PosOffsetX", &accessory.relativePositionOffset.x(), -500.0f, +500.0f, "X: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::SliderFloat("##PosOffsetY", &accessory.relativePositionOffset.y(), -500.0f, +500.0f, "Y: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::SliderFloat("##PosOffsetZ", &accessory.relativePositionOffset.z(), -500.0f, +500.0f, "Z: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine();
|
|
drawHelpMarker("+/-500.0 = +/-250 in-game");
|
|
|
|
if(conf().advancedMode()) {
|
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
|
ImGui::DragFloat("##RotX", &accessory.relativeRotation.x(), 1.0f, -FLT_MAX, +FLT_MAX, "Roll: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::DragFloat("##RotY", &accessory.relativeRotation.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Yaw: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::DragFloat("##RotZ", &accessory.relativeRotation.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Pitch: %.3f");
|
|
ImGui::PopItemWidth();
|
|
}
|
|
|
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
|
ImGui::SliderFloat("##RotOffsetX", &accessory.relativeRotationOffset.x(), -180.0f, +180.0f, "Roll: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::SliderFloat("##RotOffsetY", &accessory.relativeRotationOffset.y(), -180.0f, +180.0f, "Yaw: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::SliderFloat("##RotOffsetZ", &accessory.relativeRotationOffset.z(), -180.0f, +180.0f, "Pitch: %.3f");
|
|
ImGui::PopItemWidth();
|
|
|
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
|
ImGui::SliderFloat("##ScaleX", &accessory.localScale.x(), -3.0f, +3.0f, "X: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::SliderFloat("##ScaleY", &accessory.localScale.y(), -3.0f, +3.0f, "Y: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
ImGui::SliderFloat("##ScaleZ", &accessory.localScale.z(), -3.0f, +3.0f, "Z: %.3f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::SameLine();
|
|
drawHelpMarker("+/-3.0 = +/-150 in-game");
|
|
ImGui::EndGroup();
|
|
}
|
|
|
|
Containers::StringView
|
|
Application::getStyleName(std::int32_t id, Containers::ArrayView<GameObjects::CustomStyle> view) {
|
|
if(id >= 0 && id <= 15) {
|
|
return view[id].name;
|
|
}
|
|
else if(id >= 50 && id <= 65) {
|
|
return _currentMass->globalStyles()[id - 50].name;
|
|
}
|
|
else {
|
|
return GameData::builtin_style_names.at(id);
|
|
}
|
|
}
|
|
|
|
}
|