diff --git a/CHANGELOG.md b/CHANGELOG.md index aeb030bda5..8f2ee0eb63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -225,6 +225,7 @@ Feature #7875: Disable MyGUI windows snapping Feature #7914: Do not allow to move GUI windows out of screen Feature #7923: Don't show non-existent higher ranks for factions with fewer than 9 ranks + Feature #7932: Support two-channel normal maps Task #5896: Do not use deprecated MyGUI properties Task #6085: Replace boost::filesystem with std::filesystem Task #6149: Dehardcode Lua API_REVISION diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 269cc44707..3919507bd1 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -347,6 +347,16 @@ add_qt_style_dlls() { QT_STYLES[$CONFIG]="${QT_STYLES[$CONFIG]} $@" } +declare -A QT_IMAGEFORMATS +QT_IMAGEFORMATS["Release"]="" +QT_IMAGEFORMATS["Debug"]="" +QT_IMAGEFORMATS["RelWithDebInfo"]="" +add_qt_image_dlls() { + local CONFIG=$1 + shift + QT_IMAGEFORMATS[$CONFIG]="${QT_IMAGEFORMATS[$CONFIG]} $@" +} + if [ -z $PLATFORM ]; then PLATFORM="$(uname -m)" fi @@ -913,12 +923,13 @@ printf "Qt ${QT_VER}... " DLLSUFFIX="" fi if [ "${QT_VER:0:1}" -eq "6" ]; then - add_runtime_dlls $CONFIGURATION "$(pwd)/bin/Qt${QT_VER:0:1}"{Core,Gui,Network,OpenGL,OpenGLWidgets,Widgets}${DLLSUFFIX}.dll + add_runtime_dlls $CONFIGURATION "$(pwd)/bin/Qt${QT_VER:0:1}"{Core,Gui,Network,OpenGL,OpenGLWidgets,Widgets,Svg}${DLLSUFFIX}.dll else - add_runtime_dlls $CONFIGURATION "$(pwd)/bin/Qt${QT_VER:0:1}"{Core,Gui,Network,OpenGL,Widgets}${DLLSUFFIX}.dll + add_runtime_dlls $CONFIGURATION "$(pwd)/bin/Qt${QT_VER:0:1}"{Core,Gui,Network,OpenGL,Widgets,Svg}${DLLSUFFIX}.dll fi add_qt_platform_dlls $CONFIGURATION "$(pwd)/plugins/platforms/qwindows${DLLSUFFIX}.dll" add_qt_style_dlls $CONFIGURATION "$(pwd)/plugins/styles/qwindowsvistastyle${DLLSUFFIX}.dll" + add_qt_image_dlls $CONFIGURATION "$(pwd)/plugins/imageformats/qsvg${DLLSUFFIX}.dll" done echo Done. } @@ -1112,6 +1123,13 @@ fi echo " $(basename $DLL)" cp "$DLL" "${DLL_PREFIX}styles" done + + echo "- Qt Image Format DLLs..." + mkdir -p ${DLL_PREFIX}imageformats + for DLL in ${QT_IMAGEFORMATS[$CONFIGURATION]}; do + echo " $(basename $DLL)" + cp "$DLL" "${DLL_PREFIX}imageformats" + done echo done #fi diff --git a/CI/install_debian_deps.sh b/CI/install_debian_deps.sh index b7784cf3f0..d29f16f55f 100755 --- a/CI/install_debian_deps.sh +++ b/CI/install_debian_deps.sh @@ -36,7 +36,7 @@ declare -rA GROUPED_DEPS=( libsdl2-dev libqt5opengl5-dev qttools5-dev qttools5-dev-tools libopenal-dev libunshield-dev libtinyxml-dev libbullet-dev liblz4-dev libpng-dev libjpeg-dev libluajit-5.1-dev librecast-dev libsqlite3-dev ca-certificates libicu-dev - libyaml-cpp-dev + libyaml-cpp-dev libqt5svg5 libqt5svg5-dev " # These dependencies can alternatively be built and linked statically. diff --git a/CMakeLists.txt b/CMakeLists.txt index 93da5feec4..074c91344b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,7 +234,7 @@ else() endif(APPLE) if (WIN32) - option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON) + option(USE_DEBUG_CONSOLE "Whether a console should be displayed if OpenMW isn't launched from the command line. Does not affect the Release configuration." ON) endif() if(MSVC) @@ -249,9 +249,9 @@ find_package(LZ4 REQUIRED) if (USE_QT) find_package(QT REQUIRED COMPONENTS Core NAMES Qt6 Qt5) if (QT_VERSION_MAJOR VERSION_EQUAL 5) - find_package(Qt5 5.15 COMPONENTS Core Widgets Network OpenGL LinguistTools REQUIRED) + find_package(Qt5 5.15 COMPONENTS Core Widgets Network OpenGL LinguistTools Svg REQUIRED) else() - find_package(Qt6 COMPONENTS Core Widgets Network OpenGL OpenGLWidgets LinguistTools REQUIRED) + find_package(Qt6 COMPONENTS Core Widgets Network OpenGL OpenGLWidgets LinguistTools Svg REQUIRED) endif() message(STATUS "Using Qt${QT_VERSION}") endif() @@ -710,9 +710,8 @@ if (WIN32) if (USE_DEBUG_CONSOLE AND BUILD_OPENMW) set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE") set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE") - set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS $<$:_CONSOLE>) elseif (BUILD_OPENMW) - # Turn off debug console, debug output will be written to visual studio output instead + # Turn off implicit console, you won't see stdout unless launching OpenMW from a command line shell or look at openmw.log set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:WINDOWS") set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:WINDOWS") endif() @@ -834,6 +833,12 @@ if (OPENMW_OSX_DEPLOYMENT AND APPLE) configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/PlugIns/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY) configure_file("${QT_QMACSTYLE_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/PlugIns/${QT_QMACSTYLE_PLUGIN_GROUP}/${QT_QMACSTYLE_PLUGIN_NAME}" COPYONLY) configure_file("${OpenMW_SOURCE_DIR}/files/mac/qt.conf" "${OPENCS_BUNDLE_NAME}/Contents/Resources/qt.conf" COPYONLY) + + get_property(QT_QSVG_PLUGIN_PATH TARGET Qt${QT_VERSION_MAJOR}::QSvgPlugin PROPERTY LOCATION_RELEASE) + get_filename_component(QT_QSVG_PLUGIN_DIR "${QT_QSVG_PLUGIN_PATH}" DIRECTORY) + get_filename_component(QT_QSVG_PLUGIN_GROUP "${QT_QSVG_PLUGIN_DIR}" NAME) + get_filename_component(QT_QSVG_PLUGIN_NAME "${QT_QSVG_PLUGIN_PATH}" NAME) + configure_file("${QT_QSVG_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/PlugIns/${QT_QSVG_PLUGIN_GROUP}/${QT_QSVG_PLUGIN_NAME}" COPYONLY) endif () install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "." COMPONENT Runtime) diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index 6def8b4a42..83b4a486e1 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -1,5 +1,6 @@ #include "labels.hpp" +#include #include #include #include @@ -572,13 +573,14 @@ std::string_view enchantTypeLabel(int idx) std::string_view ruleFunction(int idx) { - if (idx >= 0 && idx <= 72) + if (idx >= ESM::DialogueCondition::Function_FacReactionLowest + && idx <= ESM::DialogueCondition::Function_PcWerewolfKills) { static constexpr std::string_view ruleFunctions[] = { - "Reaction Low", - "Reaction High", + "Lowest Faction Reaction", + "Highest Faction Reaction", "Rank Requirement", - "NPC? Reputation", + "NPC Reputation", "Health Percent", "Player Reputation", "NPC Level", @@ -648,6 +650,7 @@ std::string_view ruleFunction(int idx) "Flee", "Should Attack", "Werewolf", + "Werewolf Kills", }; return ruleFunctions[idx]; } diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 4526b891e2..cd38dadf3f 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -57,112 +57,82 @@ namespace std::cout << " Cell Name: " << p.mCellName << std::endl; } - std::string ruleString(const ESM::DialInfo::SelectStruct& ss) + std::string ruleString(const ESM::DialogueCondition& ss) { - std::string rule = ss.mSelectRule; + std::string_view type_str = "INVALID"; + std::string_view func_str; - if (rule.length() < 5) - return "INVALID"; - - char type = rule[1]; - char indicator = rule[2]; - - std::string type_str = "INVALID"; - std::string func_str = Misc::StringUtils::format("INVALID=%s", rule.substr(1, 3)); - int func = Misc::StringUtils::toNumeric(rule.substr(2, 2), 0); - - switch (type) + switch (ss.mFunction) { - case '1': - type_str = "Function"; - func_str = std::string(ruleFunction(func)); + case ESM::DialogueCondition::Function_Global: + type_str = "Global"; + func_str = ss.mVariable; break; - case '2': - if (indicator == 's') - type_str = "Global short"; - else if (indicator == 'l') - type_str = "Global long"; - else if (indicator == 'f') - type_str = "Global float"; + case ESM::DialogueCondition::Function_Local: + type_str = "Local"; + func_str = ss.mVariable; break; - case '3': - if (indicator == 's') - type_str = "Local short"; - else if (indicator == 'l') - type_str = "Local long"; - else if (indicator == 'f') - type_str = "Local float"; + case ESM::DialogueCondition::Function_Journal: + type_str = "Journal"; + func_str = ss.mVariable; break; - case '4': - if (indicator == 'J') - type_str = "Journal"; + case ESM::DialogueCondition::Function_Item: + type_str = "Item count"; + func_str = ss.mVariable; break; - case '5': - if (indicator == 'I') - type_str = "Item type"; + case ESM::DialogueCondition::Function_Dead: + type_str = "Dead"; + func_str = ss.mVariable; break; - case '6': - if (indicator == 'D') - type_str = "NPC Dead"; + case ESM::DialogueCondition::Function_NotId: + type_str = "Not ID"; + func_str = ss.mVariable; break; - case '7': - if (indicator == 'X') - type_str = "Not ID"; + case ESM::DialogueCondition::Function_NotFaction: + type_str = "Not Faction"; + func_str = ss.mVariable; break; - case '8': - if (indicator == 'F') - type_str = "Not Faction"; + case ESM::DialogueCondition::Function_NotClass: + type_str = "Not Class"; + func_str = ss.mVariable; break; - case '9': - if (indicator == 'C') - type_str = "Not Class"; + case ESM::DialogueCondition::Function_NotRace: + type_str = "Not Race"; + func_str = ss.mVariable; break; - case 'A': - if (indicator == 'R') - type_str = "Not Race"; + case ESM::DialogueCondition::Function_NotCell: + type_str = "Not Cell"; + func_str = ss.mVariable; break; - case 'B': - if (indicator == 'L') - type_str = "Not Cell"; - break; - case 'C': - if (indicator == 's') - type_str = "Not Local"; + case ESM::DialogueCondition::Function_NotLocal: + type_str = "Not Local"; + func_str = ss.mVariable; break; default: + type_str = "Function"; + func_str = ruleFunction(ss.mFunction); break; } - // Append the variable name to the function string if any. - if (type != '1') - func_str = rule.substr(5); - - // In the previous switch, we assumed that the second char was X - // for all types not qual to one. If this wasn't true, go back to - // the error message. - if (type != '1' && rule[3] != 'X') - func_str = Misc::StringUtils::format("INVALID=%s", rule.substr(1, 3)); - - char oper = rule[4]; - std::string oper_str = "??"; - switch (oper) + std::string_view oper_str = "??"; + switch (ss.mComparison) { - case '0': + case ESM::DialogueCondition::Comp_Eq: oper_str = "=="; break; - case '1': + case ESM::DialogueCondition::Comp_Ne: oper_str = "!="; break; - case '2': + case ESM::DialogueCondition::Comp_Gt: oper_str = "> "; break; - case '3': + case ESM::DialogueCondition::Comp_Ge: oper_str = ">="; break; - case '4': + case ESM::DialogueCondition::Comp_Ls: oper_str = "< "; break; - case '5': + case ESM::DialogueCondition::Comp_Le: oper_str = "<="; break; default: @@ -170,7 +140,7 @@ namespace } std::ostringstream stream; - stream << ss.mValue; + std::visit([&](auto value) { stream << value; }, ss.mValue); std::string result = Misc::StringUtils::format("%-12s %-32s %2s %s", type_str, func_str, oper_str, stream.str()); @@ -842,7 +812,7 @@ namespace EsmTool << std::endl; std::cout << " Type: " << dialogTypeLabel(mData.mData.mType) << std::endl; - for (const ESM::DialInfo::SelectStruct& rule : mData.mSelects) + for (const auto& rule : mData.mSelects) std::cout << " Select Rule: " << ruleString(rule) << std::endl; if (!mData.mResultScript.empty()) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index c2f249171a..3353a4586f 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -250,9 +250,9 @@ target_link_libraries(openmw-cs-lib ) if (QT_VERSION_MAJOR VERSION_EQUAL 6) - target_link_libraries(openmw-cs-lib Qt::Widgets Qt::Core Qt::Network Qt::OpenGL Qt::OpenGLWidgets) + target_link_libraries(openmw-cs-lib Qt::Widgets Qt::Core Qt::Network Qt::OpenGL Qt::OpenGLWidgets Qt::Svg) else() - target_link_libraries(openmw-cs-lib Qt::Widgets Qt::Core Qt::Network Qt::OpenGL) + target_link_libraries(openmw-cs-lib Qt::Widgets Qt::Core Qt::Network Qt::OpenGL Qt::Svg) endif() if (WIN32) diff --git a/apps/opencs/main.cpp b/apps/opencs/main.cpp index e7f980dc0d..62fb29e600 100644 --- a/apps/opencs/main.cpp +++ b/apps/opencs/main.cpp @@ -81,7 +81,7 @@ int runApplication(int argc, char* argv[]) Application application(argc, argv); - application.setWindowIcon(QIcon(":./openmw-cs.png")); + application.setWindowIcon(QIcon(":openmw-cs")); CS::Editor editor(argc, argv); #ifdef __linux__ diff --git a/apps/opencs/model/tools/topicinfocheck.cpp b/apps/opencs/model/tools/topicinfocheck.cpp index ba99a33a28..fab90d951a 100644 --- a/apps/opencs/model/tools/topicinfocheck.cpp +++ b/apps/opencs/model/tools/topicinfocheck.cpp @@ -171,10 +171,9 @@ void CSMTools::TopicInfoCheckStage::perform(int stage, CSMDoc::Messages& message // Check info conditions - for (std::vector::const_iterator it = topicInfo.mSelects.begin(); - it != topicInfo.mSelects.end(); ++it) + for (const auto& select : topicInfo.mSelects) { - verifySelectStruct((*it), id, messages); + verifySelectStruct(select, id, messages); } } @@ -308,49 +307,15 @@ bool CSMTools::TopicInfoCheckStage::verifyItem( } bool CSMTools::TopicInfoCheckStage::verifySelectStruct( - const ESM::DialInfo::SelectStruct& select, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) + const ESM::DialogueCondition& select, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages) { CSMWorld::ConstInfoSelectWrapper infoCondition(select); - if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_None) + if (select.mFunction == ESM::DialogueCondition::Function_None) { messages.add(id, "Invalid condition '" + infoCondition.toString() + "'", "", CSMDoc::Message::Severity_Error); return false; } - else if (!infoCondition.variantTypeIsValid()) - { - std::ostringstream stream; - stream << "Value of condition '" << infoCondition.toString() << "' has invalid "; - - switch (select.mValue.getType()) - { - case ESM::VT_None: - stream << "None"; - break; - case ESM::VT_Short: - stream << "Short"; - break; - case ESM::VT_Int: - stream << "Int"; - break; - case ESM::VT_Long: - stream << "Long"; - break; - case ESM::VT_Float: - stream << "Float"; - break; - case ESM::VT_String: - stream << "String"; - break; - default: - stream << "unknown"; - break; - } - stream << " type"; - - messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error); - return false; - } else if (infoCondition.conditionIsAlwaysTrue()) { messages.add( @@ -365,48 +330,48 @@ bool CSMTools::TopicInfoCheckStage::verifySelectStruct( } // Id checks - if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Global - && !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mGlobals, id, messages)) + if (select.mFunction == ESM::DialogueCondition::Function_Global + && !verifyId(ESM::RefId::stringRefId(select.mVariable), mGlobals, id, messages)) { return false; } - else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Journal - && !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mJournals, id, messages)) + else if (select.mFunction == ESM::DialogueCondition::Function_Journal + && !verifyId(ESM::RefId::stringRefId(select.mVariable), mJournals, id, messages)) { return false; } - else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Item - && !verifyItem(ESM::RefId::stringRefId(infoCondition.getVariableName()), id, messages)) + else if (select.mFunction == ESM::DialogueCondition::Function_Item + && !verifyItem(ESM::RefId::stringRefId(select.mVariable), id, messages)) { return false; } - else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Dead - && !verifyActor(ESM::RefId::stringRefId(infoCondition.getVariableName()), id, messages)) + else if (select.mFunction == ESM::DialogueCondition::Function_Dead + && !verifyActor(ESM::RefId::stringRefId(select.mVariable), id, messages)) { return false; } - else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotId - && !verifyActor(ESM::RefId::stringRefId(infoCondition.getVariableName()), id, messages)) + else if (select.mFunction == ESM::DialogueCondition::Function_NotId + && !verifyActor(ESM::RefId::stringRefId(select.mVariable), id, messages)) { return false; } - else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotFaction - && !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mFactions, id, messages)) + else if (select.mFunction == ESM::DialogueCondition::Function_NotFaction + && !verifyId(ESM::RefId::stringRefId(select.mVariable), mFactions, id, messages)) { return false; } - else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotClass - && !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mClasses, id, messages)) + else if (select.mFunction == ESM::DialogueCondition::Function_NotClass + && !verifyId(ESM::RefId::stringRefId(select.mVariable), mClasses, id, messages)) { return false; } - else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotRace - && !verifyId(ESM::RefId::stringRefId(infoCondition.getVariableName()), mRaces, id, messages)) + else if (select.mFunction == ESM::DialogueCondition::Function_NotRace + && !verifyId(ESM::RefId::stringRefId(select.mVariable), mRaces, id, messages)) { return false; } - else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotCell - && !verifyCell(infoCondition.getVariableName(), id, messages)) + else if (select.mFunction == ESM::DialogueCondition::Function_NotCell + && !verifyCell(select.mVariable, id, messages)) { return false; } diff --git a/apps/opencs/model/tools/topicinfocheck.hpp b/apps/opencs/model/tools/topicinfocheck.hpp index 1bb2fc61dc..3069fbc0ff 100644 --- a/apps/opencs/model/tools/topicinfocheck.hpp +++ b/apps/opencs/model/tools/topicinfocheck.hpp @@ -84,7 +84,7 @@ namespace CSMTools const ESM::RefId& name, int rank, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); bool verifyItem(const ESM::RefId& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); bool verifySelectStruct( - const ESM::DialInfo::SelectStruct& select, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); + const ESM::DialogueCondition& select, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); bool verifySound(const std::string& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages); template diff --git a/apps/opencs/model/world/infoselectwrapper.cpp b/apps/opencs/model/world/infoselectwrapper.cpp index fb1adf16d4..2e9ed6e150 100644 --- a/apps/opencs/model/world/infoselectwrapper.cpp +++ b/apps/opencs/model/world/infoselectwrapper.cpp @@ -6,16 +6,9 @@ #include -const size_t CSMWorld::ConstInfoSelectWrapper::RuleMinSize = 5; - -const size_t CSMWorld::ConstInfoSelectWrapper::FunctionPrefixOffset = 1; -const size_t CSMWorld::ConstInfoSelectWrapper::FunctionIndexOffset = 2; -const size_t CSMWorld::ConstInfoSelectWrapper::RelationIndexOffset = 4; -const size_t CSMWorld::ConstInfoSelectWrapper::VarNameOffset = 5; - const char* CSMWorld::ConstInfoSelectWrapper::FunctionEnumStrings[] = { - "Rank Low", - "Rank High", + "Faction Reaction Low", + "Faction Reaction High", "Rank Requirement", "Reputation", "Health Percent", @@ -72,7 +65,7 @@ const char* CSMWorld::ConstInfoSelectWrapper::FunctionEnumStrings[] = { "PC Endurance", "PC Personality", "PC Luck", - "PC Corpus", + "PC Corprus", "Weather", "PC Vampire", "Level", @@ -112,55 +105,40 @@ const char* CSMWorld::ConstInfoSelectWrapper::RelationEnumStrings[] = { nullptr, }; -const char* CSMWorld::ConstInfoSelectWrapper::ComparisonEnumStrings[] = { - "Boolean", - "Integer", - "Numeric", - nullptr, -}; - -// static functions - -std::string CSMWorld::ConstInfoSelectWrapper::convertToString(FunctionName name) +namespace { - if (name < Function_None) - return FunctionEnumStrings[name]; - else + std::string_view convertToString(ESM::DialogueCondition::Function name) + { + if (name < ESM::DialogueCondition::Function_None) + return CSMWorld::ConstInfoSelectWrapper::FunctionEnumStrings[name]; return "(Invalid Data: Function)"; -} + } -std::string CSMWorld::ConstInfoSelectWrapper::convertToString(RelationType type) -{ - if (type < Relation_None) - return RelationEnumStrings[type]; - else + std::string_view convertToString(ESM::DialogueCondition::Comparison type) + { + if (type != ESM::DialogueCondition::Comp_None) + return CSMWorld::ConstInfoSelectWrapper::RelationEnumStrings[type - ESM::DialogueCondition::Comp_Eq]; return "(Invalid Data: Relation)"; -} - -std::string CSMWorld::ConstInfoSelectWrapper::convertToString(ComparisonType type) -{ - if (type < Comparison_None) - return ComparisonEnumStrings[type]; - else - return "(Invalid Data: Comparison)"; + } } // ConstInfoSelectWrapper -CSMWorld::ConstInfoSelectWrapper::ConstInfoSelectWrapper(const ESM::DialInfo::SelectStruct& select) +CSMWorld::ConstInfoSelectWrapper::ConstInfoSelectWrapper(const ESM::DialogueCondition& select) : mConstSelect(select) { - readRule(); + updateHasVariable(); + updateComparisonType(); } -CSMWorld::ConstInfoSelectWrapper::FunctionName CSMWorld::ConstInfoSelectWrapper::getFunctionName() const +ESM::DialogueCondition::Function CSMWorld::ConstInfoSelectWrapper::getFunctionName() const { - return mFunctionName; + return mConstSelect.mFunction; } -CSMWorld::ConstInfoSelectWrapper::RelationType CSMWorld::ConstInfoSelectWrapper::getRelationType() const +ESM::DialogueCondition::Comparison CSMWorld::ConstInfoSelectWrapper::getRelationType() const { - return mRelationType; + return mConstSelect.mComparison; } CSMWorld::ConstInfoSelectWrapper::ComparisonType CSMWorld::ConstInfoSelectWrapper::getComparisonType() const @@ -175,24 +153,21 @@ bool CSMWorld::ConstInfoSelectWrapper::hasVariable() const const std::string& CSMWorld::ConstInfoSelectWrapper::getVariableName() const { - return mVariableName; + return mConstSelect.mVariable; } bool CSMWorld::ConstInfoSelectWrapper::conditionIsAlwaysTrue() const { - if (!variantTypeIsValid()) - return false; - if (mComparisonType == Comparison_Boolean || mComparisonType == Comparison_Integer) { - if (mConstSelect.mValue.getType() == ESM::VT_Float) + if (std::holds_alternative(mConstSelect.mValue)) return conditionIsAlwaysTrue(getConditionFloatRange(), getValidIntRange()); else return conditionIsAlwaysTrue(getConditionIntRange(), getValidIntRange()); } else if (mComparisonType == Comparison_Numeric) { - if (mConstSelect.mValue.getType() == ESM::VT_Float) + if (std::holds_alternative(mConstSelect.mValue)) return conditionIsAlwaysTrue(getConditionFloatRange(), getValidFloatRange()); else return conditionIsAlwaysTrue(getConditionIntRange(), getValidFloatRange()); @@ -203,19 +178,16 @@ bool CSMWorld::ConstInfoSelectWrapper::conditionIsAlwaysTrue() const bool CSMWorld::ConstInfoSelectWrapper::conditionIsNeverTrue() const { - if (!variantTypeIsValid()) - return false; - if (mComparisonType == Comparison_Boolean || mComparisonType == Comparison_Integer) { - if (mConstSelect.mValue.getType() == ESM::VT_Float) + if (std::holds_alternative(mConstSelect.mValue)) return conditionIsNeverTrue(getConditionFloatRange(), getValidIntRange()); else return conditionIsNeverTrue(getConditionIntRange(), getValidIntRange()); } else if (mComparisonType == Comparison_Numeric) { - if (mConstSelect.mValue.getType() == ESM::VT_Float) + if (std::holds_alternative(mConstSelect.mValue)) return conditionIsNeverTrue(getConditionFloatRange(), getValidFloatRange()); else return conditionIsNeverTrue(getConditionIntRange(), getValidFloatRange()); @@ -224,170 +196,36 @@ bool CSMWorld::ConstInfoSelectWrapper::conditionIsNeverTrue() const return false; } -bool CSMWorld::ConstInfoSelectWrapper::variantTypeIsValid() const -{ - return (mConstSelect.mValue.getType() == ESM::VT_Int || mConstSelect.mValue.getType() == ESM::VT_Float); -} - -const ESM::Variant& CSMWorld::ConstInfoSelectWrapper::getVariant() const -{ - return mConstSelect.mValue; -} - std::string CSMWorld::ConstInfoSelectWrapper::toString() const { std::ostringstream stream; - stream << convertToString(mFunctionName) << " "; + stream << convertToString(getFunctionName()) << " "; if (mHasVariable) - stream << mVariableName << " "; + stream << getVariableName() << " "; - stream << convertToString(mRelationType) << " "; + stream << convertToString(getRelationType()) << " "; - switch (mConstSelect.mValue.getType()) - { - case ESM::VT_Int: - stream << mConstSelect.mValue.getInteger(); - break; - - case ESM::VT_Float: - stream << mConstSelect.mValue.getFloat(); - break; - - default: - stream << "(Invalid value type)"; - break; - } + std::visit([&](auto value) { stream << value; }, mConstSelect.mValue); return stream.str(); } -void CSMWorld::ConstInfoSelectWrapper::readRule() -{ - if (mConstSelect.mSelectRule.size() < RuleMinSize) - throw std::runtime_error("InfoSelectWrapper: rule is to small"); - - readFunctionName(); - readRelationType(); - readVariableName(); - updateHasVariable(); - updateComparisonType(); -} - -void CSMWorld::ConstInfoSelectWrapper::readFunctionName() -{ - char functionPrefix = mConstSelect.mSelectRule[FunctionPrefixOffset]; - std::string functionIndex = mConstSelect.mSelectRule.substr(FunctionIndexOffset, 2); - int convertedIndex = -1; - - // Read in function index, form ## from 00 .. 73, skip leading zero - if (functionIndex[0] == '0') - functionIndex = functionIndex[1]; - - std::stringstream stream; - stream << functionIndex; - stream >> convertedIndex; - - switch (functionPrefix) - { - case '1': - if (convertedIndex >= 0 && convertedIndex <= 73) - mFunctionName = static_cast(convertedIndex); - else - mFunctionName = Function_None; - break; - - case '2': - mFunctionName = Function_Global; - break; - case '3': - mFunctionName = Function_Local; - break; - case '4': - mFunctionName = Function_Journal; - break; - case '5': - mFunctionName = Function_Item; - break; - case '6': - mFunctionName = Function_Dead; - break; - case '7': - mFunctionName = Function_NotId; - break; - case '8': - mFunctionName = Function_NotFaction; - break; - case '9': - mFunctionName = Function_NotClass; - break; - case 'A': - mFunctionName = Function_NotRace; - break; - case 'B': - mFunctionName = Function_NotCell; - break; - case 'C': - mFunctionName = Function_NotLocal; - break; - default: - mFunctionName = Function_None; - break; - } -} - -void CSMWorld::ConstInfoSelectWrapper::readRelationType() -{ - char relationIndex = mConstSelect.mSelectRule[RelationIndexOffset]; - - switch (relationIndex) - { - case '0': - mRelationType = Relation_Equal; - break; - case '1': - mRelationType = Relation_NotEqual; - break; - case '2': - mRelationType = Relation_Greater; - break; - case '3': - mRelationType = Relation_GreaterOrEqual; - break; - case '4': - mRelationType = Relation_Less; - break; - case '5': - mRelationType = Relation_LessOrEqual; - break; - default: - mRelationType = Relation_None; - } -} - -void CSMWorld::ConstInfoSelectWrapper::readVariableName() -{ - if (mConstSelect.mSelectRule.size() >= VarNameOffset) - mVariableName = mConstSelect.mSelectRule.substr(VarNameOffset); - else - mVariableName.clear(); -} - void CSMWorld::ConstInfoSelectWrapper::updateHasVariable() { - switch (mFunctionName) + switch (getFunctionName()) { - case Function_Global: - case Function_Local: - case Function_Journal: - case Function_Item: - case Function_Dead: - case Function_NotId: - case Function_NotFaction: - case Function_NotClass: - case Function_NotRace: - case Function_NotCell: - case Function_NotLocal: + case ESM::DialogueCondition::Function_Global: + case ESM::DialogueCondition::Function_Local: + case ESM::DialogueCondition::Function_Journal: + case ESM::DialogueCondition::Function_Item: + case ESM::DialogueCondition::Function_Dead: + case ESM::DialogueCondition::Function_NotId: + case ESM::DialogueCondition::Function_NotFaction: + case ESM::DialogueCondition::Function_NotClass: + case ESM::DialogueCondition::Function_NotRace: + case ESM::DialogueCondition::Function_NotCell: + case ESM::DialogueCondition::Function_NotLocal: mHasVariable = true; break; @@ -399,103 +237,103 @@ void CSMWorld::ConstInfoSelectWrapper::updateHasVariable() void CSMWorld::ConstInfoSelectWrapper::updateComparisonType() { - switch (mFunctionName) + switch (getFunctionName()) { // Boolean - case Function_NotId: - case Function_NotFaction: - case Function_NotClass: - case Function_NotRace: - case Function_NotCell: - case Function_PcExpelled: - case Function_PcCommonDisease: - case Function_PcBlightDisease: - case Function_SameSex: - case Function_SameRace: - case Function_SameFaction: - case Function_Detected: - case Function_Alarmed: - case Function_PcCorpus: - case Function_PcVampire: - case Function_Attacked: - case Function_TalkedToPc: - case Function_ShouldAttack: - case Function_Werewolf: + case ESM::DialogueCondition::Function_NotId: + case ESM::DialogueCondition::Function_NotFaction: + case ESM::DialogueCondition::Function_NotClass: + case ESM::DialogueCondition::Function_NotRace: + case ESM::DialogueCondition::Function_NotCell: + case ESM::DialogueCondition::Function_PcExpelled: + case ESM::DialogueCondition::Function_PcCommonDisease: + case ESM::DialogueCondition::Function_PcBlightDisease: + case ESM::DialogueCondition::Function_SameSex: + case ESM::DialogueCondition::Function_SameRace: + case ESM::DialogueCondition::Function_SameFaction: + case ESM::DialogueCondition::Function_Detected: + case ESM::DialogueCondition::Function_Alarmed: + case ESM::DialogueCondition::Function_PcCorprus: + case ESM::DialogueCondition::Function_PcVampire: + case ESM::DialogueCondition::Function_Attacked: + case ESM::DialogueCondition::Function_TalkedToPc: + case ESM::DialogueCondition::Function_ShouldAttack: + case ESM::DialogueCondition::Function_Werewolf: mComparisonType = Comparison_Boolean; break; // Integer - case Function_Journal: - case Function_Item: - case Function_Dead: - case Function_RankLow: - case Function_RankHigh: - case Function_RankRequirement: - case Function_Reputation: - case Function_PcReputation: - case Function_PcLevel: - case Function_PcStrength: - case Function_PcBlock: - case Function_PcArmorer: - case Function_PcMediumArmor: - case Function_PcHeavyArmor: - case Function_PcBluntWeapon: - case Function_PcLongBlade: - case Function_PcAxe: - case Function_PcSpear: - case Function_PcAthletics: - case Function_PcEnchant: - case Function_PcDestruction: - case Function_PcAlteration: - case Function_PcIllusion: - case Function_PcConjuration: - case Function_PcMysticism: - case Function_PcRestoration: - case Function_PcAlchemy: - case Function_PcUnarmored: - case Function_PcSecurity: - case Function_PcSneak: - case Function_PcAcrobatics: - case Function_PcLightArmor: - case Function_PcShortBlade: - case Function_PcMarksman: - case Function_PcMerchantile: - case Function_PcSpeechcraft: - case Function_PcHandToHand: - case Function_PcGender: - case Function_PcClothingModifier: - case Function_PcCrimeLevel: - case Function_FactionRankDifference: - case Function_Choice: - case Function_PcIntelligence: - case Function_PcWillpower: - case Function_PcAgility: - case Function_PcSpeed: - case Function_PcEndurance: - case Function_PcPersonality: - case Function_PcLuck: - case Function_Weather: - case Function_Level: - case Function_CreatureTarget: - case Function_FriendHit: - case Function_Fight: - case Function_Hello: - case Function_Alarm: - case Function_Flee: - case Function_PcWerewolfKills: + case ESM::DialogueCondition::Function_Journal: + case ESM::DialogueCondition::Function_Item: + case ESM::DialogueCondition::Function_Dead: + case ESM::DialogueCondition::Function_FacReactionLowest: + case ESM::DialogueCondition::Function_FacReactionHighest: + case ESM::DialogueCondition::Function_RankRequirement: + case ESM::DialogueCondition::Function_Reputation: + case ESM::DialogueCondition::Function_PcReputation: + case ESM::DialogueCondition::Function_PcLevel: + case ESM::DialogueCondition::Function_PcStrength: + case ESM::DialogueCondition::Function_PcBlock: + case ESM::DialogueCondition::Function_PcArmorer: + case ESM::DialogueCondition::Function_PcMediumArmor: + case ESM::DialogueCondition::Function_PcHeavyArmor: + case ESM::DialogueCondition::Function_PcBluntWeapon: + case ESM::DialogueCondition::Function_PcLongBlade: + case ESM::DialogueCondition::Function_PcAxe: + case ESM::DialogueCondition::Function_PcSpear: + case ESM::DialogueCondition::Function_PcAthletics: + case ESM::DialogueCondition::Function_PcEnchant: + case ESM::DialogueCondition::Function_PcDestruction: + case ESM::DialogueCondition::Function_PcAlteration: + case ESM::DialogueCondition::Function_PcIllusion: + case ESM::DialogueCondition::Function_PcConjuration: + case ESM::DialogueCondition::Function_PcMysticism: + case ESM::DialogueCondition::Function_PcRestoration: + case ESM::DialogueCondition::Function_PcAlchemy: + case ESM::DialogueCondition::Function_PcUnarmored: + case ESM::DialogueCondition::Function_PcSecurity: + case ESM::DialogueCondition::Function_PcSneak: + case ESM::DialogueCondition::Function_PcAcrobatics: + case ESM::DialogueCondition::Function_PcLightArmor: + case ESM::DialogueCondition::Function_PcShortBlade: + case ESM::DialogueCondition::Function_PcMarksman: + case ESM::DialogueCondition::Function_PcMerchantile: + case ESM::DialogueCondition::Function_PcSpeechcraft: + case ESM::DialogueCondition::Function_PcHandToHand: + case ESM::DialogueCondition::Function_PcGender: + case ESM::DialogueCondition::Function_PcClothingModifier: + case ESM::DialogueCondition::Function_PcCrimeLevel: + case ESM::DialogueCondition::Function_FactionRankDifference: + case ESM::DialogueCondition::Function_Choice: + case ESM::DialogueCondition::Function_PcIntelligence: + case ESM::DialogueCondition::Function_PcWillpower: + case ESM::DialogueCondition::Function_PcAgility: + case ESM::DialogueCondition::Function_PcSpeed: + case ESM::DialogueCondition::Function_PcEndurance: + case ESM::DialogueCondition::Function_PcPersonality: + case ESM::DialogueCondition::Function_PcLuck: + case ESM::DialogueCondition::Function_Weather: + case ESM::DialogueCondition::Function_Level: + case ESM::DialogueCondition::Function_CreatureTarget: + case ESM::DialogueCondition::Function_FriendHit: + case ESM::DialogueCondition::Function_Fight: + case ESM::DialogueCondition::Function_Hello: + case ESM::DialogueCondition::Function_Alarm: + case ESM::DialogueCondition::Function_Flee: + case ESM::DialogueCondition::Function_PcWerewolfKills: mComparisonType = Comparison_Integer; break; // Numeric - case Function_Global: - case Function_Local: - case Function_NotLocal: + case ESM::DialogueCondition::Function_Global: + case ESM::DialogueCondition::Function_Local: + case ESM::DialogueCondition::Function_NotLocal: - case Function_Health_Percent: - case Function_PcHealthPercent: - case Function_PcMagicka: - case Function_PcFatigue: - case Function_PcHealth: + case ESM::DialogueCondition::Function_Health_Percent: + case ESM::DialogueCondition::Function_PcHealthPercent: + case ESM::DialogueCondition::Function_PcMagicka: + case ESM::DialogueCondition::Function_PcFatigue: + case ESM::DialogueCondition::Function_PcHealth: mComparisonType = Comparison_Numeric; break; @@ -511,15 +349,15 @@ std::pair CSMWorld::ConstInfoSelectWrapper::getConditionIntRange() con const int IntMin = std::numeric_limits::min(); const std::pair InvalidRange(IntMax, IntMin); - int value = mConstSelect.mValue.getInteger(); + int value = std::get(mConstSelect.mValue); - switch (mRelationType) + switch (getRelationType()) { - case Relation_Equal: - case Relation_NotEqual: + case ESM::DialogueCondition::Comp_Eq: + case ESM::DialogueCondition::Comp_Ne: return std::pair(value, value); - case Relation_Greater: + case ESM::DialogueCondition::Comp_Gt: if (value == IntMax) { return InvalidRange; @@ -530,10 +368,10 @@ std::pair CSMWorld::ConstInfoSelectWrapper::getConditionIntRange() con } break; - case Relation_GreaterOrEqual: + case ESM::DialogueCondition::Comp_Ge: return std::pair(value, IntMax); - case Relation_Less: + case ESM::DialogueCondition::Comp_Ls: if (value == IntMin) { return InvalidRange; @@ -543,7 +381,7 @@ std::pair CSMWorld::ConstInfoSelectWrapper::getConditionIntRange() con return std::pair(IntMin, value - 1); } - case Relation_LessOrEqual: + case ESM::DialogueCondition::Comp_Le: return std::pair(IntMin, value); default: @@ -557,24 +395,24 @@ std::pair CSMWorld::ConstInfoSelectWrapper::getConditionFloatRange const float FloatMin = -std::numeric_limits::infinity(); const float Epsilon = std::numeric_limits::epsilon(); - float value = mConstSelect.mValue.getFloat(); + float value = std::get(mConstSelect.mValue); - switch (mRelationType) + switch (getRelationType()) { - case Relation_Equal: - case Relation_NotEqual: + case ESM::DialogueCondition::Comp_Eq: + case ESM::DialogueCondition::Comp_Ne: return std::pair(value, value); - case Relation_Greater: + case ESM::DialogueCondition::Comp_Gt: return std::pair(value + Epsilon, FloatMax); - case Relation_GreaterOrEqual: + case ESM::DialogueCondition::Comp_Ge: return std::pair(value, FloatMax); - case Relation_Less: + case ESM::DialogueCondition::Comp_Ls: return std::pair(FloatMin, value - Epsilon); - case Relation_LessOrEqual: + case ESM::DialogueCondition::Comp_Le: return std::pair(FloatMin, value); default: @@ -587,120 +425,120 @@ std::pair CSMWorld::ConstInfoSelectWrapper::getValidIntRange() const const int IntMax = std::numeric_limits::max(); const int IntMin = std::numeric_limits::min(); - switch (mFunctionName) + switch (getFunctionName()) { // Boolean - case Function_NotId: - case Function_NotFaction: - case Function_NotClass: - case Function_NotRace: - case Function_NotCell: - case Function_PcExpelled: - case Function_PcCommonDisease: - case Function_PcBlightDisease: - case Function_SameSex: - case Function_SameRace: - case Function_SameFaction: - case Function_Detected: - case Function_Alarmed: - case Function_PcCorpus: - case Function_PcVampire: - case Function_Attacked: - case Function_TalkedToPc: - case Function_ShouldAttack: - case Function_Werewolf: + case ESM::DialogueCondition::Function_NotId: + case ESM::DialogueCondition::Function_NotFaction: + case ESM::DialogueCondition::Function_NotClass: + case ESM::DialogueCondition::Function_NotRace: + case ESM::DialogueCondition::Function_NotCell: + case ESM::DialogueCondition::Function_PcExpelled: + case ESM::DialogueCondition::Function_PcCommonDisease: + case ESM::DialogueCondition::Function_PcBlightDisease: + case ESM::DialogueCondition::Function_SameSex: + case ESM::DialogueCondition::Function_SameRace: + case ESM::DialogueCondition::Function_SameFaction: + case ESM::DialogueCondition::Function_Detected: + case ESM::DialogueCondition::Function_Alarmed: + case ESM::DialogueCondition::Function_PcCorprus: + case ESM::DialogueCondition::Function_PcVampire: + case ESM::DialogueCondition::Function_Attacked: + case ESM::DialogueCondition::Function_TalkedToPc: + case ESM::DialogueCondition::Function_ShouldAttack: + case ESM::DialogueCondition::Function_Werewolf: return std::pair(0, 1); // Integer - case Function_RankLow: - case Function_RankHigh: - case Function_Reputation: - case Function_PcReputation: - case Function_Journal: + case ESM::DialogueCondition::Function_FacReactionLowest: + case ESM::DialogueCondition::Function_FacReactionHighest: + case ESM::DialogueCondition::Function_Reputation: + case ESM::DialogueCondition::Function_PcReputation: + case ESM::DialogueCondition::Function_Journal: return std::pair(IntMin, IntMax); - case Function_Item: - case Function_Dead: - case Function_PcLevel: - case Function_PcStrength: - case Function_PcBlock: - case Function_PcArmorer: - case Function_PcMediumArmor: - case Function_PcHeavyArmor: - case Function_PcBluntWeapon: - case Function_PcLongBlade: - case Function_PcAxe: - case Function_PcSpear: - case Function_PcAthletics: - case Function_PcEnchant: - case Function_PcDestruction: - case Function_PcAlteration: - case Function_PcIllusion: - case Function_PcConjuration: - case Function_PcMysticism: - case Function_PcRestoration: - case Function_PcAlchemy: - case Function_PcUnarmored: - case Function_PcSecurity: - case Function_PcSneak: - case Function_PcAcrobatics: - case Function_PcLightArmor: - case Function_PcShortBlade: - case Function_PcMarksman: - case Function_PcMerchantile: - case Function_PcSpeechcraft: - case Function_PcHandToHand: - case Function_PcClothingModifier: - case Function_PcCrimeLevel: - case Function_Choice: - case Function_PcIntelligence: - case Function_PcWillpower: - case Function_PcAgility: - case Function_PcSpeed: - case Function_PcEndurance: - case Function_PcPersonality: - case Function_PcLuck: - case Function_Level: - case Function_PcWerewolfKills: + case ESM::DialogueCondition::Function_Item: + case ESM::DialogueCondition::Function_Dead: + case ESM::DialogueCondition::Function_PcLevel: + case ESM::DialogueCondition::Function_PcStrength: + case ESM::DialogueCondition::Function_PcBlock: + case ESM::DialogueCondition::Function_PcArmorer: + case ESM::DialogueCondition::Function_PcMediumArmor: + case ESM::DialogueCondition::Function_PcHeavyArmor: + case ESM::DialogueCondition::Function_PcBluntWeapon: + case ESM::DialogueCondition::Function_PcLongBlade: + case ESM::DialogueCondition::Function_PcAxe: + case ESM::DialogueCondition::Function_PcSpear: + case ESM::DialogueCondition::Function_PcAthletics: + case ESM::DialogueCondition::Function_PcEnchant: + case ESM::DialogueCondition::Function_PcDestruction: + case ESM::DialogueCondition::Function_PcAlteration: + case ESM::DialogueCondition::Function_PcIllusion: + case ESM::DialogueCondition::Function_PcConjuration: + case ESM::DialogueCondition::Function_PcMysticism: + case ESM::DialogueCondition::Function_PcRestoration: + case ESM::DialogueCondition::Function_PcAlchemy: + case ESM::DialogueCondition::Function_PcUnarmored: + case ESM::DialogueCondition::Function_PcSecurity: + case ESM::DialogueCondition::Function_PcSneak: + case ESM::DialogueCondition::Function_PcAcrobatics: + case ESM::DialogueCondition::Function_PcLightArmor: + case ESM::DialogueCondition::Function_PcShortBlade: + case ESM::DialogueCondition::Function_PcMarksman: + case ESM::DialogueCondition::Function_PcMerchantile: + case ESM::DialogueCondition::Function_PcSpeechcraft: + case ESM::DialogueCondition::Function_PcHandToHand: + case ESM::DialogueCondition::Function_PcClothingModifier: + case ESM::DialogueCondition::Function_PcCrimeLevel: + case ESM::DialogueCondition::Function_Choice: + case ESM::DialogueCondition::Function_PcIntelligence: + case ESM::DialogueCondition::Function_PcWillpower: + case ESM::DialogueCondition::Function_PcAgility: + case ESM::DialogueCondition::Function_PcSpeed: + case ESM::DialogueCondition::Function_PcEndurance: + case ESM::DialogueCondition::Function_PcPersonality: + case ESM::DialogueCondition::Function_PcLuck: + case ESM::DialogueCondition::Function_Level: + case ESM::DialogueCondition::Function_PcWerewolfKills: return std::pair(0, IntMax); - case Function_Fight: - case Function_Hello: - case Function_Alarm: - case Function_Flee: + case ESM::DialogueCondition::Function_Fight: + case ESM::DialogueCondition::Function_Hello: + case ESM::DialogueCondition::Function_Alarm: + case ESM::DialogueCondition::Function_Flee: return std::pair(0, 100); - case Function_Weather: + case ESM::DialogueCondition::Function_Weather: return std::pair(0, 9); - case Function_FriendHit: + case ESM::DialogueCondition::Function_FriendHit: return std::pair(0, 4); - case Function_RankRequirement: + case ESM::DialogueCondition::Function_RankRequirement: return std::pair(0, 3); - case Function_CreatureTarget: + case ESM::DialogueCondition::Function_CreatureTarget: return std::pair(0, 2); - case Function_PcGender: + case ESM::DialogueCondition::Function_PcGender: return std::pair(0, 1); - case Function_FactionRankDifference: + case ESM::DialogueCondition::Function_FactionRankDifference: return std::pair(-9, 9); // Numeric - case Function_Global: - case Function_Local: - case Function_NotLocal: + case ESM::DialogueCondition::Function_Global: + case ESM::DialogueCondition::Function_Local: + case ESM::DialogueCondition::Function_NotLocal: return std::pair(IntMin, IntMax); - case Function_PcMagicka: - case Function_PcFatigue: - case Function_PcHealth: + case ESM::DialogueCondition::Function_PcMagicka: + case ESM::DialogueCondition::Function_PcFatigue: + case ESM::DialogueCondition::Function_PcHealth: return std::pair(0, IntMax); - case Function_Health_Percent: - case Function_PcHealthPercent: + case ESM::DialogueCondition::Function_Health_Percent: + case ESM::DialogueCondition::Function_PcHealthPercent: return std::pair(0, 100); default: @@ -713,21 +551,21 @@ std::pair CSMWorld::ConstInfoSelectWrapper::getValidFloatRange() c const float FloatMax = std::numeric_limits::infinity(); const float FloatMin = -std::numeric_limits::infinity(); - switch (mFunctionName) + switch (getFunctionName()) { // Numeric - case Function_Global: - case Function_Local: - case Function_NotLocal: + case ESM::DialogueCondition::Function_Global: + case ESM::DialogueCondition::Function_Local: + case ESM::DialogueCondition::Function_NotLocal: return std::pair(FloatMin, FloatMax); - case Function_PcMagicka: - case Function_PcFatigue: - case Function_PcHealth: + case ESM::DialogueCondition::Function_PcMagicka: + case ESM::DialogueCondition::Function_PcFatigue: + case ESM::DialogueCondition::Function_PcHealth: return std::pair(0, FloatMax); - case Function_Health_Percent: - case Function_PcHealthPercent: + case ESM::DialogueCondition::Function_Health_Percent: + case ESM::DialogueCondition::Function_PcHealthPercent: return std::pair(0, 100); default: @@ -768,19 +606,19 @@ template bool CSMWorld::ConstInfoSelectWrapper::conditionIsAlwaysTrue( std::pair conditionRange, std::pair validRange) const { - switch (mRelationType) + switch (getRelationType()) { - case Relation_Equal: + case ESM::DialogueCondition::Comp_Eq: return false; - case Relation_NotEqual: + case ESM::DialogueCondition::Comp_Ne: // If value is not within range, it will always be true return !rangeContains(conditionRange.first, validRange); - case Relation_Greater: - case Relation_GreaterOrEqual: - case Relation_Less: - case Relation_LessOrEqual: + case ESM::DialogueCondition::Comp_Gt: + case ESM::DialogueCondition::Comp_Ge: + case ESM::DialogueCondition::Comp_Ls: + case ESM::DialogueCondition::Comp_Le: // If the valid range is completely within the condition range, it will always be true return rangeFullyContains(conditionRange, validRange); @@ -795,18 +633,18 @@ template bool CSMWorld::ConstInfoSelectWrapper::conditionIsNeverTrue( std::pair conditionRange, std::pair validRange) const { - switch (mRelationType) + switch (getRelationType()) { - case Relation_Equal: + case ESM::DialogueCondition::Comp_Eq: return !rangeContains(conditionRange.first, validRange); - case Relation_NotEqual: + case ESM::DialogueCondition::Comp_Ne: return false; - case Relation_Greater: - case Relation_GreaterOrEqual: - case Relation_Less: - case Relation_LessOrEqual: + case ESM::DialogueCondition::Comp_Gt: + case ESM::DialogueCondition::Comp_Ge: + case ESM::DialogueCondition::Comp_Ls: + case ESM::DialogueCondition::Comp_Le: // If ranges do not overlap, it will never be true return !rangesOverlap(conditionRange, validRange); @@ -817,153 +655,47 @@ bool CSMWorld::ConstInfoSelectWrapper::conditionIsNeverTrue( return false; } +QVariant CSMWorld::ConstInfoSelectWrapper::getValue() const +{ + return std::visit([](auto value) { return QVariant(value); }, mConstSelect.mValue); +} + // InfoSelectWrapper -CSMWorld::InfoSelectWrapper::InfoSelectWrapper(ESM::DialInfo::SelectStruct& select) +CSMWorld::InfoSelectWrapper::InfoSelectWrapper(ESM::DialogueCondition& select) : CSMWorld::ConstInfoSelectWrapper(select) , mSelect(select) { } -void CSMWorld::InfoSelectWrapper::setFunctionName(FunctionName name) +void CSMWorld::InfoSelectWrapper::setFunctionName(ESM::DialogueCondition::Function name) { - mFunctionName = name; + mSelect.mFunction = name; updateHasVariable(); updateComparisonType(); + if (getComparisonType() != ConstInfoSelectWrapper::Comparison_Numeric + && std::holds_alternative(mSelect.mValue)) + { + mSelect.mValue = std::visit([](auto value) { return static_cast(value); }, mSelect.mValue); + } } -void CSMWorld::InfoSelectWrapper::setRelationType(RelationType type) +void CSMWorld::InfoSelectWrapper::setRelationType(ESM::DialogueCondition::Comparison type) { - mRelationType = type; + mSelect.mComparison = type; } void CSMWorld::InfoSelectWrapper::setVariableName(const std::string& name) { - mVariableName = name; + mSelect.mVariable = name; } -void CSMWorld::InfoSelectWrapper::setDefaults() +void CSMWorld::InfoSelectWrapper::setValue(int value) { - if (!variantTypeIsValid()) - mSelect.mValue.setType(ESM::VT_Int); - - switch (mComparisonType) - { - case Comparison_Boolean: - setRelationType(Relation_Equal); - mSelect.mValue.setInteger(1); - break; - - case Comparison_Integer: - case Comparison_Numeric: - setRelationType(Relation_Greater); - mSelect.mValue.setInteger(0); - break; - - default: - // Do nothing - break; - } - - update(); + mSelect.mValue = value; } -void CSMWorld::InfoSelectWrapper::update() +void CSMWorld::InfoSelectWrapper::setValue(float value) { - std::ostringstream stream; - - // Leading 0 - stream << '0'; - - // Write Function - - bool writeIndex = false; - size_t functionIndex = static_cast(mFunctionName); - - switch (mFunctionName) - { - case Function_None: - stream << '0'; - break; - case Function_Global: - stream << '2'; - break; - case Function_Local: - stream << '3'; - break; - case Function_Journal: - stream << '4'; - break; - case Function_Item: - stream << '5'; - break; - case Function_Dead: - stream << '6'; - break; - case Function_NotId: - stream << '7'; - break; - case Function_NotFaction: - stream << '8'; - break; - case Function_NotClass: - stream << '9'; - break; - case Function_NotRace: - stream << 'A'; - break; - case Function_NotCell: - stream << 'B'; - break; - case Function_NotLocal: - stream << 'C'; - break; - default: - stream << '1'; - writeIndex = true; - break; - } - - if (writeIndex && functionIndex < 10) // leading 0 - stream << '0' << functionIndex; - else if (writeIndex) - stream << functionIndex; - else - stream << "00"; - - // Write Relation - switch (mRelationType) - { - case Relation_Equal: - stream << '0'; - break; - case Relation_NotEqual: - stream << '1'; - break; - case Relation_Greater: - stream << '2'; - break; - case Relation_GreaterOrEqual: - stream << '3'; - break; - case Relation_Less: - stream << '4'; - break; - case Relation_LessOrEqual: - stream << '5'; - break; - default: - stream << '0'; - break; - } - - if (mHasVariable) - stream << mVariableName; - - mSelect.mSelectRule = stream.str(); -} - -ESM::Variant& CSMWorld::InfoSelectWrapper::getVariant() -{ - return mSelect.mValue; + mSelect.mValue = value; } diff --git a/apps/opencs/model/world/infoselectwrapper.hpp b/apps/opencs/model/world/infoselectwrapper.hpp index 4ecdc676dc..b3b5abe462 100644 --- a/apps/opencs/model/world/infoselectwrapper.hpp +++ b/apps/opencs/model/world/infoselectwrapper.hpp @@ -7,133 +7,13 @@ #include -namespace ESM -{ - class Variant; -} +#include namespace CSMWorld { - // ESM::DialInfo::SelectStruct.mSelectRule - // 012345... - // ^^^ ^^ - // ||| || - // ||| |+------------- condition variable string - // ||| +-------------- comparison type, ['0'..'5']; e.g. !=, <, >=, etc - // ||+---------------- function index (encoded, where function == '1') - // |+----------------- function, ['1'..'C']; e.g. Global, Local, Not ID, etc - // +------------------ unknown - // - - // Wrapper for DialInfo::SelectStruct class ConstInfoSelectWrapper { public: - // Order matters - enum FunctionName - { - Function_RankLow = 0, - Function_RankHigh, - Function_RankRequirement, - Function_Reputation, - Function_Health_Percent, - Function_PcReputation, - Function_PcLevel, - Function_PcHealthPercent, - Function_PcMagicka, - Function_PcFatigue, - Function_PcStrength, - Function_PcBlock, - Function_PcArmorer, - Function_PcMediumArmor, - Function_PcHeavyArmor, - Function_PcBluntWeapon, - Function_PcLongBlade, - Function_PcAxe, - Function_PcSpear, - Function_PcAthletics, - Function_PcEnchant, - Function_PcDestruction, - Function_PcAlteration, - Function_PcIllusion, - Function_PcConjuration, - Function_PcMysticism, - Function_PcRestoration, - Function_PcAlchemy, - Function_PcUnarmored, - Function_PcSecurity, - Function_PcSneak, - Function_PcAcrobatics, - Function_PcLightArmor, - Function_PcShortBlade, - Function_PcMarksman, - Function_PcMerchantile, - Function_PcSpeechcraft, - Function_PcHandToHand, - Function_PcGender, - Function_PcExpelled, - Function_PcCommonDisease, - Function_PcBlightDisease, - Function_PcClothingModifier, - Function_PcCrimeLevel, - Function_SameSex, - Function_SameRace, - Function_SameFaction, - Function_FactionRankDifference, - Function_Detected, - Function_Alarmed, - Function_Choice, - Function_PcIntelligence, - Function_PcWillpower, - Function_PcAgility, - Function_PcSpeed, - Function_PcEndurance, - Function_PcPersonality, - Function_PcLuck, - Function_PcCorpus, - Function_Weather, - Function_PcVampire, - Function_Level, - Function_Attacked, - Function_TalkedToPc, - Function_PcHealth, - Function_CreatureTarget, - Function_FriendHit, - Function_Fight, - Function_Hello, - Function_Alarm, - Function_Flee, - Function_ShouldAttack, - Function_Werewolf, - Function_PcWerewolfKills = 73, - - Function_Global, - Function_Local, - Function_Journal, - Function_Item, - Function_Dead, - Function_NotId, - Function_NotFaction, - Function_NotClass, - Function_NotRace, - Function_NotCell, - Function_NotLocal, - - Function_None - }; - - enum RelationType - { - Relation_Equal, - Relation_NotEqual, - Relation_Greater, - Relation_GreaterOrEqual, - Relation_Less, - Relation_LessOrEqual, - - Relation_None - }; - enum ComparisonType { Comparison_Boolean, @@ -143,25 +23,13 @@ namespace CSMWorld Comparison_None }; - static const size_t RuleMinSize; - - static const size_t FunctionPrefixOffset; - static const size_t FunctionIndexOffset; - static const size_t RelationIndexOffset; - static const size_t VarNameOffset; - static const char* FunctionEnumStrings[]; static const char* RelationEnumStrings[]; - static const char* ComparisonEnumStrings[]; - static std::string convertToString(FunctionName name); - static std::string convertToString(RelationType type); - static std::string convertToString(ComparisonType type); + ConstInfoSelectWrapper(const ESM::DialogueCondition& select); - ConstInfoSelectWrapper(const ESM::DialInfo::SelectStruct& select); - - FunctionName getFunctionName() const; - RelationType getRelationType() const; + ESM::DialogueCondition::Function getFunctionName() const; + ESM::DialogueCondition::Comparison getRelationType() const; ComparisonType getComparisonType() const; bool hasVariable() const; @@ -169,17 +37,12 @@ namespace CSMWorld bool conditionIsAlwaysTrue() const; bool conditionIsNeverTrue() const; - bool variantTypeIsValid() const; - const ESM::Variant& getVariant() const; + QVariant getValue() const; std::string toString() const; protected: - void readRule(); - void readFunctionName(); - void readRelationType(); - void readVariableName(); void updateHasVariable(); void updateComparisonType(); @@ -207,38 +70,29 @@ namespace CSMWorld template bool conditionIsNeverTrue(std::pair conditionRange, std::pair validRange) const; - FunctionName mFunctionName; - RelationType mRelationType; ComparisonType mComparisonType; bool mHasVariable; - std::string mVariableName; private: - const ESM::DialInfo::SelectStruct& mConstSelect; + const ESM::DialogueCondition& mConstSelect; }; - // Wrapper for DialInfo::SelectStruct that can modify the wrapped select struct + // Wrapper for DialogueCondition that can modify the wrapped select struct class InfoSelectWrapper : public ConstInfoSelectWrapper { public: - InfoSelectWrapper(ESM::DialInfo::SelectStruct& select); + InfoSelectWrapper(ESM::DialogueCondition& select); // Wrapped SelectStruct will not be modified until update() is called - void setFunctionName(FunctionName name); - void setRelationType(RelationType type); + void setFunctionName(ESM::DialogueCondition::Function name); + void setRelationType(ESM::DialogueCondition::Comparison type); void setVariableName(const std::string& name); - - // Modified wrapped SelectStruct - void update(); - - // This sets properties based on the function name to its defaults and updates the wrapped object - void setDefaults(); - - ESM::Variant& getVariant(); + void setValue(int value); + void setValue(float value); private: - ESM::DialInfo::SelectStruct& mSelect; + ESM::DialogueCondition& mSelect; void writeRule(); }; diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 0d90ea0d68..c844c5a18f 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -538,13 +538,11 @@ namespace CSMWorld { Info info = record.get(); - std::vector& conditions = info.mSelects; + auto& conditions = info.mSelects; // default row - ESM::DialInfo::SelectStruct condStruct; - condStruct.mSelectRule = "01000"; - condStruct.mValue = ESM::Variant(); - condStruct.mValue.setType(ESM::VT_Int); + ESM::DialogueCondition condStruct; + condStruct.mIndex = conditions.size(); conditions.insert(conditions.begin() + position, condStruct); @@ -555,7 +553,7 @@ namespace CSMWorld { Info info = record.get(); - std::vector& conditions = info.mSelects; + auto& conditions = info.mSelects; if (rowToRemove < 0 || rowToRemove >= static_cast(conditions.size())) throw std::runtime_error("index out of range"); @@ -569,8 +567,8 @@ namespace CSMWorld { Info info = record.get(); - info.mSelects = static_cast>&>(nestedTable) - .mNestedTable; + info.mSelects + = static_cast>&>(nestedTable).mNestedTable; record.setModified(info); } @@ -578,14 +576,14 @@ namespace CSMWorld NestedTableWrapperBase* InfoConditionAdapter::table(const Record& record) const { // deleted by dtor of NestedTableStoring - return new NestedTableWrapper>(record.get().mSelects); + return new NestedTableWrapper>(record.get().mSelects); } QVariant InfoConditionAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { Info info = record.get(); - std::vector& conditions = info.mSelects; + auto& conditions = info.mSelects; if (subRowIndex < 0 || subRowIndex >= static_cast(conditions.size())) throw std::runtime_error("index out of range"); @@ -607,23 +605,11 @@ namespace CSMWorld } case 2: { - return infoSelectWrapper.getRelationType(); + return infoSelectWrapper.getRelationType() - ESM::DialogueCondition::Comp_Eq; } case 3: { - switch (infoSelectWrapper.getVariant().getType()) - { - case ESM::VT_Int: - { - return infoSelectWrapper.getVariant().getInteger(); - } - case ESM::VT_Float: - { - return infoSelectWrapper.getVariant().getFloat(); - } - default: - return QVariant(); - } + return infoSelectWrapper.getValue(); } default: throw std::runtime_error("Info condition subcolumn index out of range"); @@ -635,7 +621,7 @@ namespace CSMWorld { Info info = record.get(); - std::vector& conditions = info.mSelects; + auto& conditions = info.mSelects; if (subRowIndex < 0 || subRowIndex >= static_cast(conditions.size())) throw std::runtime_error("index out of range"); @@ -647,27 +633,18 @@ namespace CSMWorld { case 0: // Function { - infoSelectWrapper.setFunctionName(static_cast(value.toInt())); - - if (infoSelectWrapper.getComparisonType() != ConstInfoSelectWrapper::Comparison_Numeric - && infoSelectWrapper.getVariant().getType() != ESM::VT_Int) - { - infoSelectWrapper.getVariant().setType(ESM::VT_Int); - } - - infoSelectWrapper.update(); + infoSelectWrapper.setFunctionName(static_cast(value.toInt())); break; } case 1: // Variable { infoSelectWrapper.setVariableName(value.toString().toUtf8().constData()); - infoSelectWrapper.update(); break; } case 2: // Relation { - infoSelectWrapper.setRelationType(static_cast(value.toInt())); - infoSelectWrapper.update(); + infoSelectWrapper.setRelationType( + static_cast(value.toInt() + ESM::DialogueCondition::Comp_Eq)); break; } case 3: // Value @@ -679,13 +656,11 @@ namespace CSMWorld // QVariant seems to have issues converting 0 if ((value.toInt(&conversionResult) && conversionResult) || value.toString().compare("0") == 0) { - infoSelectWrapper.getVariant().setType(ESM::VT_Int); - infoSelectWrapper.getVariant().setInteger(value.toInt()); + infoSelectWrapper.setValue(value.toInt()); } else if (value.toFloat(&conversionResult) && conversionResult) { - infoSelectWrapper.getVariant().setType(ESM::VT_Float); - infoSelectWrapper.getVariant().setFloat(value.toFloat()); + infoSelectWrapper.setValue(value.toFloat()); } break; } @@ -694,8 +669,7 @@ namespace CSMWorld { if ((value.toInt(&conversionResult) && conversionResult) || value.toString().compare("0") == 0) { - infoSelectWrapper.getVariant().setType(ESM::VT_Int); - infoSelectWrapper.getVariant().setInteger(value.toInt()); + infoSelectWrapper.setValue(value.toInt()); } break; } diff --git a/apps/opencs/model/world/tablemimedata.cpp b/apps/opencs/model/world/tablemimedata.cpp index a966a53eee..a40698bc27 100644 --- a/apps/opencs/model/world/tablemimedata.cpp +++ b/apps/opencs/model/world/tablemimedata.cpp @@ -58,7 +58,7 @@ std::string CSMWorld::TableMimeData::getIcon() const if (tmpIcon != id.getIcon()) { - return ":/multitype.png"; // icon stolen from gnome TODO: get new icon + return ":multitype"; } tmpIcon = id.getIcon(); diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 9daf87e20a..0ebccd6253 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -23,158 +23,137 @@ namespace constexpr TypeData sNoArg[] = { { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "-", ":placeholder" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables", - ":./global-variable.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings", ":./gmst.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills", ":./skill.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes", ":./class.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions", ":./faction.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races", ":./race.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds", ":./sound.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts", ":./script.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions", ":./region.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns", - ":./birthsign.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells", ":./spell.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Topics, "Topics", - ":./dialogue-topics.png" }, + ":global-variable" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings", ":gmst" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills", ":skill" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes", ":class" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions", ":faction" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races", ":race" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds", ":sound" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts", ":script" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions", ":region" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns", ":birthsign" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells", ":spell" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Topics, "Topics", ":dialogue-topics" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Journals, "Journals", - ":./journal-topics.png" }, + ":journal-topics" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_TopicInfos, "Topic Infos", - ":./dialogue-topic-infos.png" }, + ":dialogue-info" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_JournalInfos, "Journal Infos", - ":./journal-topic-infos.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells", ":./cell.png" }, + ":journal-topic-infos" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells", ":cell" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Enchantments, "Enchantments", - ":./enchantment.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_BodyParts, "Body Parts", - ":./body-part.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables, "Objects", - ":./object.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_References, "Instances", - ":./instance.png" }, - { CSMWorld::UniversalId::Class_NonRecord, CSMWorld::UniversalId::Type_RegionMap, "Region Map", - ":./region-map.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Filters, "Filters", ":./filter.png" }, - { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Meshes, "Meshes", - ":./resources-mesh" }, - { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Icons, "Icons", ":./resources-icon" }, + ":enchantment" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_BodyParts, "Body Parts", ":body-part" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables, "Objects", ":object" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_References, "Instances", ":instance" }, + { CSMWorld::UniversalId::Class_NonRecord, CSMWorld::UniversalId::Type_RegionMap, "Region Map", ":region-map" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Filters, "Filters", ":filter" }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Meshes, "Meshes", ":resources-mesh" }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Icons, "Icons", ":resources-icon" }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Musics, "Music Files", - ":./resources-music" }, + ":resources-music" }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_SoundsRes, "Sound Files", ":resources-sound" }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Textures, "Textures", - ":./resources-texture" }, - { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Videos, "Videos", - ":./resources-video" }, + ":resources-texture" }, + { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Videos, "Videos", ":resources-video" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_DebugProfiles, "Debug Profiles", - ":./debug-profile.png" }, + ":debug-profile" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SelectionGroup, "Selection Groups", "" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", ":./run-log.png" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", ":run-log" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_SoundGens, "Sound Generators", - ":./sound-generator.png" }, + ":sound-generator" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", - ":./magic-effect.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Lands, "Lands", - ":./land-heightmap.png" }, + ":magic-effect" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Lands, "Lands", ":land-heightmap" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_LandTextures, "Land Textures", - ":./land-texture.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", - ":./pathgrid.png" }, + ":land-texture" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", ":pathgrid" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", - ":./start-script.png" }, - { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Metadata", - ":./metadata.png" }, + ":start-script" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Metadata", ":metadata" }, }; constexpr TypeData sIdArg[] = { { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable", - ":./global-variable.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting", ":./gmst.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill", ":./skill.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class", ":./class.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction", ":./faction.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race", ":./race.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound", ":./sound.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script", ":./script.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region", ":./region.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign", ":./birthsign.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell", ":./spell.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Topic, "Topic", ":./dialogue-topics.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal", - ":./journal-topics.png" }, + ":global-variable" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting", ":gmst" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill", ":skill" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class", ":class" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction", ":faction" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race", ":race" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound", ":sound" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script", ":script" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region", ":region" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign", ":birthsign" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell", ":spell" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Topic, "Topic", ":dialogue-topics" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal", ":journal-topics" }, { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", - ":./dialogue-topic-infos.png" }, + ":dialogue-info" }, { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", - ":./journal-topic-infos.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", ":./cell.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell_Missing, "Cell", ":./cell.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Object", ":./object.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Activator, "Activator", - ":./activator.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Potion, "Potion", ":./potion.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Apparatus, "Apparatus", - ":./apparatus.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Armor, "Armor", ":./armor.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Book, "Book", ":./book.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Clothing, "Clothing", ":./clothing.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Container, "Container", - ":./container.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Creature, "Creature", ":./creature.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Door, "Door", ":./door.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Ingredient, "Ingredient", - ":./ingredient.png" }, + ":journal-topic-infos" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", ":cell" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell_Missing, "Cell", ":cell" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Object", ":object" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Activator, "Activator", ":activator" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Potion, "Potion", ":potion" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Apparatus, "Apparatus", ":apparatus" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Armor, "Armor", ":armor" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Book, "Book", ":book" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Clothing, "Clothing", ":clothing" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Container, "Container", ":container" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Creature, "Creature", ":creature" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Door, "Door", ":door" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Ingredient, "Ingredient", ":ingredient" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_CreatureLevelledList, - "Creature Levelled List", ":./levelled-creature.png" }, + "Creature Levelled List", ":levelled-creature" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_ItemLevelledList, "Item Levelled List", - ":./levelled-item.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Light, "Light", ":./light.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Lockpick, "Lockpick", ":./lockpick.png" }, + ":levelled-item" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Light, "Light", ":light" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Lockpick, "Lockpick", ":lockpick" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Miscellaneous, "Miscellaneous", - ":./miscellaneous.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Npc, "NPC", ":./npc.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Probe, "Probe", ":./probe.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Repair, "Repair", ":./repair.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Static, "Static", ":./static.png" }, - { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" }, - { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Instance", - ":./instance.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" }, - { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", ":./scene.png" }, - { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview", - ":./record-preview.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Enchantment, "Enchantment", - ":./enchantment.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_BodyPart, "Body Part", ":./body-part.png" }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Mesh, "Mesh", ":./resources-mesh" }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Icon, "Icon", ":./resources-icon" }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Music, "Music", ":./resources-music" }, + ":miscellaneous" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Npc, "NPC", ":npc" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Probe, "Probe", ":probe" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Repair, "Repair", ":repair" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Static, "Static", ":static" }, + { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":weapon" }, + { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Instance", ":instance" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Filter, "Filter", ":filter" }, + { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", ":scene" }, + { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview", ":edit-preview" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Enchantment, "Enchantment", ":enchantment" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_BodyPart, "Body Part", ":body-part" }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Mesh, "Mesh", ":resources-mesh" }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Icon, "Icon", ":resources-icon" }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Music, "Music", ":resources-music" }, { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_SoundRes, "Sound File", - ":./resources-sound" }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture", - ":./resources-texture" }, - { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Video, "Video", ":./resources-video" }, + ":resources-sound" }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture", ":resources-texture" }, + { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Video, "Video", ":resources-video" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_DebugProfile, "Debug Profile", - ":./debug-profile.png" }, + ":debug-profile" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_SoundGen, "Sound Generator", - ":./sound-generator.png" }, + ":sound-generator" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", - ":./magic-effect.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Land, "Land", ":./land-heightmap.png" }, + ":magic-effect" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Land, "Land", ":land-heightmap" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_LandTexture, "Land Texture", - ":./land-texture.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", ":./pathgrid.png" }, + ":land-texture" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", ":pathgrid" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", - ":./start-script.png" }, - { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Metadata", ":./metadata.png" }, + ":start-script" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Metadata", ":metadata" }, }; constexpr TypeData sIndexArg[] = { { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, - "Verification Results", ":./menu-verify.png" }, + "Verification Results", ":menu-verify" }, { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_LoadErrorLog, "Load Error Log", - ":./error-log.png" }, - { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Search, "Global Search", - ":./menu-search.png" }, + ":error-log" }, + { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_Search, "Global Search", ":menu-search" }, }; struct WriteToStream diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index e1bf7e6ac6..f5cdb1b8fc 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -71,30 +71,30 @@ void CSVDoc::View::setupFileMenu() { QMenu* file = menuBar()->addMenu(tr("File")); - QAction* newGame = createMenuEntry("New Game", ":./menu-new-game.png", file, "document-file-newgame"); + QAction* newGame = createMenuEntry("New Game", ":menu-new-game", file, "document-file-newgame"); connect(newGame, &QAction::triggered, this, &View::newGameRequest); - QAction* newAddon = createMenuEntry("New Addon", ":./menu-new-addon.png", file, "document-file-newaddon"); + QAction* newAddon = createMenuEntry("New Addon", ":menu-new-addon", file, "document-file-newaddon"); connect(newAddon, &QAction::triggered, this, &View::newAddonRequest); - QAction* open = createMenuEntry("Open", ":./menu-open.png", file, "document-file-open"); + QAction* open = createMenuEntry("Open", ":menu-open", file, "document-file-open"); connect(open, &QAction::triggered, this, &View::loadDocumentRequest); - QAction* save = createMenuEntry("Save", ":./menu-save.png", file, "document-file-save"); + QAction* save = createMenuEntry("Save", ":menu-save", file, "document-file-save"); connect(save, &QAction::triggered, this, &View::save); mSave = save; file->addSeparator(); - QAction* verify = createMenuEntry("Verify", ":./menu-verify.png", file, "document-file-verify"); + QAction* verify = createMenuEntry("Verify", ":menu-verify", file, "document-file-verify"); connect(verify, &QAction::triggered, this, &View::verify); mVerify = verify; - QAction* merge = createMenuEntry("Merge", ":./menu-merge.png", file, "document-file-merge"); + QAction* merge = createMenuEntry("Merge", ":menu-merge", file, "document-file-merge"); connect(merge, &QAction::triggered, this, &View::merge); mMerge = merge; - QAction* loadErrors = createMenuEntry("Error Log", ":./error-log.png", file, "document-file-errorlog"); + QAction* loadErrors = createMenuEntry("Error Log", ":error-log", file, "document-file-errorlog"); connect(loadErrors, &QAction::triggered, this, &View::loadErrorLog); QAction* meta = createMenuEntry(CSMWorld::UniversalId::Type_MetaDatas, file, "document-file-metadata"); @@ -102,10 +102,10 @@ void CSVDoc::View::setupFileMenu() file->addSeparator(); - QAction* close = createMenuEntry("Close", ":./menu-close.png", file, "document-file-close"); + QAction* close = createMenuEntry("Close", ":menu-close", file, "document-file-close"); connect(close, &QAction::triggered, this, &View::close); - QAction* exit = createMenuEntry("Exit", ":./menu-exit.png", file, "document-file-exit"); + QAction* exit = createMenuEntry("Exit", ":menu-exit", file, "document-file-exit"); connect(exit, &QAction::triggered, this, &View::exit); connect(this, &View::exitApplicationRequest, &mViewManager, &ViewManager::exitApplication); @@ -140,17 +140,16 @@ void CSVDoc::View::setupEditMenu() mUndo = mDocument->getUndoStack().createUndoAction(this, tr("Undo")); setupShortcut("document-edit-undo", mUndo); connect(mUndo, &QAction::changed, this, &View::undoActionChanged); - mUndo->setIcon(QIcon(QString::fromStdString(":./menu-undo.png"))); + mUndo->setIcon(QIcon(QString::fromStdString(":menu-undo"))); edit->addAction(mUndo); mRedo = mDocument->getUndoStack().createRedoAction(this, tr("Redo")); connect(mRedo, &QAction::changed, this, &View::redoActionChanged); setupShortcut("document-edit-redo", mRedo); - mRedo->setIcon(QIcon(QString::fromStdString(":./menu-redo.png"))); + mRedo->setIcon(QIcon(QString::fromStdString(":menu-redo"))); edit->addAction(mRedo); - QAction* userSettings - = createMenuEntry("Preferences", ":./menu-preferences.png", edit, "document-edit-preferences"); + QAction* userSettings = createMenuEntry("Preferences", ":menu-preferences", edit, "document-edit-preferences"); connect(userSettings, &QAction::triggered, this, &View::editSettingsRequest); QAction* search = createMenuEntry(CSMWorld::UniversalId::Type_Search, edit, "document-edit-search"); @@ -161,10 +160,10 @@ void CSVDoc::View::setupViewMenu() { QMenu* view = menuBar()->addMenu(tr("View")); - QAction* newWindow = createMenuEntry("New View", ":./menu-new-window.png", view, "document-view-newview"); + QAction* newWindow = createMenuEntry("New View", ":menu-new-window", view, "document-view-newview"); connect(newWindow, &QAction::triggered, this, &View::newView); - mShowStatusBar = createMenuEntry("Toggle Status Bar", ":./menu-status-bar.png", view, "document-view-statusbar"); + mShowStatusBar = createMenuEntry("Toggle Status Bar", ":menu-status-bar", view, "document-view-statusbar"); connect(mShowStatusBar, &QAction::toggled, this, &View::toggleShowStatusBar); mShowStatusBar->setCheckable(true); mShowStatusBar->setChecked(CSMPrefs::get()["Windows"]["show-statusbar"].isTrue()); @@ -289,7 +288,7 @@ void CSVDoc::View::setupAssetsMenu() { QMenu* assets = menuBar()->addMenu(tr("Assets")); - QAction* reload = createMenuEntry("Reload", ":./menu-reload.png", assets, "document-assets-reload"); + QAction* reload = createMenuEntry("Reload", ":menu-reload", assets, "document-assets-reload"); connect(reload, &QAction::triggered, &mDocument->getData(), &CSMWorld::Data::assetsChanged); assets->addSeparator(); @@ -341,9 +340,9 @@ void CSVDoc::View::setupDebugMenu() QAction* runDebug = debug->addMenu(mGlobalDebugProfileMenu); runDebug->setText(tr("Run OpenMW")); setupShortcut("document-debug-run", runDebug); - runDebug->setIcon(QIcon(QString::fromStdString(":./run-openmw.png"))); + runDebug->setIcon(QIcon(QString::fromStdString(":run-openmw"))); - QAction* stopDebug = createMenuEntry("Stop OpenMW", ":./stop-openmw.png", debug, "document-debug-shutdown"); + QAction* stopDebug = createMenuEntry("Stop OpenMW", ":stop-openmw", debug, "document-debug-shutdown"); connect(stopDebug, &QAction::triggered, this, &View::stop); mStopDebug = stopDebug; @@ -355,16 +354,16 @@ void CSVDoc::View::setupHelpMenu() { QMenu* help = menuBar()->addMenu(tr("Help")); - QAction* helpInfo = createMenuEntry("Help", ":/info.png", help, "document-help-help"); + QAction* helpInfo = createMenuEntry("Help", ":info", help, "document-help-help"); connect(helpInfo, &QAction::triggered, this, &View::openHelp); - QAction* tutorial = createMenuEntry("Tutorial", ":/info.png", help, "document-help-tutorial"); + QAction* tutorial = createMenuEntry("Tutorial", ":info", help, "document-help-tutorial"); connect(tutorial, &QAction::triggered, this, &View::tutorial); - QAction* about = createMenuEntry("About OpenMW-CS", ":./info.png", help, "document-help-about"); + QAction* about = createMenuEntry("About OpenMW-CS", ":info", help, "document-help-about"); connect(about, &QAction::triggered, this, &View::infoAbout); - QAction* aboutQt = createMenuEntry("About Qt", ":./qt.png", help, "document-help-qt"); + QAction* aboutQt = createMenuEntry("About Qt", ":qt", help, "document-help-qt"); connect(aboutQt, &QAction::triggered, this, &View::infoAboutQt); } diff --git a/apps/opencs/view/filter/editwidget.cpp b/apps/opencs/view/filter/editwidget.cpp index 50735bf703..0d7ab679b2 100644 --- a/apps/opencs/view/filter/editwidget.cpp +++ b/apps/opencs/view/filter/editwidget.cpp @@ -44,7 +44,7 @@ CSVFilter::EditWidget::EditWidget(CSMWorld::Data& data, QWidget* parent) mHelpAction = new QAction(tr("Help"), this); connect(mHelpAction, &QAction::triggered, this, &EditWidget::openHelp); - mHelpAction->setIcon(QIcon(":/info.png")); + mHelpAction->setIcon(QIcon(":info")); addAction(mHelpAction); auto* openHelpShortcut = new CSMPrefs::Shortcut("help", this); openHelpShortcut->associateAction(mHelpAction); diff --git a/apps/opencs/view/render/mask.hpp b/apps/opencs/view/render/mask.hpp index 7f767e19ac..1c84d886d3 100644 --- a/apps/opencs/view/render/mask.hpp +++ b/apps/opencs/view/render/mask.hpp @@ -12,11 +12,10 @@ namespace CSVRender { // elements that are part of the actual scene Mask_Hidden = 0x0, - Mask_Reference = 0x2, - Mask_Pathgrid = 0x4, - Mask_Water = 0x8, - Mask_Fog = 0x10, - Mask_Terrain = 0x20, + Mask_Reference = 0x1, + Mask_Pathgrid = 0x2, + Mask_Water = 0x4, + Mask_Terrain = 0x8, // used within models Mask_ParticleSystem = 0x100, diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 214618a627..58523ab595 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -160,7 +160,6 @@ void CSVRender::PagedWorldspaceWidget::addVisibilitySelectorButtons(CSVWidget::S { WorldspaceWidget::addVisibilitySelectorButtons(tool); tool->addButton(Button_Terrain, Mask_Terrain, "Terrain"); - tool->addButton(Button_Fog, Mask_Fog, "Fog", "", true); } void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons(CSVWidget::SceneToolMode* tool) @@ -170,9 +169,10 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons(CSVWidget::Sce /// \todo replace EditMode with suitable subclasses tool->addButton(new TerrainShapeMode(this, mRootNode, tool), "terrain-shape"); tool->addButton(new TerrainTextureMode(this, mRootNode, tool), "terrain-texture"); - tool->addButton( - new EditMode(this, QIcon(":placeholder"), Mask_Reference, "Terrain vertex paint editing"), "terrain-vertex"); - tool->addButton(new EditMode(this, QIcon(":placeholder"), Mask_Reference, "Terrain movement"), "terrain-move"); + const QIcon vertexIcon = QIcon(":scenetoolbar/editing-terrain-vertex-paint"); + const QIcon movementIcon = QIcon(":scenetoolbar/editing-terrain-movement"); + tool->addButton(new EditMode(this, vertexIcon, Mask_Reference, "Terrain vertex paint editing"), "terrain-vertex"); + tool->addButton(new EditMode(this, movementIcon, Mask_Reference, "Terrain movement"), "terrain-move"); } void CSVRender::PagedWorldspaceWidget::handleInteractionPress(const WorldspaceHitResult& hit, InteractionType type) diff --git a/apps/opencs/view/render/pathgridmode.cpp b/apps/opencs/view/render/pathgridmode.cpp index 5c45e2b31f..8550195e8c 100644 --- a/apps/opencs/view/render/pathgridmode.cpp +++ b/apps/opencs/view/render/pathgridmode.cpp @@ -36,8 +36,8 @@ class QWidget; namespace CSVRender { PathgridMode::PathgridMode(WorldspaceWidget* worldspaceWidget, QWidget* parent) - : EditMode(worldspaceWidget, QIcon(":placeholder"), Mask_Pathgrid | Mask_Terrain | Mask_Reference, getTooltip(), - parent) + : EditMode(worldspaceWidget, QIcon(":scenetoolbar/editing-pathgrid"), + Mask_Pathgrid | Mask_Terrain | Mask_Reference, getTooltip(), parent) , mDragMode(DragMode_None) , mFromNode(0) , mSelectionMode(nullptr) diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 899918c3b9..fee43b5de5 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -347,7 +347,6 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons(CSVWidget: { WorldspaceWidget::addVisibilitySelectorButtons(tool); tool->addButton(Button_Terrain, Mask_Terrain, "Terrain", "", true); - tool->addButton(Button_Fog, Mask_Fog, "Fog"); } std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 505d985ffa..06470d2883 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -222,8 +222,7 @@ namespace CSVRender Button_Reference = 0x1, Button_Pathgrid = 0x2, Button_Water = 0x4, - Button_Fog = 0x8, - Button_Terrain = 0x10 + Button_Terrain = 0x8 }; virtual void addVisibilitySelectorButtons(CSVWidget::SceneToolToggle2* tool); diff --git a/apps/opencs/view/world/idcompletiondelegate.cpp b/apps/opencs/view/world/idcompletiondelegate.cpp index 3e26ed9250..e39be392f4 100644 --- a/apps/opencs/view/world/idcompletiondelegate.cpp +++ b/apps/opencs/view/world/idcompletiondelegate.cpp @@ -46,41 +46,41 @@ QWidget* CSVWorld::IdCompletionDelegate::createEditor(QWidget* parent, const QSt switch (conditionFunction) { - case CSMWorld::ConstInfoSelectWrapper::Function_Global: + case ESM::DialogueCondition::Function_Global: { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_GlobalVariable); } - case CSMWorld::ConstInfoSelectWrapper::Function_Journal: + case ESM::DialogueCondition::Function_Journal: { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Journal); } - case CSMWorld::ConstInfoSelectWrapper::Function_Item: + case ESM::DialogueCondition::Function_Item: { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Referenceable); } - case CSMWorld::ConstInfoSelectWrapper::Function_Dead: - case CSMWorld::ConstInfoSelectWrapper::Function_NotId: + case ESM::DialogueCondition::Function_Dead: + case ESM::DialogueCondition::Function_NotId: { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Referenceable); } - case CSMWorld::ConstInfoSelectWrapper::Function_NotFaction: + case ESM::DialogueCondition::Function_NotFaction: { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Faction); } - case CSMWorld::ConstInfoSelectWrapper::Function_NotClass: + case ESM::DialogueCondition::Function_NotClass: { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Class); } - case CSMWorld::ConstInfoSelectWrapper::Function_NotRace: + case ESM::DialogueCondition::Function_NotRace: { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Race); } - case CSMWorld::ConstInfoSelectWrapper::Function_NotCell: + case ESM::DialogueCondition::Function_NotCell: { return createEditor(parent, option, index, CSMWorld::ColumnBase::Display_Cell); } - case CSMWorld::ConstInfoSelectWrapper::Function_Local: - case CSMWorld::ConstInfoSelectWrapper::Function_NotLocal: + case ESM::DialogueCondition::Function_Local: + case ESM::DialogueCondition::Function_NotLocal: { return new CSVWidget::DropLineEdit(display, parent); } diff --git a/apps/opencs/view/world/recordbuttonbar.cpp b/apps/opencs/view/world/recordbuttonbar.cpp index 67270bd1ed..1333a4a7da 100644 --- a/apps/opencs/view/world/recordbuttonbar.cpp +++ b/apps/opencs/view/world/recordbuttonbar.cpp @@ -92,7 +92,7 @@ CSVWorld::RecordButtonBar::RecordButtonBar(const CSMWorld::UniversalId& id, CSMW if (mTable.getFeatures() & CSMWorld::IdTable::Feature_View) { QToolButton* viewButton = new QToolButton(this); - viewButton->setIcon(QIcon(":/cell.png")); + viewButton->setIcon(QIcon(":cell")); viewButton->setToolTip("Open a scene view of the cell this record is located in"); buttonsLayout->addWidget(viewButton); connect(viewButton, &QToolButton::clicked, this, &RecordButtonBar::viewRecord); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 4212e952e8..b7be2b90c8 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -385,7 +385,7 @@ CSVWorld::Table::Table(const CSMWorld::UniversalId& id, bool createAndDelete, bo mViewAction = new QAction(tr("View"), this); connect(mViewAction, &QAction::triggered, this, &Table::viewRecord); - mViewAction->setIcon(QIcon(":/cell.png")); + mViewAction->setIcon(QIcon(":cell")); addAction(mViewAction); CSMPrefs::Shortcut* viewShortcut = new CSMPrefs::Shortcut("table-view", this); viewShortcut->associateAction(mViewAction); @@ -417,7 +417,7 @@ CSVWorld::Table::Table(const CSMWorld::UniversalId& id, bool createAndDelete, bo mHelpAction = new QAction(tr("Help"), this); connect(mHelpAction, &QAction::triggered, this, &Table::openHelp); - mHelpAction->setIcon(QIcon(":/info.png")); + mHelpAction->setIcon(QIcon(":info")); addAction(mHelpAction); CSMPrefs::Shortcut* openHelpShortcut = new CSMPrefs::Shortcut("help", this); openHelpShortcut->associateAction(mHelpAction); diff --git a/apps/opencs_tests/model/world/testuniversalid.cpp b/apps/opencs_tests/model/world/testuniversalid.cpp index 54538a591d..871a5218d4 100644 --- a/apps/opencs_tests/model/world/testuniversalid.cpp +++ b/apps/opencs_tests/model/world/testuniversalid.cpp @@ -149,39 +149,36 @@ namespace CSMWorld Params{ UniversalId(UniversalId::Type_None), UniversalId::Type_None, UniversalId::Class_None, UniversalId::ArgumentType_None, "-", "-", ":placeholder" }, Params{ UniversalId(UniversalId::Type_RegionMap), UniversalId::Type_RegionMap, UniversalId::Class_NonRecord, - UniversalId::ArgumentType_None, "Region Map", "Region Map", ":./region-map.png" }, + UniversalId::ArgumentType_None, "Region Map", "Region Map", ":region-map" }, Params{ UniversalId(UniversalId::Type_RunLog), UniversalId::Type_RunLog, UniversalId::Class_Transient, - UniversalId::ArgumentType_None, "Run Log", "Run Log", ":./run-log.png" }, + UniversalId::ArgumentType_None, "Run Log", "Run Log", ":run-log" }, Params{ UniversalId(UniversalId::Type_Lands), UniversalId::Type_Lands, UniversalId::Class_RecordList, - UniversalId::ArgumentType_None, "Lands", "Lands", ":./land-heightmap.png" }, + UniversalId::ArgumentType_None, "Lands", "Lands", ":land-heightmap" }, Params{ UniversalId(UniversalId::Type_Icons), UniversalId::Type_Icons, UniversalId::Class_ResourceList, - UniversalId::ArgumentType_None, "Icons", "Icons", ":./resources-icon" }, + UniversalId::ArgumentType_None, "Icons", "Icons", ":resources-icon" }, Params{ UniversalId(UniversalId::Type_Activator, "a"), UniversalId::Type_Activator, - UniversalId::Class_RefRecord, UniversalId::ArgumentType_Id, "Activator", "Activator: a", - ":./activator.png" }, + UniversalId::Class_RefRecord, UniversalId::ArgumentType_Id, "Activator", "Activator: a", ":activator" }, Params{ UniversalId(UniversalId::Type_Gmst, "b"), UniversalId::Type_Gmst, UniversalId::Class_Record, - UniversalId::ArgumentType_Id, "Game Setting", "Game Setting: b", ":./gmst.png" }, + UniversalId::ArgumentType_Id, "Game Setting", "Game Setting: b", ":gmst" }, Params{ UniversalId(UniversalId::Type_Mesh, "c"), UniversalId::Type_Mesh, UniversalId::Class_Resource, - UniversalId::ArgumentType_Id, "Mesh", "Mesh: c", ":./resources-mesh" }, + UniversalId::ArgumentType_Id, "Mesh", "Mesh: c", ":resources-mesh" }, Params{ UniversalId(UniversalId::Type_Scene, "d"), UniversalId::Type_Scene, UniversalId::Class_Collection, - UniversalId::ArgumentType_Id, "Scene", "Scene: d", ":./scene.png" }, + UniversalId::ArgumentType_Id, "Scene", "Scene: d", ":scene" }, Params{ UniversalId(UniversalId::Type_Reference, "e"), UniversalId::Type_Reference, - UniversalId::Class_SubRecord, UniversalId::ArgumentType_Id, "Instance", "Instance: e", - ":./instance.png" }, + UniversalId::Class_SubRecord, UniversalId::ArgumentType_Id, "Instance", "Instance: e", ":instance" }, Params{ UniversalId(UniversalId::Type_Search, 42), UniversalId::Type_Search, UniversalId::Class_Transient, - UniversalId::ArgumentType_Index, "Global Search", "Global Search: 42", ":./menu-search.png" }, + UniversalId::ArgumentType_Index, "Global Search", "Global Search: 42", ":menu-search" }, Params{ UniversalId("Instance: f"), UniversalId::Type_Reference, UniversalId::Class_SubRecord, - UniversalId::ArgumentType_Id, "Instance", "Instance: f", ":./instance.png" }, + UniversalId::ArgumentType_Id, "Instance", "Instance: f", ":instance" }, Params{ UniversalId(UniversalId::Type_Reference, ESM::RefId::stringRefId("g")), UniversalId::Type_Reference, - UniversalId::Class_SubRecord, UniversalId::ArgumentType_RefId, "Instance", "Instance: g", - ":./instance.png" }, + UniversalId::Class_SubRecord, UniversalId::ArgumentType_RefId, "Instance", "Instance: g", ":instance" }, Params{ UniversalId(UniversalId::Type_Reference, ESM::RefId::index(ESM::REC_SKIL, 42)), UniversalId::Type_Reference, UniversalId::Class_SubRecord, UniversalId::ArgumentType_RefId, "Instance", - "Instance: SKIL:0x2a", ":./instance.png" }, + "Instance: SKIL:0x2a", ":instance" }, }; INSTANTIATE_TEST_SUITE_P(ValidParams, CSMWorldUniversalIdValidPerTypeTest, ValuesIn(validParams)); diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 8b67ea28b3..295d690ce5 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -30,16 +30,16 @@ namespace { bool matchesStaticFilters(const MWDialogue::SelectWrapper& select, const MWWorld::Ptr& actor) { - const ESM::RefId selectId = ESM::RefId::stringRefId(select.getName()); - if (select.getFunction() == MWDialogue::SelectWrapper::Function_NotId) + const ESM::RefId selectId = select.getId(); + if (select.getFunction() == ESM::DialogueCondition::Function_NotId) return actor.getCellRef().getRefId() != selectId; if (actor.getClass().isNpc()) { - if (select.getFunction() == MWDialogue::SelectWrapper::Function_NotFaction) + if (select.getFunction() == ESM::DialogueCondition::Function_NotFaction) return actor.getClass().getPrimaryFaction(actor) != selectId; - else if (select.getFunction() == MWDialogue::SelectWrapper::Function_NotClass) + else if (select.getFunction() == ESM::DialogueCondition::Function_NotClass) return actor.get()->mBase->mClass != selectId; - else if (select.getFunction() == MWDialogue::SelectWrapper::Function_NotRace) + else if (select.getFunction() == ESM::DialogueCondition::Function_NotRace) return actor.get()->mBase->mRace != selectId; } return true; @@ -47,7 +47,7 @@ namespace bool matchesStaticFilters(const ESM::DialInfo& info, const MWWorld::Ptr& actor) { - for (const ESM::DialInfo::SelectStruct& select : info.mSelects) + for (const auto& select : info.mSelects) { MWDialogue::SelectWrapper wrapper = select; if (wrapper.getType() == MWDialogue::SelectWrapper::Type_Boolean) @@ -62,7 +62,7 @@ namespace } else if (wrapper.getType() == MWDialogue::SelectWrapper::Type_Numeric) { - if (wrapper.getFunction() == MWDialogue::SelectWrapper::Function_Local) + if (wrapper.getFunction() == ESM::DialogueCondition::Function_Local) { const ESM::RefId& scriptName = actor.getClass().getScript(actor); if (scriptName.empty()) @@ -207,9 +207,8 @@ bool MWDialogue::Filter::testPlayer(const ESM::DialInfo& info) const bool MWDialogue::Filter::testSelectStructs(const ESM::DialInfo& info) const { - for (std::vector::const_iterator iter(info.mSelects.begin()); - iter != info.mSelects.end(); ++iter) - if (!testSelectStruct(*iter)) + for (const auto& select : info.mSelects) + if (!testSelectStruct(select)) return false; return true; @@ -270,11 +269,11 @@ bool MWDialogue::Filter::testSelectStruct(const SelectWrapper& select) const // If the actor is a creature, we pass all conditions only applicable to NPCs. return true; - if (select.getFunction() == SelectWrapper::Function_Choice && mChoice == -1) + if (select.getFunction() == ESM::DialogueCondition::Function_Choice && mChoice == -1) // If not currently in a choice, we reject all conditions that test against choices. return false; - if (select.getFunction() == SelectWrapper::Function_Weather + if (select.getFunction() == ESM::DialogueCondition::Function_Weather && !(MWBase::Environment::get().getWorld()->isCellExterior() || MWBase::Environment::get().getWorld()->isCellQuasiExterior())) // Reject weather conditions in interior cells @@ -305,29 +304,31 @@ bool MWDialogue::Filter::testSelectStructNumeric(const SelectWrapper& select) co { switch (select.getFunction()) { - case SelectWrapper::Function_Global: + case ESM::DialogueCondition::Function_Global: // internally all globals are float :( return select.selectCompare(MWBase::Environment::get().getWorld()->getGlobalFloat(select.getName())); - case SelectWrapper::Function_Local: + case ESM::DialogueCondition::Function_Local: { return testFunctionLocal(select); } - case SelectWrapper::Function_NotLocal: + case ESM::DialogueCondition::Function_NotLocal: { return !testFunctionLocal(select); } - case SelectWrapper::Function_PcHealthPercent: + case ESM::DialogueCondition::Function_PcHealthPercent: { MWWorld::Ptr player = MWMechanics::getPlayer(); return select.selectCompare( static_cast(player.getClass().getCreatureStats(player).getHealth().getRatio() * 100)); } - case SelectWrapper::Function_PcDynamicStat: + case ESM::DialogueCondition::Function_PcMagicka: + case ESM::DialogueCondition::Function_PcFatigue: + case ESM::DialogueCondition::Function_PcHealth: { MWWorld::Ptr player = MWMechanics::getPlayer(); @@ -336,7 +337,7 @@ bool MWDialogue::Filter::testSelectStructNumeric(const SelectWrapper& select) co return select.selectCompare(value); } - case SelectWrapper::Function_HealthPercent: + case ESM::DialogueCondition::Function_Health_Percent: { return select.selectCompare( static_cast(mActor.getClass().getCreatureStats(mActor).getHealth().getRatio() * 100)); @@ -354,27 +355,29 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons switch (select.getFunction()) { - case SelectWrapper::Function_Journal: + case ESM::DialogueCondition::Function_Journal: - return MWBase::Environment::get().getJournal()->getJournalIndex(ESM::RefId::stringRefId(select.getName())); + return MWBase::Environment::get().getJournal()->getJournalIndex(select.getId()); - case SelectWrapper::Function_Item: + case ESM::DialogueCondition::Function_Item: { MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); - return store.count(ESM::RefId::stringRefId(select.getName())); + return store.count(select.getId()); } - case SelectWrapper::Function_Dead: + case ESM::DialogueCondition::Function_Dead: - return MWBase::Environment::get().getMechanicsManager()->countDeaths( - ESM::RefId::stringRefId(select.getName())); + return MWBase::Environment::get().getMechanicsManager()->countDeaths(select.getId()); - case SelectWrapper::Function_Choice: + case ESM::DialogueCondition::Function_Choice: return mChoice; - case SelectWrapper::Function_AiSetting: + case ESM::DialogueCondition::Function_Fight: + case ESM::DialogueCondition::Function_Hello: + case ESM::DialogueCondition::Function_Alarm: + case ESM::DialogueCondition::Function_Flee: { int argument = select.getArgument(); if (argument < 0 || argument > 3) @@ -387,32 +390,65 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons .getAiSetting(static_cast(argument)) .getModified(false); } - case SelectWrapper::Function_PcAttribute: + case ESM::DialogueCondition::Function_PcStrength: + case ESM::DialogueCondition::Function_PcIntelligence: + case ESM::DialogueCondition::Function_PcWillpower: + case ESM::DialogueCondition::Function_PcAgility: + case ESM::DialogueCondition::Function_PcSpeed: + case ESM::DialogueCondition::Function_PcEndurance: + case ESM::DialogueCondition::Function_PcPersonality: + case ESM::DialogueCondition::Function_PcLuck: { ESM::RefId attribute = ESM::Attribute::indexToRefId(select.getArgument()); return player.getClass().getCreatureStats(player).getAttribute(attribute).getModified(); } - case SelectWrapper::Function_PcSkill: + case ESM::DialogueCondition::Function_PcBlock: + case ESM::DialogueCondition::Function_PcArmorer: + case ESM::DialogueCondition::Function_PcMediumArmor: + case ESM::DialogueCondition::Function_PcHeavyArmor: + case ESM::DialogueCondition::Function_PcBluntWeapon: + case ESM::DialogueCondition::Function_PcLongBlade: + case ESM::DialogueCondition::Function_PcAxe: + case ESM::DialogueCondition::Function_PcSpear: + case ESM::DialogueCondition::Function_PcAthletics: + case ESM::DialogueCondition::Function_PcEnchant: + case ESM::DialogueCondition::Function_PcDestruction: + case ESM::DialogueCondition::Function_PcAlteration: + case ESM::DialogueCondition::Function_PcIllusion: + case ESM::DialogueCondition::Function_PcConjuration: + case ESM::DialogueCondition::Function_PcMysticism: + case ESM::DialogueCondition::Function_PcRestoration: + case ESM::DialogueCondition::Function_PcAlchemy: + case ESM::DialogueCondition::Function_PcUnarmored: + case ESM::DialogueCondition::Function_PcSecurity: + case ESM::DialogueCondition::Function_PcSneak: + case ESM::DialogueCondition::Function_PcAcrobatics: + case ESM::DialogueCondition::Function_PcLightArmor: + case ESM::DialogueCondition::Function_PcShortBlade: + case ESM::DialogueCondition::Function_PcMarksman: + case ESM::DialogueCondition::Function_PcMerchantile: + case ESM::DialogueCondition::Function_PcSpeechcraft: + case ESM::DialogueCondition::Function_PcHandToHand: { ESM::RefId skill = ESM::Skill::indexToRefId(select.getArgument()); return static_cast(player.getClass().getNpcStats(player).getSkill(skill).getModified()); } - case SelectWrapper::Function_FriendlyHit: + case ESM::DialogueCondition::Function_FriendHit: { int hits = mActor.getClass().getCreatureStats(mActor).getFriendlyHits(); return hits > 4 ? 4 : hits; } - case SelectWrapper::Function_PcLevel: + case ESM::DialogueCondition::Function_PcLevel: return player.getClass().getCreatureStats(player).getLevel(); - case SelectWrapper::Function_PcGender: + case ESM::DialogueCondition::Function_PcGender: return player.get()->mBase->isMale() ? 0 : 1; - case SelectWrapper::Function_PcClothingModifier: + case ESM::DialogueCondition::Function_PcClothingModifier: { const MWWorld::InventoryStore& store = player.getClass().getInventoryStore(player); @@ -429,11 +465,11 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons return value; } - case SelectWrapper::Function_PcCrimeLevel: + case ESM::DialogueCondition::Function_PcCrimeLevel: return player.getClass().getNpcStats(player).getBounty(); - case SelectWrapper::Function_RankRequirement: + case ESM::DialogueCondition::Function_RankRequirement: { const ESM::RefId& faction = mActor.getClass().getPrimaryFaction(mActor); if (faction.empty()) @@ -455,23 +491,23 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons return result; } - case SelectWrapper::Function_Level: + case ESM::DialogueCondition::Function_Level: return mActor.getClass().getCreatureStats(mActor).getLevel(); - case SelectWrapper::Function_PCReputation: + case ESM::DialogueCondition::Function_PcReputation: return player.getClass().getNpcStats(player).getReputation(); - case SelectWrapper::Function_Weather: + case ESM::DialogueCondition::Function_Weather: return MWBase::Environment::get().getWorld()->getCurrentWeather(); - case SelectWrapper::Function_Reputation: + case ESM::DialogueCondition::Function_Reputation: return mActor.getClass().getNpcStats(mActor).getReputation(); - case SelectWrapper::Function_FactionRankDiff: + case ESM::DialogueCondition::Function_FactionRankDifference: { const ESM::RefId& faction = mActor.getClass().getPrimaryFaction(mActor); @@ -483,14 +519,14 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons return rank - npcRank; } - case SelectWrapper::Function_WerewolfKills: + case ESM::DialogueCondition::Function_PcWerewolfKills: return player.getClass().getNpcStats(player).getWerewolfKills(); - case SelectWrapper::Function_RankLow: - case SelectWrapper::Function_RankHigh: + case ESM::DialogueCondition::Function_FacReactionLowest: + case ESM::DialogueCondition::Function_FacReactionHighest: { - bool low = select.getFunction() == SelectWrapper::Function_RankLow; + bool low = select.getFunction() == ESM::DialogueCondition::Function_FacReactionLowest; const ESM::RefId& factionId = mActor.getClass().getPrimaryFaction(mActor); @@ -513,7 +549,7 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons return value; } - case SelectWrapper::Function_CreatureTargetted: + case ESM::DialogueCondition::Function_CreatureTarget: { MWWorld::Ptr target; @@ -540,53 +576,49 @@ bool MWDialogue::Filter::getSelectStructBoolean(const SelectWrapper& select) con switch (select.getFunction()) { - case SelectWrapper::Function_False: + case ESM::DialogueCondition::Function_NotId: - return false; + return mActor.getCellRef().getRefId() != select.getId(); - case SelectWrapper::Function_NotId: + case ESM::DialogueCondition::Function_NotFaction: - return !(mActor.getCellRef().getRefId() == ESM::RefId::stringRefId(select.getName())); + return mActor.getClass().getPrimaryFaction(mActor) != select.getId(); - case SelectWrapper::Function_NotFaction: + case ESM::DialogueCondition::Function_NotClass: - return !(mActor.getClass().getPrimaryFaction(mActor) == ESM::RefId::stringRefId(select.getName())); + return mActor.get()->mBase->mClass != select.getId(); - case SelectWrapper::Function_NotClass: + case ESM::DialogueCondition::Function_NotRace: - return !(mActor.get()->mBase->mClass == ESM::RefId::stringRefId(select.getName())); + return mActor.get()->mBase->mRace != select.getId(); - case SelectWrapper::Function_NotRace: - - return !(mActor.get()->mBase->mRace == ESM::RefId::stringRefId(select.getName())); - - case SelectWrapper::Function_NotCell: + case ESM::DialogueCondition::Function_NotCell: { std::string_view actorCell = MWBase::Environment::get().getWorld()->getCellName(mActor.getCell()); - return !Misc::StringUtils::ciStartsWith(actorCell, select.getName()); + return !Misc::StringUtils::ciStartsWith(actorCell, select.getCellName()); } - case SelectWrapper::Function_SameGender: + case ESM::DialogueCondition::Function_SameSex: return (player.get()->mBase->mFlags & ESM::NPC::Female) == (mActor.get()->mBase->mFlags & ESM::NPC::Female); - case SelectWrapper::Function_SameRace: + case ESM::DialogueCondition::Function_SameRace: return mActor.get()->mBase->mRace == player.get()->mBase->mRace; - case SelectWrapper::Function_SameFaction: + case ESM::DialogueCondition::Function_SameFaction: return player.getClass().getNpcStats(player).isInFaction(mActor.getClass().getPrimaryFaction(mActor)); - case SelectWrapper::Function_PcCommonDisease: + case ESM::DialogueCondition::Function_PcCommonDisease: return player.getClass().getCreatureStats(player).hasCommonDisease(); - case SelectWrapper::Function_PcBlightDisease: + case ESM::DialogueCondition::Function_PcBlightDisease: return player.getClass().getCreatureStats(player).hasBlightDisease(); - case SelectWrapper::Function_PcCorprus: + case ESM::DialogueCondition::Function_PcCorprus: return player.getClass() .getCreatureStats(player) @@ -595,7 +627,7 @@ bool MWDialogue::Filter::getSelectStructBoolean(const SelectWrapper& select) con .getMagnitude() != 0; - case SelectWrapper::Function_PcExpelled: + case ESM::DialogueCondition::Function_PcExpelled: { const ESM::RefId& faction = mActor.getClass().getPrimaryFaction(mActor); @@ -605,7 +637,7 @@ bool MWDialogue::Filter::getSelectStructBoolean(const SelectWrapper& select) con return player.getClass().getNpcStats(player).getExpelled(faction); } - case SelectWrapper::Function_PcVampire: + case ESM::DialogueCondition::Function_PcVampire: return player.getClass() .getCreatureStats(player) @@ -614,27 +646,27 @@ bool MWDialogue::Filter::getSelectStructBoolean(const SelectWrapper& select) con .getMagnitude() > 0; - case SelectWrapper::Function_TalkedToPc: + case ESM::DialogueCondition::Function_TalkedToPc: return mTalkedToPlayer; - case SelectWrapper::Function_Alarmed: + case ESM::DialogueCondition::Function_Alarmed: return mActor.getClass().getCreatureStats(mActor).isAlarmed(); - case SelectWrapper::Function_Detected: + case ESM::DialogueCondition::Function_Detected: return MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, mActor); - case SelectWrapper::Function_Attacked: + case ESM::DialogueCondition::Function_Attacked: return mActor.getClass().getCreatureStats(mActor).getAttacked(); - case SelectWrapper::Function_ShouldAttack: + case ESM::DialogueCondition::Function_ShouldAttack: return MWBase::Environment::get().getMechanicsManager()->isAggressive(mActor, MWMechanics::getPlayer()); - case SelectWrapper::Function_Werewolf: + case ESM::DialogueCondition::Function_Werewolf: return mActor.getClass().getNpcStats(mActor).isWerewolf(); diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 94f7f73097..02c9d29b59 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -10,431 +10,264 @@ namespace { template - bool selectCompareImp(char comp, T1 value1, T2 value2) + bool selectCompareImp(ESM::DialogueCondition::Comparison comp, T1 value1, T2 value2) { switch (comp) { - case '0': + case ESM::DialogueCondition::Comp_Eq: return value1 == value2; - case '1': + case ESM::DialogueCondition::Comp_Ne: return value1 != value2; - case '2': + case ESM::DialogueCondition::Comp_Gt: return value1 > value2; - case '3': + case ESM::DialogueCondition::Comp_Ge: return value1 >= value2; - case '4': + case ESM::DialogueCondition::Comp_Ls: return value1 < value2; - case '5': + case ESM::DialogueCondition::Comp_Le: return value1 <= value2; + default: + throw std::runtime_error("unknown compare type in dialogue info select"); } - - throw std::runtime_error("unknown compare type in dialogue info select"); } template - bool selectCompareImp(const ESM::DialInfo::SelectStruct& select, T value1) + bool selectCompareImp(const ESM::DialogueCondition& select, T value1) { - if (select.mValue.getType() == ESM::VT_Int) - { - return selectCompareImp(select.mSelectRule[4], value1, select.mValue.getInteger()); - } - else if (select.mValue.getType() == ESM::VT_Float) - { - return selectCompareImp(select.mSelectRule[4], value1, select.mValue.getFloat()); - } - else - throw std::runtime_error("unsupported variable type in dialogue info select"); + return std::visit( + [&](auto value) { return selectCompareImp(select.mComparison, value1, value); }, select.mValue); } } -MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::decodeFunction() const -{ - const int index = Misc::StringUtils::toNumeric(mSelect.mSelectRule.substr(2, 2), 0); - - switch (index) - { - case 0: - return Function_RankLow; - case 1: - return Function_RankHigh; - case 2: - return Function_RankRequirement; - case 3: - return Function_Reputation; - case 4: - return Function_HealthPercent; - case 5: - return Function_PCReputation; - case 6: - return Function_PcLevel; - case 7: - return Function_PcHealthPercent; - case 8: - case 9: - return Function_PcDynamicStat; - case 10: - return Function_PcAttribute; - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - case 18: - case 19: - case 20: - case 21: - case 22: - case 23: - case 24: - case 25: - case 26: - case 27: - case 28: - case 29: - case 30: - case 31: - case 32: - case 33: - case 34: - case 35: - case 36: - case 37: - return Function_PcSkill; - case 38: - return Function_PcGender; - case 39: - return Function_PcExpelled; - case 40: - return Function_PcCommonDisease; - case 41: - return Function_PcBlightDisease; - case 42: - return Function_PcClothingModifier; - case 43: - return Function_PcCrimeLevel; - case 44: - return Function_SameGender; - case 45: - return Function_SameRace; - case 46: - return Function_SameFaction; - case 47: - return Function_FactionRankDiff; - case 48: - return Function_Detected; - case 49: - return Function_Alarmed; - case 50: - return Function_Choice; - case 51: - case 52: - case 53: - case 54: - case 55: - case 56: - case 57: - return Function_PcAttribute; - case 58: - return Function_PcCorprus; - case 59: - return Function_Weather; - case 60: - return Function_PcVampire; - case 61: - return Function_Level; - case 62: - return Function_Attacked; - case 63: - return Function_TalkedToPc; - case 64: - return Function_PcDynamicStat; - case 65: - return Function_CreatureTargetted; - case 66: - return Function_FriendlyHit; - case 67: - case 68: - case 69: - case 70: - return Function_AiSetting; - case 71: - return Function_ShouldAttack; - case 72: - return Function_Werewolf; - case 73: - return Function_WerewolfKills; - } - - return Function_False; -} - -MWDialogue::SelectWrapper::SelectWrapper(const ESM::DialInfo::SelectStruct& select) +MWDialogue::SelectWrapper::SelectWrapper(const ESM::DialogueCondition& select) : mSelect(select) { } -MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::getFunction() const +ESM::DialogueCondition::Function MWDialogue::SelectWrapper::getFunction() const { - char type = mSelect.mSelectRule[1]; - - switch (type) - { - case '1': - return decodeFunction(); - case '2': - return Function_Global; - case '3': - return Function_Local; - case '4': - return Function_Journal; - case '5': - return Function_Item; - case '6': - return Function_Dead; - case '7': - return Function_NotId; - case '8': - return Function_NotFaction; - case '9': - return Function_NotClass; - case 'A': - return Function_NotRace; - case 'B': - return Function_NotCell; - case 'C': - return Function_NotLocal; - } - - return Function_None; + return mSelect.mFunction; } int MWDialogue::SelectWrapper::getArgument() const { - if (mSelect.mSelectRule[1] != '1') - return 0; - - int index = 0; - - std::istringstream(mSelect.mSelectRule.substr(2, 2)) >> index; - - switch (index) + switch (mSelect.mFunction) { // AI settings - case 67: + case ESM::DialogueCondition::Function_Fight: return 1; - case 68: + case ESM::DialogueCondition::Function_Hello: return 0; - case 69: + case ESM::DialogueCondition::Function_Alarm: return 3; - case 70: + case ESM::DialogueCondition::Function_Flee: return 2; // attributes - case 10: + case ESM::DialogueCondition::Function_PcStrength: return 0; - case 51: + case ESM::DialogueCondition::Function_PcIntelligence: return 1; - case 52: + case ESM::DialogueCondition::Function_PcWillpower: return 2; - case 53: + case ESM::DialogueCondition::Function_PcAgility: return 3; - case 54: + case ESM::DialogueCondition::Function_PcSpeed: return 4; - case 55: + case ESM::DialogueCondition::Function_PcEndurance: return 5; - case 56: + case ESM::DialogueCondition::Function_PcPersonality: return 6; - case 57: + case ESM::DialogueCondition::Function_PcLuck: return 7; // skills - case 11: + case ESM::DialogueCondition::Function_PcBlock: return 0; - case 12: + case ESM::DialogueCondition::Function_PcArmorer: return 1; - case 13: + case ESM::DialogueCondition::Function_PcMediumArmor: return 2; - case 14: + case ESM::DialogueCondition::Function_PcHeavyArmor: return 3; - case 15: + case ESM::DialogueCondition::Function_PcBluntWeapon: return 4; - case 16: + case ESM::DialogueCondition::Function_PcLongBlade: return 5; - case 17: + case ESM::DialogueCondition::Function_PcAxe: return 6; - case 18: + case ESM::DialogueCondition::Function_PcSpear: return 7; - case 19: + case ESM::DialogueCondition::Function_PcAthletics: return 8; - case 20: + case ESM::DialogueCondition::Function_PcEnchant: return 9; - case 21: + case ESM::DialogueCondition::Function_PcDestruction: return 10; - case 22: + case ESM::DialogueCondition::Function_PcAlteration: return 11; - case 23: + case ESM::DialogueCondition::Function_PcIllusion: return 12; - case 24: + case ESM::DialogueCondition::Function_PcConjuration: return 13; - case 25: + case ESM::DialogueCondition::Function_PcMysticism: return 14; - case 26: + case ESM::DialogueCondition::Function_PcRestoration: return 15; - case 27: + case ESM::DialogueCondition::Function_PcAlchemy: return 16; - case 28: + case ESM::DialogueCondition::Function_PcUnarmored: return 17; - case 29: + case ESM::DialogueCondition::Function_PcSecurity: return 18; - case 30: + case ESM::DialogueCondition::Function_PcSneak: return 19; - case 31: + case ESM::DialogueCondition::Function_PcAcrobatics: return 20; - case 32: + case ESM::DialogueCondition::Function_PcLightArmor: return 21; - case 33: + case ESM::DialogueCondition::Function_PcShortBlade: return 22; - case 34: + case ESM::DialogueCondition::Function_PcMarksman: return 23; - case 35: + case ESM::DialogueCondition::Function_PcMerchantile: return 24; - case 36: + case ESM::DialogueCondition::Function_PcSpeechcraft: return 25; - case 37: + case ESM::DialogueCondition::Function_PcHandToHand: return 26; // dynamic stats - case 8: + case ESM::DialogueCondition::Function_PcMagicka: return 1; - case 9: + case ESM::DialogueCondition::Function_PcFatigue: return 2; - case 64: + case ESM::DialogueCondition::Function_PcHealth: + return 0; + default: return 0; } - - return 0; } MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const { - static const Function integerFunctions[] = { - Function_Journal, - Function_Item, - Function_Dead, - Function_Choice, - Function_AiSetting, - Function_PcAttribute, - Function_PcSkill, - Function_FriendlyHit, - Function_PcLevel, - Function_PcGender, - Function_PcClothingModifier, - Function_PcCrimeLevel, - Function_RankRequirement, - Function_Level, - Function_PCReputation, - Function_Weather, - Function_Reputation, - Function_FactionRankDiff, - Function_WerewolfKills, - Function_RankLow, - Function_RankHigh, - Function_CreatureTargetted, - // end marker - Function_None, - }; - - static const Function numericFunctions[] = { - Function_Global, - Function_Local, - Function_NotLocal, - Function_PcDynamicStat, - Function_PcHealthPercent, - Function_HealthPercent, - // end marker - Function_None, - }; - - static const Function booleanFunctions[] = { - Function_False, - Function_SameGender, - Function_SameRace, - Function_SameFaction, - Function_PcCommonDisease, - Function_PcBlightDisease, - Function_PcCorprus, - Function_PcExpelled, - Function_PcVampire, - Function_TalkedToPc, - Function_Alarmed, - Function_Detected, - Function_Attacked, - Function_ShouldAttack, - Function_Werewolf, - // end marker - Function_None, - }; - - static const Function invertedBooleanFunctions[] = { - Function_NotId, - Function_NotFaction, - Function_NotClass, - Function_NotRace, - Function_NotCell, - // end marker - Function_None, - }; - - Function function = getFunction(); - - for (int i = 0; integerFunctions[i] != Function_None; ++i) - if (integerFunctions[i] == function) + switch (mSelect.mFunction) + { + case ESM::DialogueCondition::Function_Journal: + case ESM::DialogueCondition::Function_Item: + case ESM::DialogueCondition::Function_Dead: + case ESM::DialogueCondition::Function_Choice: + case ESM::DialogueCondition::Function_Fight: + case ESM::DialogueCondition::Function_Hello: + case ESM::DialogueCondition::Function_Alarm: + case ESM::DialogueCondition::Function_Flee: + case ESM::DialogueCondition::Function_PcStrength: + case ESM::DialogueCondition::Function_PcIntelligence: + case ESM::DialogueCondition::Function_PcWillpower: + case ESM::DialogueCondition::Function_PcAgility: + case ESM::DialogueCondition::Function_PcSpeed: + case ESM::DialogueCondition::Function_PcEndurance: + case ESM::DialogueCondition::Function_PcPersonality: + case ESM::DialogueCondition::Function_PcLuck: + case ESM::DialogueCondition::Function_PcBlock: + case ESM::DialogueCondition::Function_PcArmorer: + case ESM::DialogueCondition::Function_PcMediumArmor: + case ESM::DialogueCondition::Function_PcHeavyArmor: + case ESM::DialogueCondition::Function_PcBluntWeapon: + case ESM::DialogueCondition::Function_PcLongBlade: + case ESM::DialogueCondition::Function_PcAxe: + case ESM::DialogueCondition::Function_PcSpear: + case ESM::DialogueCondition::Function_PcAthletics: + case ESM::DialogueCondition::Function_PcEnchant: + case ESM::DialogueCondition::Function_PcDestruction: + case ESM::DialogueCondition::Function_PcAlteration: + case ESM::DialogueCondition::Function_PcIllusion: + case ESM::DialogueCondition::Function_PcConjuration: + case ESM::DialogueCondition::Function_PcMysticism: + case ESM::DialogueCondition::Function_PcRestoration: + case ESM::DialogueCondition::Function_PcAlchemy: + case ESM::DialogueCondition::Function_PcUnarmored: + case ESM::DialogueCondition::Function_PcSecurity: + case ESM::DialogueCondition::Function_PcSneak: + case ESM::DialogueCondition::Function_PcAcrobatics: + case ESM::DialogueCondition::Function_PcLightArmor: + case ESM::DialogueCondition::Function_PcShortBlade: + case ESM::DialogueCondition::Function_PcMarksman: + case ESM::DialogueCondition::Function_PcMerchantile: + case ESM::DialogueCondition::Function_PcSpeechcraft: + case ESM::DialogueCondition::Function_PcHandToHand: + case ESM::DialogueCondition::Function_FriendHit: + case ESM::DialogueCondition::Function_PcLevel: + case ESM::DialogueCondition::Function_PcGender: + case ESM::DialogueCondition::Function_PcClothingModifier: + case ESM::DialogueCondition::Function_PcCrimeLevel: + case ESM::DialogueCondition::Function_RankRequirement: + case ESM::DialogueCondition::Function_Level: + case ESM::DialogueCondition::Function_PcReputation: + case ESM::DialogueCondition::Function_Weather: + case ESM::DialogueCondition::Function_Reputation: + case ESM::DialogueCondition::Function_FactionRankDifference: + case ESM::DialogueCondition::Function_PcWerewolfKills: + case ESM::DialogueCondition::Function_FacReactionLowest: + case ESM::DialogueCondition::Function_FacReactionHighest: + case ESM::DialogueCondition::Function_CreatureTarget: return Type_Integer; - - for (int i = 0; numericFunctions[i] != Function_None; ++i) - if (numericFunctions[i] == function) + case ESM::DialogueCondition::Function_Global: + case ESM::DialogueCondition::Function_Local: + case ESM::DialogueCondition::Function_NotLocal: + case ESM::DialogueCondition::Function_PcHealth: + case ESM::DialogueCondition::Function_PcMagicka: + case ESM::DialogueCondition::Function_PcFatigue: + case ESM::DialogueCondition::Function_PcHealthPercent: + case ESM::DialogueCondition::Function_Health_Percent: return Type_Numeric; - - for (int i = 0; booleanFunctions[i] != Function_None; ++i) - if (booleanFunctions[i] == function) + case ESM::DialogueCondition::Function_SameSex: + case ESM::DialogueCondition::Function_SameRace: + case ESM::DialogueCondition::Function_SameFaction: + case ESM::DialogueCondition::Function_PcCommonDisease: + case ESM::DialogueCondition::Function_PcBlightDisease: + case ESM::DialogueCondition::Function_PcCorprus: + case ESM::DialogueCondition::Function_PcExpelled: + case ESM::DialogueCondition::Function_PcVampire: + case ESM::DialogueCondition::Function_TalkedToPc: + case ESM::DialogueCondition::Function_Alarmed: + case ESM::DialogueCondition::Function_Detected: + case ESM::DialogueCondition::Function_Attacked: + case ESM::DialogueCondition::Function_ShouldAttack: + case ESM::DialogueCondition::Function_Werewolf: return Type_Boolean; - - for (int i = 0; invertedBooleanFunctions[i] != Function_None; ++i) - if (invertedBooleanFunctions[i] == function) + case ESM::DialogueCondition::Function_NotId: + case ESM::DialogueCondition::Function_NotFaction: + case ESM::DialogueCondition::Function_NotClass: + case ESM::DialogueCondition::Function_NotRace: + case ESM::DialogueCondition::Function_NotCell: return Type_Inverted; - - return Type_None; + default: + return Type_None; + }; } bool MWDialogue::SelectWrapper::isNpcOnly() const { - static const Function functions[] = { - Function_NotFaction, - Function_NotClass, - Function_NotRace, - Function_SameGender, - Function_SameRace, - Function_SameFaction, - Function_RankRequirement, - Function_Reputation, - Function_FactionRankDiff, - Function_Werewolf, - Function_WerewolfKills, - Function_RankLow, - Function_RankHigh, - // end marker - Function_None, - }; - - Function function = getFunction(); - - for (int i = 0; functions[i] != Function_None; ++i) - if (functions[i] == function) + switch (mSelect.mFunction) + { + case ESM::DialogueCondition::Function_NotFaction: + case ESM::DialogueCondition::Function_NotClass: + case ESM::DialogueCondition::Function_NotRace: + case ESM::DialogueCondition::Function_SameSex: + case ESM::DialogueCondition::Function_SameRace: + case ESM::DialogueCondition::Function_SameFaction: + case ESM::DialogueCondition::Function_RankRequirement: + case ESM::DialogueCondition::Function_Reputation: + case ESM::DialogueCondition::Function_FactionRankDifference: + case ESM::DialogueCondition::Function_Werewolf: + case ESM::DialogueCondition::Function_PcWerewolfKills: + case ESM::DialogueCondition::Function_FacReactionLowest: + case ESM::DialogueCondition::Function_FacReactionHighest: return true; - - return false; + default: + return false; + } } bool MWDialogue::SelectWrapper::selectCompare(int value) const @@ -454,5 +287,15 @@ bool MWDialogue::SelectWrapper::selectCompare(bool value) const std::string MWDialogue::SelectWrapper::getName() const { - return Misc::StringUtils::lowerCase(std::string_view(mSelect.mSelectRule).substr(5)); + return Misc::StringUtils::lowerCase(mSelect.mVariable); +} + +std::string_view MWDialogue::SelectWrapper::getCellName() const +{ + return mSelect.mVariable; +} + +ESM::RefId MWDialogue::SelectWrapper::getId() const +{ + return ESM::RefId::stringRefId(mSelect.mVariable); } diff --git a/apps/openmw/mwdialogue/selectwrapper.hpp b/apps/openmw/mwdialogue/selectwrapper.hpp index 0d376d957c..d831b6cea0 100644 --- a/apps/openmw/mwdialogue/selectwrapper.hpp +++ b/apps/openmw/mwdialogue/selectwrapper.hpp @@ -7,62 +7,9 @@ namespace MWDialogue { class SelectWrapper { - const ESM::DialInfo::SelectStruct& mSelect; + const ESM::DialogueCondition& mSelect; public: - enum Function - { - Function_None, - Function_False, - Function_Journal, - Function_Item, - Function_Dead, - Function_NotId, - Function_NotFaction, - Function_NotClass, - Function_NotRace, - Function_NotCell, - Function_NotLocal, - Function_Local, - Function_Global, - Function_SameGender, - Function_SameRace, - Function_SameFaction, - Function_Choice, - Function_PcCommonDisease, - Function_PcBlightDisease, - Function_PcCorprus, - Function_AiSetting, - Function_PcAttribute, - Function_PcSkill, - Function_PcExpelled, - Function_PcVampire, - Function_FriendlyHit, - Function_TalkedToPc, - Function_PcLevel, - Function_PcHealthPercent, - Function_PcDynamicStat, - Function_PcGender, - Function_PcClothingModifier, - Function_PcCrimeLevel, - Function_RankRequirement, - Function_HealthPercent, - Function_Level, - Function_PCReputation, - Function_Weather, - Function_Reputation, - Function_Alarmed, - Function_FactionRankDiff, - Function_Detected, - Function_Attacked, - Function_ShouldAttack, - Function_CreatureTargetted, - Function_Werewolf, - Function_WerewolfKills, - Function_RankLow, - Function_RankHigh - }; - enum Type { Type_None, @@ -72,13 +19,10 @@ namespace MWDialogue Type_Inverted }; - private: - Function decodeFunction() const; - public: - SelectWrapper(const ESM::DialInfo::SelectStruct& select); + SelectWrapper(const ESM::DialogueCondition& select); - Function getFunction() const; + ESM::DialogueCondition::Function getFunction() const; int getArgument() const; @@ -95,6 +39,10 @@ namespace MWDialogue std::string getName() const; ///< Return case-smashed name. + + std::string_view getCellName() const; + + ESM::RefId getId() const; }; } diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index a6f3d0336f..9e7a2be3a8 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -1,15 +1,41 @@ #include "ffmpeg_decoder.hpp" -#include - #include +#include #include +#include #include #include namespace MWSound { + void AVIOContextDeleter::operator()(AVIOContext* ptr) const + { + if (ptr->buffer != nullptr) + av_freep(&ptr->buffer); + +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 80, 100) + avio_context_free(&ptr); +#else + av_free(ptr); +#endif + } + + void AVFormatContextDeleter::operator()(AVFormatContext* ptr) const + { + avformat_close_input(&ptr); + } + + void AVCodecContextDeleter::operator()(AVCodecContext* ptr) const + { + avcodec_free_context(&ptr); + } + + void AVFrameDeleter::operator()(AVFrame* ptr) const + { + av_frame_free(&ptr); + } int FFmpeg_Decoder::readPacket(void* user_data, uint8_t* buf, int buf_size) { @@ -75,7 +101,7 @@ namespace MWSound return false; std::ptrdiff_t stream_idx = mStream - mFormatCtx->streams; - while (av_read_frame(mFormatCtx, &mPacket) >= 0) + while (av_read_frame(mFormatCtx.get(), &mPacket) >= 0) { /* Check if the packet belongs to this stream */ if (stream_idx == mPacket.stream_index) @@ -102,12 +128,12 @@ namespace MWSound do { /* Decode some data, and check for errors */ - int ret = avcodec_receive_frame(mCodecCtx, mFrame); + int ret = avcodec_receive_frame(mCodecCtx.get(), mFrame.get()); if (ret == AVERROR(EAGAIN)) { if (mPacket.size == 0 && !getNextPacket()) return false; - ret = avcodec_send_packet(mCodecCtx, &mPacket); + ret = avcodec_send_packet(mCodecCtx.get(), &mPacket); av_packet_unref(&mPacket); if (ret == 0) continue; @@ -187,137 +213,95 @@ namespace MWSound close(); mDataStream = mResourceMgr->get(fname); - if ((mFormatCtx = avformat_alloc_context()) == nullptr) + AVIOContextPtr ioCtx(avio_alloc_context(nullptr, 0, 0, this, readPacket, writePacket, seek)); + if (ioCtx == nullptr) + throw std::runtime_error("Failed to allocate AVIO context"); + + AVFormatContext* formatCtx = avformat_alloc_context(); + if (formatCtx == nullptr) throw std::runtime_error("Failed to allocate context"); - try + formatCtx->pb = ioCtx.get(); + + // avformat_open_input frees user supplied AVFormatContext on failure + if (avformat_open_input(&formatCtx, fname.c_str(), nullptr, nullptr) != 0) + throw std::runtime_error("Failed to open input"); + + AVFormatContextPtr formatCtxPtr(std::exchange(formatCtx, nullptr)); + + if (avformat_find_stream_info(formatCtxPtr.get(), nullptr) < 0) + throw std::runtime_error("Failed to find stream info"); + + AVStream** stream = nullptr; + for (size_t j = 0; j < formatCtxPtr->nb_streams; j++) { - mFormatCtx->pb = avio_alloc_context(nullptr, 0, 0, this, readPacket, writePacket, seek); - if (!mFormatCtx->pb || avformat_open_input(&mFormatCtx, fname.c_str(), nullptr, nullptr) != 0) + if (formatCtxPtr->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - // "Note that a user-supplied AVFormatContext will be freed on failure". - if (mFormatCtx) - { - if (mFormatCtx->pb != nullptr) - { - if (mFormatCtx->pb->buffer != nullptr) - { - av_free(mFormatCtx->pb->buffer); - mFormatCtx->pb->buffer = nullptr; - } - av_free(mFormatCtx->pb); - mFormatCtx->pb = nullptr; - } - avformat_free_context(mFormatCtx); - } - mFormatCtx = nullptr; - throw std::runtime_error("Failed to allocate input stream"); + stream = &formatCtxPtr->streams[j]; + break; } + } - if (avformat_find_stream_info(mFormatCtx, nullptr) < 0) - throw std::runtime_error("Failed to find stream info in " + fname); + if (stream == nullptr) + throw std::runtime_error("No audio streams"); - for (size_t j = 0; j < mFormatCtx->nb_streams; j++) - { - if (mFormatCtx->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) - { - mStream = &mFormatCtx->streams[j]; - break; - } - } - if (!mStream) - throw std::runtime_error("No audio streams in " + fname); + const AVCodec* codec = avcodec_find_decoder((*stream)->codecpar->codec_id); + if (codec == nullptr) + throw std::runtime_error("No codec found for id " + std::to_string((*stream)->codecpar->codec_id)); - const AVCodec* codec = avcodec_find_decoder((*mStream)->codecpar->codec_id); - if (!codec) - { - std::string ss = "No codec found for id " + std::to_string((*mStream)->codecpar->codec_id); - throw std::runtime_error(ss); - } + AVCodecContext* codecCtx = avcodec_alloc_context3(codec); + if (codecCtx == nullptr) + throw std::runtime_error("Failed to allocate codec context"); - AVCodecContext* avctx = avcodec_alloc_context3(codec); - avcodec_parameters_to_context(avctx, (*mStream)->codecpar); + avcodec_parameters_to_context(codecCtx, (*stream)->codecpar); // This is not needed anymore above FFMpeg version 4.0 #if LIBAVCODEC_VERSION_INT < 3805796 - av_codec_set_pkt_timebase(avctx, (*mStream)->time_base); + av_codec_set_pkt_timebase(avctx, (*stream)->time_base); #endif - mCodecCtx = avctx; + AVCodecContextPtr codecCtxPtr(std::exchange(codecCtx, nullptr)); - if (avcodec_open2(mCodecCtx, codec, nullptr) < 0) - throw std::runtime_error(std::string("Failed to open audio codec ") + codec->long_name); + if (avcodec_open2(codecCtxPtr.get(), codec, nullptr) < 0) + throw std::runtime_error(std::string("Failed to open audio codec ") + codec->long_name); - mFrame = av_frame_alloc(); + AVFramePtr frame(av_frame_alloc()); + if (frame == nullptr) + throw std::runtime_error("Failed to allocate frame"); - if (mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8P) - mOutputSampleFormat = AV_SAMPLE_FMT_U8; - // FIXME: Check for AL_EXT_FLOAT32 support - // else if (mCodecCtx->sample_fmt == AV_SAMPLE_FMT_FLT || mCodecCtx->sample_fmt == AV_SAMPLE_FMT_FLTP) - // mOutputSampleFormat = AV_SAMPLE_FMT_S16; - else - mOutputSampleFormat = AV_SAMPLE_FMT_S16; + if (codecCtxPtr->sample_fmt == AV_SAMPLE_FMT_U8P) + mOutputSampleFormat = AV_SAMPLE_FMT_U8; + // FIXME: Check for AL_EXT_FLOAT32 support + // else if (codecCtxPtr->sample_fmt == AV_SAMPLE_FMT_FLT || codecCtxPtr->sample_fmt == AV_SAMPLE_FMT_FLTP) + // mOutputSampleFormat = AV_SAMPLE_FMT_S16; + else + mOutputSampleFormat = AV_SAMPLE_FMT_S16; - mOutputChannelLayout = (*mStream)->codecpar->channel_layout; - if (mOutputChannelLayout == 0) - mOutputChannelLayout = av_get_default_channel_layout(mCodecCtx->channels); + mOutputChannelLayout = (*stream)->codecpar->channel_layout; + if (mOutputChannelLayout == 0) + mOutputChannelLayout = av_get_default_channel_layout(codecCtxPtr->channels); - mCodecCtx->channel_layout = mOutputChannelLayout; - } - catch (...) - { - if (mStream) - avcodec_free_context(&mCodecCtx); - mStream = nullptr; + codecCtxPtr->channel_layout = mOutputChannelLayout; - if (mFormatCtx != nullptr) - { - if (mFormatCtx->pb->buffer != nullptr) - { - av_free(mFormatCtx->pb->buffer); - mFormatCtx->pb->buffer = nullptr; - } - av_free(mFormatCtx->pb); - mFormatCtx->pb = nullptr; - - avformat_close_input(&mFormatCtx); - } - } + mIoCtx = std::move(ioCtx); + mFrame = std::move(frame); + mFormatCtx = std::move(formatCtxPtr); + mCodecCtx = std::move(codecCtxPtr); + mStream = stream; } void FFmpeg_Decoder::close() { - if (mStream) - avcodec_free_context(&mCodecCtx); mStream = nullptr; + mCodecCtx.reset(); av_packet_unref(&mPacket); av_freep(&mDataBuf); - av_frame_free(&mFrame); + mFrame.reset(); swr_free(&mSwr); - if (mFormatCtx) - { - if (mFormatCtx->pb != nullptr) - { - // mFormatCtx->pb->buffer must be freed by hand, - // if not, valgrind will show memleak, see: - // - // https://trac.ffmpeg.org/ticket/1357 - // - if (mFormatCtx->pb->buffer != nullptr) - { - av_freep(&mFormatCtx->pb->buffer); - } -#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 80, 100) - avio_context_free(&mFormatCtx->pb); -#else - av_freep(&mFormatCtx->pb); -#endif - } - avformat_close_input(&mFormatCtx); - } - + mFormatCtx.reset(); + mIoCtx.reset(); mDataStream.reset(); } @@ -436,10 +420,7 @@ namespace MWSound FFmpeg_Decoder::FFmpeg_Decoder(const VFS::Manager* vfs) : Sound_Decoder(vfs) - , mFormatCtx(nullptr) - , mCodecCtx(nullptr) , mStream(nullptr) - , mFrame(nullptr) , mFrameSize(0) , mFramePos(0) , mNextPts(0.0) @@ -470,5 +451,4 @@ namespace MWSound { close(); } - } diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp index 9d15888fcf..ed3297403e 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.hpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -32,14 +32,43 @@ extern "C" namespace MWSound { + struct AVIOContextDeleter + { + void operator()(AVIOContext* ptr) const; + }; + + using AVIOContextPtr = std::unique_ptr; + + struct AVFormatContextDeleter + { + void operator()(AVFormatContext* ptr) const; + }; + + using AVFormatContextPtr = std::unique_ptr; + + struct AVCodecContextDeleter + { + void operator()(AVCodecContext* ptr) const; + }; + + using AVCodecContextPtr = std::unique_ptr; + + struct AVFrameDeleter + { + void operator()(AVFrame* ptr) const; + }; + + using AVFramePtr = std::unique_ptr; + class FFmpeg_Decoder final : public Sound_Decoder { - AVFormatContext* mFormatCtx; - AVCodecContext* mCodecCtx; + AVIOContextPtr mIoCtx; + AVFormatContextPtr mFormatCtx; + AVCodecContextPtr mCodecCtx; AVStream** mStream; AVPacket mPacket; - AVFrame* mFrame; + AVFramePtr mFrame; std::size_t mFrameSize; std::size_t mFramePos; diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index b498bb488b..7849ba1458 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -325,6 +325,7 @@ namespace MWWorld player.mObject.mEnabled = true; } + MWBase::Environment::get().getWorldModel()->deregisterLiveCellRef(mPlayer); mPlayer.load(player.mObject); for (size_t i = 0; i < mSaveAttributes.size(); ++i) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ec58f779d0..74335a1534 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -591,6 +591,12 @@ namespace MWWorld // Must be cleared before mRendering is destroyed if (mProjectileManager) mProjectileManager->clear(); + + if (Settings::navigator().mWaitForAllJobsOnExit) + { + Log(Debug::Verbose) << "Waiting for all navmesh jobs to be done..."; + mNavigator->wait(DetourNavigator::WaitConditionType::allJobsDone, nullptr); + } } void World::setRandomSeed(uint32_t seed) diff --git a/apps/openmw_test_suite/detournavigator/asyncnavmeshupdater.cpp b/apps/openmw_test_suite/detournavigator/asyncnavmeshupdater.cpp index bc1288f5f6..51ab37b123 100644 --- a/apps/openmw_test_suite/detournavigator/asyncnavmeshupdater.cpp +++ b/apps/openmw_test_suite/detournavigator/asyncnavmeshupdater.cpp @@ -267,7 +267,6 @@ namespace updater.wait(WaitConditionType::allJobsDone, &mListener); updater.stop(); const std::set present{ - TilePosition(-2, 0), TilePosition(-1, -1), TilePosition(-1, 0), TilePosition(-1, 1), @@ -278,6 +277,7 @@ namespace TilePosition(0, 2), TilePosition(1, -1), TilePosition(1, 0), + TilePosition(1, 1), }; for (int x = -5; x <= 5; ++x) for (int y = -5; y <= 5; ++y) @@ -336,4 +336,273 @@ namespace EXPECT_EQ(tile->mTileId, 2); EXPECT_EQ(tile->mVersion, navMeshFormatVersion); } + + TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, repeated_tile_updates_should_be_delayed) + { + mRecastMeshManager.setWorldspace(mWorldspace, nullptr); + + mSettings.mMaxTilesNumber = 9; + mSettings.mMinUpdateInterval = std::chrono::milliseconds(250); + + AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr); + const auto navMeshCacheItem = std::make_shared(1, mSettings); + + std::map changedTiles; + + for (int x = -3; x <= 3; ++x) + for (int y = -3; y <= 3; ++y) + changedTiles.emplace(TilePosition{ x, y }, ChangeType::update); + + updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); + + updater.wait(WaitConditionType::allJobsDone, &mListener); + + { + const AsyncNavMeshUpdaterStats stats = updater.getStats(); + EXPECT_EQ(stats.mJobs, 0); + EXPECT_EQ(stats.mWaiting.mDelayed, 0); + } + + updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles); + + { + const AsyncNavMeshUpdaterStats stats = updater.getStats(); + EXPECT_EQ(stats.mJobs, 49); + EXPECT_EQ(stats.mWaiting.mDelayed, 49); + } + + updater.wait(WaitConditionType::allJobsDone, &mListener); + + { + const AsyncNavMeshUpdaterStats stats = updater.getStats(); + EXPECT_EQ(stats.mJobs, 0); + EXPECT_EQ(stats.mWaiting.mDelayed, 0); + } + } + + struct DetourNavigatorSpatialJobQueueTest : Test + { + const AgentBounds mAgentBounds{ CollisionShapeType::Aabb, osg::Vec3f(1, 1, 1) }; + const std::shared_ptr mNavMeshCacheItemPtr; + const std::weak_ptr mNavMeshCacheItem = mNavMeshCacheItemPtr; + const std::string_view mWorldspace = "worldspace"; + const TilePosition mChangedTile{ 0, 0 }; + const std::chrono::steady_clock::time_point mProcessTime{}; + const TilePosition mPlayerTile{ 0, 0 }; + const int mMaxTiles = 9; + }; + + TEST_F(DetourNavigatorSpatialJobQueueTest, should_store_multiple_jobs_per_tile) + { + std::list jobs; + SpatialJobQueue queue; + + queue.push(jobs.emplace(jobs.end(), mAgentBounds, mNavMeshCacheItem, "worldspace1", mChangedTile, + ChangeType::remove, mProcessTime)); + queue.push(jobs.emplace(jobs.end(), mAgentBounds, mNavMeshCacheItem, "worldspace2", mChangedTile, + ChangeType::update, mProcessTime)); + + ASSERT_EQ(queue.size(), 2); + + const auto job1 = queue.pop(mChangedTile); + ASSERT_TRUE(job1.has_value()); + EXPECT_EQ((*job1)->mWorldspace, "worldspace1"); + + const auto job2 = queue.pop(mChangedTile); + ASSERT_TRUE(job2.has_value()); + EXPECT_EQ((*job2)->mWorldspace, "worldspace2"); + + EXPECT_EQ(queue.size(), 0); + } + + struct DetourNavigatorJobQueueTest : DetourNavigatorSpatialJobQueueTest + { + }; + + TEST_F(DetourNavigatorJobQueueTest, pop_should_return_nullptr_from_empty) + { + JobQueue queue; + ASSERT_FALSE(queue.hasJob()); + ASSERT_FALSE(queue.pop(mPlayerTile).has_value()); + } + + TEST_F(DetourNavigatorJobQueueTest, push_on_change_type_remove_should_add_to_removing) + { + const std::chrono::steady_clock::time_point processTime{}; + + std::list jobs; + const JobIt job = jobs.emplace( + jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, mChangedTile, ChangeType::remove, processTime); + + JobQueue queue; + queue.push(job); + + EXPECT_EQ(queue.getStats().mRemoving, 1); + } + + TEST_F(DetourNavigatorJobQueueTest, pop_should_return_last_removing) + { + std::list jobs; + JobQueue queue; + + queue.push(jobs.emplace(jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, TilePosition(0, 0), + ChangeType::remove, mProcessTime)); + queue.push(jobs.emplace(jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, TilePosition(1, 0), + ChangeType::remove, mProcessTime)); + + ASSERT_TRUE(queue.hasJob()); + const auto job = queue.pop(mPlayerTile); + ASSERT_TRUE(job.has_value()); + EXPECT_EQ((*job)->mChangedTile, TilePosition(1, 0)); + } + + TEST_F(DetourNavigatorJobQueueTest, push_on_change_type_not_remove_should_add_to_updating) + { + std::list jobs; + const JobIt job = jobs.emplace( + jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, mChangedTile, ChangeType::update, mProcessTime); + + JobQueue queue; + queue.push(job); + + EXPECT_EQ(queue.getStats().mUpdating, 1); + } + + TEST_F(DetourNavigatorJobQueueTest, pop_should_return_nearest_to_player_tile) + { + std::list jobs; + + JobQueue queue; + queue.push(jobs.emplace(jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, TilePosition(0, 0), + ChangeType::update, mProcessTime)); + queue.push(jobs.emplace(jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, TilePosition(1, 0), + ChangeType::update, mProcessTime)); + + ASSERT_TRUE(queue.hasJob()); + const auto job = queue.pop(TilePosition(1, 0)); + ASSERT_TRUE(job.has_value()); + EXPECT_EQ((*job)->mChangedTile, TilePosition(1, 0)); + } + + TEST_F(DetourNavigatorJobQueueTest, push_on_processing_time_more_than_now_should_add_to_delayed) + { + const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + const std::chrono::steady_clock::time_point processTime = now + std::chrono::seconds(1); + + std::list jobs; + const JobIt job = jobs.emplace( + jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, mChangedTile, ChangeType::update, processTime); + + JobQueue queue; + queue.push(job, now); + + EXPECT_EQ(queue.getStats().mDelayed, 1); + } + + TEST_F(DetourNavigatorJobQueueTest, pop_should_return_when_delayed_job_is_ready) + { + const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + const std::chrono::steady_clock::time_point processTime = now + std::chrono::seconds(1); + + std::list jobs; + const JobIt job = jobs.emplace( + jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, mChangedTile, ChangeType::update, processTime); + + JobQueue queue; + queue.push(job, now); + + ASSERT_FALSE(queue.hasJob(now)); + ASSERT_FALSE(queue.pop(mPlayerTile, now).has_value()); + + ASSERT_TRUE(queue.hasJob(processTime)); + EXPECT_TRUE(queue.pop(mPlayerTile, processTime).has_value()); + } + + TEST_F(DetourNavigatorJobQueueTest, update_should_move_ready_delayed_to_updating) + { + const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + const std::chrono::steady_clock::time_point processTime = now + std::chrono::seconds(1); + + std::list jobs; + const JobIt job = jobs.emplace( + jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, mChangedTile, ChangeType::update, processTime); + + JobQueue queue; + queue.push(job, now); + + ASSERT_EQ(queue.getStats().mDelayed, 1); + + queue.update(mPlayerTile, mMaxTiles, processTime); + + EXPECT_EQ(queue.getStats().mDelayed, 0); + EXPECT_EQ(queue.getStats().mUpdating, 1); + } + + TEST_F(DetourNavigatorJobQueueTest, update_should_move_ready_delayed_to_removing_when_out_of_range) + { + const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + const std::chrono::steady_clock::time_point processTime = now + std::chrono::seconds(1); + + std::list jobs; + const JobIt job = jobs.emplace( + jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, mChangedTile, ChangeType::update, processTime); + + JobQueue queue; + queue.push(job, now); + + ASSERT_EQ(queue.getStats().mDelayed, 1); + + queue.update(TilePosition(10, 10), mMaxTiles, processTime); + + EXPECT_EQ(queue.getStats().mDelayed, 0); + EXPECT_EQ(queue.getStats().mRemoving, 1); + EXPECT_EQ(job->mChangeType, ChangeType::remove); + } + + TEST_F(DetourNavigatorJobQueueTest, update_should_move_updating_to_removing_when_out_of_range) + { + std::list jobs; + + JobQueue queue; + queue.push(jobs.emplace( + jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, mChangedTile, ChangeType::update, mProcessTime)); + queue.push(jobs.emplace(jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, TilePosition(10, 10), + ChangeType::update, mProcessTime)); + + ASSERT_EQ(queue.getStats().mUpdating, 2); + + queue.update(TilePosition(10, 10), mMaxTiles); + + EXPECT_EQ(queue.getStats().mUpdating, 1); + EXPECT_EQ(queue.getStats().mRemoving, 1); + } + + TEST_F(DetourNavigatorJobQueueTest, clear_should_remove_all) + { + const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + const std::chrono::steady_clock::time_point processTime = now + std::chrono::seconds(1); + + std::list jobs; + const JobIt removing = jobs.emplace(jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, + TilePosition(0, 0), ChangeType::remove, mProcessTime); + const JobIt updating = jobs.emplace(jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, + TilePosition(1, 0), ChangeType::update, mProcessTime); + const JobIt delayed = jobs.emplace(jobs.end(), mAgentBounds, mNavMeshCacheItem, mWorldspace, TilePosition(2, 0), + ChangeType::update, processTime); + + JobQueue queue; + queue.push(removing); + queue.push(updating); + queue.push(delayed, now); + + ASSERT_EQ(queue.getStats().mRemoving, 1); + ASSERT_EQ(queue.getStats().mUpdating, 1); + ASSERT_EQ(queue.getStats().mDelayed, 1); + + queue.clear(); + + EXPECT_EQ(queue.getStats().mRemoving, 0); + EXPECT_EQ(queue.getStats().mUpdating, 0); + EXPECT_EQ(queue.getStats().mDelayed, 0); + } } diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index b61a88662b..6dcade083a 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -1055,6 +1055,96 @@ namespace } } + TEST_P(DetourNavigatorUpdateTest, update_should_change_covered_area_when_player_moves_without_waiting_for_all) + { + Loading::Listener listener; + Settings settings = makeSettings(); + settings.mMaxTilesNumber = 1; + settings.mWaitUntilMinDistanceToPlayer = 1; + NavigatorImpl navigator(settings, nullptr); + const AgentBounds agentBounds{ CollisionShapeType::Aabb, { 29, 29, 66 } }; + ASSERT_TRUE(navigator.addAgent(agentBounds)); + + GetParam()(navigator); + + { + auto updateGuard = navigator.makeUpdateGuard(); + navigator.update(osg::Vec3f(3000, 3000, 0), updateGuard.get()); + } + + navigator.wait(WaitConditionType::requiredTilesPresent, &listener); + + { + const auto navMesh = navigator.getNavMesh(agentBounds); + ASSERT_NE(navMesh, nullptr); + + const TilePosition expectedTile(4, 4); + const auto usedTiles = getUsedTiles(*navMesh->lockConst()); + EXPECT_THAT(usedTiles, Contains(expectedTile)) << usedTiles; + } + + { + auto updateGuard = navigator.makeUpdateGuard(); + navigator.update(osg::Vec3f(6000, 3000, 0), updateGuard.get()); + } + + navigator.wait(WaitConditionType::requiredTilesPresent, &listener); + + { + const auto navMesh = navigator.getNavMesh(agentBounds); + ASSERT_NE(navMesh, nullptr); + + const TilePosition expectedTile(8, 4); + const auto usedTiles = getUsedTiles(*navMesh->lockConst()); + EXPECT_THAT(usedTiles, Contains(expectedTile)) << usedTiles; + } + } + + TEST_P(DetourNavigatorUpdateTest, update_should_change_covered_area_when_player_moves_with_db) + { + Loading::Listener listener; + Settings settings = makeSettings(); + settings.mMaxTilesNumber = 1; + settings.mWaitUntilMinDistanceToPlayer = 1; + NavigatorImpl navigator(settings, std::make_unique(":memory:", settings.mMaxDbFileSize)); + const AgentBounds agentBounds{ CollisionShapeType::Aabb, { 29, 29, 66 } }; + ASSERT_TRUE(navigator.addAgent(agentBounds)); + + GetParam()(navigator); + + { + auto updateGuard = navigator.makeUpdateGuard(); + navigator.update(osg::Vec3f(3000, 3000, 0), updateGuard.get()); + } + + navigator.wait(WaitConditionType::requiredTilesPresent, &listener); + + { + const auto navMesh = navigator.getNavMesh(agentBounds); + ASSERT_NE(navMesh, nullptr); + + const TilePosition expectedTile(4, 4); + const auto usedTiles = getUsedTiles(*navMesh->lockConst()); + EXPECT_THAT(usedTiles, Contains(expectedTile)) << usedTiles; + } + + { + auto updateGuard = navigator.makeUpdateGuard(); + navigator.update(osg::Vec3f(6000, 3000, 0), updateGuard.get()); + } + + navigator.wait(WaitConditionType::requiredTilesPresent, &listener); + + { + const auto navMesh = navigator.getNavMesh(agentBounds); + ASSERT_NE(navMesh, nullptr); + + const TilePosition expectedTile(8, 4); + const auto usedTiles = getUsedTiles(*navMesh->lockConst()); + EXPECT_THAT(usedTiles, Contains(expectedTile)) << usedTiles; + } + } + struct AddHeightfieldSurface { static constexpr std::size_t sSize = 65; diff --git a/apps/openmw_test_suite/esm3/testsaveload.cpp b/apps/openmw_test_suite/esm3/testsaveload.cpp index 2629442563..afffbbb3d6 100644 --- a/apps/openmw_test_suite/esm3/testsaveload.cpp +++ b/apps/openmw_test_suite/esm3/testsaveload.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -603,6 +604,83 @@ namespace ESM EXPECT_EQ(result.mIcon, record.mIcon); } + TEST_P(Esm3SaveLoadRecordTest, infoShouldNotChange) + { + DialInfo record = { + .mData = { + .mType = ESM::Dialogue::Topic, + .mDisposition = 1, + .mRank = 2, + .mGender = ESM::DialInfo::NA, + .mPCrank = 3, + }, + .mSelects = { + ESM::DialogueCondition{ + .mVariable = {}, + .mValue = 42, + .mIndex = 0, + .mFunction = ESM::DialogueCondition::Function_Level, + .mComparison = ESM::DialogueCondition::Comp_Eq + }, + ESM::DialogueCondition{ + .mVariable = generateRandomString(32), + .mValue = 0, + .mIndex = 1, + .mFunction = ESM::DialogueCondition::Function_NotLocal, + .mComparison = ESM::DialogueCondition::Comp_Eq + }, + }, + .mId = generateRandomRefId(32), + .mPrev = generateRandomRefId(32), + .mNext = generateRandomRefId(32), + .mActor = generateRandomRefId(32), + .mRace = generateRandomRefId(32), + .mClass = generateRandomRefId(32), + .mFaction = generateRandomRefId(32), + .mPcFaction = generateRandomRefId(32), + .mCell = generateRandomRefId(32), + .mSound = generateRandomString(32), + .mResponse = generateRandomString(32), + .mResultScript = generateRandomString(32), + .mFactionLess = false, + .mQuestStatus = ESM::DialInfo::QS_None, + }; + + DialInfo result; + saveAndLoadRecord(record, GetParam(), result); + + EXPECT_EQ(result.mData.mType, record.mData.mType); + EXPECT_EQ(result.mData.mDisposition, record.mData.mDisposition); + EXPECT_EQ(result.mData.mRank, record.mData.mRank); + EXPECT_EQ(result.mData.mGender, record.mData.mGender); + EXPECT_EQ(result.mData.mPCrank, record.mData.mPCrank); + EXPECT_EQ(result.mId, record.mId); + EXPECT_EQ(result.mPrev, record.mPrev); + EXPECT_EQ(result.mNext, record.mNext); + EXPECT_EQ(result.mActor, record.mActor); + EXPECT_EQ(result.mRace, record.mRace); + EXPECT_EQ(result.mClass, record.mClass); + EXPECT_EQ(result.mFaction, record.mFaction); + EXPECT_EQ(result.mPcFaction, record.mPcFaction); + EXPECT_EQ(result.mCell, record.mCell); + EXPECT_EQ(result.mSound, record.mSound); + EXPECT_EQ(result.mResponse, record.mResponse); + EXPECT_EQ(result.mResultScript, record.mResultScript); + EXPECT_EQ(result.mFactionLess, record.mFactionLess); + EXPECT_EQ(result.mQuestStatus, record.mQuestStatus); + EXPECT_EQ(result.mSelects.size(), record.mSelects.size()); + for (size_t i = 0; i < result.mSelects.size(); ++i) + { + const auto& resultS = result.mSelects[i]; + const auto& recordS = record.mSelects[i]; + EXPECT_EQ(resultS.mVariable, recordS.mVariable); + EXPECT_EQ(resultS.mValue, recordS.mValue); + EXPECT_EQ(resultS.mIndex, recordS.mIndex); + EXPECT_EQ(resultS.mFunction, recordS.mFunction); + EXPECT_EQ(resultS.mComparison, recordS.mComparison); + } + } + INSTANTIATE_TEST_SUITE_P(FormatVersions, Esm3SaveLoadRecordTest, ValuesIn(getFormats())); } } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 7ac01ef169..68411be2fc 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -181,7 +181,7 @@ add_component_dir (esm3 inventorystate containerstate npcstate creaturestate dialoguestate statstate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile aisequence magiceffects custommarkerstate stolenitems transport animationstate controlsstate mappings readerscache - infoorder timestamp formatversion landrecorddata selectiongroup + infoorder timestamp formatversion landrecorddata selectiongroup dialoguecondition ) add_component_dir (esmterrain diff --git a/components/debug/debugging.cpp b/components/debug/debugging.cpp index e9e50ff836..67e7ecaaf3 100644 --- a/components/debug/debugging.cpp +++ b/components/debug/debugging.cpp @@ -61,6 +61,11 @@ namespace Debug bool outRedirected = isRedirected(STD_OUTPUT_HANDLE); bool errRedirected = isRedirected(STD_ERROR_HANDLE); + // Note: Do not spend three days reinvestigating this PowerShell bug thinking its our bug. + // https://gitlab.com/OpenMW/openmw/-/merge_requests/408#note_447467393 + // The handles look valid, but GetFinalPathNameByHandleA can't tell what files they go to and writing to them + // doesn't work. + if (AttachConsole(ATTACH_PARENT_PROCESS)) { fflush(stdout); @@ -73,16 +78,19 @@ namespace Debug { _wfreopen(L"CON", L"r", stdin); freopen("CON", "r", stdin); + std::cin.clear(); } if (!outRedirected) { _wfreopen(L"CON", L"w", stdout); freopen("CON", "w", stdout); + std::cout.clear(); } if (!errRedirected) { _wfreopen(L"CON", L"w", stderr); freopen("CON", "w", stderr); + std::cerr.clear(); } return true; @@ -256,9 +264,17 @@ namespace Debug private: static bool useColoredOutput() { - // Note: cmd.exe in Win10 should support ANSI colors, but in its own way. #if defined(_WIN32) - return 0; + if (getenv("NO_COLOR")) + return false; + + DWORD mode; + if (GetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), &mode) && mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) + return true; + + // some console emulators may not use the Win32 API, so try the Unixy approach + char* term = getenv("TERM"); + return term && GetFileType(GetStdHandle(STD_ERROR_HANDLE)) == FILE_TYPE_CHAR; #else char* term = getenv("TERM"); bool useColor = term && !getenv("NO_COLOR") && isatty(fileno(stderr)); diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 03f6062788..fe6d0625f5 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -16,8 +16,9 @@ #include +#include + #include -#include #include #include #include @@ -49,40 +50,6 @@ namespace DetourNavigator return false; } - auto getPriority(const Job& job) noexcept - { - return std::make_tuple(-static_cast>(job.mState), job.mProcessTime, - job.mChangeType, job.mTryNumber, job.mDistanceToPlayer, job.mDistanceToOrigin); - } - - struct LessByJobPriority - { - bool operator()(JobIt lhs, JobIt rhs) const noexcept { return getPriority(*lhs) < getPriority(*rhs); } - }; - - void insertPrioritizedJob(JobIt job, std::deque& queue) - { - const auto it = std::upper_bound(queue.begin(), queue.end(), job, LessByJobPriority{}); - queue.insert(it, job); - } - - auto getDbPriority(const Job& job) noexcept - { - return std::make_tuple(static_cast>(job.mState), job.mChangeType, - job.mDistanceToPlayer, job.mDistanceToOrigin); - } - - struct LessByJobDbPriority - { - bool operator()(JobIt lhs, JobIt rhs) const noexcept { return getDbPriority(*lhs) < getDbPriority(*rhs); } - }; - - void insertPrioritizedDbJob(JobIt job, std::deque& queue) - { - const auto it = std::upper_bound(queue.begin(), queue.end(), job, LessByJobDbPriority{}); - queue.insert(it, job); - } - auto getAgentAndTile(const Job& job) noexcept { return std::make_tuple(job.mAgentBounds, job.mChangedTile); @@ -97,16 +64,6 @@ namespace DetourNavigator settings.mRecast, settings.mWriteToNavMeshDb); } - void updateJobs(std::deque& jobs, TilePosition playerTile, int maxTiles) - { - for (JobIt job : jobs) - { - job->mDistanceToPlayer = getManhattanDistance(job->mChangedTile, playerTile); - if (!shouldAddTile(job->mChangedTile, playerTile, maxTiles)) - job->mChangeType = ChangeType::remove; - } - } - std::size_t getNextJobId() { static std::atomic_size_t nextJobId{ 1 }; @@ -134,7 +91,7 @@ namespace DetourNavigator } Job::Job(const AgentBounds& agentBounds, std::weak_ptr navMeshCacheItem, - std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer, + std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, std::chrono::steady_clock::time_point processTime) : mId(getNextJobId()) , mAgentBounds(agentBounds) @@ -143,11 +100,148 @@ namespace DetourNavigator , mChangedTile(changedTile) , mProcessTime(processTime) , mChangeType(changeType) - , mDistanceToPlayer(distanceToPlayer) - , mDistanceToOrigin(getManhattanDistance(changedTile, TilePosition{ 0, 0 })) { } + void SpatialJobQueue::clear() + { + mValues.clear(); + mIndex.clear(); + mSize = 0; + } + + void SpatialJobQueue::push(JobIt job) + { + auto it = mValues.find(job->mChangedTile); + + if (it == mValues.end()) + { + it = mValues.emplace_hint(it, job->mChangedTile, std::deque()); + mIndex.insert(IndexValue(IndexPoint(job->mChangedTile.x(), job->mChangedTile.y()), it)); + } + + it->second.push_back(job); + + ++mSize; + } + + std::optional SpatialJobQueue::pop(TilePosition playerTile) + { + const IndexPoint point(playerTile.x(), playerTile.y()); + const auto it = mIndex.qbegin(boost::geometry::index::nearest(point, 1)); + + if (it == mIndex.qend()) + return std::nullopt; + + const UpdatingMap::iterator mapIt = it->second; + std::deque& tileJobs = mapIt->second; + JobIt result = tileJobs.front(); + tileJobs.pop_front(); + + --mSize; + + if (tileJobs.empty()) + { + mValues.erase(mapIt); + mIndex.remove(*it); + } + + return result; + } + + void SpatialJobQueue::update(TilePosition playerTile, int maxTiles, std::vector& removing) + { + for (auto it = mValues.begin(); it != mValues.end();) + { + if (shouldAddTile(it->first, playerTile, maxTiles)) + { + ++it; + continue; + } + + for (JobIt job : it->second) + { + job->mChangeType = ChangeType::remove; + removing.push_back(job); + } + + mSize -= it->second.size(); + mIndex.remove(IndexValue(IndexPoint(it->first.x(), it->first.y()), it)); + it = mValues.erase(it); + } + } + + bool JobQueue::hasJob(std::chrono::steady_clock::time_point now) const + { + return !mRemoving.empty() || mUpdating.size() > 0 + || (!mDelayed.empty() && mDelayed.front()->mProcessTime <= now); + } + + void JobQueue::clear() + { + mRemoving.clear(); + mDelayed.clear(); + mUpdating.clear(); + } + + void JobQueue::push(JobIt job, std::chrono::steady_clock::time_point now) + { + if (job->mProcessTime > now) + { + mDelayed.push_back(job); + return; + } + + if (job->mChangeType == ChangeType::remove) + { + mRemoving.push_back(job); + return; + } + + mUpdating.push(job); + } + + std::optional JobQueue::pop(TilePosition playerTile, std::chrono::steady_clock::time_point now) + { + if (!mRemoving.empty()) + { + const JobIt result = mRemoving.back(); + mRemoving.pop_back(); + return result; + } + + if (const std::optional result = mUpdating.pop(playerTile)) + return result; + + if (mDelayed.empty() || mDelayed.front()->mProcessTime > now) + return std::nullopt; + + const JobIt result = mDelayed.front(); + mDelayed.pop_front(); + return result; + } + + void JobQueue::update(TilePosition playerTile, int maxTiles, std::chrono::steady_clock::time_point now) + { + mUpdating.update(playerTile, maxTiles, mRemoving); + + while (!mDelayed.empty() && mDelayed.front()->mProcessTime <= now) + { + const JobIt job = mDelayed.front(); + mDelayed.pop_front(); + + if (shouldAddTile(job->mChangedTile, playerTile, maxTiles)) + { + mUpdating.push(job); + } + else + { + job->mChangeType = ChangeType::remove; + mRemoving.push_back(job); + } + } + } + AsyncNavMeshUpdater::AsyncNavMeshUpdater(const Settings& settings, TileCachedRecastMeshManager& recastMeshManager, OffMeshConnectionsManager& offMeshConnectionsManager, std::unique_ptr&& db) : mSettings(settings) @@ -180,48 +274,47 @@ namespace DetourNavigator if (!playerTileChanged && changedTiles.empty()) return; - const int maxTiles - = std::min(mSettings.get().mMaxTilesNumber, navMeshCacheItem->lockConst()->getImpl().getParams()->maxTiles); - std::unique_lock lock(mMutex); if (playerTileChanged) - updateJobs(mWaiting, playerTile, maxTiles); + { + Log(Debug::Debug) << "Player tile has been changed to " << playerTile; + mWaiting.update(playerTile, mSettings.get().mMaxTilesNumber); + } for (const auto& [changedTile, changeType] : changedTiles) { if (mPushed.emplace(agentBounds, changedTile).second) { - const auto processTime = changeType == ChangeType::update - ? mLastUpdates[std::tie(agentBounds, changedTile)] + mSettings.get().mMinUpdateInterval - : std::chrono::steady_clock::time_point(); + const auto processTime = [&, changedTile = changedTile, changeType = changeType] { + if (changeType != ChangeType::update) + return std::chrono::steady_clock::time_point(); + const auto lastUpdate = mLastUpdates.find(std::tie(agentBounds, changedTile)); + if (lastUpdate == mLastUpdates.end()) + return std::chrono::steady_clock::time_point(); + return lastUpdate->second + mSettings.get().mMinUpdateInterval; + }(); - const JobIt it = mJobs.emplace(mJobs.end(), agentBounds, navMeshCacheItem, worldspace, changedTile, - changeType, getManhattanDistance(changedTile, playerTile), processTime); + const JobIt it = mJobs.emplace( + mJobs.end(), agentBounds, navMeshCacheItem, worldspace, changedTile, changeType, processTime); Log(Debug::Debug) << "Post job " << it->mId << " for agent=(" << it->mAgentBounds << ")" - << " changedTile=(" << it->mChangedTile << ") " + << " changedTile=(" << it->mChangedTile << ")" << " changeType=" << it->mChangeType; - if (playerTileChanged) - mWaiting.push_back(it); - else - insertPrioritizedJob(it, mWaiting); + mWaiting.push(it); } } - if (playerTileChanged) - std::sort(mWaiting.begin(), mWaiting.end(), LessByJobPriority{}); - Log(Debug::Debug) << "Posted " << mJobs.size() << " navigator jobs"; - if (!mWaiting.empty()) + if (mWaiting.hasJob()) mHasJob.notify_all(); lock.unlock(); if (playerTileChanged && mDbWorker != nullptr) - mDbWorker->updateJobs(playerTile, maxTiles); + mDbWorker->update(playerTile); } void AsyncNavMeshUpdater::wait(WaitConditionType waitConditionType, Loading::Listener* listener) @@ -313,7 +406,7 @@ namespace DetourNavigator { const std::lock_guard lock(mMutex); result.mJobs = mJobs.size(); - result.mWaiting = mWaiting.size(); + result.mWaiting = mWaiting.getStats(); result.mPushed = mPushed.size(); } result.mProcessing = mProcessingTiles.lockConst()->size(); @@ -335,7 +428,8 @@ namespace DetourNavigator if (JobIt job = getNextJob(); job != mJobs.end()) { const JobStatus status = processJob(*job); - Log(Debug::Debug) << "Processed job " << job->mId << " with status=" << status; + Log(Debug::Debug) << "Processed job " << job->mId << " with status=" << status + << " changeType=" << job->mChangeType; switch (status) { case JobStatus::Done: @@ -346,7 +440,8 @@ namespace DetourNavigator removeJob(job); break; case JobStatus::Fail: - repost(job); + unlockTile(job->mId, job->mAgentBounds, job->mChangedTile); + removeJob(job); break; case JobStatus::MemoryCacheMiss: { @@ -368,7 +463,9 @@ namespace DetourNavigator JobStatus AsyncNavMeshUpdater::processJob(Job& job) { - Log(Debug::Debug) << "Processing job " << job.mId << " by thread=" << std::this_thread::get_id(); + Log(Debug::Debug) << "Processing job " << job.mId << " for agent=(" << job.mAgentBounds << ")" + << " changedTile=(" << job.mChangedTile << ")" + << " changeType=" << job.mChangeType << " by thread=" << std::this_thread::get_id(); const auto navMeshCacheItem = job.mNavMeshCacheItem.lock(); @@ -376,12 +473,11 @@ namespace DetourNavigator return JobStatus::Done; const auto playerTile = *mPlayerTile.lockConst(); - const int maxTiles - = std::min(mSettings.get().mMaxTilesNumber, navMeshCacheItem->lockConst()->getImpl().getParams()->maxTiles); - if (!shouldAddTile(job.mChangedTile, playerTile, maxTiles)) + if (!shouldAddTile(job.mChangedTile, playerTile, mSettings.get().mMaxTilesNumber)) { Log(Debug::Debug) << "Ignore add tile by job " << job.mId << ": too far from player"; + job.mChangeType = ChangeType::remove; navMeshCacheItem->lock()->removeTile(job.mChangedTile); return JobStatus::Done; } @@ -549,9 +645,8 @@ namespace DetourNavigator bool shouldStop = false; const auto hasJob = [&] { - shouldStop = mShouldStop; - return shouldStop - || (!mWaiting.empty() && mWaiting.front()->mProcessTime <= std::chrono::steady_clock::now()); + shouldStop = mShouldStop.load(); + return shouldStop || mWaiting.hasJob(); }; if (!mHasJob.wait_for(lock, std::chrono::milliseconds(10), hasJob)) @@ -564,9 +659,15 @@ namespace DetourNavigator if (shouldStop) return mJobs.end(); - const JobIt job = mWaiting.front(); + const TilePosition playerTile = *mPlayerTile.lockConst(); - mWaiting.pop_front(); + JobIt job = mJobs.end(); + + if (const std::optional nextJob = mWaiting.pop(playerTile)) + job = *nextJob; + + if (job == mJobs.end()) + return job; Log(Debug::Debug) << "Pop job " << job->mId << " by thread=" << std::this_thread::get_id(); @@ -575,9 +676,9 @@ namespace DetourNavigator if (!lockTile(job->mId, job->mAgentBounds, job->mChangedTile)) { - Log(Debug::Debug) << "Failed to lock tile by job " << job->mId << " try=" << job->mTryNumber; - ++job->mTryNumber; - insertPrioritizedJob(job, mWaiting); + Log(Debug::Debug) << "Failed to lock tile by job " << job->mId; + job->mProcessTime = std::chrono::steady_clock::now() + mSettings.get().mMinUpdateInterval; + mWaiting.push(job); return mJobs.end(); } @@ -613,26 +714,6 @@ namespace DetourNavigator writeToFile(shared->lockConst()->getImpl(), mSettings.get().mNavMeshPathPrefix, navMeshRevision); } - void AsyncNavMeshUpdater::repost(JobIt job) - { - unlockTile(job->mId, job->mAgentBounds, job->mChangedTile); - - if (mShouldStop || job->mTryNumber > 2) - return; - - const std::lock_guard lock(mMutex); - - if (mPushed.emplace(job->mAgentBounds, job->mChangedTile).second) - { - ++job->mTryNumber; - insertPrioritizedJob(job, mWaiting); - mHasJob.notify_all(); - return; - } - - mJobs.erase(job); - } - bool AsyncNavMeshUpdater::lockTile( std::size_t jobId, const AgentBounds& agentBounds, const TilePosition& changedTile) { @@ -677,7 +758,7 @@ namespace DetourNavigator { Log(Debug::Debug) << "Enqueueing job " << job->mId << " by thread=" << std::this_thread::get_id(); const std::lock_guard lock(mMutex); - insertPrioritizedJob(job, mWaiting); + mWaiting.push(job); mHasJob.notify_all(); } @@ -691,40 +772,47 @@ namespace DetourNavigator void DbJobQueue::push(JobIt job) { const std::lock_guard lock(mMutex); - insertPrioritizedDbJob(job, mJobs); if (isWritingDbJob(*job)) - ++mWritingJobs; + mWriting.push_back(job); else - ++mReadingJobs; + mReading.push(job); mHasJob.notify_all(); } std::optional DbJobQueue::pop() { std::unique_lock lock(mMutex); - mHasJob.wait(lock, [&] { return mShouldStop || !mJobs.empty(); }); - if (mJobs.empty()) + + const auto hasJob = [&] { return mShouldStop || mReading.size() > 0 || mWriting.size() > 0; }; + + mHasJob.wait(lock, hasJob); + + if (mShouldStop) return std::nullopt; - const JobIt job = mJobs.front(); - mJobs.pop_front(); - if (isWritingDbJob(*job)) - --mWritingJobs; - else - --mReadingJobs; + + if (const std::optional job = mReading.pop(mPlayerTile)) + return job; + + if (mWriting.empty()) + return std::nullopt; + + const JobIt job = mWriting.front(); + mWriting.pop_front(); + return job; } - void DbJobQueue::update(TilePosition playerTile, int maxTiles) + void DbJobQueue::update(TilePosition playerTile) { const std::lock_guard lock(mMutex); - updateJobs(mJobs, playerTile, maxTiles); - std::sort(mJobs.begin(), mJobs.end(), LessByJobDbPriority{}); + mPlayerTile = playerTile; } void DbJobQueue::stop() { const std::lock_guard lock(mMutex); - mJobs.clear(); + mReading.clear(); + mWriting.clear(); mShouldStop = true; mHasJob.notify_all(); } @@ -732,7 +820,10 @@ namespace DetourNavigator DbJobQueueStats DbJobQueue::getStats() const { const std::lock_guard lock(mMutex); - return DbJobQueueStats{ .mWritingJobs = mWritingJobs, .mReadingJobs = mReadingJobs }; + return DbJobQueueStats{ + .mReadingJobs = mReading.size(), + .mWritingJobs = mWriting.size(), + }; } DbWorker::DbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr&& db, TileVersion version, @@ -761,8 +852,10 @@ namespace DetourNavigator DbWorkerStats DbWorker::getStats() const { - return DbWorkerStats{ .mJobs = mQueue.getStats(), - .mGetTileCount = mGetTileCount.load(std::memory_order_relaxed) }; + return DbWorkerStats{ + .mJobs = mQueue.getStats(), + .mGetTileCount = mGetTileCount.load(std::memory_order_relaxed), + }; } void DbWorker::stop() diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index 9b95d4f4b3..f3d624a8a6 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -14,6 +14,9 @@ #include "tileposition.hpp" #include "waitconditiontype.hpp" +#include +#include + #include #include #include @@ -49,11 +52,8 @@ namespace DetourNavigator const std::weak_ptr mNavMeshCacheItem; const std::string mWorldspace; const TilePosition mChangedTile; - const std::chrono::steady_clock::time_point mProcessTime; - unsigned mTryNumber = 0; + std::chrono::steady_clock::time_point mProcessTime; ChangeType mChangeType; - int mDistanceToPlayer; - const int mDistanceToOrigin; JobState mState = JobState::Initial; std::vector mInput; std::shared_ptr mRecastMesh; @@ -61,12 +61,65 @@ namespace DetourNavigator std::unique_ptr mGeneratedNavMeshData; Job(const AgentBounds& agentBounds, std::weak_ptr navMeshCacheItem, - std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer, + std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, std::chrono::steady_clock::time_point processTime); }; using JobIt = std::list::iterator; + class SpatialJobQueue + { + public: + std::size_t size() const { return mSize; } + + void clear(); + + void push(JobIt job); + + std::optional pop(TilePosition playerTile); + + void update(TilePosition playerTile, int maxTiles, std::vector& removing); + + private: + using IndexPoint = boost::geometry::model::point; + using UpdatingMap = std::map>; + using IndexValue = std::pair; + + std::size_t mSize = 0; + UpdatingMap mValues; + boost::geometry::index::rtree> mIndex; + }; + + class JobQueue + { + public: + JobQueueStats getStats() const + { + return JobQueueStats{ + .mRemoving = mRemoving.size(), + .mUpdating = mUpdating.size(), + .mDelayed = mDelayed.size(), + }; + } + + bool hasJob(std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now()) const; + + void clear(); + + void push(JobIt job, std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now()); + + std::optional pop( + TilePosition playerTile, std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now()); + + void update(TilePosition playerTile, int maxTiles, + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now()); + + private: + std::vector mRemoving; + SpatialJobQueue mUpdating; + std::deque mDelayed; + }; + enum class JobStatus { Done, @@ -83,7 +136,7 @@ namespace DetourNavigator std::optional pop(); - void update(TilePosition playerTile, int maxTiles); + void update(TilePosition playerTile); void stop(); @@ -92,10 +145,10 @@ namespace DetourNavigator private: mutable std::mutex mMutex; std::condition_variable mHasJob; - std::deque mJobs; + SpatialJobQueue mReading; + std::deque mWriting; + TilePosition mPlayerTile; bool mShouldStop = false; - std::size_t mWritingJobs = 0; - std::size_t mReadingJobs = 0; }; class AsyncNavMeshUpdater; @@ -112,7 +165,7 @@ namespace DetourNavigator void enqueueJob(JobIt job); - void updateJobs(TilePosition playerTile, int maxTiles) { mQueue.update(playerTile, maxTiles); } + void update(TilePosition playerTile) { mQueue.update(playerTile); } void stop(); @@ -169,7 +222,7 @@ namespace DetourNavigator std::condition_variable mDone; std::condition_variable mProcessed; std::list mJobs; - std::deque mWaiting; + JobQueue mWaiting; std::set> mPushed; Misc::ScopeGuarded mPlayerTile; NavMeshTilesCache mNavMeshTilesCache; @@ -197,8 +250,6 @@ namespace DetourNavigator void writeDebugFiles(const Job& job, const RecastMesh* recastMesh) const; - void repost(JobIt job); - bool lockTile(std::size_t jobId, const AgentBounds& agentBounds, const TilePosition& changedTile); void unlockTile(std::size_t jobId, const AgentBounds& agentBounds, const TilePosition& changedTile); diff --git a/components/detournavigator/changetype.hpp b/components/detournavigator/changetype.hpp index e6d0bce0a9..63a43e88fb 100644 --- a/components/detournavigator/changetype.hpp +++ b/components/detournavigator/changetype.hpp @@ -6,15 +6,9 @@ namespace DetourNavigator enum class ChangeType { remove = 0, - mixed = 1, - add = 2, - update = 3, + add = 1, + update = 2, }; - - inline ChangeType addChangeType(const ChangeType current, const ChangeType add) - { - return current == add ? current : ChangeType::mixed; - } } #endif diff --git a/components/detournavigator/debug.cpp b/components/detournavigator/debug.cpp index 835f37f999..5ce1464bdd 100644 --- a/components/detournavigator/debug.cpp +++ b/components/detournavigator/debug.cpp @@ -79,13 +79,13 @@ namespace DetourNavigator switch (v) { case CollisionShapeType::Aabb: - return s << "AgentShapeType::Aabb"; + return s << "CollisionShapeType::Aabb"; case CollisionShapeType::RotatingBox: - return s << "AgentShapeType::RotatingBox"; + return s << "CollisionShapeType::RotatingBox"; case CollisionShapeType::Cylinder: - return s << "AgentShapeType::Cylinder"; + return s << "CollisionShapeType::Cylinder"; } - return s << "AgentShapeType::" << static_cast>(v); + return s << "CollisionShapeType::" << static_cast>(v); } std::ostream& operator<<(std::ostream& s, const AgentBounds& v) @@ -184,8 +184,6 @@ namespace DetourNavigator { case ChangeType::remove: return stream << "ChangeType::remove"; - case ChangeType::mixed: - return stream << "ChangeType::mixed"; case ChangeType::add: return stream << "ChangeType::add"; case ChangeType::update: diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index d35ecf499d..e143bf1837 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -480,15 +480,6 @@ namespace DetourNavigator return true; } - template - unsigned long getMinValuableBitsNumber(const T value) - { - unsigned long power = 0; - while (power < sizeof(T) * 8 && (static_cast(1) << power) < value) - ++power; - return power; - } - std::pair getBoundsByZ( const RecastMesh& recastMesh, float agentHalfExtentsZ, const RecastSettings& settings) { @@ -528,10 +519,7 @@ namespace DetourNavigator return { minZ, maxZ }; } } -} // namespace DetourNavigator -namespace DetourNavigator -{ std::unique_ptr prepareNavMeshTileData(const RecastMesh& recastMesh, std::string_view worldspace, const TilePosition& tilePosition, const AgentBounds& agentBounds, const RecastSettings& settings) @@ -621,22 +609,12 @@ namespace DetourNavigator void initEmptyNavMesh(const Settings& settings, dtNavMesh& navMesh) { - // Max tiles and max polys affect how the tile IDs are caculated. - // There are 22 bits available for identifying a tile and a polygon. - const int polysAndTilesBits = 22; - const auto polysBits = getMinValuableBitsNumber(settings.mDetour.mMaxPolys); - - if (polysBits >= polysAndTilesBits) - throw InvalidArgument("Too many polygons per tile"); - - const auto tilesBits = polysAndTilesBits - polysBits; - dtNavMeshParams params; std::fill_n(params.orig, 3, 0.0f); params.tileWidth = settings.mRecast.mTileSize * settings.mRecast.mCellSize; params.tileHeight = settings.mRecast.mTileSize * settings.mRecast.mCellSize; - params.maxTiles = 1 << tilesBits; - params.maxPolys = 1 << polysBits; + params.maxTiles = settings.mMaxTilesNumber; + params.maxPolys = settings.mDetour.mMaxPolys; const auto status = navMesh.init(¶ms); diff --git a/components/detournavigator/navmeshcacheitem.hpp b/components/detournavigator/navmeshcacheitem.hpp index ec76b56a46..120a374195 100644 --- a/components/detournavigator/navmeshcacheitem.hpp +++ b/components/detournavigator/navmeshcacheitem.hpp @@ -131,6 +131,15 @@ namespace DetourNavigator function(position, tile.mVersion, *meshTile); } + template + void forEachTilePosition(Function&& function) const + { + for (const auto& [position, tile] : mUsedTiles) + function(position); + for (const TilePosition& position : mEmptyTiles) + function(position); + } + private: struct Tile { diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index f4a82b850f..3b62866ed7 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -13,8 +13,6 @@ #include -#include - namespace { /// Safely reset shared_ptr with definite underlying object destrutor call. @@ -179,9 +177,9 @@ namespace DetourNavigator { std::map tilesToPost = changedTiles; { + const int maxTiles = mSettings.mMaxTilesNumber; const auto locked = cached->lockConst(); const auto& navMesh = locked->getImpl(); - const auto maxTiles = std::min(mSettings.mMaxTilesNumber, navMesh.getParams()->maxTiles); getTilesPositions(range, [&](const TilePosition& tile) { if (changedTiles.find(tile) != changedTiles.end()) return; @@ -190,7 +188,11 @@ namespace DetourNavigator if (shouldAdd && !presentInNavMesh) tilesToPost.emplace(tile, locked->isEmptyTile(tile) ? ChangeType::update : ChangeType::add); else if (!shouldAdd && presentInNavMesh) - tilesToPost.emplace(tile, ChangeType::mixed); + tilesToPost.emplace(tile, ChangeType::remove); + }); + locked->forEachTilePosition([&](const TilePosition& tile) { + if (!shouldAddTile(tile, playerTile, maxTiles)) + tilesToPost.emplace(tile, ChangeType::remove); }); } mAsyncNavMeshUpdater.post(agentBounds, cached, playerTile, mWorldspace, tilesToPost); diff --git a/components/detournavigator/settings.cpp b/components/detournavigator/settings.cpp index 0470c629e5..5e555050f7 100644 --- a/components/detournavigator/settings.cpp +++ b/components/detournavigator/settings.cpp @@ -3,41 +3,81 @@ #include #include +#include +#include +#include + namespace DetourNavigator { - RecastSettings makeRecastSettingsFromSettingsManager() + namespace { - RecastSettings result; + struct NavMeshLimits + { + int mMaxTiles; + int mMaxPolys; + }; - result.mBorderSize = ::Settings::navigator().mBorderSize; - result.mCellHeight = ::Settings::navigator().mCellHeight; - result.mCellSize = ::Settings::navigator().mCellSize; - result.mDetailSampleDist = ::Settings::navigator().mDetailSampleDist; - result.mDetailSampleMaxError = ::Settings::navigator().mDetailSampleMaxError; - result.mMaxClimb = Constants::sStepSizeUp; - result.mMaxSimplificationError = ::Settings::navigator().mMaxSimplificationError; - result.mMaxSlope = Constants::sMaxSlope; - result.mRecastScaleFactor = ::Settings::navigator().mRecastScaleFactor; - result.mSwimHeightScale = 0; - result.mMaxEdgeLen = ::Settings::navigator().mMaxEdgeLen; - result.mMaxVertsPerPoly = ::Settings::navigator().mMaxVertsPerPoly; - result.mRegionMergeArea = ::Settings::navigator().mRegionMergeArea; - result.mRegionMinArea = ::Settings::navigator().mRegionMinArea; - result.mTileSize = ::Settings::navigator().mTileSize; + template + unsigned long getMinValuableBitsNumber(const T value) + { + unsigned long power = 0; + while (power < sizeof(T) * 8 && (static_cast(1) << power) < value) + ++power; + return power; + } - return result; - } + NavMeshLimits getNavMeshTileLimits(const DetourSettings& settings) + { + // Max tiles and max polys affect how the tile IDs are caculated. + // There are 22 bits available for identifying a tile and a polygon. + constexpr int polysAndTilesBits = 22; + const unsigned long polysBits = getMinValuableBitsNumber(settings.mMaxPolys); - DetourSettings makeDetourSettingsFromSettingsManager() - { - DetourSettings result; + if (polysBits >= polysAndTilesBits) + throw std::invalid_argument("Too many polygons per tile: " + std::to_string(settings.mMaxPolys)); - result.mMaxNavMeshQueryNodes = ::Settings::navigator().mMaxNavMeshQueryNodes; - result.mMaxPolys = ::Settings::navigator().mMaxPolygonsPerTile; - result.mMaxPolygonPathSize = ::Settings::navigator().mMaxPolygonPathSize; - result.mMaxSmoothPathSize = ::Settings::navigator().mMaxSmoothPathSize; + const unsigned long tilesBits = polysAndTilesBits - polysBits; - return result; + return NavMeshLimits{ + .mMaxTiles = static_cast(1 << tilesBits), + .mMaxPolys = static_cast(1 << polysBits), + }; + } + + RecastSettings makeRecastSettingsFromSettingsManager() + { + RecastSettings result; + + result.mBorderSize = ::Settings::navigator().mBorderSize; + result.mCellHeight = ::Settings::navigator().mCellHeight; + result.mCellSize = ::Settings::navigator().mCellSize; + result.mDetailSampleDist = ::Settings::navigator().mDetailSampleDist; + result.mDetailSampleMaxError = ::Settings::navigator().mDetailSampleMaxError; + result.mMaxClimb = Constants::sStepSizeUp; + result.mMaxSimplificationError = ::Settings::navigator().mMaxSimplificationError; + result.mMaxSlope = Constants::sMaxSlope; + result.mRecastScaleFactor = ::Settings::navigator().mRecastScaleFactor; + result.mSwimHeightScale = 0; + result.mMaxEdgeLen = ::Settings::navigator().mMaxEdgeLen; + result.mMaxVertsPerPoly = ::Settings::navigator().mMaxVertsPerPoly; + result.mRegionMergeArea = ::Settings::navigator().mRegionMergeArea; + result.mRegionMinArea = ::Settings::navigator().mRegionMinArea; + result.mTileSize = ::Settings::navigator().mTileSize; + + return result; + } + + DetourSettings makeDetourSettingsFromSettingsManager() + { + DetourSettings result; + + result.mMaxNavMeshQueryNodes = ::Settings::navigator().mMaxNavMeshQueryNodes; + result.mMaxPolys = ::Settings::navigator().mMaxPolygonsPerTile; + result.mMaxPolygonPathSize = ::Settings::navigator().mMaxPolygonPathSize; + result.mMaxSmoothPathSize = ::Settings::navigator().mMaxSmoothPathSize; + + return result; + } } Settings makeSettingsFromSettingsManager() @@ -46,7 +86,12 @@ namespace DetourNavigator result.mRecast = makeRecastSettingsFromSettingsManager(); result.mDetour = makeDetourSettingsFromSettingsManager(); - result.mMaxTilesNumber = ::Settings::navigator().mMaxTilesNumber; + + const NavMeshLimits limits = getNavMeshTileLimits(result.mDetour); + + result.mDetour.mMaxPolys = limits.mMaxPolys; + + result.mMaxTilesNumber = std::min(limits.mMaxTiles, ::Settings::navigator().mMaxTilesNumber.get()); result.mWaitUntilMinDistanceToPlayer = ::Settings::navigator().mWaitUntilMinDistanceToPlayer; result.mAsyncNavMeshUpdaterThreads = ::Settings::navigator().mAsyncNavMeshUpdaterThreads; result.mMaxNavMeshTilesCacheSize = ::Settings::navigator().mMaxNavMeshTilesCacheSize; diff --git a/components/detournavigator/settings.hpp b/components/detournavigator/settings.hpp index 45bcf15dbf..1d1f6f5847 100644 --- a/components/detournavigator/settings.hpp +++ b/components/detournavigator/settings.hpp @@ -55,10 +55,6 @@ namespace DetourNavigator inline constexpr std::int64_t navMeshFormatVersion = 2; - RecastSettings makeRecastSettingsFromSettingsManager(); - - DetourSettings makeDetourSettingsFromSettingsManager(); - Settings makeSettingsFromSettingsManager(); } diff --git a/components/detournavigator/stats.cpp b/components/detournavigator/stats.cpp index 1d7dcac553..da56f91a38 100644 --- a/components/detournavigator/stats.cpp +++ b/components/detournavigator/stats.cpp @@ -9,16 +9,18 @@ namespace DetourNavigator void reportStats(const AsyncNavMeshUpdaterStats& stats, unsigned int frameNumber, osg::Stats& out) { out.setAttribute(frameNumber, "NavMesh Jobs", static_cast(stats.mJobs)); - out.setAttribute(frameNumber, "NavMesh Waiting", static_cast(stats.mWaiting)); + out.setAttribute(frameNumber, "NavMesh Removing", static_cast(stats.mWaiting.mRemoving)); + out.setAttribute(frameNumber, "NavMesh Updating", static_cast(stats.mWaiting.mUpdating)); + out.setAttribute(frameNumber, "NavMesh Delayed", static_cast(stats.mWaiting.mDelayed)); out.setAttribute(frameNumber, "NavMesh Pushed", static_cast(stats.mPushed)); out.setAttribute(frameNumber, "NavMesh Processing", static_cast(stats.mProcessing)); if (stats.mDb.has_value()) { - out.setAttribute( - frameNumber, "NavMesh DbJobs Write", static_cast(stats.mDb->mJobs.mWritingJobs)); out.setAttribute( frameNumber, "NavMesh DbJobs Read", static_cast(stats.mDb->mJobs.mReadingJobs)); + out.setAttribute( + frameNumber, "NavMesh DbJobs Write", static_cast(stats.mDb->mJobs.mWritingJobs)); out.setAttribute(frameNumber, "NavMesh DbCache Get", static_cast(stats.mDb->mGetTileCount)); out.setAttribute(frameNumber, "NavMesh DbCache Hit", static_cast(stats.mDbGetTileHits)); diff --git a/components/detournavigator/stats.hpp b/components/detournavigator/stats.hpp index c644f1db87..0b62b9e669 100644 --- a/components/detournavigator/stats.hpp +++ b/components/detournavigator/stats.hpp @@ -11,10 +11,17 @@ namespace osg namespace DetourNavigator { + struct JobQueueStats + { + std::size_t mRemoving = 0; + std::size_t mUpdating = 0; + std::size_t mDelayed = 0; + }; + struct DbJobQueueStats { - std::size_t mWritingJobs = 0; std::size_t mReadingJobs = 0; + std::size_t mWritingJobs = 0; }; struct DbWorkerStats @@ -35,7 +42,7 @@ namespace DetourNavigator struct AsyncNavMeshUpdaterStats { std::size_t mJobs = 0; - std::size_t mWaiting = 0; + JobQueueStats mWaiting; std::size_t mPushed = 0; std::size_t mProcessing = 0; std::size_t mDbGetTileHits = 0; diff --git a/components/detournavigator/tilecachedrecastmeshmanager.cpp b/components/detournavigator/tilecachedrecastmeshmanager.cpp index 0bab808300..3e3927bf65 100644 --- a/components/detournavigator/tilecachedrecastmeshmanager.cpp +++ b/components/detournavigator/tilecachedrecastmeshmanager.cpp @@ -10,7 +10,6 @@ #include -#include #include #include @@ -416,7 +415,7 @@ namespace DetourNavigator if (tile == mChangedTiles.end()) mChangedTiles.emplace(tilePosition, changeType); else - tile->second = addChangeType(tile->second, changeType); + tile->second = changeType == ChangeType::remove ? changeType : tile->second; } std::map TileCachedRecastMeshManager::takeChangedTiles(const UpdateGuard* guard) diff --git a/components/esm3/dialoguecondition.cpp b/components/esm3/dialoguecondition.cpp new file mode 100644 index 0000000000..a6a28307c2 --- /dev/null +++ b/components/esm3/dialoguecondition.cpp @@ -0,0 +1,206 @@ +#include "dialoguecondition.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" +#include "variant.hpp" + +#include +#include +#include + +namespace ESM +{ + std::optional DialogueCondition::load(ESMReader& esm, ESM::RefId context) + { + std::string rule = esm.getHString(); + ESM::Variant variant; + variant.read(esm, Variant::Format_Info); + if (rule.size() < 5) + { + Log(Debug::Warning) << "Found invalid SCVR rule of size " << rule.size() << " in INFO " << context; + return {}; + } + if (rule[4] < '0' || rule[4] > '5') + { + Log(Debug::Warning) << "Found invalid SCVR comparison operator " << static_cast(rule[4]) << " in INFO " + << context; + return {}; + } + DialogueCondition condition; + if (rule[0] >= '0' && rule[0] <= '9') + condition.mIndex = rule[0] - '0'; + else + { + Log(Debug::Info) << "Found invalid SCVR index " << static_cast(rule[0]) << " in INFO " << context; + condition.mIndex = 0; + } + if (rule[1] == '1') + { + int function = Misc::StringUtils::toNumeric(std::string_view{ rule }.substr(2, 2), -1); + if (function >= Function_FacReactionLowest && function <= Function_PcWerewolfKills) + condition.mFunction = static_cast(function); + else + { + Log(Debug::Warning) << "Encountered invalid SCVR function index " << function << " in INFO " << context; + return {}; + } + } + else if ((rule[1] > '1' && rule[1] <= '9') || (rule[1] >= 'A' && rule[1] <= 'C')) + { + if (rule.size() == 5) + { + Log(Debug::Warning) << "Missing variable for SCVR of type " << rule[1] << " in INFO " << context; + return {}; + } + bool malformed = rule[3] != 'X'; + if (rule[1] == '2') + { + condition.mFunction = Function_Global; + malformed |= rule[2] != 'f' && rule[2] != 'l' && rule[2] != 's'; + } + else if (rule[1] == '3') + { + condition.mFunction = Function_Local; + malformed |= rule[2] != 'f' && rule[2] != 'l' && rule[2] != 's'; + } + else if (rule[1] == '4') + { + condition.mFunction = Function_Journal; + malformed |= rule[2] != 'J'; + } + else if (rule[1] == '5') + { + condition.mFunction = Function_Item; + malformed |= rule[2] != 'I'; + } + else if (rule[1] == '6') + { + condition.mFunction = Function_Dead; + malformed |= rule[2] != 'D'; + } + else if (rule[1] == '7') + { + condition.mFunction = Function_NotId; + malformed |= rule[2] != 'X'; + } + else if (rule[1] == '8') + { + condition.mFunction = Function_NotFaction; + malformed |= rule[2] != 'F'; + } + else if (rule[1] == '9') + { + condition.mFunction = Function_NotClass; + malformed |= rule[2] != 'C'; + } + else if (rule[1] == 'A') + { + condition.mFunction = Function_NotRace; + malformed |= rule[2] != 'R'; + } + else if (rule[1] == 'B') + { + condition.mFunction = Function_NotCell; + malformed |= rule[2] != 'L'; + } + else if (rule[1] == 'C') + { + condition.mFunction = Function_NotLocal; + malformed |= rule[2] != 'f' && rule[2] != 'l' && rule[2] != 's'; + } + if (malformed) + Log(Debug::Info) << "Found malformed SCVR rule in INFO " << context; + } + else + { + Log(Debug::Warning) << "Found invalid SCVR function " << static_cast(rule[1]) << " in INFO " + << context; + return {}; + } + condition.mComparison = static_cast(rule[4]); + condition.mVariable = rule.substr(5); + if (variant.getType() == VT_Int) + condition.mValue = variant.getInteger(); + else if (variant.getType() == VT_Float) + condition.mValue = variant.getFloat(); + else + { + Log(Debug::Warning) << "Found invalid SCVR variant " << variant.getType() << " in INFO " << context; + return {}; + } + return condition; + } + + void DialogueCondition::save(ESMWriter& esm) const + { + auto variant = std::visit([](auto value) { return ESM::Variant(value); }, mValue); + if (variant.getType() != VT_Float) + variant.setType(VT_Int); + std::string rule; + rule.reserve(5 + mVariable.size()); + rule += static_cast(mIndex + '0'); + const auto appendVariableType = [&]() { + if (variant.getType() == VT_Float) + rule += "fX"; + else + { + int32_t value = variant.getInteger(); + if (static_cast(value) == value) + rule += "sX"; + else + rule += "lX"; + } + }; + if (mFunction == Function_Global) + { + rule += '2'; + appendVariableType(); + } + else if (mFunction == Function_Local) + { + rule += '3'; + appendVariableType(); + } + else if (mFunction == Function_Journal) + rule += "4JX"; + else if (mFunction == Function_Item) + rule += "5IX"; + else if (mFunction == Function_Dead) + rule += "6DX"; + else if (mFunction == Function_NotId) + rule += "7XX"; + else if (mFunction == Function_NotFaction) + rule += "8FX"; + else if (mFunction == Function_NotClass) + rule += "9CX"; + else if (mFunction == Function_NotRace) + rule += "ARX"; + else if (mFunction == Function_NotCell) + rule += "BLX"; + else if (mFunction == Function_NotLocal) + { + rule += 'C'; + appendVariableType(); + } + else + { + rule += "100"; + char* start = rule.data() + rule.size(); + char* end = start; + if (mFunction < Function_PcStrength) + start--; + else + start -= 2; + auto result = std::to_chars(start, end, static_cast(mFunction)); + if (result.ec != std::errc()) + { + Log(Debug::Error) << "Failed to save SCVR rule"; + return; + } + } + rule += static_cast(mComparison); + rule += mVariable; + esm.writeHNString("SCVR", rule); + variant.write(esm, Variant::Format_Info); + } +} diff --git a/components/esm3/dialoguecondition.hpp b/components/esm3/dialoguecondition.hpp new file mode 100644 index 0000000000..c06d50b601 --- /dev/null +++ b/components/esm3/dialoguecondition.hpp @@ -0,0 +1,134 @@ +#ifndef OPENMW_ESM3_DIALOGUECONDITION_H +#define OPENMW_ESM3_DIALOGUECONDITION_H + +#include +#include +#include +#include + +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + struct DialogueCondition + { + enum Function : std::int8_t + { + Function_FacReactionLowest = 0, + Function_FacReactionHighest, + Function_RankRequirement, + Function_Reputation, + Function_Health_Percent, + Function_PcReputation, + Function_PcLevel, + Function_PcHealthPercent, + Function_PcMagicka, + Function_PcFatigue, + Function_PcStrength, + Function_PcBlock, + Function_PcArmorer, + Function_PcMediumArmor, + Function_PcHeavyArmor, + Function_PcBluntWeapon, + Function_PcLongBlade, + Function_PcAxe, + Function_PcSpear, + Function_PcAthletics, + Function_PcEnchant, + Function_PcDestruction, + Function_PcAlteration, + Function_PcIllusion, + Function_PcConjuration, + Function_PcMysticism, + Function_PcRestoration, + Function_PcAlchemy, + Function_PcUnarmored, + Function_PcSecurity, + Function_PcSneak, + Function_PcAcrobatics, + Function_PcLightArmor, + Function_PcShortBlade, + Function_PcMarksman, + Function_PcMerchantile, + Function_PcSpeechcraft, + Function_PcHandToHand, + Function_PcGender, + Function_PcExpelled, + Function_PcCommonDisease, + Function_PcBlightDisease, + Function_PcClothingModifier, + Function_PcCrimeLevel, + Function_SameSex, + Function_SameRace, + Function_SameFaction, + Function_FactionRankDifference, + Function_Detected, + Function_Alarmed, + Function_Choice, + Function_PcIntelligence, + Function_PcWillpower, + Function_PcAgility, + Function_PcSpeed, + Function_PcEndurance, + Function_PcPersonality, + Function_PcLuck, + Function_PcCorprus, + Function_Weather, + Function_PcVampire, + Function_Level, + Function_Attacked, + Function_TalkedToPc, + Function_PcHealth, + Function_CreatureTarget, + Function_FriendHit, + Function_Fight, + Function_Hello, + Function_Alarm, + Function_Flee, + Function_ShouldAttack, + Function_Werewolf, + Function_PcWerewolfKills = 73, + + Function_Global, + Function_Local, + Function_Journal, + Function_Item, + Function_Dead, + Function_NotId, + Function_NotFaction, + Function_NotClass, + Function_NotRace, + Function_NotCell, + Function_NotLocal, + + Function_None, // Editor only + }; + + enum Comparison : char + { + Comp_Eq = '0', + Comp_Ne = '1', + Comp_Gt = '2', + Comp_Ge = '3', + Comp_Ls = '4', + Comp_Le = '5', + + Comp_None = ' ', // Editor only + }; + + std::string mVariable; + std::variant mValue = 0; + std::uint8_t mIndex = 0; + Function mFunction = Function_None; + Comparison mComparison = Comp_None; + + static std::optional load(ESMReader& esm, ESM::RefId context); + + void save(ESMWriter& esm) const; + }; +} + +#endif diff --git a/components/esm3/loadinfo.cpp b/components/esm3/loadinfo.cpp index 714d59fef4..8b1147ed45 100644 --- a/components/esm3/loadinfo.cpp +++ b/components/esm3/loadinfo.cpp @@ -66,10 +66,9 @@ namespace ESM break; case fourCC("SCVR"): { - SelectStruct ss; - ss.mSelectRule = esm.getHString(); - ss.mValue.read(esm, Variant::Format_Info); - mSelects.push_back(ss); + auto filter = DialogueCondition::load(esm, mId); + if (filter) + mSelects.emplace_back(std::move(*filter)); break; } case fourCC("BNAM"): @@ -120,11 +119,8 @@ namespace ESM esm.writeHNOCString("SNAM", mSound); esm.writeHNOString("NAME", mResponse); - for (std::vector::const_iterator it = mSelects.begin(); it != mSelects.end(); ++it) - { - esm.writeHNString("SCVR", it->mSelectRule); - it->mValue.write(esm, Variant::Format_Info); - } + for (const auto& rule : mSelects) + rule.save(esm); esm.writeHNOString("BNAM", mResultScript); diff --git a/components/esm3/loadinfo.hpp b/components/esm3/loadinfo.hpp index c2756e8d9c..a3fb4abffa 100644 --- a/components/esm3/loadinfo.hpp +++ b/components/esm3/loadinfo.hpp @@ -4,8 +4,10 @@ #include #include -#include "components/esm/defs.hpp" -#include "components/esm/refid.hpp" +#include +#include + +#include "dialoguecondition.hpp" #include "variant.hpp" namespace ESM @@ -47,13 +49,6 @@ namespace ESM }; // 12 bytes DATAstruct mData; - // The rules for whether or not we will select this dialog item. - struct SelectStruct - { - std::string mSelectRule; // This has a complicated format - Variant mValue; - }; - // Journal quest indices (introduced with the quest system in Tribunal) enum QuestStatus { @@ -65,7 +60,7 @@ namespace ESM // Rules for when to include this item in the final list of options // visible to the player. - std::vector mSelects; + std::vector mSelects; // Id of this, previous and next INFO items RefId mId, mPrev, mNext; diff --git a/components/resource/imagemanager.cpp b/components/resource/imagemanager.cpp index a7d2ef61a1..e7cc9f03e5 100644 --- a/components/resource/imagemanager.cpp +++ b/components/resource/imagemanager.cpp @@ -78,8 +78,7 @@ namespace Resource } break; } - // not bothering with checks for other compression formats right now, we are unlikely to ever use those - // anyway + // not bothering with checks for other compression formats right now default: return true; } diff --git a/components/resource/stats.cpp b/components/resource/stats.cpp index 65b009deff..9bb90635d1 100644 --- a/components/resource/stats.cpp +++ b/components/resource/stats.cpp @@ -49,6 +49,8 @@ namespace Resource std::vector generateAllStatNames() { + constexpr std::size_t itemsPerPage = 24; + constexpr std::string_view firstPage[] = { "FrameNumber", "", @@ -76,6 +78,8 @@ namespace Resource "", }; + static_assert(std::size(firstPage) == itemsPerPage); + constexpr std::string_view caches[] = { "Node", "Shape", @@ -100,7 +104,9 @@ namespace Resource constexpr std::string_view navMesh[] = { "NavMesh Jobs", - "NavMesh Waiting", + "NavMesh Removing", + "NavMesh Updating", + "NavMesh Delayed", "NavMesh Pushed", "NavMesh Processing", "NavMesh DbJobs Write", @@ -129,7 +135,8 @@ namespace Resource for (std::string_view name : cellPreloader) statNames.emplace_back(name); - statNames.emplace_back(); + while (statNames.size() % itemsPerPage != 0) + statNames.emplace_back(); for (std::string_view name : navMesh) statNames.emplace_back(name); diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp index ab600de11d..21a753df12 100644 --- a/components/sceneutil/util.cpp +++ b/components/sceneutil/util.cpp @@ -286,4 +286,125 @@ namespace SceneUtil mOperationQueue->add(operation); } + GLenum computeUnsizedPixelFormat(GLenum format) + { + switch (format) + { + // Try compressed formats first, they're more likely to be used + + // Generic + case GL_COMPRESSED_ALPHA_ARB: + return GL_ALPHA; + case GL_COMPRESSED_INTENSITY_ARB: + return GL_INTENSITY; + case GL_COMPRESSED_LUMINANCE_ALPHA_ARB: + return GL_LUMINANCE_ALPHA; + case GL_COMPRESSED_LUMINANCE_ARB: + return GL_LUMINANCE; + case GL_COMPRESSED_RGB_ARB: + return GL_RGB; + case GL_COMPRESSED_RGBA_ARB: + return GL_RGBA; + + // S3TC + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + return GL_RGB; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + return GL_RGBA; + + // RGTC + case GL_COMPRESSED_RED_RGTC1_EXT: + case GL_COMPRESSED_SIGNED_RED_RGTC1_EXT: + return GL_RED; + case GL_COMPRESSED_RED_GREEN_RGTC2_EXT: + case GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: + return GL_RG; + + // PVRTC + case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: + case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: + return GL_RGB; + case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: + case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: + return GL_RGBA; + + // ETC + case GL_COMPRESSED_R11_EAC: + case GL_COMPRESSED_SIGNED_R11_EAC: + return GL_RED; + case GL_COMPRESSED_RG11_EAC: + case GL_COMPRESSED_SIGNED_RG11_EAC: + return GL_RG; + case GL_ETC1_RGB8_OES: + case GL_COMPRESSED_RGB8_ETC2: + case GL_COMPRESSED_SRGB8_ETC2: + return GL_RGB; + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: + case GL_COMPRESSED_RGBA8_ETC2_EAC: + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: + return GL_RGBA; + + // ASTC + case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: + case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: + case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: + case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: + case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: + case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: + case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: + case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: + case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: + case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: + case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: + case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: + case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: + case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: + return GL_RGBA; + + // Plug in some holes computePixelFormat has, you never know when these could come in handy + case GL_INTENSITY4: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + return GL_INTENSITY; + + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + return GL_LUMINANCE; + + case GL_LUMINANCE4_ALPHA4: + case GL_LUMINANCE6_ALPHA2: + case GL_LUMINANCE8_ALPHA8: + case GL_LUMINANCE12_ALPHA4: + case GL_LUMINANCE12_ALPHA12: + case GL_LUMINANCE16_ALPHA16: + return GL_LUMINANCE_ALPHA; + } + + return osg::Image::computePixelFormat(format); + } + } diff --git a/components/sceneutil/util.hpp b/components/sceneutil/util.hpp index 29fee09176..b76f46a688 100644 --- a/components/sceneutil/util.hpp +++ b/components/sceneutil/util.hpp @@ -112,6 +112,10 @@ namespace SceneUtil protected: osg::ref_ptr mOperationQueue; }; + + // Compute the unsized format equivalent to the given pixel format + // Unlike osg::Image::computePixelFormat, this also covers compressed formats + GLenum computeUnsizedPixelFormat(GLenum format); } #endif diff --git a/components/settings/categories/navigator.hpp b/components/settings/categories/navigator.hpp index d6d7adcd56..c65dd3392e 100644 --- a/components/settings/categories/navigator.hpp +++ b/components/settings/categories/navigator.hpp @@ -63,6 +63,7 @@ namespace Settings SettingValue mEnableNavMeshDiskCache{ mIndex, "Navigator", "enable nav mesh disk cache" }; SettingValue mWriteToNavmeshdb{ mIndex, "Navigator", "write to navmeshdb" }; SettingValue mMaxNavmeshdbFileSize{ mIndex, "Navigator", "max navmeshdb file size" }; + SettingValue mWaitForAllJobsOnExit{ mIndex, "Navigator", "wait for all jobs on exit" }; }; } diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 7bce9de2a6..2676ea3168 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -184,6 +185,7 @@ namespace Shader , mAdditiveBlending(false) , mDiffuseHeight(false) , mNormalHeight(false) + , mReconstructNormalZ(false) , mTexStageRequiringTangents(-1) , mSoftParticles(false) , mNode(nullptr) @@ -429,6 +431,7 @@ namespace Shader normalMapTex->setFilter(osg::Texture::MAG_FILTER, diffuseMap->getFilter(osg::Texture::MAG_FILTER)); normalMapTex->setMaxAnisotropy(diffuseMap->getMaxAnisotropy()); normalMapTex->setName("normalMap"); + normalMap = normalMapTex; int unit = texAttributes.size(); if (!writableStateSet) @@ -440,6 +443,21 @@ namespace Shader mRequirements.back().mNormalHeight = normalHeight; } } + + if (normalMap != nullptr && normalMap->getImage(0)) + { + // Special handling for red-green normal maps (e.g. BC5 or R8G8) + switch (SceneUtil::computeUnsizedPixelFormat(normalMap->getImage(0)->getPixelFormat())) + { + case GL_RG: + case GL_RG_INTEGER: + { + mRequirements.back().mReconstructNormalZ = true; + mRequirements.back().mNormalHeight = false; + } + } + } + if (mAutoUseSpecularMaps && diffuseMap != nullptr && specularMap == nullptr && diffuseMap->getImage(0)) { std::string specularMapFileName = diffuseMap->getImage(0)->getFileName(); @@ -629,6 +647,7 @@ namespace Shader defineMap["diffuseParallax"] = reqs.mDiffuseHeight ? "1" : "0"; defineMap["parallax"] = reqs.mNormalHeight ? "1" : "0"; + defineMap["reconstructNormalZ"] = reqs.mReconstructNormalZ ? "1" : "0"; writableStateSet->addUniform(new osg::Uniform("colorMode", reqs.mColorMode)); addedState->addUniform("colorMode"); diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index a8e79ec995..9ce0819bd3 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -110,6 +110,7 @@ namespace Shader bool mDiffuseHeight; // true if diffuse map has height info in alpha channel bool mNormalHeight; // true if normal map has height info in alpha channel + bool mReconstructNormalZ; // used for red-green normal maps (e.g. BC5) // -1 == no tangents required int mTexStageRequiringTangents; diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index fafe2dcb58..09d2680acd 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -271,18 +272,37 @@ namespace Terrain stateset->addUniform(UniformCollection::value().mBlendMap); } + bool parallax = it->mNormalMap && it->mParallax; + bool reconstructNormalZ = false; + if (it->mNormalMap) { stateset->setTextureAttributeAndModes(2, it->mNormalMap); stateset->addUniform(UniformCollection::value().mNormalMap); + + // Special handling for red-green normal maps (e.g. BC5 or R8G8). + const osg::Image* image = it->mNormalMap->getImage(0); + if (image) + { + switch (SceneUtil::computeUnsizedPixelFormat(image->getPixelFormat())) + { + case GL_RG: + case GL_RG_INTEGER: + { + reconstructNormalZ = true; + parallax = false; + } + } + } } Shader::ShaderManager::DefineMap defineMap; defineMap["normalMap"] = (it->mNormalMap) ? "1" : "0"; defineMap["blendMap"] = (!blendmaps.empty()) ? "1" : "0"; defineMap["specularMap"] = it->mSpecular ? "1" : "0"; - defineMap["parallax"] = (it->mNormalMap && it->mParallax) ? "1" : "0"; + defineMap["parallax"] = parallax ? "1" : "0"; defineMap["writeNormals"] = (it == layers.end() - 1) ? "1" : "0"; + defineMap["reconstructNormalZ"] = reconstructNormalZ ? "1" : "0"; Stereo::shaderStereoDefines(defineMap); stateset->setAttributeAndModes(shaderManager.getProgram("terrain", defineMap)); diff --git a/docs/source/reference/modding/settings/navigator.rst b/docs/source/reference/modding/settings/navigator.rst index 55b9e19b19..6fafdcdfd2 100644 --- a/docs/source/reference/modding/settings/navigator.rst +++ b/docs/source/reference/modding/settings/navigator.rst @@ -245,6 +245,16 @@ Absent pieces usually mean a bug in recast mesh tiles building. Allows to do in-game debug. Potentially decreases performance. +wait for all jobs on exit +------------------------- + +:Type: boolean +:Range: True/False +:Default: False + +Wait until all queued async navmesh jobs are processed before exiting the engine. +Useful when a benchmark generates jobs to write into navmeshdb faster than they are processed. + Expert settings *************** diff --git a/docs/source/reference/modding/texture-modding/texture-basics.rst b/docs/source/reference/modding/texture-modding/texture-basics.rst index 78ae007704..8bbf018fba 100644 --- a/docs/source/reference/modding/texture-modding/texture-basics.rst +++ b/docs/source/reference/modding/texture-modding/texture-basics.rst @@ -25,6 +25,19 @@ Content creators need to know that OpenMW uses the DX format for normal maps, an See the section `Automatic use`_ further down below for detailed information. +The RGB channels of the normal map are used to store XYZ components of tangent space normals and the alpha channel of the normal map may be used to store a height map used for parallax. + +This is different from the setup used in Bethesda games that use the traditional pipeline, which may store specular information in the alpha channel. + +Special pixel formats that only store two color channels exist and are used by Bethesda games that employ a PBR-based pipeline. Compressed red-green formats are optimized for use with normal maps and suffer from far less quality degradation than S3TC-compressed normal maps of equivalent size. + +OpenMW supports the use of such pixel formats. When a red-green normal map is provided, the Z component of the normal will be reconstructed based on XY components it stores. +Naturally, since these formats cannot provide an alpha channel, they do not support parallax. + +Keep in mind, however, that while the necessary hardware support is widespread for compressed red-green formats, it is less ubiquitous than the support for S3TC family of compressed formats. +Should you run into the consequences of this, you might want to convert such textures into an uncompressed red-green format such as R8G8. +Be careful not to try and convert such textures into a full-color format as the previously non-existent blue channel would then be used. + Specular Mapping ################ diff --git a/files/data/l10n/Calendar/sv.yaml b/files/data/l10n/Calendar/sv.yaml new file mode 100644 index 0000000000..858e586412 --- /dev/null +++ b/files/data/l10n/Calendar/sv.yaml @@ -0,0 +1,50 @@ +# Swedish does not actually upper-case first letter on months and weekday names, so I'm doing them lower case right now. + +month1: "januari" +month2: "februari" +month3: "mars" +month4: "april" +month5: "maj" +month6: "juni" +month7: "juli" +month8: "augusti" +month9: "september" +month10: "oktober" +month11: "november" +month12: "december" + +# There are no different grammatical forms of the months in Swedish + +monthInGenitive1: "januari" +monthInGenitive2: "februari" +monthInGenitive3: "mars" +monthInGenitive4: "april" +monthInGenitive5: "maj" +monthInGenitive6: "juni" +monthInGenitive7: "juli" +monthInGenitive8: "augusti" +monthInGenitive9: "september" +monthInGenitive10: "oktober" +monthInGenitive11: "november" +monthInGenitive12: "december" + +# Standard Swedish date format: d MMMM YYYY +# Source: http://www4.sprakochfolkminnen.se/cgi-bin/srfl/visasvar.py?sok=datum&svar=26089 +# Example: "23 februari 1337" +dateFormat: "{day} {month} {year, number, :: group-off}" + +# The Swedish week starts with monday actually, but whatever. + +weekday1: "söndag" +weekday2: "mÃ¥ndag" +weekday3: "tisdag" +weekday4: "onsdag" +weekday5: "torsdag" +weekday6: "fredag" +weekday7: "lördag" + +# In Swedish, as with German, we don't use AM/PM but instead a 24h clock. +# But instead of that, we could use "förmiddag" and "eftermiddag", which is basically "morning" and "afternoon" +am: "förmiddag" +pm: "eftermiddag" +day: "dag" diff --git a/files/opencs/activator.png b/files/opencs/activator.png deleted file mode 100644 index ded6ab835b..0000000000 Binary files a/files/opencs/activator.png and /dev/null differ diff --git a/files/opencs/activator.svg b/files/opencs/activator.svg new file mode 100644 index 0000000000..11a23003da --- /dev/null +++ b/files/opencs/activator.svg @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/apparatus.png b/files/opencs/apparatus.png deleted file mode 100644 index 4e95397dfa..0000000000 Binary files a/files/opencs/apparatus.png and /dev/null differ diff --git a/files/opencs/apparatus.svg b/files/opencs/apparatus.svg new file mode 100644 index 0000000000..1345efee56 --- /dev/null +++ b/files/opencs/apparatus.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + diff --git a/files/opencs/armor.png b/files/opencs/armor.png deleted file mode 100644 index 6f5cc83c59..0000000000 Binary files a/files/opencs/armor.png and /dev/null differ diff --git a/files/opencs/armor.svg b/files/opencs/armor.svg new file mode 100644 index 0000000000..e7925a23bc --- /dev/null +++ b/files/opencs/armor.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + diff --git a/files/opencs/attribute.png b/files/opencs/attribute.png deleted file mode 100644 index c124567179..0000000000 Binary files a/files/opencs/attribute.png and /dev/null differ diff --git a/files/opencs/attribute.svg b/files/opencs/attribute.svg new file mode 100644 index 0000000000..5e02090f07 --- /dev/null +++ b/files/opencs/attribute.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + diff --git a/files/opencs/birthsign.png b/files/opencs/birthsign.png deleted file mode 100644 index 861dbd4d10..0000000000 Binary files a/files/opencs/birthsign.png and /dev/null differ diff --git a/files/opencs/birthsign.svg b/files/opencs/birthsign.svg new file mode 100644 index 0000000000..c9316ed9d6 --- /dev/null +++ b/files/opencs/birthsign.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/body-part.png b/files/opencs/body-part.png deleted file mode 100644 index 8baec72024..0000000000 Binary files a/files/opencs/body-part.png and /dev/null differ diff --git a/files/opencs/body-part.svg b/files/opencs/body-part.svg new file mode 100644 index 0000000000..60c06defc8 --- /dev/null +++ b/files/opencs/body-part.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + diff --git a/files/opencs/book.png b/files/opencs/book.png deleted file mode 100644 index fdecb1585a..0000000000 Binary files a/files/opencs/book.png and /dev/null differ diff --git a/files/opencs/book.svg b/files/opencs/book.svg new file mode 100644 index 0000000000..b34827d7b1 --- /dev/null +++ b/files/opencs/book.svg @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/brush-circle.png b/files/opencs/brush-circle.png deleted file mode 100644 index 22e92c1c7f..0000000000 Binary files a/files/opencs/brush-circle.png and /dev/null differ diff --git a/files/opencs/brush-circle.svg b/files/opencs/brush-circle.svg new file mode 100644 index 0000000000..8bb2491173 --- /dev/null +++ b/files/opencs/brush-circle.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/brush-custom.png b/files/opencs/brush-custom.png deleted file mode 100644 index 58c0485502..0000000000 Binary files a/files/opencs/brush-custom.png and /dev/null differ diff --git a/files/opencs/brush-custom.svg b/files/opencs/brush-custom.svg new file mode 100644 index 0000000000..9eb59597cc --- /dev/null +++ b/files/opencs/brush-custom.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/brush-point.png b/files/opencs/brush-point.png deleted file mode 100644 index 19b2354f8c..0000000000 Binary files a/files/opencs/brush-point.png and /dev/null differ diff --git a/files/opencs/brush-point.svg b/files/opencs/brush-point.svg new file mode 100644 index 0000000000..384ed0af4a --- /dev/null +++ b/files/opencs/brush-point.svg @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/brush-square.png b/files/opencs/brush-square.png deleted file mode 100644 index 08628772e7..0000000000 Binary files a/files/opencs/brush-square.png and /dev/null differ diff --git a/files/opencs/brush-square.svg b/files/opencs/brush-square.svg new file mode 100644 index 0000000000..09fdcb3e16 --- /dev/null +++ b/files/opencs/brush-square.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/camera-first-person.png b/files/opencs/camera-first-person.png deleted file mode 100644 index b497198df5..0000000000 Binary files a/files/opencs/camera-first-person.png and /dev/null differ diff --git a/files/opencs/camera-first-person.svg b/files/opencs/camera-first-person.svg new file mode 100644 index 0000000000..d56c6b5afb --- /dev/null +++ b/files/opencs/camera-first-person.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/camera-free.png b/files/opencs/camera-free.png deleted file mode 100644 index d8e7ccae5d..0000000000 Binary files a/files/opencs/camera-free.png and /dev/null differ diff --git a/files/opencs/camera-free.svg b/files/opencs/camera-free.svg new file mode 100644 index 0000000000..ee1ed5afa0 --- /dev/null +++ b/files/opencs/camera-free.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/camera-orbit.png b/files/opencs/camera-orbit.png deleted file mode 100644 index 1aedf28479..0000000000 Binary files a/files/opencs/camera-orbit.png and /dev/null differ diff --git a/files/opencs/camera-orbit.svg b/files/opencs/camera-orbit.svg new file mode 100644 index 0000000000..904463b9b8 --- /dev/null +++ b/files/opencs/camera-orbit.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/cell.png b/files/opencs/cell.png deleted file mode 100644 index 4c3fbe2515..0000000000 Binary files a/files/opencs/cell.png and /dev/null differ diff --git a/files/opencs/cell.svg b/files/opencs/cell.svg new file mode 100644 index 0000000000..9348165dc9 --- /dev/null +++ b/files/opencs/cell.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/class.png b/files/opencs/class.png deleted file mode 100644 index 272f2630c7..0000000000 Binary files a/files/opencs/class.png and /dev/null differ diff --git a/files/opencs/class.svg b/files/opencs/class.svg new file mode 100644 index 0000000000..c9d5e7c5f5 --- /dev/null +++ b/files/opencs/class.svg @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/clothing.png b/files/opencs/clothing.png deleted file mode 100644 index e42988e749..0000000000 Binary files a/files/opencs/clothing.png and /dev/null differ diff --git a/files/opencs/clothing.svg b/files/opencs/clothing.svg new file mode 100644 index 0000000000..9b1ffb54b3 --- /dev/null +++ b/files/opencs/clothing.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/container.png b/files/opencs/container.png deleted file mode 100644 index 336a05dbfe..0000000000 Binary files a/files/opencs/container.png and /dev/null differ diff --git a/files/opencs/container.svg b/files/opencs/container.svg new file mode 100644 index 0000000000..91b417e9e3 --- /dev/null +++ b/files/opencs/container.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/creature.png b/files/opencs/creature.png deleted file mode 100644 index 003684dca0..0000000000 Binary files a/files/opencs/creature.png and /dev/null differ diff --git a/files/opencs/creature.svg b/files/opencs/creature.svg new file mode 100644 index 0000000000..e7fe8cf5a3 --- /dev/null +++ b/files/opencs/creature.svg @@ -0,0 +1,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/debug-profile.png b/files/opencs/debug-profile.png deleted file mode 100644 index ddb01da437..0000000000 Binary files a/files/opencs/debug-profile.png and /dev/null differ diff --git a/files/opencs/debug-profile.svg b/files/opencs/debug-profile.svg new file mode 100644 index 0000000000..28be0e4a16 --- /dev/null +++ b/files/opencs/debug-profile.svg @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/dialogue-greeting.png b/files/opencs/dialogue-greeting.png deleted file mode 100644 index de6b22b42c..0000000000 Binary files a/files/opencs/dialogue-greeting.png and /dev/null differ diff --git a/files/opencs/dialogue-info.png b/files/opencs/dialogue-info.png deleted file mode 100644 index 6242eddf4f..0000000000 Binary files a/files/opencs/dialogue-info.png and /dev/null differ diff --git a/files/opencs/dialogue-info.svg b/files/opencs/dialogue-info.svg new file mode 100644 index 0000000000..a0b4f4236e --- /dev/null +++ b/files/opencs/dialogue-info.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/dialogue-journal.png b/files/opencs/dialogue-journal.png deleted file mode 100644 index 086cb8a422..0000000000 Binary files a/files/opencs/dialogue-journal.png and /dev/null differ diff --git a/files/opencs/dialogue-persuasion.png b/files/opencs/dialogue-persuasion.png deleted file mode 100644 index 3138862c83..0000000000 Binary files a/files/opencs/dialogue-persuasion.png and /dev/null differ diff --git a/files/opencs/dialogue-regular.png b/files/opencs/dialogue-regular.png deleted file mode 100644 index 933afc5952..0000000000 Binary files a/files/opencs/dialogue-regular.png and /dev/null differ diff --git a/files/opencs/dialogue-topic-infos.png b/files/opencs/dialogue-topic-infos.png deleted file mode 100644 index 6242eddf4f..0000000000 Binary files a/files/opencs/dialogue-topic-infos.png and /dev/null differ diff --git a/files/opencs/dialogue-topics.png b/files/opencs/dialogue-topics.png deleted file mode 100644 index caa6d7e7cb..0000000000 Binary files a/files/opencs/dialogue-topics.png and /dev/null differ diff --git a/files/opencs/dialogue-topics.svg b/files/opencs/dialogue-topics.svg new file mode 100644 index 0000000000..57dd0b9444 --- /dev/null +++ b/files/opencs/dialogue-topics.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/dialogue-voice.png b/files/opencs/dialogue-voice.png deleted file mode 100644 index 1d67745e55..0000000000 Binary files a/files/opencs/dialogue-voice.png and /dev/null differ diff --git a/files/opencs/door.png b/files/opencs/door.png deleted file mode 100644 index a1a823ecdc..0000000000 Binary files a/files/opencs/door.png and /dev/null differ diff --git a/files/opencs/door.svg b/files/opencs/door.svg new file mode 100644 index 0000000000..846e5efb8e --- /dev/null +++ b/files/opencs/door.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/editing-instance.png b/files/opencs/editing-instance.png deleted file mode 100644 index 7349e8f66d..0000000000 Binary files a/files/opencs/editing-instance.png and /dev/null differ diff --git a/files/opencs/editing-instance.svg b/files/opencs/editing-instance.svg new file mode 100644 index 0000000000..92e20fade3 --- /dev/null +++ b/files/opencs/editing-instance.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/editing-pathgrid.png b/files/opencs/editing-pathgrid.png deleted file mode 100644 index 0ec024cadf..0000000000 Binary files a/files/opencs/editing-pathgrid.png and /dev/null differ diff --git a/files/opencs/editing-pathgrid.svg b/files/opencs/editing-pathgrid.svg new file mode 100644 index 0000000000..2fe9499553 --- /dev/null +++ b/files/opencs/editing-pathgrid.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/editing-terrain-movement.png b/files/opencs/editing-terrain-movement.png deleted file mode 100644 index 40777334bd..0000000000 Binary files a/files/opencs/editing-terrain-movement.png and /dev/null differ diff --git a/files/opencs/editing-terrain-movement.svg b/files/opencs/editing-terrain-movement.svg new file mode 100644 index 0000000000..6c1417fdd0 --- /dev/null +++ b/files/opencs/editing-terrain-movement.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + diff --git a/files/opencs/editing-terrain-shape.png b/files/opencs/editing-terrain-shape.png deleted file mode 100644 index a11bd95d54..0000000000 Binary files a/files/opencs/editing-terrain-shape.png and /dev/null differ diff --git a/files/opencs/editing-terrain-shape.svg b/files/opencs/editing-terrain-shape.svg new file mode 100644 index 0000000000..8f16b10dbf --- /dev/null +++ b/files/opencs/editing-terrain-shape.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + diff --git a/files/opencs/editing-terrain-texture.png b/files/opencs/editing-terrain-texture.png deleted file mode 100644 index 4a88353eea..0000000000 Binary files a/files/opencs/editing-terrain-texture.png and /dev/null differ diff --git a/files/opencs/editing-terrain-texture.svg b/files/opencs/editing-terrain-texture.svg new file mode 100644 index 0000000000..e0386d5061 --- /dev/null +++ b/files/opencs/editing-terrain-texture.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/editing-terrain-vertex-paint.png b/files/opencs/editing-terrain-vertex-paint.png deleted file mode 100644 index 2b3f0beac0..0000000000 Binary files a/files/opencs/editing-terrain-vertex-paint.png and /dev/null differ diff --git a/files/opencs/editing-terrain-vertex-paint.svg b/files/opencs/editing-terrain-vertex-paint.svg new file mode 100644 index 0000000000..7970597ea4 --- /dev/null +++ b/files/opencs/editing-terrain-vertex-paint.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/enchantment.png b/files/opencs/enchantment.png deleted file mode 100644 index 9bd54b8f0a..0000000000 Binary files a/files/opencs/enchantment.png and /dev/null differ diff --git a/files/opencs/enchantment.svg b/files/opencs/enchantment.svg new file mode 100644 index 0000000000..02849172f3 --- /dev/null +++ b/files/opencs/enchantment.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + diff --git a/files/opencs/error-log.png b/files/opencs/error-log.png deleted file mode 100644 index df698d1453..0000000000 Binary files a/files/opencs/error-log.png and /dev/null differ diff --git a/files/opencs/error-log.svg b/files/opencs/error-log.svg new file mode 100644 index 0000000000..1feb39dfe6 --- /dev/null +++ b/files/opencs/error-log.svg @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/faction.png b/files/opencs/faction.png deleted file mode 100644 index b58756bdc0..0000000000 Binary files a/files/opencs/faction.png and /dev/null differ diff --git a/files/opencs/faction.svg b/files/opencs/faction.svg new file mode 100644 index 0000000000..c0bba7f235 --- /dev/null +++ b/files/opencs/faction.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/filter.png b/files/opencs/filter.png deleted file mode 100644 index 55f442377c..0000000000 Binary files a/files/opencs/filter.png and /dev/null differ diff --git a/files/opencs/filter.svg b/files/opencs/filter.svg new file mode 100644 index 0000000000..12ae65d398 --- /dev/null +++ b/files/opencs/filter.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/global-variable.png b/files/opencs/global-variable.png deleted file mode 100644 index e1642ac355..0000000000 Binary files a/files/opencs/global-variable.png and /dev/null differ diff --git a/files/opencs/global-variable.svg b/files/opencs/global-variable.svg new file mode 100644 index 0000000000..00221d24c8 --- /dev/null +++ b/files/opencs/global-variable.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/gmst.png b/files/opencs/gmst.png deleted file mode 100644 index 2605fb4b96..0000000000 Binary files a/files/opencs/gmst.png and /dev/null differ diff --git a/files/opencs/gmst.svg b/files/opencs/gmst.svg new file mode 100644 index 0000000000..2d96e4cc39 --- /dev/null +++ b/files/opencs/gmst.svg @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/info.png b/files/opencs/info.png deleted file mode 100644 index d7bdad6cb1..0000000000 Binary files a/files/opencs/info.png and /dev/null differ diff --git a/files/opencs/info.svg b/files/opencs/info.svg new file mode 100644 index 0000000000..6594827943 --- /dev/null +++ b/files/opencs/info.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/ingredient.png b/files/opencs/ingredient.png deleted file mode 100644 index f31e6f5813..0000000000 Binary files a/files/opencs/ingredient.png and /dev/null differ diff --git a/files/opencs/ingredient.svg b/files/opencs/ingredient.svg new file mode 100644 index 0000000000..af2f736e64 --- /dev/null +++ b/files/opencs/ingredient.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/instance.png b/files/opencs/instance.png deleted file mode 100644 index ce63e64ed6..0000000000 Binary files a/files/opencs/instance.png and /dev/null differ diff --git a/files/opencs/instance.svg b/files/opencs/instance.svg new file mode 100644 index 0000000000..fe344c905d --- /dev/null +++ b/files/opencs/instance.svg @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/journal-topic-infos.png b/files/opencs/journal-topic-infos.png deleted file mode 100644 index 4cc4464897..0000000000 Binary files a/files/opencs/journal-topic-infos.png and /dev/null differ diff --git a/files/opencs/journal-topic-infos.svg b/files/opencs/journal-topic-infos.svg new file mode 100644 index 0000000000..4351d0668b --- /dev/null +++ b/files/opencs/journal-topic-infos.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/journal-topics.png b/files/opencs/journal-topics.png deleted file mode 100644 index d4e58a2885..0000000000 Binary files a/files/opencs/journal-topics.png and /dev/null differ diff --git a/files/opencs/journal-topics.svg b/files/opencs/journal-topics.svg new file mode 100644 index 0000000000..ecb78d869b --- /dev/null +++ b/files/opencs/journal-topics.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/land-heightmap.png b/files/opencs/land-heightmap.png deleted file mode 100644 index 5b460a0024..0000000000 Binary files a/files/opencs/land-heightmap.png and /dev/null differ diff --git a/files/opencs/land-heightmap.svg b/files/opencs/land-heightmap.svg new file mode 100644 index 0000000000..701b246640 --- /dev/null +++ b/files/opencs/land-heightmap.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/land-texture.png b/files/opencs/land-texture.png deleted file mode 100644 index a96c4bf8c7..0000000000 Binary files a/files/opencs/land-texture.png and /dev/null differ diff --git a/files/opencs/land-texture.svg b/files/opencs/land-texture.svg new file mode 100644 index 0000000000..3f9c7dfe1b --- /dev/null +++ b/files/opencs/land-texture.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/levelled-creature.png b/files/opencs/levelled-creature.png deleted file mode 100644 index e6cb1f54c7..0000000000 Binary files a/files/opencs/levelled-creature.png and /dev/null differ diff --git a/files/opencs/levelled-creature.svg b/files/opencs/levelled-creature.svg new file mode 100644 index 0000000000..7c996d23a9 --- /dev/null +++ b/files/opencs/levelled-creature.svg @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/levelled-item.png b/files/opencs/levelled-item.png deleted file mode 100644 index 3c819c56d0..0000000000 Binary files a/files/opencs/levelled-item.png and /dev/null differ diff --git a/files/opencs/levelled-item.svg b/files/opencs/levelled-item.svg new file mode 100644 index 0000000000..e81aaed75b --- /dev/null +++ b/files/opencs/levelled-item.svg @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/light.png b/files/opencs/light.png deleted file mode 100644 index 55d03bcd12..0000000000 Binary files a/files/opencs/light.png and /dev/null differ diff --git a/files/opencs/light.svg b/files/opencs/light.svg new file mode 100644 index 0000000000..35f0664f22 --- /dev/null +++ b/files/opencs/light.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/lighting-lamp.png b/files/opencs/lighting-lamp.png deleted file mode 100644 index c86517aa57..0000000000 Binary files a/files/opencs/lighting-lamp.png and /dev/null differ diff --git a/files/opencs/lighting-lamp.svg b/files/opencs/lighting-lamp.svg new file mode 100644 index 0000000000..5d34d68817 --- /dev/null +++ b/files/opencs/lighting-lamp.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + diff --git a/files/opencs/lighting-moon.png b/files/opencs/lighting-moon.png deleted file mode 100644 index 36a6e9b5b1..0000000000 Binary files a/files/opencs/lighting-moon.png and /dev/null differ diff --git a/files/opencs/lighting-moon.svg b/files/opencs/lighting-moon.svg new file mode 100644 index 0000000000..0441eb3bd5 --- /dev/null +++ b/files/opencs/lighting-moon.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + diff --git a/files/opencs/lighting-sun.png b/files/opencs/lighting-sun.png deleted file mode 100644 index a54d0ab124..0000000000 Binary files a/files/opencs/lighting-sun.png and /dev/null differ diff --git a/files/opencs/lighting-sun.svg b/files/opencs/lighting-sun.svg new file mode 100644 index 0000000000..2873a9f89c --- /dev/null +++ b/files/opencs/lighting-sun.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/list-added.png b/files/opencs/list-added.png deleted file mode 100644 index 4da2659839..0000000000 Binary files a/files/opencs/list-added.png and /dev/null differ diff --git a/files/opencs/list-added.svg b/files/opencs/list-added.svg new file mode 100644 index 0000000000..ecfa8595e5 --- /dev/null +++ b/files/opencs/list-added.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/list-base.png b/files/opencs/list-base.png deleted file mode 100644 index 336d4c59c1..0000000000 Binary files a/files/opencs/list-base.png and /dev/null differ diff --git a/files/opencs/list-base.svg b/files/opencs/list-base.svg new file mode 100644 index 0000000000..a050b15629 --- /dev/null +++ b/files/opencs/list-base.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/list-modified.png b/files/opencs/list-modified.png deleted file mode 100644 index 8b269a31d3..0000000000 Binary files a/files/opencs/list-modified.png and /dev/null differ diff --git a/files/opencs/list-modified.svg b/files/opencs/list-modified.svg new file mode 100644 index 0000000000..6efcab4cd4 --- /dev/null +++ b/files/opencs/list-modified.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/list-removed.png b/files/opencs/list-removed.png deleted file mode 100644 index 618a202bb9..0000000000 Binary files a/files/opencs/list-removed.png and /dev/null differ diff --git a/files/opencs/list-removed.svg b/files/opencs/list-removed.svg new file mode 100644 index 0000000000..157d4ab5e1 --- /dev/null +++ b/files/opencs/list-removed.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/lockpick.png b/files/opencs/lockpick.png deleted file mode 100644 index 7b1865f504..0000000000 Binary files a/files/opencs/lockpick.png and /dev/null differ diff --git a/files/opencs/lockpick.svg b/files/opencs/lockpick.svg new file mode 100644 index 0000000000..b7e8ca1c3d --- /dev/null +++ b/files/opencs/lockpick.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/magic-effect.png b/files/opencs/magic-effect.png deleted file mode 100644 index 44b682bf4f..0000000000 Binary files a/files/opencs/magic-effect.png and /dev/null differ diff --git a/files/opencs/magic-effect.svg b/files/opencs/magic-effect.svg new file mode 100644 index 0000000000..0e949c04bb --- /dev/null +++ b/files/opencs/magic-effect.svg @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-close.png b/files/opencs/menu-close.png deleted file mode 100644 index 81bc986775..0000000000 Binary files a/files/opencs/menu-close.png and /dev/null differ diff --git a/files/opencs/menu-close.svg b/files/opencs/menu-close.svg new file mode 100644 index 0000000000..6bd1e9f275 --- /dev/null +++ b/files/opencs/menu-close.svg @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-exit.png b/files/opencs/menu-exit.png deleted file mode 100644 index f583536fb6..0000000000 Binary files a/files/opencs/menu-exit.png and /dev/null differ diff --git a/files/opencs/menu-exit.svg b/files/opencs/menu-exit.svg new file mode 100644 index 0000000000..e1256eab72 --- /dev/null +++ b/files/opencs/menu-exit.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-merge.png b/files/opencs/menu-merge.png deleted file mode 100644 index c76288ae16..0000000000 Binary files a/files/opencs/menu-merge.png and /dev/null differ diff --git a/files/opencs/menu-merge.svg b/files/opencs/menu-merge.svg new file mode 100644 index 0000000000..e2d7f394fb --- /dev/null +++ b/files/opencs/menu-merge.svg @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-new-addon.png b/files/opencs/menu-new-addon.png deleted file mode 100644 index df137b2b20..0000000000 Binary files a/files/opencs/menu-new-addon.png and /dev/null differ diff --git a/files/opencs/menu-new-addon.svg b/files/opencs/menu-new-addon.svg new file mode 100644 index 0000000000..46aaa1e1ec --- /dev/null +++ b/files/opencs/menu-new-addon.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-new-game.png b/files/opencs/menu-new-game.png deleted file mode 100644 index 701daf34b1..0000000000 Binary files a/files/opencs/menu-new-game.png and /dev/null differ diff --git a/files/opencs/menu-new-game.svg b/files/opencs/menu-new-game.svg new file mode 100644 index 0000000000..416a774d30 --- /dev/null +++ b/files/opencs/menu-new-game.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-new-window.png b/files/opencs/menu-new-window.png deleted file mode 100644 index 4a42da0d12..0000000000 Binary files a/files/opencs/menu-new-window.png and /dev/null differ diff --git a/files/opencs/menu-new-window.svg b/files/opencs/menu-new-window.svg new file mode 100644 index 0000000000..33262366dc --- /dev/null +++ b/files/opencs/menu-new-window.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-open.png b/files/opencs/menu-open.png deleted file mode 100644 index 3766e17549..0000000000 Binary files a/files/opencs/menu-open.png and /dev/null differ diff --git a/files/opencs/menu-open.svg b/files/opencs/menu-open.svg new file mode 100644 index 0000000000..a895b4157f --- /dev/null +++ b/files/opencs/menu-open.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-preferences.png b/files/opencs/menu-preferences.png deleted file mode 100644 index 4644297ad0..0000000000 Binary files a/files/opencs/menu-preferences.png and /dev/null differ diff --git a/files/opencs/menu-preferences.svg b/files/opencs/menu-preferences.svg new file mode 100644 index 0000000000..f7c657deb2 --- /dev/null +++ b/files/opencs/menu-preferences.svg @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-redo.png b/files/opencs/menu-redo.png deleted file mode 100644 index 0cd0eedcae..0000000000 Binary files a/files/opencs/menu-redo.png and /dev/null differ diff --git a/files/opencs/menu-redo.svg b/files/opencs/menu-redo.svg new file mode 100644 index 0000000000..f19f236e7e --- /dev/null +++ b/files/opencs/menu-redo.svg @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-reload.png b/files/opencs/menu-reload.png deleted file mode 100644 index 2b780598c4..0000000000 Binary files a/files/opencs/menu-reload.png and /dev/null differ diff --git a/files/opencs/menu-reload.svg b/files/opencs/menu-reload.svg new file mode 100644 index 0000000000..aef27dd104 --- /dev/null +++ b/files/opencs/menu-reload.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-save.png b/files/opencs/menu-save.png deleted file mode 100644 index 4be88765be..0000000000 Binary files a/files/opencs/menu-save.png and /dev/null differ diff --git a/files/opencs/menu-save.svg b/files/opencs/menu-save.svg new file mode 100644 index 0000000000..c9cb6f4bef --- /dev/null +++ b/files/opencs/menu-save.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-search.png b/files/opencs/menu-search.png deleted file mode 100644 index 1ec63f0e82..0000000000 Binary files a/files/opencs/menu-search.png and /dev/null differ diff --git a/files/opencs/menu-search.svg b/files/opencs/menu-search.svg new file mode 100644 index 0000000000..10b5b20b00 --- /dev/null +++ b/files/opencs/menu-search.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-status-bar.png b/files/opencs/menu-status-bar.png deleted file mode 100644 index dfb72b1e13..0000000000 Binary files a/files/opencs/menu-status-bar.png and /dev/null differ diff --git a/files/opencs/menu-status-bar.svg b/files/opencs/menu-status-bar.svg new file mode 100644 index 0000000000..a6b4d15d1e --- /dev/null +++ b/files/opencs/menu-status-bar.svg @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-undo.png b/files/opencs/menu-undo.png deleted file mode 100644 index bd177ce65a..0000000000 Binary files a/files/opencs/menu-undo.png and /dev/null differ diff --git a/files/opencs/menu-undo.svg b/files/opencs/menu-undo.svg new file mode 100644 index 0000000000..1fffc9959d --- /dev/null +++ b/files/opencs/menu-undo.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/menu-verify.png b/files/opencs/menu-verify.png deleted file mode 100644 index a7878ebb3f..0000000000 Binary files a/files/opencs/menu-verify.png and /dev/null differ diff --git a/files/opencs/menu-verify.svg b/files/opencs/menu-verify.svg new file mode 100644 index 0000000000..d72d229edd --- /dev/null +++ b/files/opencs/menu-verify.svg @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/metadata.png b/files/opencs/metadata.png deleted file mode 100644 index 34c78ffd61..0000000000 Binary files a/files/opencs/metadata.png and /dev/null differ diff --git a/files/opencs/metadata.svg b/files/opencs/metadata.svg new file mode 100644 index 0000000000..acccf4f4b7 --- /dev/null +++ b/files/opencs/metadata.svg @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/miscellaneous.png b/files/opencs/miscellaneous.png deleted file mode 100644 index b21f6e2141..0000000000 Binary files a/files/opencs/miscellaneous.png and /dev/null differ diff --git a/files/opencs/miscellaneous.svg b/files/opencs/miscellaneous.svg new file mode 100644 index 0000000000..ac1bda5e5a --- /dev/null +++ b/files/opencs/miscellaneous.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/multitype.png b/files/opencs/multitype.png deleted file mode 100644 index 05676e2de0..0000000000 Binary files a/files/opencs/multitype.png and /dev/null differ diff --git a/files/opencs/multitype.svg b/files/opencs/multitype.svg new file mode 100644 index 0000000000..c42da95866 --- /dev/null +++ b/files/opencs/multitype.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/npc.png b/files/opencs/npc.png deleted file mode 100644 index 5b5b199be6..0000000000 Binary files a/files/opencs/npc.png and /dev/null differ diff --git a/files/opencs/npc.svg b/files/opencs/npc.svg new file mode 100644 index 0000000000..3ae9a3127c --- /dev/null +++ b/files/opencs/npc.svg @@ -0,0 +1,316 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/object.png b/files/opencs/object.png deleted file mode 100644 index 4f552151db..0000000000 Binary files a/files/opencs/object.png and /dev/null differ diff --git a/files/opencs/object.svg b/files/opencs/object.svg new file mode 100644 index 0000000000..717269b9d6 --- /dev/null +++ b/files/opencs/object.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/pathgrid.png b/files/opencs/pathgrid.png deleted file mode 100644 index 710ff13576..0000000000 Binary files a/files/opencs/pathgrid.png and /dev/null differ diff --git a/files/opencs/pathgrid.svg b/files/opencs/pathgrid.svg new file mode 100644 index 0000000000..ba16efcacf --- /dev/null +++ b/files/opencs/pathgrid.svg @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/potion.png b/files/opencs/potion.png deleted file mode 100644 index cb173bb9ed..0000000000 Binary files a/files/opencs/potion.png and /dev/null differ diff --git a/files/opencs/potion.svg b/files/opencs/potion.svg new file mode 100644 index 0000000000..b59d12683f --- /dev/null +++ b/files/opencs/potion.svg @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/probe.png b/files/opencs/probe.png deleted file mode 100644 index 2e405d3653..0000000000 Binary files a/files/opencs/probe.png and /dev/null differ diff --git a/files/opencs/probe.svg b/files/opencs/probe.svg new file mode 100644 index 0000000000..0d812c5ace --- /dev/null +++ b/files/opencs/probe.svg @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/qt.png b/files/opencs/qt.png deleted file mode 100644 index 381cb2251f..0000000000 Binary files a/files/opencs/qt.png and /dev/null differ diff --git a/files/opencs/qt.svg b/files/opencs/qt.svg new file mode 100644 index 0000000000..cc84a363e5 --- /dev/null +++ b/files/opencs/qt.svg @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/race.png b/files/opencs/race.png deleted file mode 100644 index aeed2fdf3e..0000000000 Binary files a/files/opencs/race.png and /dev/null differ diff --git a/files/opencs/race.svg b/files/opencs/race.svg new file mode 100644 index 0000000000..cd7778127e --- /dev/null +++ b/files/opencs/race.svg @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/random.png b/files/opencs/random.png deleted file mode 100644 index 2667630f5c..0000000000 Binary files a/files/opencs/random.png and /dev/null differ diff --git a/files/opencs/record-add.png b/files/opencs/record-add.png deleted file mode 100644 index d477f19460..0000000000 Binary files a/files/opencs/record-add.png and /dev/null differ diff --git a/files/opencs/record-add.svg b/files/opencs/record-add.svg new file mode 100644 index 0000000000..d29682bc59 --- /dev/null +++ b/files/opencs/record-add.svg @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/record-clone.png b/files/opencs/record-clone.png deleted file mode 100644 index 262a67a424..0000000000 Binary files a/files/opencs/record-clone.png and /dev/null differ diff --git a/files/opencs/record-clone.svg b/files/opencs/record-clone.svg new file mode 100644 index 0000000000..3014b2b4e0 --- /dev/null +++ b/files/opencs/record-clone.svg @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/record-delete.png b/files/opencs/record-delete.png deleted file mode 100644 index 817988a5d1..0000000000 Binary files a/files/opencs/record-delete.png and /dev/null differ diff --git a/files/opencs/record-delete.svg b/files/opencs/record-delete.svg new file mode 100644 index 0000000000..9a21973542 --- /dev/null +++ b/files/opencs/record-delete.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/record-down.png b/files/opencs/record-down.png deleted file mode 100644 index 92fe788602..0000000000 Binary files a/files/opencs/record-down.png and /dev/null differ diff --git a/files/opencs/record-down.svg b/files/opencs/record-down.svg new file mode 100644 index 0000000000..9febe57065 --- /dev/null +++ b/files/opencs/record-down.svg @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/record-edit.png b/files/opencs/record-edit.png deleted file mode 100644 index 8b94e16341..0000000000 Binary files a/files/opencs/record-edit.png and /dev/null differ diff --git a/files/opencs/record-edit.svg b/files/opencs/record-edit.svg new file mode 100644 index 0000000000..2db10e9c78 --- /dev/null +++ b/files/opencs/record-edit.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/record-next.png b/files/opencs/record-next.png deleted file mode 100644 index 76866e4734..0000000000 Binary files a/files/opencs/record-next.png and /dev/null differ diff --git a/files/opencs/record-next.svg b/files/opencs/record-next.svg new file mode 100644 index 0000000000..bbc44e7459 --- /dev/null +++ b/files/opencs/record-next.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/record-preview.png b/files/opencs/record-preview.png deleted file mode 100644 index e3adb6ede4..0000000000 Binary files a/files/opencs/record-preview.png and /dev/null differ diff --git a/files/opencs/record-preview.svg b/files/opencs/record-preview.svg new file mode 100644 index 0000000000..a516d6b596 --- /dev/null +++ b/files/opencs/record-preview.svg @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/record-previous.png b/files/opencs/record-previous.png deleted file mode 100644 index 2009d84e04..0000000000 Binary files a/files/opencs/record-previous.png and /dev/null differ diff --git a/files/opencs/record-previous.svg b/files/opencs/record-previous.svg new file mode 100644 index 0000000000..2479c8bd49 --- /dev/null +++ b/files/opencs/record-previous.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/record-revert.png b/files/opencs/record-revert.png deleted file mode 100644 index bd177ce65a..0000000000 Binary files a/files/opencs/record-revert.png and /dev/null differ diff --git a/files/opencs/record-revert.svg b/files/opencs/record-revert.svg new file mode 100644 index 0000000000..11920a329a --- /dev/null +++ b/files/opencs/record-revert.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/record-touch.png b/files/opencs/record-touch.png deleted file mode 100644 index 808e1b6c4b..0000000000 Binary files a/files/opencs/record-touch.png and /dev/null differ diff --git a/files/opencs/record-touch.svg b/files/opencs/record-touch.svg new file mode 100644 index 0000000000..4d53a591b5 --- /dev/null +++ b/files/opencs/record-touch.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/record-up.png b/files/opencs/record-up.png deleted file mode 100644 index c8bfa4a342..0000000000 Binary files a/files/opencs/record-up.png and /dev/null differ diff --git a/files/opencs/record-up.svg b/files/opencs/record-up.svg new file mode 100644 index 0000000000..351cb14d4a --- /dev/null +++ b/files/opencs/record-up.svg @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/region-map.png b/files/opencs/region-map.png deleted file mode 100644 index 7631847bee..0000000000 Binary files a/files/opencs/region-map.png and /dev/null differ diff --git a/files/opencs/region-map.svg b/files/opencs/region-map.svg new file mode 100644 index 0000000000..0067fb9901 --- /dev/null +++ b/files/opencs/region-map.svg @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/region.png b/files/opencs/region.png deleted file mode 100644 index 2ebaeb0285..0000000000 Binary files a/files/opencs/region.png and /dev/null differ diff --git a/files/opencs/region.svg b/files/opencs/region.svg new file mode 100644 index 0000000000..4458c7e376 --- /dev/null +++ b/files/opencs/region.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/repair.png b/files/opencs/repair.png deleted file mode 100644 index 1b5a9ccc11..0000000000 Binary files a/files/opencs/repair.png and /dev/null differ diff --git a/files/opencs/repair.svg b/files/opencs/repair.svg new file mode 100644 index 0000000000..5e2d09d58c --- /dev/null +++ b/files/opencs/repair.svg @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/resources-icon.png b/files/opencs/resources-icon.png deleted file mode 100644 index d84c90d5dc..0000000000 Binary files a/files/opencs/resources-icon.png and /dev/null differ diff --git a/files/opencs/resources-icon.svg b/files/opencs/resources-icon.svg new file mode 100644 index 0000000000..2054ba0b2e --- /dev/null +++ b/files/opencs/resources-icon.svg @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/resources-mesh.png b/files/opencs/resources-mesh.png deleted file mode 100644 index fdfa3528b1..0000000000 Binary files a/files/opencs/resources-mesh.png and /dev/null differ diff --git a/files/opencs/resources-mesh.svg b/files/opencs/resources-mesh.svg new file mode 100644 index 0000000000..ba93da8091 --- /dev/null +++ b/files/opencs/resources-mesh.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/resources-music.png b/files/opencs/resources-music.png deleted file mode 100644 index 53775109c5..0000000000 Binary files a/files/opencs/resources-music.png and /dev/null differ diff --git a/files/opencs/resources-music.svg b/files/opencs/resources-music.svg new file mode 100644 index 0000000000..bf81130e3c --- /dev/null +++ b/files/opencs/resources-music.svg @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/resources-sound.png b/files/opencs/resources-sound.png deleted file mode 100644 index 86871611f5..0000000000 Binary files a/files/opencs/resources-sound.png and /dev/null differ diff --git a/files/opencs/resources-sound.svg b/files/opencs/resources-sound.svg new file mode 100644 index 0000000000..c2019ca176 --- /dev/null +++ b/files/opencs/resources-sound.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/resources-texture.png b/files/opencs/resources-texture.png deleted file mode 100644 index a96c4bf8c7..0000000000 Binary files a/files/opencs/resources-texture.png and /dev/null differ diff --git a/files/opencs/resources-texture.svg b/files/opencs/resources-texture.svg new file mode 100644 index 0000000000..fd9fa88c93 --- /dev/null +++ b/files/opencs/resources-texture.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/resources-video.png b/files/opencs/resources-video.png deleted file mode 100644 index d86bc6025e..0000000000 Binary files a/files/opencs/resources-video.png and /dev/null differ diff --git a/files/opencs/resources-video.svg b/files/opencs/resources-video.svg new file mode 100644 index 0000000000..fa1ce3c1b6 --- /dev/null +++ b/files/opencs/resources-video.svg @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/resources.qrc b/files/opencs/resources.qrc index eef5c01bf8..786040623c 100644 --- a/files/opencs/resources.qrc +++ b/files/opencs/resources.qrc @@ -1,109 +1,102 @@ - openmw-cs.png - activator.png - list-added.png - apparatus.png - armor.png - attribute.png - list-base.png - birthsign.png - body-part.png - book.png - cell.png - class.png - clothing.png - container.png - creature.png - debug-profile.png - dialogue-info.png - dialogue-journal.png - dialogue-regular.png - dialogue-greeting.png - dialogue-persuasion.png - dialogue-voice.png - dialogue-topics.png - dialogue-topic-infos.png - journal-topic-infos.png - journal-topics.png - door.png - enchantment.png - error-log.png - faction.png - filter.png - global-variable.png - gmst.png - info.png - ingredient.png - instance.png - land-heightmap.png - land-texture.png - levelled-creature.png - levelled-item.png - light.png - lockpick.png - magic-effect.png - probe.png - menu-close.png - menu-exit.png - menu-new-addon.png - menu-new-game.png - menu-new-window.png - menu-merge.png - menu-open.png - menu-preferences.png - menu-reload.png - menu-redo.png - menu-save.png - menu-search.png - menu-status-bar.png - menu-undo.png - menu-verify.png - metadata.png - miscellaneous.png - list-modified.png - npc.png - object.png - pathgrid.png - potion.png - qt.png - race.png - random.png - list-removed.png - region.png - region-map.png - repair.png - run-log.png - run-openmw.png - scene.png - script.png - skill.png - start-script.png - stop-openmw.png - sound-generator.png - sound.png - spell.png - static.png - weapon.png - multitype.png - record-next.png - record-previous.png - record-down.png - record-up.png - record-delete.png - record-preview.png - record-clone.png - record-add.png - record-edit.png - record-touch.png - record-revert.png - resources-icon.png - resources-mesh.png - resources-music.png - resources-sound.png - resources-texture.png - resources-video.png + activator.svg + apparatus.svg + armor.svg + attribute.svg + birthsign.svg + body-part.svg + book.svg + cell.svg + class.svg + clothing.svg + container.svg + creature.svg + debug-profile.svg + dialogue-info.svg + dialogue-topics.svg + door.svg + record-add.svg + record-clone.svg + record-delete.svg + record-edit.svg + record-preview.svg + record-touch.svg + record-revert.svg + enchantment.svg + error-log.svg + faction.svg + filter.svg + global-variable.svg + gmst.svg + info.svg + ingredient.svg + instance.svg + journal-topic-infos.svg + journal-topics.svg + land-heightmap.svg + land-texture.svg + levelled-creature.svg + levelled-item.svg + light.svg + list-base.svg + list-added.svg + list-modified.svg + list-removed.svg + lockpick.svg + magic-effect.svg + menu-close.svg + menu-exit.svg + menu-merge.svg + menu-new-addon.svg + menu-new-game.svg + menu-new-window.svg + menu-open.svg + menu-preferences.svg + menu-redo.svg + menu-reload.svg + menu-save.svg + menu-search.svg + menu-status-bar.svg + menu-undo.svg + menu-verify.svg + metadata.svg + miscellaneous.svg + multitype.svg + npc.svg + object.svg + openmw-cs.png + pathgrid.svg placeholder.png + potion.svg + probe.svg + qt.svg + race.svg + record-down.svg + record-next.svg + record-previous.svg + record-up.svg + region.svg + region-map.svg + repair.svg + resources-icon.svg + resources-mesh.svg + resources-music.svg + resources-sound.svg + resources-texture.svg + resources-video.svg + run-log.svg + run-openmw.svg + scene.svg + script.svg + skill.svg + sound-generator.svg + sound.svg + spell.svg + start-script.svg + static.svg + stop-openmw.svg + weapon.svg raster/startup/big/create-addon.png @@ -112,76 +105,59 @@ raster/startup/small/configure.png - lighting-moon.png - lighting-sun.png - lighting-lamp.png - camera-first-person.png - camera-free.png - camera-orbit.png - run-game.png - scene-view-instance.png - scene-view-terrain.png - scene-view-water.png - scene-view-pathgrid.png - scene-view-fog.png - scene-view-status-0.png - scene-view-status-1.png - scene-view-status-2.png - scene-view-status-3.png - scene-view-status-4.png - scene-view-status-5.png - scene-view-status-6.png - scene-view-status-7.png - scene-view-status-8.png - scene-view-status-9.png - scene-view-status-10.png - scene-view-status-11.png - scene-view-status-12.png - scene-view-status-13.png - scene-view-status-14.png - scene-view-status-15.png - scene-view-status-16.png - scene-view-status-17.png - scene-view-status-18.png - scene-view-status-19.png - scene-view-status-20.png - scene-view-status-21.png - scene-view-status-22.png - scene-view-status-23.png - scene-view-status-24.png - scene-view-status-25.png - scene-view-status-26.png - scene-view-status-27.png - scene-view-status-28.png - scene-view-status-29.png - scene-view-status-30.png - scene-view-status-31.png - scene-exterior-arrows.png - scene-exterior-borders.png - scene-exterior-markers.png - scene-exterior-status-0.png - scene-exterior-status-1.png - scene-exterior-status-2.png - scene-exterior-status-3.png - scene-exterior-status-4.png - scene-exterior-status-5.png - scene-exterior-status-6.png - scene-exterior-status-7.png - editing-instance.png - editing-pathgrid.png - editing-terrain-movement.png - editing-terrain-shape.png - editing-terrain-texture.png - editing-terrain-vertex-paint.png - transform-move.png - transform-rotate.png - transform-scale.png - selection-mode-cube.png - selection-mode-cube-corner.png - selection-mode-cube-sphere.png - brush-point.png - brush-square.png - brush-circle.png - brush-custom.png + lighting-moon.svg + lighting-sun.svg + lighting-lamp.svg + camera-first-person.svg + camera-free.svg + camera-orbit.svg + run-game.svg + scene-view-instance.svg + scene-view-terrain.svg + scene-view-water.svg + scene-view-pathgrid.svg + scene-view-status-0.svg + scene-view-status-1.svg + scene-view-status-2.svg + scene-view-status-3.svg + scene-view-status-4.svg + scene-view-status-5.svg + scene-view-status-6.svg + scene-view-status-7.svg + scene-view-status-8.svg + scene-view-status-9.svg + scene-view-status-10.svg + scene-view-status-11.svg + scene-view-status-12.svg + scene-view-status-13.svg + scene-view-status-14.svg + scene-view-status-15.svg + scene-exterior-arrows.svg + scene-exterior-borders.svg + scene-exterior-markers.svg + scene-exterior-status-0.svg + scene-exterior-status-1.svg + scene-exterior-status-2.svg + scene-exterior-status-3.svg + scene-exterior-status-4.svg + scene-exterior-status-5.svg + scene-exterior-status-6.svg + scene-exterior-status-7.svg + editing-instance.svg + editing-pathgrid.svg + editing-terrain-movement.svg + editing-terrain-shape.svg + editing-terrain-texture.svg + editing-terrain-vertex-paint.svg + transform-move.svg + transform-rotate.svg + transform-scale.svg + selection-mode-cube.svg + selection-mode-cube-corner.svg + selection-mode-sphere.svg + brush-point.svg + brush-square.svg + brush-circle.svg + brush-custom.svg diff --git a/files/opencs/run-game.png b/files/opencs/run-game.png deleted file mode 100644 index f5038654fa..0000000000 Binary files a/files/opencs/run-game.png and /dev/null differ diff --git a/files/opencs/run-game.svg b/files/opencs/run-game.svg new file mode 100644 index 0000000000..818d1dd5b7 --- /dev/null +++ b/files/opencs/run-game.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/run-log.png b/files/opencs/run-log.png deleted file mode 100644 index 463ead176d..0000000000 Binary files a/files/opencs/run-log.png and /dev/null differ diff --git a/files/opencs/run-log.svg b/files/opencs/run-log.svg new file mode 100644 index 0000000000..404f74a6d4 --- /dev/null +++ b/files/opencs/run-log.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/run-openmw.png b/files/opencs/run-openmw.png deleted file mode 100644 index 1033d62baa..0000000000 Binary files a/files/opencs/run-openmw.png and /dev/null differ diff --git a/files/opencs/run-openmw.svg b/files/opencs/run-openmw.svg new file mode 100644 index 0000000000..f0ae78619e --- /dev/null +++ b/files/opencs/run-openmw.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/editor-icons.svg b/files/opencs/scalable/editor-icons.svg index d41fdbde60..921c5f6d8d 100644 --- a/files/opencs/scalable/editor-icons.svg +++ b/files/opencs/scalable/editor-icons.svg @@ -8973,9 +8973,9 @@ height="100%" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-exterior-borders.png b/files/opencs/scene-exterior-borders.png deleted file mode 100644 index ec5040dc88..0000000000 Binary files a/files/opencs/scene-exterior-borders.png and /dev/null differ diff --git a/files/opencs/scene-exterior-borders.svg b/files/opencs/scene-exterior-borders.svg new file mode 100644 index 0000000000..4a9c2ea4fa --- /dev/null +++ b/files/opencs/scene-exterior-borders.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-exterior-markers.png b/files/opencs/scene-exterior-markers.png deleted file mode 100644 index 6fffcbbcca..0000000000 Binary files a/files/opencs/scene-exterior-markers.png and /dev/null differ diff --git a/files/opencs/scene-exterior-markers.svg b/files/opencs/scene-exterior-markers.svg new file mode 100644 index 0000000000..63900d752f --- /dev/null +++ b/files/opencs/scene-exterior-markers.svg @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-exterior-status-0.png b/files/opencs/scene-exterior-status-0.png deleted file mode 100644 index 6fa47b4394..0000000000 Binary files a/files/opencs/scene-exterior-status-0.png and /dev/null differ diff --git a/files/opencs/scene-exterior-status-0.svg b/files/opencs/scene-exterior-status-0.svg new file mode 100644 index 0000000000..7e1f8aece3 --- /dev/null +++ b/files/opencs/scene-exterior-status-0.svg @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-exterior-status-1.png b/files/opencs/scene-exterior-status-1.png deleted file mode 100644 index 2e1ed0f650..0000000000 Binary files a/files/opencs/scene-exterior-status-1.png and /dev/null differ diff --git a/files/opencs/scene-exterior-status-1.svg b/files/opencs/scene-exterior-status-1.svg new file mode 100644 index 0000000000..f699d767c2 --- /dev/null +++ b/files/opencs/scene-exterior-status-1.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-exterior-status-2.png b/files/opencs/scene-exterior-status-2.png deleted file mode 100644 index 8ccd356aa9..0000000000 Binary files a/files/opencs/scene-exterior-status-2.png and /dev/null differ diff --git a/files/opencs/scene-exterior-status-2.svg b/files/opencs/scene-exterior-status-2.svg new file mode 100644 index 0000000000..2d1ab9bbf8 --- /dev/null +++ b/files/opencs/scene-exterior-status-2.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-exterior-status-3.png b/files/opencs/scene-exterior-status-3.png deleted file mode 100644 index 70fdc4111e..0000000000 Binary files a/files/opencs/scene-exterior-status-3.png and /dev/null differ diff --git a/files/opencs/scene-exterior-status-3.svg b/files/opencs/scene-exterior-status-3.svg new file mode 100644 index 0000000000..401f19a5fa --- /dev/null +++ b/files/opencs/scene-exterior-status-3.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-exterior-status-4.png b/files/opencs/scene-exterior-status-4.png deleted file mode 100644 index 2f2b907fc8..0000000000 Binary files a/files/opencs/scene-exterior-status-4.png and /dev/null differ diff --git a/files/opencs/scene-exterior-status-4.svg b/files/opencs/scene-exterior-status-4.svg new file mode 100644 index 0000000000..aebc14b932 --- /dev/null +++ b/files/opencs/scene-exterior-status-4.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-exterior-status-5.png b/files/opencs/scene-exterior-status-5.png deleted file mode 100644 index b294c1b15a..0000000000 Binary files a/files/opencs/scene-exterior-status-5.png and /dev/null differ diff --git a/files/opencs/scene-exterior-status-5.svg b/files/opencs/scene-exterior-status-5.svg new file mode 100644 index 0000000000..3fb8b98a5f --- /dev/null +++ b/files/opencs/scene-exterior-status-5.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-exterior-status-6.png b/files/opencs/scene-exterior-status-6.png deleted file mode 100644 index 872568b266..0000000000 Binary files a/files/opencs/scene-exterior-status-6.png and /dev/null differ diff --git a/files/opencs/scene-exterior-status-6.svg b/files/opencs/scene-exterior-status-6.svg new file mode 100644 index 0000000000..93c905935a --- /dev/null +++ b/files/opencs/scene-exterior-status-6.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-exterior-status-7.png b/files/opencs/scene-exterior-status-7.png deleted file mode 100644 index c19431025c..0000000000 Binary files a/files/opencs/scene-exterior-status-7.png and /dev/null differ diff --git a/files/opencs/scene-exterior-status-7.svg b/files/opencs/scene-exterior-status-7.svg new file mode 100644 index 0000000000..89b97866d8 --- /dev/null +++ b/files/opencs/scene-exterior-status-7.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-fog.png b/files/opencs/scene-view-fog.png deleted file mode 100644 index 65ea108ac5..0000000000 Binary files a/files/opencs/scene-view-fog.png and /dev/null differ diff --git a/files/opencs/scene-view-instance.png b/files/opencs/scene-view-instance.png deleted file mode 100644 index 6f5e7cb2ac..0000000000 Binary files a/files/opencs/scene-view-instance.png and /dev/null differ diff --git a/files/opencs/scene-view-instance.svg b/files/opencs/scene-view-instance.svg new file mode 100644 index 0000000000..771432bebf --- /dev/null +++ b/files/opencs/scene-view-instance.svg @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-pathgrid.png b/files/opencs/scene-view-pathgrid.png deleted file mode 100644 index edb350b8b5..0000000000 Binary files a/files/opencs/scene-view-pathgrid.png and /dev/null differ diff --git a/files/opencs/scene-view-pathgrid.svg b/files/opencs/scene-view-pathgrid.svg new file mode 100644 index 0000000000..b1a0c8845e --- /dev/null +++ b/files/opencs/scene-view-pathgrid.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-0.png b/files/opencs/scene-view-status-0.png deleted file mode 100644 index 1906fd89cd..0000000000 Binary files a/files/opencs/scene-view-status-0.png and /dev/null differ diff --git a/files/opencs/scene-view-status-0.svg b/files/opencs/scene-view-status-0.svg new file mode 100644 index 0000000000..6820c6f013 --- /dev/null +++ b/files/opencs/scene-view-status-0.svg @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-1.png b/files/opencs/scene-view-status-1.png deleted file mode 100644 index 6f5e7cb2ac..0000000000 Binary files a/files/opencs/scene-view-status-1.png and /dev/null differ diff --git a/files/opencs/scene-view-status-1.svg b/files/opencs/scene-view-status-1.svg new file mode 100644 index 0000000000..3dbfa1622a --- /dev/null +++ b/files/opencs/scene-view-status-1.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-10.png b/files/opencs/scene-view-status-10.png deleted file mode 100644 index 1216c180fe..0000000000 Binary files a/files/opencs/scene-view-status-10.png and /dev/null differ diff --git a/files/opencs/scene-view-status-10.svg b/files/opencs/scene-view-status-10.svg new file mode 100644 index 0000000000..8263818403 --- /dev/null +++ b/files/opencs/scene-view-status-10.svg @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-11.png b/files/opencs/scene-view-status-11.png deleted file mode 100644 index dbe8276f07..0000000000 Binary files a/files/opencs/scene-view-status-11.png and /dev/null differ diff --git a/files/opencs/scene-view-status-11.svg b/files/opencs/scene-view-status-11.svg new file mode 100644 index 0000000000..8c25452211 --- /dev/null +++ b/files/opencs/scene-view-status-11.svg @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-12.png b/files/opencs/scene-view-status-12.png deleted file mode 100644 index ba6d1f3235..0000000000 Binary files a/files/opencs/scene-view-status-12.png and /dev/null differ diff --git a/files/opencs/scene-view-status-12.svg b/files/opencs/scene-view-status-12.svg new file mode 100644 index 0000000000..2e16eb8256 --- /dev/null +++ b/files/opencs/scene-view-status-12.svg @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-13.png b/files/opencs/scene-view-status-13.png deleted file mode 100644 index 3651cd6094..0000000000 Binary files a/files/opencs/scene-view-status-13.png and /dev/null differ diff --git a/files/opencs/scene-view-status-13.svg b/files/opencs/scene-view-status-13.svg new file mode 100644 index 0000000000..1f2b3ab398 --- /dev/null +++ b/files/opencs/scene-view-status-13.svg @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-14.png b/files/opencs/scene-view-status-14.png deleted file mode 100644 index 4bddb7ebc3..0000000000 Binary files a/files/opencs/scene-view-status-14.png and /dev/null differ diff --git a/files/opencs/scene-view-status-14.svg b/files/opencs/scene-view-status-14.svg new file mode 100644 index 0000000000..e948ba19e7 --- /dev/null +++ b/files/opencs/scene-view-status-14.svg @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-15.png b/files/opencs/scene-view-status-15.png deleted file mode 100644 index bdd43407c9..0000000000 Binary files a/files/opencs/scene-view-status-15.png and /dev/null differ diff --git a/files/opencs/scene-view-status-15.svg b/files/opencs/scene-view-status-15.svg new file mode 100644 index 0000000000..a8a3ce8573 --- /dev/null +++ b/files/opencs/scene-view-status-15.svg @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-16.png b/files/opencs/scene-view-status-16.png deleted file mode 100644 index b0051eb127..0000000000 Binary files a/files/opencs/scene-view-status-16.png and /dev/null differ diff --git a/files/opencs/scene-view-status-17.png b/files/opencs/scene-view-status-17.png deleted file mode 100644 index def1560323..0000000000 Binary files a/files/opencs/scene-view-status-17.png and /dev/null differ diff --git a/files/opencs/scene-view-status-18.png b/files/opencs/scene-view-status-18.png deleted file mode 100644 index 7d92726876..0000000000 Binary files a/files/opencs/scene-view-status-18.png and /dev/null differ diff --git a/files/opencs/scene-view-status-19.png b/files/opencs/scene-view-status-19.png deleted file mode 100644 index 17b75ce0e2..0000000000 Binary files a/files/opencs/scene-view-status-19.png and /dev/null differ diff --git a/files/opencs/scene-view-status-2.png b/files/opencs/scene-view-status-2.png deleted file mode 100644 index edb350b8b5..0000000000 Binary files a/files/opencs/scene-view-status-2.png and /dev/null differ diff --git a/files/opencs/scene-view-status-2.svg b/files/opencs/scene-view-status-2.svg new file mode 100644 index 0000000000..656c5d9d39 --- /dev/null +++ b/files/opencs/scene-view-status-2.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-20.png b/files/opencs/scene-view-status-20.png deleted file mode 100644 index bb950d94e3..0000000000 Binary files a/files/opencs/scene-view-status-20.png and /dev/null differ diff --git a/files/opencs/scene-view-status-21.png b/files/opencs/scene-view-status-21.png deleted file mode 100644 index 76ad0022c7..0000000000 Binary files a/files/opencs/scene-view-status-21.png and /dev/null differ diff --git a/files/opencs/scene-view-status-22.png b/files/opencs/scene-view-status-22.png deleted file mode 100644 index e33820a166..0000000000 Binary files a/files/opencs/scene-view-status-22.png and /dev/null differ diff --git a/files/opencs/scene-view-status-23.png b/files/opencs/scene-view-status-23.png deleted file mode 100644 index 6c1fcc54f2..0000000000 Binary files a/files/opencs/scene-view-status-23.png and /dev/null differ diff --git a/files/opencs/scene-view-status-24.png b/files/opencs/scene-view-status-24.png deleted file mode 100644 index 057532b77a..0000000000 Binary files a/files/opencs/scene-view-status-24.png and /dev/null differ diff --git a/files/opencs/scene-view-status-25.png b/files/opencs/scene-view-status-25.png deleted file mode 100644 index 061336c995..0000000000 Binary files a/files/opencs/scene-view-status-25.png and /dev/null differ diff --git a/files/opencs/scene-view-status-26.png b/files/opencs/scene-view-status-26.png deleted file mode 100644 index 8fbcf68c63..0000000000 Binary files a/files/opencs/scene-view-status-26.png and /dev/null differ diff --git a/files/opencs/scene-view-status-27.png b/files/opencs/scene-view-status-27.png deleted file mode 100644 index 30eb053b9b..0000000000 Binary files a/files/opencs/scene-view-status-27.png and /dev/null differ diff --git a/files/opencs/scene-view-status-28.png b/files/opencs/scene-view-status-28.png deleted file mode 100644 index 3a8f77457d..0000000000 Binary files a/files/opencs/scene-view-status-28.png and /dev/null differ diff --git a/files/opencs/scene-view-status-29.png b/files/opencs/scene-view-status-29.png deleted file mode 100644 index eff6106662..0000000000 Binary files a/files/opencs/scene-view-status-29.png and /dev/null differ diff --git a/files/opencs/scene-view-status-3.png b/files/opencs/scene-view-status-3.png deleted file mode 100644 index ddf27c2db1..0000000000 Binary files a/files/opencs/scene-view-status-3.png and /dev/null differ diff --git a/files/opencs/scene-view-status-3.svg b/files/opencs/scene-view-status-3.svg new file mode 100644 index 0000000000..56b471de20 --- /dev/null +++ b/files/opencs/scene-view-status-3.svg @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-30.png b/files/opencs/scene-view-status-30.png deleted file mode 100644 index 63ce7d0d25..0000000000 Binary files a/files/opencs/scene-view-status-30.png and /dev/null differ diff --git a/files/opencs/scene-view-status-31.png b/files/opencs/scene-view-status-31.png deleted file mode 100644 index 1906fd89cd..0000000000 Binary files a/files/opencs/scene-view-status-31.png and /dev/null differ diff --git a/files/opencs/scene-view-status-4.png b/files/opencs/scene-view-status-4.png deleted file mode 100644 index 246c5aae92..0000000000 Binary files a/files/opencs/scene-view-status-4.png and /dev/null differ diff --git a/files/opencs/scene-view-status-4.svg b/files/opencs/scene-view-status-4.svg new file mode 100644 index 0000000000..8fc4e9c31a --- /dev/null +++ b/files/opencs/scene-view-status-4.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-5.png b/files/opencs/scene-view-status-5.png deleted file mode 100644 index 63d37f8be5..0000000000 Binary files a/files/opencs/scene-view-status-5.png and /dev/null differ diff --git a/files/opencs/scene-view-status-5.svg b/files/opencs/scene-view-status-5.svg new file mode 100644 index 0000000000..5a74f8e829 --- /dev/null +++ b/files/opencs/scene-view-status-5.svg @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-6.png b/files/opencs/scene-view-status-6.png deleted file mode 100644 index 051aa64ae7..0000000000 Binary files a/files/opencs/scene-view-status-6.png and /dev/null differ diff --git a/files/opencs/scene-view-status-6.svg b/files/opencs/scene-view-status-6.svg new file mode 100644 index 0000000000..4321be4269 --- /dev/null +++ b/files/opencs/scene-view-status-6.svg @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-7.png b/files/opencs/scene-view-status-7.png deleted file mode 100644 index 6b2e5fdc16..0000000000 Binary files a/files/opencs/scene-view-status-7.png and /dev/null differ diff --git a/files/opencs/scene-view-status-7.svg b/files/opencs/scene-view-status-7.svg new file mode 100644 index 0000000000..bcaefa0bba --- /dev/null +++ b/files/opencs/scene-view-status-7.svg @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-8.png b/files/opencs/scene-view-status-8.png deleted file mode 100644 index 65ea108ac5..0000000000 Binary files a/files/opencs/scene-view-status-8.png and /dev/null differ diff --git a/files/opencs/scene-view-status-8.svg b/files/opencs/scene-view-status-8.svg new file mode 100644 index 0000000000..5f6107f774 --- /dev/null +++ b/files/opencs/scene-view-status-8.svg @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-status-9.png b/files/opencs/scene-view-status-9.png deleted file mode 100644 index 72d0d9fb77..0000000000 Binary files a/files/opencs/scene-view-status-9.png and /dev/null differ diff --git a/files/opencs/scene-view-status-9.svg b/files/opencs/scene-view-status-9.svg new file mode 100644 index 0000000000..5d101ad1f4 --- /dev/null +++ b/files/opencs/scene-view-status-9.svg @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-terrain.png b/files/opencs/scene-view-terrain.png deleted file mode 100644 index b0051eb127..0000000000 Binary files a/files/opencs/scene-view-terrain.png and /dev/null differ diff --git a/files/opencs/scene-view-terrain.svg b/files/opencs/scene-view-terrain.svg new file mode 100644 index 0000000000..e816d8e3b5 --- /dev/null +++ b/files/opencs/scene-view-terrain.svg @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene-view-water.png b/files/opencs/scene-view-water.png deleted file mode 100644 index 246c5aae92..0000000000 Binary files a/files/opencs/scene-view-water.png and /dev/null differ diff --git a/files/opencs/scene-view-water.svg b/files/opencs/scene-view-water.svg new file mode 100644 index 0000000000..68edc166e4 --- /dev/null +++ b/files/opencs/scene-view-water.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scene.png b/files/opencs/scene.png deleted file mode 100644 index a9fc03f769..0000000000 Binary files a/files/opencs/scene.png and /dev/null differ diff --git a/files/opencs/scene.svg b/files/opencs/scene.svg new file mode 100644 index 0000000000..a516d6b596 --- /dev/null +++ b/files/opencs/scene.svg @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/script.png b/files/opencs/script.png deleted file mode 100644 index 29d622e19f..0000000000 Binary files a/files/opencs/script.png and /dev/null differ diff --git a/files/opencs/script.svg b/files/opencs/script.svg new file mode 100644 index 0000000000..76f3b7b28c --- /dev/null +++ b/files/opencs/script.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/selection-mode-cube-corner.png b/files/opencs/selection-mode-cube-corner.png deleted file mode 100644 index b69ef1782f..0000000000 Binary files a/files/opencs/selection-mode-cube-corner.png and /dev/null differ diff --git a/files/opencs/selection-mode-cube-corner.svg b/files/opencs/selection-mode-cube-corner.svg new file mode 100644 index 0000000000..63d5f73c56 --- /dev/null +++ b/files/opencs/selection-mode-cube-corner.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/selection-mode-cube-sphere.png b/files/opencs/selection-mode-cube-sphere.png deleted file mode 100644 index cb5432eea6..0000000000 Binary files a/files/opencs/selection-mode-cube-sphere.png and /dev/null differ diff --git a/files/opencs/selection-mode-cube.png b/files/opencs/selection-mode-cube.png deleted file mode 100644 index 1344a3fb1a..0000000000 Binary files a/files/opencs/selection-mode-cube.png and /dev/null differ diff --git a/files/opencs/selection-mode-cube.svg b/files/opencs/selection-mode-cube.svg new file mode 100644 index 0000000000..e03138bafe --- /dev/null +++ b/files/opencs/selection-mode-cube.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/selection-mode-sphere.svg b/files/opencs/selection-mode-sphere.svg new file mode 100644 index 0000000000..9f8ed79340 --- /dev/null +++ b/files/opencs/selection-mode-sphere.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/skill.png b/files/opencs/skill.png deleted file mode 100644 index 0ef7cb1cb7..0000000000 Binary files a/files/opencs/skill.png and /dev/null differ diff --git a/files/opencs/skill.svg b/files/opencs/skill.svg new file mode 100644 index 0000000000..21ae4d12c8 --- /dev/null +++ b/files/opencs/skill.svg @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/sound-generator.png b/files/opencs/sound-generator.png deleted file mode 100644 index 79833df9c3..0000000000 Binary files a/files/opencs/sound-generator.png and /dev/null differ diff --git a/files/opencs/sound-generator.svg b/files/opencs/sound-generator.svg new file mode 100644 index 0000000000..4e27f19f41 --- /dev/null +++ b/files/opencs/sound-generator.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/sound.png b/files/opencs/sound.png deleted file mode 100644 index 86871611f5..0000000000 Binary files a/files/opencs/sound.png and /dev/null differ diff --git a/files/opencs/sound.svg b/files/opencs/sound.svg new file mode 100644 index 0000000000..f482c9cd70 --- /dev/null +++ b/files/opencs/sound.svg @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/spell.png b/files/opencs/spell.png deleted file mode 100644 index 5890ea751b..0000000000 Binary files a/files/opencs/spell.png and /dev/null differ diff --git a/files/opencs/spell.svg b/files/opencs/spell.svg new file mode 100644 index 0000000000..e726d85a7e --- /dev/null +++ b/files/opencs/spell.svg @@ -0,0 +1,264 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/start-script.png b/files/opencs/start-script.png deleted file mode 100644 index 73ed157b9e..0000000000 Binary files a/files/opencs/start-script.png and /dev/null differ diff --git a/files/opencs/start-script.svg b/files/opencs/start-script.svg new file mode 100644 index 0000000000..f7348c493a --- /dev/null +++ b/files/opencs/start-script.svg @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/static.png b/files/opencs/static.png deleted file mode 100644 index 9f458e5d04..0000000000 Binary files a/files/opencs/static.png and /dev/null differ diff --git a/files/opencs/static.svg b/files/opencs/static.svg new file mode 100644 index 0000000000..8e8ce541ce --- /dev/null +++ b/files/opencs/static.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/stop-openmw.png b/files/opencs/stop-openmw.png deleted file mode 100644 index d8f8096724..0000000000 Binary files a/files/opencs/stop-openmw.png and /dev/null differ diff --git a/files/opencs/stop-openmw.svg b/files/opencs/stop-openmw.svg new file mode 100644 index 0000000000..73c5936fee --- /dev/null +++ b/files/opencs/stop-openmw.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/transform-move.png b/files/opencs/transform-move.png deleted file mode 100644 index 1e5bd573d3..0000000000 Binary files a/files/opencs/transform-move.png and /dev/null differ diff --git a/files/opencs/transform-move.svg b/files/opencs/transform-move.svg new file mode 100644 index 0000000000..1b9490f001 --- /dev/null +++ b/files/opencs/transform-move.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + diff --git a/files/opencs/transform-rotate.png b/files/opencs/transform-rotate.png deleted file mode 100644 index b6c6bc58a7..0000000000 Binary files a/files/opencs/transform-rotate.png and /dev/null differ diff --git a/files/opencs/transform-rotate.svg b/files/opencs/transform-rotate.svg new file mode 100644 index 0000000000..29bc3fdad5 --- /dev/null +++ b/files/opencs/transform-rotate.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + diff --git a/files/opencs/transform-scale.png b/files/opencs/transform-scale.png deleted file mode 100644 index c641259bd7..0000000000 Binary files a/files/opencs/transform-scale.png and /dev/null differ diff --git a/files/opencs/transform-scale.svg b/files/opencs/transform-scale.svg new file mode 100644 index 0000000000..e4d1d16422 --- /dev/null +++ b/files/opencs/transform-scale.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + diff --git a/files/opencs/weapon.png b/files/opencs/weapon.png deleted file mode 100644 index e2c1d3dc16..0000000000 Binary files a/files/opencs/weapon.png and /dev/null differ diff --git a/files/opencs/weapon.svg b/files/opencs/weapon.svg new file mode 100644 index 0000000000..6168812305 --- /dev/null +++ b/files/opencs/weapon.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 73331867a7..10c25bb430 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -981,7 +981,7 @@ enable agents paths render = false enable recast mesh render = false # Max number of navmesh tiles (value >= 0) -max tiles number = 512 +max tiles number = 1024 # Min time duration for the same tile update in milliseconds (value >= 0) min update interval ms = 250 @@ -999,6 +999,9 @@ write to navmeshdb = true # Approximate maximum file size of navigation mesh cache stored on disk in bytes (value > 0) max navmeshdb file size = 2147483648 +# Wait until all queued async navmesh jobs are processed before exiting the engine (true, false) +wait for all jobs on exit = false + [Shadows] # Enable or disable shadows. Bear in mind that this will force OpenMW to use shaders as if "[Shaders]/force shaders" was set to true. diff --git a/files/shaders/compatibility/bs/default.frag b/files/shaders/compatibility/bs/default.frag index 77131c6a52..d2c8de0b22 100644 --- a/files/shaders/compatibility/bs/default.frag +++ b/files/shaders/compatibility/bs/default.frag @@ -77,6 +77,9 @@ void main() vec3 specularColor = getSpecularColor().xyz; #if @normalMap vec4 normalTex = texture2D(normalMap, normalMapUV); +#if @reconstructNormalZ + normalTex.z = sqrt(1.0 - dot(normalTex.xy, normalTex.xy)); +#endif vec3 viewNormal = normalToView(normalTex.xyz * 2.0 - 1.0); specularColor *= normalTex.a; #else diff --git a/files/shaders/compatibility/groundcover.frag b/files/shaders/compatibility/groundcover.frag index dfdd6518c3..aab37d465d 100644 --- a/files/shaders/compatibility/groundcover.frag +++ b/files/shaders/compatibility/groundcover.frag @@ -59,7 +59,11 @@ void main() gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef); #if @normalMap - vec3 viewNormal = normalToView(texture2D(normalMap, normalMapUV).xyz * 2.0 - 1.0); + vec4 normalTex = texture2D(normalMap, normalMapUV); +#if @reconstructNormalZ + normalTex.z = sqrt(1.0 - dot(normalTex.xy, normalTex.xy)); +#endif + vec3 viewNormal = normalToView(normalTex.xyz * 2.0 - 1.0); #else vec3 viewNormal = normalToView(normalize(passNormal)); #endif diff --git a/files/shaders/compatibility/objects.frag b/files/shaders/compatibility/objects.frag index 56c7abf27c..eb5b79a0c2 100644 --- a/files/shaders/compatibility/objects.frag +++ b/files/shaders/compatibility/objects.frag @@ -167,7 +167,11 @@ vec2 screenCoords = gl_FragCoord.xy / screenRes; gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef); #if @normalMap - vec3 viewNormal = normalToView(texture2D(normalMap, normalMapUV + offset).xyz * 2.0 - 1.0); + vec4 normalTex = texture2D(normalMap, normalMapUV + offset); +#if @reconstructNormalZ + normalTex.z = sqrt(1.0 - dot(normalTex.xy, normalTex.xy)); +#endif + vec3 viewNormal = normalToView(normalTex.xyz * 2.0 - 1.0); #else vec3 viewNormal = normalize(gl_NormalMatrix * passNormal); #endif diff --git a/files/shaders/compatibility/terrain.frag b/files/shaders/compatibility/terrain.frag index abc7425eb0..f45f1f024e 100644 --- a/files/shaders/compatibility/terrain.frag +++ b/files/shaders/compatibility/terrain.frag @@ -63,7 +63,11 @@ void main() #endif #if @normalMap - vec3 viewNormal = normalToView(texture2D(normalMap, adjustedUV).xyz * 2.0 - 1.0); + vec4 normalTex = texture2D(normalMap, adjustedUV); +#if @reconstructNormalZ + normalTex.z = sqrt(1.0 - dot(normalTex.xy, normalTex.xy)); +#endif + vec3 viewNormal = normalToView(normalTex.xyz * 2.0 - 1.0); #else vec3 viewNormal = normalize(gl_NormalMatrix * passNormal); #endif