Merge branch openmw:master into master

This commit is contained in:
Andy Lanzone 2025-07-26 00:17:39 -07:00
commit c015599356
106 changed files with 579 additions and 392 deletions

View File

@ -13,3 +13,7 @@ HeaderFilterRegex: '(apps|components)/'
CheckOptions:
- key: readability-identifier-naming.ConceptCase
value: CamelCase
- key: readability-identifier-naming.NamespaceCase
value: CamelCase
- key: readability-identifier-naming.NamespaceIgnoredRegexp
value: 'osg(DB|FX|Particle|Shadow|Viewer|Util)?'

View File

@ -46,6 +46,9 @@ Ubuntu_GCC_preprocess:
- pip3 install --user click termtables
script:
- CI/ubuntu_gcc_preprocess.sh
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382"
.Ubuntu:
extends: .Ubuntu_Image
@ -268,6 +271,9 @@ Ubuntu_GCC_tests_asan:
when: always
reports:
junit: build/*-tests.xml
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382"
Ubuntu_GCC_tests_ubsan:
extends: Ubuntu_GCC
@ -285,6 +291,9 @@ Ubuntu_GCC_tests_ubsan:
when: always
reports:
junit: build/*-tests.xml
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382"
.Ubuntu_GCC_tests_tsan:
extends: Ubuntu_GCC
@ -322,6 +331,9 @@ Ubuntu_GCC_tests_coverage:
coverage_format: cobertura
path: coverage.xml
junit: build/*-tests.xml
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382"
.Ubuntu_Static_Deps:
extends: Ubuntu_Clang
@ -402,6 +414,9 @@ Ubuntu_Clang:
- build/
expire_in: 12h
timeout: 3h
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_PIPELINE_SOURCE == "push" && $CI_PROJECT_ID != "7107382"
Ubuntu_Clang_Tidy_components:
extends: .Ubuntu_Clang_Tidy_Base
@ -502,7 +517,14 @@ Ubuntu_GCC_integration_tests_asan:
.MacOS:
stage: build
rules:
- if: $CI_PROJECT_ID == "7107382"
- if: $CI_PROJECT_ID != "7107382"
when: never
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
when: manual
- if: $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule"
image: macos-15-xcode-16
tags:
- saas-macos-medium-m1
cache:
paths:
- ccache/
@ -535,13 +557,10 @@ Ubuntu_GCC_integration_tests_asan:
paths:
- build/OpenMW-*.dmg
macOS14_Xcode15_amd64:
macOS15_Xcode16_amd64:
extends: .MacOS
image: macos-14-xcode-15
tags:
- saas-macos-medium-m1
cache:
key: macOS14_Xcode15_amd64.v2
key: macOS15_Xcode16_amd64.v1
variables:
CCACHE_SIZE: 3G
DMG_IDENTIFIER: amd64
@ -550,13 +569,10 @@ macOS14_Xcode15_amd64:
HOMEBREW_NO_EMOJI: true
HOMEBREW_NO_INSTALL_CLEANUP: true
macOS14_Xcode15_arm64:
macOS15_Xcode16_arm64:
extends: .MacOS
image: macos-14-xcode-15
tags:
- saas-macos-medium-m1
cache:
key: macOS14_Xcode15_arm64.v1
key: macOS15_Xcode16_arm64.v1
variables:
DMG_IDENTIFIER: arm64
CCACHE_SIZE: 3G
@ -687,7 +703,7 @@ macOS14_Xcode15_arm64:
- Get-Volume
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
cache:
key: ninja-2022-v12
key: ninja-2022-v13
paths:
- ccache
- deps
@ -845,7 +861,7 @@ macOS14_Xcode15_arm64:
- Get-Volume
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
cache:
key: msbuild-2022-v12
key: msbuild-2022-v13
paths:
- deps
- MSVC2022_64/deps/Qt

View File

@ -197,7 +197,7 @@ Programmers
Qlonever
Radu-Marius Popovici (rpopovici)
Rafael Moura (dhustkoder)
Randy Davin (Kindi)
Randy Davin (Kuyondo)
rdimesio
rexelion
riothamus

View File

@ -377,6 +377,8 @@ case $VS_VERSION in
MSVC_DISPLAY_YEAR="2022"
QT_MSVC_YEAR="2019"
VCPKG_TRIPLET="x64-windows"
;;
16|16.0|2019 )
@ -386,6 +388,8 @@ case $VS_VERSION in
MSVC_DISPLAY_YEAR="2019"
QT_MSVC_YEAR="2019"
VCPKG_TRIPLET="x64-windows-2019"
;;
15|15.0|2017 )
@ -546,7 +550,7 @@ fi
QT_VER='6.6.3'
AQT_VERSION='v3.1.15'
VCPKG_TAG="2024-11-10"
VCPKG_TAG="2025-07-23"
VCPKG_PATH="vcpkg-x64-${VS_VERSION:?}-${VCPKG_TAG:?}"
VCPKG_PDB_PATH="vcpkg-x64-${VS_VERSION:?}-pdb-${VCPKG_TAG:?}"
VCPKG_MANIFEST="${VCPKG_PATH:?}.txt"
@ -633,16 +637,16 @@ printf "vcpkg packages ${VCPKG_TAG:?}... "
fi
add_cmake_opts -DCMAKE_TOOLCHAIN_FILE="$(real_pwd)/${VCPKG_PATH:?}/scripts/buildsystems/vcpkg.cmake"
add_cmake_opts -DLuaJit_INCLUDE_DIR="$(real_pwd)/${VCPKG_PATH:?}/installed/x64-windows/include/luajit"
add_cmake_opts -DLuaJit_LIBRARY="$(real_pwd)/${VCPKG_PATH:?}/installed/x64-windows/lib/lua51.lib"
add_cmake_opts -DLuaJit_INCLUDE_DIR="$(real_pwd)/${VCPKG_PATH:?}/installed/${VCPKG_TRIPLET}/include/luajit"
add_cmake_opts -DLuaJit_LIBRARY="$(real_pwd)/${VCPKG_PATH:?}/installed/${VCPKG_TRIPLET}/lib/lua51.lib"
for CONFIGURATION in ${CONFIGURATIONS[@]}; do
if [[ ${CONFIGURATION:?} == "Debug" ]]; then
VCPKG_DLL_BIN="$(pwd)/${VCPKG_PATH:?}/installed/x64-windows/debug/bin"
VCPKG_DLL_BIN="$(pwd)/${VCPKG_PATH:?}/installed/${VCPKG_TRIPLET}/debug/bin"
add_runtime_dlls ${CONFIGURATION:?} "${VCPKG_DLL_BIN:?}/Debug/MyGUIEngine_d.dll"
else
VCPKG_DLL_BIN="$(pwd)/${VCPKG_PATH:?}/installed/x64-windows/bin"
VCPKG_DLL_BIN="$(pwd)/${VCPKG_PATH:?}/installed/${VCPKG_TRIPLET}/bin"
add_runtime_dlls ${CONFIGURATION:?} "${VCPKG_DLL_BIN:?}/Release/MyGUIEngine.dll"
fi

View File

@ -723,7 +723,7 @@ namespace ESM
TEST_P(Esm3SaveLoadRecordTest, landShouldNotChange)
{
LandRecordData data;
std::iota(data.mHeights.begin(), data.mHeights.end(), 1);
std::iota(data.mHeights.begin(), data.mHeights.end(), 1.0f);
std::for_each(data.mHeights.begin(), data.mHeights.end(), [](float& v) { v *= Land::sHeightScale; });
data.mMinHeight = *std::min_element(data.mHeights.begin(), data.mHeights.end());
data.mMaxHeight = *std::max_element(data.mHeights.begin(), data.mHeights.end());

View File

@ -5,7 +5,7 @@
namespace
{
using namespace testing;
using namespace fx::Lexer;
using namespace Fx::Lexer;
struct LexerTest : Test
{

View File

@ -91,7 +91,7 @@ namespace
)" };
using namespace testing;
using namespace fx;
using namespace Fx;
struct TechniqueTest : Test
{

View File

@ -105,7 +105,7 @@ speed: "Speed"
lua.protectedCall([&](LuaUtil::LuaView& view) {
sol::state_view& l = view.sol();
internal::CaptureStdout();
l10n::Manager l10nManager(mVFS.get());
L10n::Manager l10nManager(mVFS.get());
l10nManager.setPreferredLocales({ "de", "en" });
EXPECT_THAT(internal::GetCapturedStdout(), "Preferred locales: gmst de en\n");

View File

@ -249,7 +249,7 @@ namespace ESSImport
{
ESM::InventoryState& invState = mContext->mPlayer.mObject.mInventory;
for (size_t i = 0; i < invState.mItems.size(); ++i)
for (uint32_t i = 0; i < static_cast<uint32_t>(invState.mItems.size()); ++i)
{
// FIXME: in case of conflict (multiple items with this refID) use the already equipped one?
if (invState.mItems[i].mRef.mRefID == refr.mActorData.mSelectedEnchantItem)

View File

@ -42,7 +42,7 @@ int runLauncher(int argc, char* argv[])
resourcesPath = Files::pathToQString(variables["resources"].as<Files::MaybeQuotedPath>().u8string());
}
l10n::installQtTranslations(app, "launcher", resourcesPath);
L10n::installQtTranslations(app, "launcher", resourcesPath);
Launcher::MainDialog mainWin(configurationManager);

View File

@ -201,8 +201,8 @@ namespace NavMeshTool
{
if (!land.has_value() || osg::Vec2i(land->mX, land->mY) != cellPosition
|| (land->mDataTypes & ESM::Land::DATA_VHGT) == 0)
return { HeightfieldPlane{ ESM::Land::DEFAULT_HEIGHT }, ESM::Land::DEFAULT_HEIGHT,
ESM::Land::DEFAULT_HEIGHT };
return { HeightfieldPlane{ static_cast<float>(ESM::Land::DEFAULT_HEIGHT) },
static_cast<float>(ESM::Land::DEFAULT_HEIGHT), static_cast<float>(ESM::Land::DEFAULT_HEIGHT) };
ESM::Land::LandData& landData = *landDatas.emplace_back(std::make_unique<ESM::Land::LandData>());
land->loadData(ESM::Land::DATA_VHGT, landData);

View File

@ -625,8 +625,6 @@ bool CSMWorld::ConstInfoSelectWrapper::conditionIsAlwaysTrue(
default:
throw std::logic_error("InfoCondition: operator can not be used to compare");
}
return false;
}
template <typename T1, typename T2>
@ -651,8 +649,6 @@ bool CSMWorld::ConstInfoSelectWrapper::conditionIsNeverTrue(
default:
throw std::logic_error("InfoCondition: operator can not be used to compare");
}
return false;
}
QVariant CSMWorld::ConstInfoSelectWrapper::getValue() const

View File

@ -753,7 +753,6 @@ void CSMWorld::RefIdCollection::cloneRecord(
bool CSMWorld::RefIdCollection::touchRecord(const ESM::RefId& id)
{
throw std::runtime_error("RefIdCollection::touchRecord is unimplemented");
return false;
}
void CSMWorld::RefIdCollection::appendRecord(std::unique_ptr<RecordBase> record, UniversalId::Type type)

View File

@ -755,7 +755,7 @@ void OMW::Engine::prepareEngine()
mViewer->addEventHandler(mScreenCaptureHandler);
mL10nManager = std::make_unique<l10n::Manager>(mVFS.get());
mL10nManager = std::make_unique<L10n::Manager>(mVFS.get());
mL10nManager->setPreferredLocales(Settings::general().mPreferredLocales, Settings::general().mGmstOverridesL10n);
mEnvironment.setL10nManager(*mL10nManager);

View File

@ -113,7 +113,7 @@ namespace MWDialogue
class Journal;
}
namespace l10n
namespace L10n
{
class Manager;
}
@ -141,7 +141,7 @@ namespace OMW
std::unique_ptr<MWState::StateManager> mStateManager;
std::unique_ptr<MWLua::LuaManager> mLuaManager;
std::unique_ptr<MWLua::Worker> mLuaWorker;
std::unique_ptr<l10n::Manager> mL10nManager;
std::unique_ptr<L10n::Manager> mL10nManager;
MWBase::Environment mEnvironment;
ToUTF8::FromType mEncoding;
std::unique_ptr<ToUTF8::Utf8Encoder> mEncoder;

View File

@ -10,7 +10,7 @@ namespace Resource
class ResourceSystem;
}
namespace l10n
namespace L10n
{
class Manager;
}
@ -57,7 +57,7 @@ namespace MWBase
StateManager* mStateManager = nullptr;
LuaManager* mLuaManager = nullptr;
Resource::ResourceSystem* mResourceSystem = nullptr;
l10n::Manager* mL10nManager = nullptr;
L10n::Manager* mL10nManager = nullptr;
float mFrameRateLimit = 0;
float mFrameDuration = 0;
@ -95,7 +95,7 @@ namespace MWBase
void setResourceSystem(Resource::ResourceSystem& value) { mResourceSystem = &value; }
void setL10nManager(l10n::Manager& value) { mL10nManager = &value; }
void setL10nManager(L10n::Manager& value) { mL10nManager = &value; }
Misc::NotNullPtr<World> getWorld() const { return mWorld; }
Misc::NotNullPtr<MWWorld::WorldModel> getWorldModel() const { return mWorldModel; }
@ -122,7 +122,7 @@ namespace MWBase
Misc::NotNullPtr<Resource::ResourceSystem> getResourceSystem() const { return mResourceSystem; }
Misc::NotNullPtr<l10n::Manager> getL10nManager() const { return mL10nManager; }
Misc::NotNullPtr<L10n::Manager> getL10nManager() const { return mL10nManager; }
float getFrameRateLimit() const { return mFrameRateLimit; }

View File

@ -92,6 +92,8 @@ namespace MWBase
virtual void executeAction(int action) = 0;
virtual bool controlsDisabled() = 0;
virtual void saveBindings() = 0;
};
}

View File

@ -1,6 +1,7 @@
#ifndef GAME_MWBASE_LUAMANAGER_H
#define GAME_MWBASE_LUAMANAGER_H
#include <filesystem>
#include <map>
#include <string>
#include <variant>
@ -75,6 +76,7 @@ namespace MWBase
virtual void questUpdated(const ESM::RefId& questId, int stage) = 0;
// `arg` is either forwarded from MWGui::pushGuiMode or empty
virtual void uiModeChanged(const MWWorld::Ptr& arg) = 0;
virtual void savePermanentStorage(const std::filesystem::path& userConfigPath) = 0;
// TODO: notify LuaManager about other events
// virtual void objectOnHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object,

View File

@ -530,10 +530,11 @@ namespace MWClass
const MWBase::World* world = MWBase::Environment::get().getWorld();
const MWMechanics::MagicEffects& mageffects = stats.getMagicEffects();
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
float moveSpeed;
if (getEncumbrance(ptr) > getCapacity(ptr))
if (normalizedEncumbrance > 1.0f)
moveSpeed = 0.0f;
else if (canFly(ptr)
|| (mageffects.getOrDefault(ESM::MagicEffect::Levitate).getMagnitude() > 0 && world->isLevitationEnabled()))
@ -543,7 +544,6 @@ namespace MWClass
+ mageffects.getOrDefault(ESM::MagicEffect::Levitate).getMagnitude());
flySpeed = gmst.fMinFlySpeed->mValue.getFloat()
+ flySpeed * (gmst.fMaxFlySpeed->mValue.getFloat() - gmst.fMinFlySpeed->mValue.getFloat());
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
flySpeed *= 1.0f - gmst.fEncumberedMoveEffect->mValue.getFloat() * normalizedEncumbrance;
flySpeed = std::max(0.0f, flySpeed);
moveSpeed = flySpeed;

View File

@ -990,15 +990,10 @@ namespace MWClass
const MWMechanics::MagicEffects& mageffects = stats.getMagicEffects();
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
bool swimming = world->isSwimming(ptr);
bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr);
bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run);
bool inair = !world->isOnGround(ptr) && !swimming && !world->isFlying(ptr);
running = running && (inair || MWBase::Environment::get().getMechanicsManager()->isRunning(ptr));
const bool running = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr);
float moveSpeed;
if (getEncumbrance(ptr) > getCapacity(ptr))
if (normalizedEncumbrance > 1.0f)
moveSpeed = 0.0f;
else if (mageffects.getOrDefault(ESM::MagicEffect::Levitate).getMagnitude() > 0 && world->isLevitationEnabled())
{
@ -1011,9 +1006,9 @@ namespace MWClass
flySpeed = std::max(0.0f, flySpeed);
moveSpeed = flySpeed;
}
else if (swimming)
else if (world->isSwimming(ptr))
moveSpeed = getSwimSpeed(ptr);
else if (running && !sneaking)
else if (running && !MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr))
moveSpeed = getRunSpeed(ptr);
else
moveSpeed = getWalkSpeed(ptr);
@ -1509,14 +1504,8 @@ namespace MWClass
float Npc::getSwimSpeed(const MWWorld::Ptr& ptr) const
{
const MWBase::World* world = MWBase::Environment::get().getWorld();
const MWMechanics::NpcStats& stats = getNpcStats(ptr);
const MWMechanics::MagicEffects& mageffects = stats.getMagicEffects();
const bool swimming = world->isSwimming(ptr);
const bool inair = !world->isOnGround(ptr) && !swimming && !world->isFlying(ptr);
const bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run)
&& (inair || MWBase::Environment::get().getMechanicsManager()->isRunning(ptr));
return getSwimSpeedImpl(ptr, getGmst(), mageffects, running ? getRunSpeed(ptr) : getWalkSpeed(ptr));
const MWMechanics::MagicEffects& effects = getNpcStats(ptr).getMagicEffects();
const bool running = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr);
return getSwimSpeedImpl(ptr, getGmst(), effects, running ? getRunSpeed(ptr) : getWalkSpeed(ptr));
}
}

View File

@ -12,6 +12,7 @@
#include <components/esm3/loaddial.hpp>
#include <components/esm3/loadfact.hpp>
#include <components/esm3/loadinfo.hpp>
#include <components/esm3/loadmgef.hpp>
#include <components/compiler/errorhandler.hpp>
#include <components/compiler/exception.hpp>
@ -448,12 +449,14 @@ namespace MWDialogue
{
updateOriginalDisposition();
MWMechanics::NpcStats& npcStats = mActor.getClass().getNpcStats(mActor);
// Clamp permanent disposition change so that final disposition doesn't go below 0 (could happen with
// intimidate)
npcStats.setBaseDisposition(0);
int zero = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor, false);
int disposition = std::clamp(mOriginalDisposition + mPermanentDispositionChange, -zero, 100 - zero);
// Get the sum of disposition effects minus charm (shouldn't be made permanent)
npcStats.setBaseDisposition(0);
int zero = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor, false)
- npcStats.getMagicEffects().getOrDefault(ESM::MagicEffect::Charm).getMagnitude();
// Clamp new permanent disposition to avoid negative derived disposition (can be caused by intimidate)
int disposition = std::clamp(mOriginalDisposition + mPermanentDispositionChange, -zero, 100 - zero);
npcStats.setBaseDisposition(disposition);
}
mPermanentDispositionChange = 0;

View File

@ -224,7 +224,7 @@ namespace MWGui
if (target.getType() != ESM::Container::sRecordId)
return true;
// check container organic flag
// Check container organic flag
MWWorld::LiveCellRef<ESM::Container>* ref = target.get<ESM::Container>();
if (ref->mBase->mFlags & ESM::Container::Organic)
{
@ -232,9 +232,18 @@ namespace MWGui
return false;
}
// check that we don't exceed container capacity
float weight = item.getClass().getWeight(item) * count;
if (target.getClass().getCapacity(target) < target.getClass().getEncumbrance(target) + weight)
// Check for container without capacity
float capacity = target.getClass().getCapacity(target);
if (capacity <= 0.0f)
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sContentsMessage3}");
return false;
}
// Check the container capacity plus one increment so the expected total weight can
// fit in the container with floating-point imprecision
float newEncumbrance = target.getClass().getEncumbrance(target) + (item.getClass().getWeight(item) * count);
if (std::nextafterf(capacity, std::numeric_limits<float>::max()) < newEncumbrance)
{
MWBase::Environment::get().getWindowManager()->messageBox("#{sContentsMessage3}");
return false;

View File

@ -97,7 +97,7 @@ namespace MWGui
, mPendingControllerAction(ControllerAction::None)
{
mPreviewTexture
= std::make_unique<osgMyGUI::OSGTexture>(mPreview->getTexture(), mPreview->getTextureStateSet());
= std::make_unique<MyGUIPlatform::OSGTexture>(mPreview->getTexture(), mPreview->getTextureStateSet());
mPreview->rebuild();
mMainWidget->castType<MyGUI::Window>()->eventWindowChangeCoord
@ -646,24 +646,37 @@ namespace MWGui
}
std::unique_ptr<MWWorld::Action> action = ptr.getClass().use(ptr, force);
MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr);
auto [eqSlots, canStack] = ptr.getClass().getEquipmentSlots(ptr);
bool isFromDragAndDrop = mDragAndDrop->mItem.mBase == ptr;
int useCount = isFromDragAndDrop ? mDragAndDrop->mDraggedCount : ptr.getCellRef().getCount();
if (!eqSlots.empty())
{
MWWorld::ContainerStoreIterator it = invStore.getSlot(eqSlots.front());
if (it != invStore.end() && it->getCellRef().getRefId() == ptr.getCellRef().getRefId())
useCount += it->getCellRef().getCount();
}
action->execute(player, !canEquip);
// Handles partial equipping (final part)
if (mEquippedStackableCount.has_value())
{
// the count to unequip
int count = ptr.getCellRef().getCount() - mDragAndDrop->mDraggedCount - mEquippedStackableCount.value();
if (count > 0)
{
MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr);
invStore.unequipItemQuantity(ptr, count);
updateItemView();
}
mEquippedStackableCount.reset();
}
// Partial equipping
int excess = ptr.getCellRef().getCount() - useCount;
if (excess > 0 && canStack)
invStore.unequipItemQuantity(ptr, excess);
if (isVisible())
{
if (isFromDragAndDrop)
{
// Feature: Don't stop draganddrop if potion or ingredient was used
if (ptr.getType() != ESM::Potion::sRecordId && ptr.getType() != ESM::Ingredient::sRecordId)
mDragAndDrop->finish();
else
mDragAndDrop->update();
}
mItemView->update();
notifyContentChanged();
@ -685,8 +698,6 @@ namespace MWGui
return;
}
mDragAndDrop->finish();
if (mDragAndDrop->mSourceModel != mTradeModel)
{
// Move item to the player's inventory
@ -694,33 +705,7 @@ namespace MWGui
mDragAndDrop->mItem, mDragAndDrop->mDraggedCount, mTradeModel);
}
// Handles partial equipping
mEquippedStackableCount.reset();
const auto slots = ptr.getClass().getEquipmentSlots(ptr);
if (!slots.first.empty() && slots.second)
{
MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr);
MWWorld::ConstContainerStoreIterator slotIt = invStore.getSlot(slots.first.front());
// Save the currently equipped count before useItem()
if (slotIt != invStore.end() && slotIt->getCellRef().getRefId() == ptr.getCellRef().getRefId())
mEquippedStackableCount = slotIt->getCellRef().getCount();
else
mEquippedStackableCount = 0;
}
MWBase::Environment::get().getLuaManager()->useItem(ptr, MWMechanics::getPlayer(), false);
// If item is ingredient or potion don't stop drag and drop to simplify action of taking more than one 1
// item
if ((ptr.getType() == ESM::Potion::sRecordId || ptr.getType() == ESM::Ingredient::sRecordId)
&& mDragAndDrop->mDraggedCount > 1)
{
// Item can be provided from other window for example container.
// But after DragAndDrop::startDrag item automaticly always gets to player inventory.
mSelectedItem = getModel()->getIndex(mDragAndDrop->mItem);
dragItem(nullptr, mDragAndDrop->mDraggedCount - 1);
}
}
else
{

View File

@ -89,7 +89,6 @@ namespace MWGui
Misc::NotNullPtr<ItemTransfer> mItemTransfer;
int mSelectedItem;
std::optional<int> mEquippedStackableCount;
MWWorld::Ptr mPtr;

View File

@ -294,7 +294,7 @@ namespace MWGui
if (!mGuiTexture.get())
{
mGuiTexture = std::make_unique<osgMyGUI::OSGTexture>(mTexture);
mGuiTexture = std::make_unique<MyGUIPlatform::OSGTexture>(mTexture);
}
if (!mCopyFramebufferToTextureCallback)

View File

@ -600,27 +600,27 @@ namespace MWGui
osg::ref_ptr<osg::Texture2D> texture = mLocalMapRender->getMapTexture(entry.mCellX, entry.mCellY);
if (texture)
{
entry.mMapTexture = std::make_unique<osgMyGUI::OSGTexture>(texture);
entry.mMapTexture = std::make_unique<MyGUIPlatform::OSGTexture>(texture);
entry.mMapWidget->setRenderItemTexture(entry.mMapTexture.get());
entry.mMapWidget->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f));
needRedraw = true;
}
else
entry.mMapTexture = std::make_unique<osgMyGUI::OSGTexture>(std::string(), nullptr);
entry.mMapTexture = std::make_unique<MyGUIPlatform::OSGTexture>(std::string(), nullptr);
}
if (!entry.mFogTexture && mFogOfWarToggled && mFogOfWarEnabled)
{
osg::ref_ptr<osg::Texture2D> tex = mLocalMapRender->getFogOfWarTexture(entry.mCellX, entry.mCellY);
if (tex)
{
entry.mFogTexture = std::make_unique<osgMyGUI::OSGTexture>(tex);
entry.mFogTexture = std::make_unique<MyGUIPlatform::OSGTexture>(tex);
entry.mFogWidget->setRenderItemTexture(entry.mFogTexture.get());
entry.mFogWidget->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f));
}
else
{
entry.mFogWidget->setImageTexture("black");
entry.mFogTexture = std::make_unique<osgMyGUI::OSGTexture>(std::string(), nullptr);
entry.mFogTexture = std::make_unique<MyGUIPlatform::OSGTexture>(std::string(), nullptr);
}
needRedraw = true;
}
@ -1306,11 +1306,12 @@ namespace MWGui
{
if (!mGlobalMapTexture.get())
{
mGlobalMapTexture = std::make_unique<osgMyGUI::OSGTexture>(mGlobalMapRender->getBaseTexture());
mGlobalMapTexture = std::make_unique<MyGUIPlatform::OSGTexture>(mGlobalMapRender->getBaseTexture());
mGlobalMapImage->setRenderItemTexture(mGlobalMapTexture.get());
mGlobalMapImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f));
mGlobalMapOverlayTexture = std::make_unique<osgMyGUI::OSGTexture>(mGlobalMapRender->getOverlayTexture());
mGlobalMapOverlayTexture
= std::make_unique<MyGUIPlatform::OSGTexture>(mGlobalMapRender->getOverlayTexture());
mGlobalMapOverlay->setRenderItemTexture(mGlobalMapOverlayTexture.get());
mGlobalMapOverlay->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f));

View File

@ -17,6 +17,7 @@
#include <MyGUI_WidgetInput.h>
#include <MyGUI_Window.h>
#include <components/files/configurationmanager.hpp>
#include <components/fx/technique.hpp>
#include <components/fx/widgets.hpp>
@ -35,9 +36,9 @@ namespace MWGui
{
namespace
{
std::shared_ptr<fx::Technique>& getTechnique(const MyGUI::ListBox& list, size_t selected)
std::shared_ptr<Fx::Technique>& getTechnique(const MyGUI::ListBox& list, size_t selected)
{
return *list.getItemDataAt<std::shared_ptr<fx::Technique>>(selected);
return *list.getItemDataAt<std::shared_ptr<Fx::Technique>>(selected);
}
}
@ -50,8 +51,9 @@ namespace MWGui
MyGUI::ListBox::onKeyButtonPressed(key, ch);
}
PostProcessorHud::PostProcessorHud()
PostProcessorHud::PostProcessorHud(Files::ConfigurationManager& cfgMgr)
: WindowBase("openmw_postprocessor_hud.layout")
, mCfgMgr(cfgMgr)
{
getWidget(mActiveList, "ActiveList");
getWidget(mInactiveList, "InactiveList");
@ -110,7 +112,7 @@ namespace MWGui
{
for (size_t i = 1; i < mConfigArea->getChildCount(); ++i)
{
if (auto* child = dynamic_cast<fx::Widgets::UniformBase*>(mConfigArea->getChildAt(i)))
if (auto* child = dynamic_cast<Fx::Widgets::UniformBase*>(mConfigArea->getChildAt(i)))
child->toDefault();
}
}
@ -243,6 +245,8 @@ namespace MWGui
void PostProcessorHud::onClose()
{
Settings::ShaderManager::get().save();
Settings::Manager::saveUser(mCfgMgr.getUserConfigPath() / "settings.cfg");
toggleMode(Settings::ShaderManager::Mode::Normal);
}
@ -309,7 +313,7 @@ namespace MWGui
auto technique = processor->loadTechnique(path);
if (technique->getStatus() == fx::Technique::Status::File_Not_exists)
if (technique->getStatus() == Fx::Technique::Status::File_Not_exists)
return;
while (mConfigArea->getChildCount() > 0)
@ -330,15 +334,15 @@ namespace MWGui
const auto flags = technique->getFlags();
const auto flag_interior = serializeBool(!(flags & fx::Technique::Flag_Disable_Interiors));
const auto flag_exterior = serializeBool(!(flags & fx::Technique::Flag_Disable_Exteriors));
const auto flag_underwater = serializeBool(!(flags & fx::Technique::Flag_Disable_Underwater));
const auto flag_abovewater = serializeBool(!(flags & fx::Technique::Flag_Disable_Abovewater));
const auto flag_interior = serializeBool(!(flags & Fx::Technique::Flag_Disable_Interiors));
const auto flag_exterior = serializeBool(!(flags & Fx::Technique::Flag_Disable_Exteriors));
const auto flag_underwater = serializeBool(!(flags & Fx::Technique::Flag_Disable_Underwater));
const auto flag_abovewater = serializeBool(!(flags & Fx::Technique::Flag_Disable_Abovewater));
switch (technique->getStatus())
{
case fx::Technique::Status::Success:
case fx::Technique::Status::Uncompiled:
case Fx::Technique::Status::Success:
case Fx::Technique::Status::Uncompiled:
{
if (technique->getDynamic())
ss << "#{fontcolourhtml=header}#{OMWShaders:ShaderLocked}: #{fontcolourhtml=normal} "
@ -360,13 +364,13 @@ namespace MWGui
<< flag_abovewater;
break;
}
case fx::Technique::Status::Parse_Error:
case Fx::Technique::Status::Parse_Error:
ss << "#{fontcolourhtml=negative}Shader Compile Error: #{fontcolourhtml=normal} <"
<< std::string(technique->getName()) << "> failed to compile." << endl
<< endl
<< technique->getLastError();
break;
case fx::Technique::Status::File_Not_exists:
case Fx::Technique::Status::File_Not_exists:
break;
}
@ -398,7 +402,7 @@ namespace MWGui
divider->setCaptionWithReplacing(uniform->mHeader);
}
fx::Widgets::UniformBase* uwidget = mConfigArea->createWidget<fx::Widgets::UniformBase>(
Fx::Widgets::UniformBase* uwidget = mConfigArea->createWidget<Fx::Widgets::UniformBase>(
"MW_UniformEdit", { 0, 0, 0, 22 }, MyGUI::Align::Default);
uwidget->init(uniform);
uwidget->getLabel()->eventMouseWheel += MyGUI::newDelegate(this, &PostProcessorHud::notifyMouseWheel);
@ -489,14 +493,14 @@ namespace MWGui
void PostProcessorHud::registerMyGUIComponents()
{
MyGUI::FactoryManager& factory = MyGUI::FactoryManager::getInstance();
factory.registerFactory<fx::Widgets::UniformBase>("Widget");
factory.registerFactory<fx::Widgets::EditNumberFloat4>("Widget");
factory.registerFactory<fx::Widgets::EditNumberFloat3>("Widget");
factory.registerFactory<fx::Widgets::EditNumberFloat2>("Widget");
factory.registerFactory<fx::Widgets::EditNumberFloat>("Widget");
factory.registerFactory<fx::Widgets::EditNumberInt>("Widget");
factory.registerFactory<fx::Widgets::EditBool>("Widget");
factory.registerFactory<fx::Widgets::EditChoice>("Widget");
factory.registerFactory<Fx::Widgets::UniformBase>("Widget");
factory.registerFactory<Fx::Widgets::EditNumberFloat4>("Widget");
factory.registerFactory<Fx::Widgets::EditNumberFloat3>("Widget");
factory.registerFactory<Fx::Widgets::EditNumberFloat2>("Widget");
factory.registerFactory<Fx::Widgets::EditNumberFloat>("Widget");
factory.registerFactory<Fx::Widgets::EditNumberInt>("Widget");
factory.registerFactory<Fx::Widgets::EditBool>("Widget");
factory.registerFactory<Fx::Widgets::EditChoice>("Widget");
factory.registerFactory<ListWrapper>("Widget");
}
}

View File

@ -5,6 +5,7 @@
#include <MyGUI_ListBox.h>
#include <components/files/configurationmanager.hpp>
#include <components/settings/shadermanager.hpp>
#include <components/vfs/pathutil.hpp>
@ -32,7 +33,7 @@ namespace MWGui
};
public:
PostProcessorHud();
PostProcessorHud(Files::ConfigurationManager& cfgMgr);
void onOpen() override;
@ -99,6 +100,8 @@ namespace MWGui
std::string mOverrideHint;
int mOffset = 0;
Files::ConfigurationManager& mCfgMgr;
};
}

View File

@ -161,7 +161,7 @@ namespace MWGui
mPreview->setAngle(mCurrentAngle);
mPreviewTexture
= std::make_unique<osgMyGUI::OSGTexture>(mPreview->getTexture(), mPreview->getTextureStateSet());
= std::make_unique<MyGUIPlatform::OSGTexture>(mPreview->getTexture(), mPreview->getTextureStateSet());
mPreviewImage->setRenderItemTexture(mPreviewTexture.get());
mPreviewImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f));

View File

@ -522,7 +522,7 @@ namespace MWGui
texture->setResizeNonPowerOfTwoHint(false);
texture->setUnRefImageDataAfterApply(true);
mScreenshotTexture = std::make_unique<osgMyGUI::OSGTexture>(texture);
mScreenshotTexture = std::make_unique<MyGUIPlatform::OSGTexture>(texture);
mScreenshot->setRenderItemTexture(mScreenshotTexture.get());
}

View File

@ -18,6 +18,7 @@
#include <SDL_video.h>
#include <components/debug/debuglog.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/l10n/manager.hpp>
#include <components/lua_ui/scriptsettings.hpp>
#include <components/misc/constants.hpp>
@ -39,6 +40,7 @@
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwlua/luamanagerimp.hpp"
#include "confirmationdialog.hpp"
@ -247,10 +249,11 @@ namespace MWGui
}
}
SettingsWindow::SettingsWindow()
SettingsWindow::SettingsWindow(Files::ConfigurationManager& cfgMgr)
: WindowBase("openmw_settings_window.layout")
, mKeyboardMode(true)
, mCurrentPage(-1)
, mCfgMgr(cfgMgr)
{
const bool terrain = Settings::terrain().mDistantTerrain;
const std::string_view widgetName = terrain ? "RenderingDistanceSlider" : "LargeRenderingDistanceSlider";
@ -1096,6 +1099,14 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mOkButton);
}
void SettingsWindow::onClose()
{
// Save user settings
Settings::Manager::saveUser(mCfgMgr.getUserConfigPath() / "settings.cfg");
MWBase::Environment::get().getLuaManager()->savePermanentStorage(mCfgMgr.getUserConfigPath());
MWBase::Environment::get().getInputManager()->saveBindings();
}
void SettingsWindow::onWindowResize(MyGUI::Window* _sender)
{
layoutControlsBox();

View File

@ -1,6 +1,7 @@
#ifndef MWGUI_SETTINGS_H
#define MWGUI_SETTINGS_H
#include <components/files/configurationmanager.hpp>
#include <components/lua_ui/adapter.hpp>
#include "windowbase.hpp"
@ -10,10 +11,12 @@ namespace MWGui
class SettingsWindow : public WindowBase
{
public:
SettingsWindow();
SettingsWindow(Files::ConfigurationManager& cfgMgr);
void onOpen() override;
void onClose() override;
void onFrame(float duration) override;
void updateControlsBox();
@ -122,6 +125,7 @@ namespace MWGui
private:
void resetScrollbars();
Files::ConfigurationManager& mCfgMgr;
};
}

View File

@ -50,7 +50,7 @@ namespace MWGui
if (!texture)
return;
mTexture = std::make_unique<osgMyGUI::OSGTexture>(texture);
mTexture = std::make_unique<MyGUIPlatform::OSGTexture>(texture);
setRenderItemTexture(mTexture.get());
getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 1.f, 1.f, 0.f));

View File

@ -207,7 +207,7 @@ namespace MWGui
SDL_GL_GetDrawableSize(window, &dw, &dh);
mScalingFactor = Settings::gui().mScalingFactor * (dw / w);
mGuiPlatform = std::make_unique<osgMyGUI::Platform>(viewer, guiRoot, resourceSystem->getImageManager(),
mGuiPlatform = std::make_unique<MyGUIPlatform::Platform>(viewer, guiRoot, resourceSystem->getImageManager(),
resourceSystem->getVFS(), mScalingFactor, "mygui", logpath / "MyGUI.log");
mGui = std::make_unique<MyGUI::Gui>();
@ -231,8 +231,8 @@ namespace MWGui
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Window>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<VideoWidget>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<BackgroundImage>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<osgMyGUI::AdditiveLayer>("Layer");
MyGUI::FactoryManager::getInstance().registerFactory<osgMyGUI::ScalingLayer>("Layer");
MyGUI::FactoryManager::getInstance().registerFactory<MyGUIPlatform::AdditiveLayer>("Layer");
MyGUI::FactoryManager::getInstance().registerFactory<MyGUIPlatform::ScalingLayer>("Layer");
BookPage::registerMyGUIComponents();
PostProcessorHud::registerMyGUIComponents();
ItemView::registerComponents();
@ -411,7 +411,7 @@ namespace MWGui
mCountDialog = countDialog.get();
mWindows.push_back(std::move(countDialog));
auto settingsWindow = std::make_unique<SettingsWindow>();
auto settingsWindow = std::make_unique<SettingsWindow>(mCfgMgr);
mSettingsWindow = settingsWindow.get();
mWindows.push_back(std::move(settingsWindow));
trackWindow(mSettingsWindow, makeSettingsWindowSettingValues());
@ -505,7 +505,7 @@ namespace MWGui
mWindows.push_back(std::move(debugWindow));
trackWindow(mDebugWindow, makeDebugWindowSettingValues());
auto postProcessorHud = std::make_unique<PostProcessorHud>();
auto postProcessorHud = std::make_unique<PostProcessorHud>(mCfgMgr);
mPostProcessorHud = postProcessorHud.get();
mWindows.push_back(std::move(postProcessorHud));
trackWindow(mPostProcessorHud, makePostprocessorWindowSettingValues());
@ -1252,7 +1252,7 @@ namespace MWGui
std::vector<std::string> split;
Misc::StringUtils::split(tag, split, ":");
l10n::Manager& l10nManager = *MWBase::Environment::get().getL10nManager();
L10n::Manager& l10nManager = *MWBase::Environment::get().getL10nManager();
// If a key has a "Context:KeyName" format, use YAML to translate data
if (split.size() == 2)

View File

@ -416,7 +416,7 @@ namespace MWGui
Resource::ResourceSystem* mResourceSystem;
osg::ref_ptr<SceneUtil::WorkQueue> mWorkQueue;
std::unique_ptr<osgMyGUI::Platform> mGuiPlatform;
std::unique_ptr<MyGUIPlatform::Platform> mGuiPlatform;
osgViewer::Viewer* mViewer;
std::unique_ptr<Gui::FontLoader> mFontLoader;

View File

@ -196,23 +196,7 @@ namespace MWInput
BindingsManager::~BindingsManager()
{
const std::string newFileName = Files::pathToUnicodeString(mUserFile) + ".new";
try
{
if (mInputBinder->save(newFileName))
{
std::filesystem::rename(Files::pathFromUnicodeString(newFileName), mUserFile);
Log(Debug::Info) << "Saved input bindings: " << mUserFile;
}
else
{
Log(Debug::Error) << "Failed to save input bindings to " << newFileName;
}
}
catch (const std::exception& e)
{
Log(Debug::Error) << "Failed to save input bindings to " << newFileName << ": " << e.what();
}
saveBindings();
}
void BindingsManager::update(float dt)
@ -715,4 +699,25 @@ namespace MWInput
if (previousValue <= 0.6 && currentValue > 0.6)
manager->executeAction(action);
}
void BindingsManager::saveBindings()
{
const std::string newFileName = Files::pathToUnicodeString(mUserFile) + ".new";
try
{
if (mInputBinder->save(newFileName))
{
std::filesystem::rename(Files::pathFromUnicodeString(newFileName), mUserFile);
Log(Debug::Info) << "Saved input bindings: " << mUserFile;
}
else
{
Log(Debug::Error) << "Failed to save input bindings to " << newFileName;
}
}
catch (const std::exception& e)
{
Log(Debug::Error) << "Failed to save input bindings to " << newFileName << ": " << e.what();
}
}
}

View File

@ -65,6 +65,8 @@ namespace MWInput
void actionValueChanged(int action, float currentValue, float previousValue);
void saveBindings();
private:
void setupSDLKeyMappings();

View File

@ -263,4 +263,9 @@ namespace MWInput
{
mActionManager->executeAction(action);
}
void InputManager::saveBindings()
{
mBindingsManager->saveBindings();
}
}

View File

@ -109,6 +109,8 @@ namespace MWInput
private:
bool mControlsDisabled;
void saveBindings() override;
std::unique_ptr<SDLUtil::InputWrapper> mInputWrapper;
std::unique_ptr<BindingsManager> mBindingsManager;
std::unique_ptr<ControlSwitch> mControlSwitch;

View File

@ -43,7 +43,7 @@ namespace MWLua
void init();
void loadPermanentStorage(const std::filesystem::path& userConfigPath);
void savePermanentStorage(const std::filesystem::path& userConfigPath);
void savePermanentStorage(const std::filesystem::path& userConfigPath) override;
// \brief Executes lua handlers. Defaults to running in parallel with OSG Cull.
//

View File

@ -35,9 +35,9 @@ namespace MWLua
{
struct Shader
{
std::shared_ptr<fx::Technique> mShader;
std::shared_ptr<Fx::Technique> mShader;
Shader(std::shared_ptr<fx::Technique> shader)
Shader(std::shared_ptr<Fx::Technique> shader)
: mShader(std::move(shader))
{
}

View File

@ -28,7 +28,7 @@ namespace MWMechanics
class Actor
{
public:
Actor(const MWWorld::Ptr& ptr, MWRender::Animation* animation)
Actor(const MWWorld::Ptr& ptr, MWRender::Animation& animation)
: mCharacterController(ptr, animation)
, mPositionAdjusted(ptr.getClass().getCreatureStats(ptr).getFallHeight() > 0)
{
@ -62,14 +62,22 @@ namespace MWMechanics
void setPositionAdjusted(bool adjusted) { mPositionAdjusted = adjusted; }
bool getPositionAdjusted() const { return mPositionAdjusted; }
void invalidate()
{
mInvalid = true;
mCharacterController.detachAnimation();
}
bool isInvalid() const { return mInvalid; }
private:
CharacterController mCharacterController;
int mGreetingTimer{ 0 };
float mTargetAngleRadians{ 0.f };
GreetingState mGreetingState{ Greet_None };
bool mIsTurningToPlayer{ false };
Misc::DeviatingPeriodicTimer mEngageCombat{ 1.0f, 0.25f,
Misc::Rng::deviate(0, 0.25f, MWBase::Environment::get().getWorld()->getPrng()) };
bool mIsTurningToPlayer{ false };
bool mInvalid{ false };
bool mPositionAdjusted;
};

View File

@ -122,6 +122,8 @@ namespace
{
for (const MWMechanics::Actor& actor : actors)
{
if (actor.isInvalid())
continue;
const MWWorld::Ptr& iteratedActor = actor.getPtr();
if (iteratedActor == player || iteratedActor == actorPtr)
continue;
@ -345,7 +347,7 @@ namespace MWMechanics
// Find something nearby.
for (const Actor& otherActor : actors)
{
if (otherActor.getPtr() == ptr)
if (otherActor.isInvalid() || otherActor.getPtr() == ptr)
continue;
updateHeadTracking(
@ -681,7 +683,7 @@ namespace MWMechanics
}
}
if (creatureStats2.getMagicEffects().getOrDefault(ESM::MagicEffect::Invisibility).getMagnitude() > 0)
if (isTargetMagicallyHidden(actor2))
return;
// Stop here if target is unreachable
@ -1195,7 +1197,7 @@ namespace MWMechanics
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
if (!anim)
return;
const auto it = mActors.emplace(mActors.end(), ptr, anim);
const auto it = mActors.emplace(mActors.end(), ptr, *anim);
mIndex.emplace(ptr.mRef, it);
if (updateImmediately)
@ -1247,7 +1249,7 @@ namespace MWMechanics
{
if (!keepActive)
removeTemporaryEffects(iter->second->getPtr());
mActors.erase(iter->second);
iter->second->invalidate();
mIndex.erase(iter);
}
}
@ -1299,16 +1301,15 @@ namespace MWMechanics
void Actors::dropActors(const MWWorld::CellStore* cellStore, const MWWorld::Ptr& ignore)
{
for (auto iter = mActors.begin(); iter != mActors.end();)
for (Actor& actor : mActors)
{
if ((iter->getPtr().isInCell() && iter->getPtr().getCell() == cellStore) && iter->getPtr() != ignore)
if (!actor.isInvalid() && actor.getPtr().isInCell() && actor.getPtr().getCell() == cellStore
&& actor.getPtr() != ignore)
{
removeTemporaryEffects(iter->getPtr());
mIndex.erase(iter->getPtr().mRef);
iter = mActors.erase(iter);
removeTemporaryEffects(actor.getPtr());
mIndex.erase(actor.getPtr().mRef);
actor.invalidate();
}
else
++iter;
}
}
@ -1327,6 +1328,8 @@ namespace MWMechanics
const MWBase::World* const world = MWBase::Environment::get().getWorld();
for (const Actor& actor : mActors)
{
if (actor.isInvalid())
continue;
const MWWorld::Ptr& ptr = actor.getPtr();
if (ptr == player)
continue; // Don't interfere with player controls.
@ -1391,6 +1394,8 @@ namespace MWMechanics
// Iterate through all other actors and predict collisions.
for (const Actor& otherActor : mActors)
{
if (otherActor.isInvalid())
continue;
const MWWorld::Ptr& otherPtr = otherActor.getPtr();
if (otherPtr == ptr || otherPtr == currentTarget)
continue;
@ -1509,6 +1514,8 @@ namespace MWMechanics
// AI and magic effects update
for (Actor& actor : mActors)
{
if (actor.isInvalid())
continue;
const bool isPlayer = actor.getPtr() == player;
CharacterController& ctrl = actor.getCharacterController();
MWBase::LuaManager::ActorControls* luaControls
@ -1570,6 +1577,8 @@ namespace MWMechanics
for (const Actor& otherActor : mActors)
{
if (otherActor.isInvalid())
continue;
if (otherActor.getPtr() == actor.getPtr() || isPlayer) // player is not AI-controlled
continue;
engageCombat(
@ -1627,6 +1636,8 @@ namespace MWMechanics
CharacterController* playerCharacter = nullptr;
for (Actor& actor : mActors)
{
if (actor.isInvalid())
continue;
const float dist = (playerPos - actor.getPtr().getRefData().getPosition().asVec3()).length();
const bool isPlayer = actor.getPtr() == player;
CreatureStats& stats = actor.getPtr().getClass().getCreatureStats(actor.getPtr());
@ -1692,8 +1703,15 @@ namespace MWMechanics
luaControls->mJump = false;
}
for (const Actor& actor : mActors)
for (auto it = mActors.begin(); it != mActors.end();)
{
if (it->isInvalid())
{
it = mActors.erase(it);
continue;
}
const Actor& actor = *it;
it++;
const MWWorld::Class& cls = actor.getPtr().getClass();
CreatureStats& stats = cls.getCreatureStats(actor.getPtr());
@ -1743,6 +1761,8 @@ namespace MWMechanics
{
for (Actor& actor : mActors)
{
if (actor.isInvalid())
continue;
const MWWorld::Class& cls = actor.getPtr().getClass();
CreatureStats& stats = cls.getCreatureStats(actor.getPtr());
@ -1830,6 +1850,8 @@ namespace MWMechanics
{
for (const Actor& actor : mActors)
{
if (actor.isInvalid())
continue;
MWMechanics::ActiveSpells& spells
= actor.getPtr().getClass().getCreatureStats(actor.getPtr()).getActiveSpells();
spells.purge(actor.getPtr(), casterActorId);
@ -1849,6 +1871,8 @@ namespace MWMechanics
for (const Actor& actor : mActors)
{
if (actor.isInvalid())
continue;
if (actor.getPtr().getClass().getCreatureStats(actor.getPtr()).isDead())
{
adjustMagicEffects(actor.getPtr(), duration);
@ -2046,7 +2070,10 @@ namespace MWMechanics
void Actors::persistAnimationStates() const
{
for (const Actor& actor : mActors)
actor.getCharacterController().persistAnimationState();
{
if (!actor.isInvalid())
actor.getCharacterController().persistAnimationState();
}
}
void Actors::clearAnimationQueue(const MWWorld::Ptr& ptr, bool clearScripted)
@ -2060,6 +2087,8 @@ namespace MWMechanics
{
for (const Actor& actor : mActors)
{
if (actor.isInvalid())
continue;
if ((actor.getPtr().getRefData().getPosition().asVec3() - position).length2() <= radius * radius)
out.push_back(actor.getPtr());
}
@ -2069,6 +2098,8 @@ namespace MWMechanics
{
for (const Actor& actor : mActors)
{
if (actor.isInvalid())
continue;
if ((actor.getPtr().getRefData().getPosition().asVec3() - position).length2() <= radius * radius)
return true;
}
@ -2082,6 +2113,8 @@ namespace MWMechanics
list.push_back(actorPtr);
for (const Actor& actor : mActors)
{
if (actor.isInvalid())
continue;
const MWWorld::Ptr& iteratedActor = actor.getPtr();
if (iteratedActor == getPlayer())
continue;
@ -2352,10 +2385,11 @@ namespace MWMechanics
if (!MWBase::Environment::get().getMechanicsManager()->isAIActive())
return;
for (auto it = mActors.begin(); it != mActors.end();)
for (const Actor& actor : mActors)
{
const MWWorld::Ptr ptr = it->getPtr();
++it;
if (actor.isInvalid())
continue;
const MWWorld::Ptr ptr = actor.getPtr();
if (ptr == getPlayer() || !isConscious(ptr) || ptr.getClass().getCreatureStats(ptr).isParalyzed())
continue;
MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence();

View File

@ -535,7 +535,7 @@ namespace MWMechanics
bool CharacterController::onOpen() const
{
if (mPtr.getType() == ESM::Container::sRecordId)
if (mPtr.getType() == ESM::Container::sRecordId && mAnimation)
{
if (!mAnimation->hasAnimation("containeropen"))
return true;
@ -559,7 +559,7 @@ namespace MWMechanics
{
if (mPtr.getType() == ESM::Container::sRecordId)
{
if (!mAnimation->hasAnimation("containerclose"))
if (!mAnimation || !mAnimation->hasAnimation("containerclose"))
return;
float complete, startPoint = 0.f;
@ -886,11 +886,12 @@ namespace MWMechanics
if (mDeathState == CharState_None && MWBase::Environment::get().getWorld()->isSwimming(mPtr))
mDeathState = CharState_SwimDeath;
if (mDeathState == CharState_None || !mAnimation->hasAnimation(deathStateToAnimGroup(mDeathState)))
if (mDeathState == CharState_None
|| (mAnimation && !mAnimation->hasAnimation(deathStateToAnimGroup(mDeathState))))
mDeathState = chooseRandomDeathState();
// Do not interrupt scripted animation by death
if (isScriptedAnimPlaying())
if (!mAnimation || isScriptedAnimPlaying())
return;
playDeath(startpoint, mDeathState);
@ -910,13 +911,10 @@ namespace MWMechanics
return result;
}
CharacterController::CharacterController(const MWWorld::Ptr& ptr, MWRender::Animation* anim)
CharacterController::CharacterController(const MWWorld::Ptr& ptr, MWRender::Animation& anim)
: mPtr(ptr)
, mAnimation(anim)
, mAnimation(&anim)
{
if (!mAnimation)
return;
mAnimation->setTextKeyListener(this);
const MWWorld::Class& cls = mPtr.getClass();
@ -992,17 +990,25 @@ namespace MWMechanics
}
CharacterController::~CharacterController()
{
detachAnimation();
}
void CharacterController::detachAnimation()
{
if (mAnimation)
{
persistAnimationState();
mAnimation->setTextKeyListener(nullptr);
mAnimation = nullptr;
}
}
void CharacterController::handleTextKey(
std::string_view groupname, SceneUtil::TextKeyMap::ConstIterator key, const SceneUtil::TextKeyMap& map)
{
if (!mAnimation)
return;
std::string_view evt = key->second;
MWBase::Environment::get().getLuaManager()->animationTextKey(mPtr, key->second);
@ -1232,7 +1238,8 @@ namespace MWMechanics
float CharacterController::calculateWindUp() const
{
if (mCurrentWeapon.empty() || mWeaponType == ESM::Weapon::PickProbe || isRandomAttackAnimation(mCurrentWeapon))
if (!mAnimation || mCurrentWeapon.empty() || mWeaponType == ESM::Weapon::PickProbe
|| isRandomAttackAnimation(mCurrentWeapon))
return -1.f;
float minAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon + ": " + mAttackType + " min attack");
@ -1950,6 +1957,8 @@ namespace MWMechanics
void CharacterController::update(float duration)
{
if (!mAnimation)
return;
MWBase::World* world = MWBase::Environment::get().getWorld();
MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager();
const MWWorld::Class& cls = mPtr.getClass();
@ -2528,7 +2537,7 @@ namespace MWMechanics
ESM::AnimationState::ScriptedAnimation anim;
anim.mGroup = iter->mGroup;
if (iter == mAnimQueue.begin())
if (iter == mAnimQueue.begin() && mAnimation)
{
float complete;
size_t loopcount;
@ -2741,23 +2750,18 @@ namespace MWMechanics
void CharacterController::clearAnimQueue(bool clearScriptedAnims)
{
// Do not interrupt scripted animations, if we want to keep them
if ((!isScriptedAnimPlaying() || clearScriptedAnims) && !mAnimQueue.empty())
if (mAnimation && (!isScriptedAnimPlaying() || clearScriptedAnims) && !mAnimQueue.empty())
mAnimation->disable(mAnimQueue.front().mGroup);
if (clearScriptedAnims)
{
mAnimation->setPlayScriptedOnly(false);
if (mAnimation)
mAnimation->setPlayScriptedOnly(false);
mAnimQueue.clear();
return;
}
for (AnimationQueue::iterator it = mAnimQueue.begin(); it != mAnimQueue.end();)
{
if (!it->mScripted)
it = mAnimQueue.erase(it);
else
++it;
}
std::erase_if(mAnimQueue, [](const AnimationQueueEntry& entry) { return !entry.mScripted; });
}
void CharacterController::forceStateUpdate()
@ -2866,6 +2870,8 @@ namespace MWMechanics
void CharacterController::setVisibility(float visibility) const
{
if (!mAnimation)
return;
// We should take actor's invisibility in account
if (mPtr.getClass().isActor())
{
@ -2926,7 +2932,7 @@ namespace MWMechanics
bool CharacterController::isReadyToBlock() const
{
return updateCarriedLeftVisible(mWeaponType);
return mAnimation && updateCarriedLeftVisible(mWeaponType);
}
bool CharacterController::isKnockedDown() const
@ -3030,7 +3036,8 @@ namespace MWMechanics
void CharacterController::setActive(int active) const
{
mAnimation->setActive(active);
if (mAnimation)
mAnimation->setActive(active);
}
void CharacterController::setHeadTrackTarget(const MWWorld::ConstPtr& target)
@ -3061,6 +3068,8 @@ namespace MWMechanics
float CharacterController::getAnimationMovementDirection() const
{
if (!mAnimation)
return 0.f;
switch (mMovementState)
{
case CharState_RunLeft:
@ -3155,6 +3164,8 @@ namespace MWMechanics
MWWorld::MovementDirectionFlags CharacterController::getSupportedMovementDirections() const
{
if (!mAnimation)
return 0;
using namespace std::string_view_literals;
// There are fallbacks in the CharacterController::refreshMovementAnims for certain animations. Arrays below
// represent them.

View File

@ -252,13 +252,21 @@ namespace MWMechanics
void prepareHit();
void unpersistAnimationState();
void playBlendedAnimation(const std::string& groupname, const MWRender::AnimPriority& priority, int blendMask,
bool autodisable, float speedmult, std::string_view start, std::string_view stop, float startpoint,
uint32_t loops, bool loopfallback = false) const;
public:
CharacterController(const MWWorld::Ptr& ptr, MWRender::Animation* anim);
CharacterController(const MWWorld::Ptr& ptr, MWRender::Animation& anim);
virtual ~CharacterController();
CharacterController(const CharacterController&) = delete;
CharacterController(CharacterController&&) = delete;
void detachAnimation();
const MWWorld::Ptr& getPtr() const { return mPtr; }
void handleTextKey(std::string_view groupname, SceneUtil::TextKeyMap::ConstIterator key,
@ -275,11 +283,6 @@ namespace MWMechanics
void onClose() const;
void persistAnimationState() const;
void unpersistAnimationState();
void playBlendedAnimation(const std::string& groupname, const MWRender::AnimPriority& priority, int blendMask,
bool autodisable, float speedmult, std::string_view start, std::string_view stop, float startpoint,
uint32_t loops, bool loopfallback = false) const;
bool playGroup(std::string_view groupname, int mode, uint32_t count, bool scripted = false);
bool playGroupLua(std::string_view groupname, float speed, std::string_view startKey, std::string_view stopKey,
uint32_t loops, bool forceLoop);

View File

@ -368,17 +368,28 @@ namespace MWMechanics
bool MechanicsManager::isRunning(const MWWorld::Ptr& ptr)
{
return mActors.isRunning(ptr);
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
if (!stats.getStance(MWMechanics::CreatureStats::Stance_Run))
return false;
if (mActors.isRunning(ptr))
return true;
MWBase::World* world = MWBase::Environment::get().getWorld();
return !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr);
}
bool MechanicsManager::isSneaking(const MWWorld::Ptr& ptr)
{
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
if (!stats.getStance(MWMechanics::CreatureStats::Stance_Sneak))
return false;
if (mActors.isSneaking(ptr))
return true;
MWBase::World* world = MWBase::Environment::get().getWorld();
bool animActive = mActors.isSneaking(ptr);
bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr);
return stanceOn && (animActive || inair);
return !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr);
}
void MechanicsManager::rest(double hours, bool sleep)
@ -1725,6 +1736,8 @@ namespace MWMechanics
.getActorId()); // Stops guard from ending combat if player is unreachable
for (const Actor& actor : mActors)
{
if (actor.isInvalid())
continue;
if (actor.getPtr().getClass().isClass(actor.getPtr(), "Guard"))
{
MWMechanics::AiSequence& aiSeq

View File

@ -20,7 +20,7 @@ namespace MWMechanics
if (anim == nullptr)
return;
const auto it = mObjects.emplace(mObjects.end(), ptr, anim);
const auto it = mObjects.emplace(mObjects.end(), ptr, *anim);
mIndex.emplace(ptr.mRef, it);
}

View File

@ -154,7 +154,7 @@ namespace MWRender
float mLoopStopTime = 0;
float mStopTime = 0;
std::shared_ptr<float> mTime = std::make_shared<float>(0);
std::shared_ptr<float> mTime = std::make_shared<float>(0.0f);
float mSpeedMult = 1;
bool mPlaying = false;

View File

@ -58,8 +58,6 @@ namespace MWRender
default:
return false;
}
return false;
}
void Pathgrid::addCell(const MWWorld::CellStore* store)

View File

@ -46,7 +46,7 @@ namespace MWRender
mMultiviewResolveStateSet->addUniform(new osg::Uniform("lastShader", 0));
}
void PingPongCanvas::setPasses(fx::DispatchArray&& passes)
void PingPongCanvas::setPasses(Fx::DispatchArray&& passes)
{
mPasses = std::move(passes);
}
@ -54,8 +54,8 @@ namespace MWRender
void PingPongCanvas::setMask(bool underwater, bool exterior)
{
mMask = 0;
mMask |= underwater ? fx::Technique::Flag_Disable_Underwater : fx::Technique::Flag_Disable_Abovewater;
mMask |= exterior ? fx::Technique::Flag_Disable_Exteriors : fx::Technique::Flag_Disable_Interiors;
mMask |= underwater ? Fx::Technique::Flag_Disable_Underwater : Fx::Technique::Flag_Disable_Abovewater;
mMask |= exterior ? Fx::Technique::Flag_Disable_Exteriors : Fx::Technique::Flag_Disable_Interiors;
}
void PingPongCanvas::drawGeometry(osg::RenderInfo& renderInfo) const

View File

@ -31,14 +31,14 @@ namespace MWRender
void dirty() { mDirty = true; }
void setDirtyAttachments(const std::vector<fx::Types::RenderTarget>& attachments)
void setDirtyAttachments(const std::vector<Fx::Types::RenderTarget>& attachments)
{
mDirtyAttachments = attachments;
}
const fx::DispatchArray& getPasses() { return mPasses; }
const Fx::DispatchArray& getPasses() { return mPasses; }
void setPasses(fx::DispatchArray&& passes);
void setPasses(Fx::DispatchArray&& passes);
void setMask(bool underwater, bool exterior);
@ -60,8 +60,8 @@ namespace MWRender
bool mAvgLum = false;
bool mPostprocessing = false;
fx::DispatchArray mPasses;
fx::FlagsType mMask = 0;
Fx::DispatchArray mPasses;
Fx::FlagsType mMask = 0;
osg::ref_ptr<osg::Program> mFallbackProgram;
osg::ref_ptr<osg::Program> mMultiviewResolveProgram;
@ -74,7 +74,7 @@ namespace MWRender
osg::ref_ptr<osg::Texture> mTextureDistortion;
mutable bool mDirty = false;
mutable std::vector<fx::Types::RenderTarget> mDirtyAttachments;
mutable std::vector<Fx::Types::RenderTarget> mDirtyAttachments;
mutable osg::ref_ptr<osg::Viewport> mRenderViewport;
mutable osg::ref_ptr<osg::FrameBufferObject> mMultiviewResolveFramebuffer;
mutable osg::ref_ptr<osg::FrameBufferObject> mDestinationFBO;

View File

@ -207,7 +207,7 @@ namespace MWRender
mGLSLVersion = ext->glslLanguageVersion * 100;
mUBO = ext->isUniformBufferObjectSupported && mGLSLVersion >= 330;
mStateUpdater = new fx::StateUpdater(mUBO);
mStateUpdater = new Fx::StateUpdater(mUBO);
addChild(mHUDCamera);
addChild(mRootNode);
@ -251,10 +251,10 @@ namespace MWRender
void PostProcessor::populateTechniqueFiles()
{
for (const auto& path : mVFS->getRecursiveDirectoryIterator(fx::Technique::sSubdir))
for (const auto& path : mVFS->getRecursiveDirectoryIterator(Fx::Technique::sSubdir))
{
std::string_view fileExt = Misc::getFileExtension(path);
if (path.parent().parent().empty() && fileExt == fx::Technique::sExt)
if (path.parent().parent().empty() && fileExt == Fx::Technique::sExt)
{
mTechniqueFiles.emplace(path);
}
@ -347,7 +347,7 @@ namespace MWRender
for (auto& technique : mTechniques)
{
if (technique->getStatus() == fx::Technique::Status::File_Not_exists)
if (technique->getStatus() == Fx::Technique::Status::File_Not_exists)
continue;
const auto lastWriteTime = mVFS->getLastModified(technique->getFileName());
@ -400,7 +400,7 @@ namespace MWRender
createObjectsForFrame(frameId);
mDirty = false;
mCanvases[frameId]->setPasses(fx::DispatchArray(mTemplateData));
mCanvases[frameId]->setPasses(Fx::DispatchArray(mTemplateData));
}
if ((mNormalsSupported && mNormals != mPrevNormals) || (mPassLights != mPrevPassLights))
@ -565,7 +565,7 @@ namespace MWRender
mNormals = false;
mPassLights = false;
std::vector<fx::Types::RenderTarget> attachmentsToDirty;
std::vector<Fx::Types::RenderTarget> attachmentsToDirty;
for (const auto& technique : mTechniques)
{
@ -579,7 +579,7 @@ namespace MWRender
continue;
}
fx::DispatchNode node;
Fx::DispatchNode node;
node.mFlags = technique->getFlags();
@ -592,7 +592,7 @@ namespace MWRender
if (technique->getLights())
mPassLights = true;
if (node.mFlags & fx::Technique::Flag_Disable_SunGlare)
if (node.mFlags & Fx::Technique::Flag_Disable_SunGlare)
sunglare = false;
// required default samplers available to every shader pass
@ -638,7 +638,7 @@ namespace MWRender
for (const auto& pass : technique->getPasses())
{
int subTexUnit = texUnit;
fx::DispatchNode::SubPass subPass;
Fx::DispatchNode::SubPass subPass;
pass->prepareStateSet(subPass.mStateSet, technique->getName());
@ -673,7 +673,7 @@ namespace MWRender
[renderTarget](const auto& rt) { return renderTarget.mTarget == rt.mTarget; })
== attachmentsToDirty.cend())
{
attachmentsToDirty.push_back(fx::Types::RenderTarget(renderTarget));
attachmentsToDirty.push_back(Fx::Types::RenderTarget(renderTarget));
}
}
@ -692,7 +692,7 @@ namespace MWRender
[renderTarget](const auto& rt) { return renderTarget.mTarget == rt.mTarget; })
== attachmentsToDirty.cend())
{
attachmentsToDirty.push_back(fx::Types::RenderTarget(renderTarget));
attachmentsToDirty.push_back(Fx::Types::RenderTarget(renderTarget));
}
subTexUnit++;
}
@ -705,7 +705,7 @@ namespace MWRender
mTemplateData.emplace_back(std::move(node));
}
mCanvases[frameId]->setPasses(fx::DispatchArray(mTemplateData));
mCanvases[frameId]->setPasses(Fx::DispatchArray(mTemplateData));
if (auto hud = MWBase::Environment::get().getWindowManager()->getPostProcessorHud())
hud->updateTechniques();
@ -717,7 +717,7 @@ namespace MWRender
}
PostProcessor::Status PostProcessor::enableTechnique(
std::shared_ptr<fx::Technique> technique, std::optional<int> location)
std::shared_ptr<Fx::Technique> technique, std::optional<int> location)
{
if (technique->getLocked() || (location.has_value() && location.value() < 0))
return Status_Error;
@ -732,7 +732,7 @@ namespace MWRender
return Status_Toggled;
}
PostProcessor::Status PostProcessor::disableTechnique(std::shared_ptr<fx::Technique> technique, bool dirty)
PostProcessor::Status PostProcessor::disableTechnique(std::shared_ptr<Fx::Technique> technique, bool dirty)
{
if (technique->getLocked())
return Status_Error;
@ -748,7 +748,7 @@ namespace MWRender
return Status_Toggled;
}
bool PostProcessor::isTechniqueEnabled(const std::shared_ptr<fx::Technique>& technique) const
bool PostProcessor::isTechniqueEnabled(const std::shared_ptr<Fx::Technique>& technique) const
{
if (auto it = std::find(mTechniques.begin(), mTechniques.end(), technique); it == mTechniques.end())
return false;
@ -756,13 +756,13 @@ namespace MWRender
return technique->isValid();
}
std::shared_ptr<fx::Technique> PostProcessor::loadTechnique(std::string_view name, bool loadNextFrame)
std::shared_ptr<Fx::Technique> PostProcessor::loadTechnique(std::string_view name, bool loadNextFrame)
{
VFS::Path::Normalized path = fx::Technique::makeFileName(name);
VFS::Path::Normalized path = Fx::Technique::makeFileName(name);
return loadTechnique(VFS::Path::NormalizedView(path), loadNextFrame);
}
std::shared_ptr<fx::Technique> PostProcessor::loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame)
std::shared_ptr<Fx::Technique> PostProcessor::loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame)
{
for (const auto& technique : mTemplates)
if (technique->getFileName() == path)
@ -778,12 +778,12 @@ namespace MWRender
else
name = path.stem();
auto technique = std::make_shared<fx::Technique>(*mVFS, *mRendering.getResourceSystem()->getImageManager(),
auto technique = std::make_shared<Fx::Technique>(*mVFS, *mRendering.getResourceSystem()->getImageManager(),
path, std::move(name), renderWidth(), renderHeight(), mUBO, mNormalsSupported);
technique->compile();
if (technique->getStatus() != fx::Technique::Status::File_Not_exists)
if (technique->getStatus() != Fx::Technique::Status::File_Not_exists)
technique->setLastModificationTime(mVFS->getLastModified(path));
if (loadNextFrame)
@ -840,7 +840,7 @@ namespace MWRender
{
for (auto& technique : mTemplates)
{
if (technique->getStatus() == fx::Technique::Status::File_Not_exists)
if (technique->getStatus() == Fx::Technique::Status::File_Not_exists)
continue;
technique->compile();
}

View File

@ -58,7 +58,7 @@ namespace MWRender
public:
using FBOArray = std::array<osg::ref_ptr<osg::FrameBufferObject>, 6>;
using TextureArray = std::array<osg::ref_ptr<osg::Texture>, 6>;
using TechniqueList = std::vector<std::shared_ptr<fx::Technique>>;
using TechniqueList = std::vector<std::shared_ptr<Fx::Technique>>;
enum TextureIndex
{
@ -122,7 +122,7 @@ namespace MWRender
osg::ref_ptr<osg::Camera> getHUDCamera() { return mHUDCamera; }
osg::ref_ptr<fx::StateUpdater> getStateUpdater() { return mStateUpdater; }
osg::ref_ptr<Fx::StateUpdater> getStateUpdater() { return mStateUpdater; }
const TechniqueList& getTechniques() { return mTechniques; }
@ -132,14 +132,14 @@ namespace MWRender
void resize();
Status enableTechnique(std::shared_ptr<fx::Technique> technique, std::optional<int> location = std::nullopt);
Status enableTechnique(std::shared_ptr<Fx::Technique> technique, std::optional<int> location = std::nullopt);
Status disableTechnique(std::shared_ptr<fx::Technique> technique, bool dirty = true);
Status disableTechnique(std::shared_ptr<Fx::Technique> technique, bool dirty = true);
bool getSupportsNormalsRT() const { return mNormalsSupported; }
template <class T>
void setUniform(std::shared_ptr<fx::Technique> technique, const std::string& name, const T& value)
void setUniform(std::shared_ptr<Fx::Technique> technique, const std::string& name, const T& value)
{
if (!isEnabled())
return;
@ -158,7 +158,7 @@ namespace MWRender
(*it)->setValue(value);
}
std::optional<size_t> getUniformSize(std::shared_ptr<fx::Technique> technique, const std::string& name)
std::optional<size_t> getUniformSize(std::shared_ptr<Fx::Technique> technique, const std::string& name)
{
auto it = technique->findUniform(name);
@ -168,7 +168,7 @@ namespace MWRender
return (*it)->getNumElements();
}
bool isTechniqueEnabled(const std::shared_ptr<fx::Technique>& technique) const;
bool isTechniqueEnabled(const std::shared_ptr<Fx::Technique>& technique) const;
void setExteriorFlag(bool exterior) { mExteriorFlag = exterior; }
@ -176,8 +176,8 @@ namespace MWRender
void toggleMode();
std::shared_ptr<fx::Technique> loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame = false);
std::shared_ptr<fx::Technique> loadTechnique(std::string_view name, bool loadNextFrame = false);
std::shared_ptr<Fx::Technique> loadTechnique(VFS::Path::NormalizedView path, bool loadNextFrame = false);
std::shared_ptr<Fx::Technique> loadTechnique(std::string_view name, bool loadNextFrame = false);
TechniqueList getChain();
@ -263,13 +263,13 @@ namespace MWRender
int mHeight;
int mSamples;
osg::ref_ptr<fx::StateUpdater> mStateUpdater;
osg::ref_ptr<Fx::StateUpdater> mStateUpdater;
osg::ref_ptr<PingPongCull> mPingPongCull;
std::array<osg::ref_ptr<PingPongCanvas>, 2> mCanvases;
osg::ref_ptr<TransparentDepthBinCallback> mTransparentDepthPostPass;
osg::ref_ptr<DistortionCallback> mDistortionCallback;
fx::DispatchArray mTemplateData;
Fx::DispatchArray mTemplateData;
};
}

View File

@ -164,14 +164,7 @@ namespace MWScript
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
MWBase::World* world = MWBase::Environment::get().getWorld();
bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Run);
bool running = MWBase::Environment::get().getMechanicsManager()->isRunning(ptr);
bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr);
runtime.push(stanceOn && (running || inair));
runtime.push(MWBase::Environment::get().getMechanicsManager()->isRunning(ptr));
}
};

View File

@ -34,7 +34,7 @@
namespace
{
const int sLoudnessFPS = 20; // loudness values per second of audio
const float sLoudnessFPS = 20.0f; // loudness values per second of audio
ALCenum checkALCError(ALCdevice* device, const char* func, int line)
{

View File

@ -55,7 +55,7 @@ void MWWorld::InventoryStore::storeEquipmentState(
}
if (mSelectedEnchantItem.getType() != -1 && mSelectedEnchantItem->getBase() == &ref)
inventory.mSelectedEnchantItem = index;
inventory.mSelectedEnchantItem = static_cast<uint32_t>(index);
}
void MWWorld::InventoryStore::readEquipmentState(

View File

@ -45,7 +45,7 @@ int main(int argc, char* argv[])
resourcesPath = Files::pathToQString(variables["resources"].as<Files::MaybeQuotedPath>().u8string());
}
l10n::installQtTranslations(app, "wizard", resourcesPath);
L10n::installQtTranslations(app, "wizard", resourcesPath);
Wizard::MainWizard wizard(std::move(configurationManager));

View File

@ -5,10 +5,12 @@
#include <string>
#include <vector>
// NOLINTBEGIN(readability-identifier-naming)
namespace boost
{
class any;
}
// NOLINTEND(readability-identifier-naming)
namespace Fallback
{

View File

@ -9,11 +9,13 @@
#include <components/files/collections.hpp>
#include <components/files/fixedpath.hpp>
// NOLINTBEGIN(readability-identifier-naming)
namespace boost::program_options
{
class options_description;
class variables_map;
}
// NOLINTEND(readability-identifier-naming)
/**
* \namespace Files

View File

@ -276,8 +276,8 @@ namespace Gui
{
Log(Debug::Info) << "Loading font file " << fileName;
osgMyGUI::DataManager* dataManager
= dynamic_cast<osgMyGUI::DataManager*>(&osgMyGUI::DataManager::getInstance());
MyGUIPlatform::DataManager* dataManager
= dynamic_cast<MyGUIPlatform::DataManager*>(&MyGUIPlatform::DataManager::getInstance());
if (!dataManager)
{
Log(Debug::Error) << "Can not load TrueType font " << fontId << ": osgMyGUI::DataManager is not available.";
@ -287,7 +287,7 @@ namespace Gui
// TODO: it may be worth to take in account resolution change, but it is not safe to replace used assets
std::unique_ptr<MyGUI::IDataStream> layersStream(dataManager->getData("openmw_layers.xml"));
MyGUI::IntSize bookSize = getBookSize(layersStream.get());
float bookScale = osgMyGUI::ScalingLayer::getScaleFactor(bookSize);
float bookScale = MyGUIPlatform::ScalingLayer::getScaleFactor(bookSize);
const auto oldDataPath = dataManager->getDataPath({});
dataManager->setResourcePath("fonts");

View File

@ -8,7 +8,7 @@
#include <components/misc/strings/format.hpp>
namespace fx
namespace Fx
{
namespace Lexer
{

View File

@ -9,7 +9,7 @@
#include "lexertypes.hpp"
namespace fx
namespace Fx
{
namespace Lexer
{

View File

@ -4,7 +4,7 @@
#include <string_view>
#include <variant>
namespace fx
namespace Fx
{
namespace Lexer
{

View File

@ -13,11 +13,11 @@
#include "technique.hpp"
namespace fx
namespace Fx
{
namespace constants
namespace Constants
{
constexpr std::array<std::pair<std::string_view, fx::FlagsType>, 6> TechniqueFlag = { {
constexpr std::array<std::pair<std::string_view, Fx::FlagsType>, 6> TechniqueFlag = { {
{ "disable_interiors", Technique::Flag_Disable_Interiors },
{ "disable_exteriors", Technique::Flag_Disable_Exteriors },
{ "disable_underwater", Technique::Flag_Disable_Underwater },

View File

@ -49,7 +49,7 @@ void main()
}
namespace fx
namespace Fx
{
Pass::Pass(Pass::Type type, Pass::Order order, bool ubo)
: mCompiled(false)

View File

@ -18,7 +18,7 @@ namespace osg
class StateSet;
}
namespace fx
namespace Fx
{
class Technique;

View File

@ -5,7 +5,7 @@
#include <components/resource/scenemanager.hpp>
namespace fx
namespace Fx
{
std::string StateUpdater::sDefinition = UniformData::getDefinition("_omw_data");

View File

@ -7,7 +7,7 @@
#include <components/sceneutil/statesetupdater.hpp>
#include <components/std140/ubo.hpp>
namespace fx
namespace Fx
{
class StateUpdater : public SceneUtil::StateSetUpdater
{

View File

@ -35,7 +35,7 @@ namespace
};
}
namespace fx
namespace Fx
{
VFS::Path::Normalized Technique::makeFileName(std::string_view name)
{
@ -280,7 +280,7 @@ namespace fx
if (mRenderTargets.count(mBlockName))
error(Misc::StringUtils::format("redeclaration of render target '%s'", std::string(mBlockName)));
fx::Types::RenderTarget rt;
Fx::Types::RenderTarget rt;
rt.mTarget->setTextureSize(mWidth, mHeight);
rt.mTarget->setSourceFormat(GL_RGB);
rt.mTarget->setInternalFormat(GL_RGB);
@ -341,7 +341,7 @@ namespace fx
auto& pass = mPassMap[mBlockName];
if (!pass)
pass = std::make_shared<fx::Pass>();
pass = std::make_shared<Fx::Pass>();
pass->mName = mBlockName;
@ -364,7 +364,7 @@ namespace fx
auto& pass = mPassMap[mBlockName];
if (!pass)
pass = std::make_shared<fx::Pass>();
pass = std::make_shared<Fx::Pass>();
pass->mUBO = mUBO;
pass->mName = mBlockName;
@ -388,7 +388,7 @@ namespace fx
auto& pass = mPassMap[mBlockName];
if (!pass)
pass = std::make_shared<fx::Pass>();
pass = std::make_shared<Fx::Pass>();
pass->mName = mBlockName;
@ -810,7 +810,7 @@ namespace fx
auto& pass = mPassMap[mBlockName];
if (!pass)
pass = std::make_shared<fx::Pass>();
pass = std::make_shared<Fx::Pass>();
while (!isNext<Lexer::Eof>())
{
@ -883,7 +883,7 @@ namespace fx
FlagsType Technique::parseFlags()
{
auto parseBit = [this](std::string_view term) {
for (const auto& [identifer, bit] : constants::TechniqueFlag)
for (const auto& [identifer, bit] : Constants::TechniqueFlag)
{
if (Misc::StringUtils::ciEqual(term, identifer))
return bit;
@ -902,7 +902,7 @@ namespace fx
{
expect<Lexer::Literal>();
for (const auto& [identifer, mode] : constants::FilterMode)
for (const auto& [identifer, mode] : Constants::FilterMode)
{
if (asLiteral() == identifer)
return mode;
@ -915,7 +915,7 @@ namespace fx
{
expect<Lexer::Literal>();
for (const auto& [identifer, mode] : constants::WrapMode)
for (const auto& [identifer, mode] : Constants::WrapMode)
{
if (asLiteral() == identifer)
return mode;
@ -933,7 +933,7 @@ namespace fx
{
expect<Lexer::Literal>();
for (const auto& [identifer, mode] : constants::Compression)
for (const auto& [identifer, mode] : Constants::Compression)
{
if (asLiteral() == identifer)
return mode;
@ -946,7 +946,7 @@ namespace fx
{
expect<Lexer::Literal>();
for (const auto& [identifer, mode] : constants::InternalFormat)
for (const auto& [identifer, mode] : Constants::InternalFormat)
{
if (asLiteral() == identifer)
return mode;
@ -959,7 +959,7 @@ namespace fx
{
expect<Lexer::Literal>();
for (const auto& [identifer, mode] : constants::SourceType)
for (const auto& [identifer, mode] : Constants::SourceType)
{
if (asLiteral() == identifer)
return mode;
@ -972,7 +972,7 @@ namespace fx
{
expect<Lexer::Literal>();
for (const auto& [identifer, mode] : constants::SourceFormat)
for (const auto& [identifer, mode] : Constants::SourceFormat)
{
if (asLiteral() == identifer)
return mode;
@ -985,7 +985,7 @@ namespace fx
{
expect<Lexer::Literal>();
for (const auto& [identifer, mode] : constants::BlendEquation)
for (const auto& [identifer, mode] : Constants::BlendEquation)
{
if (asLiteral() == identifer)
return mode;
@ -998,7 +998,7 @@ namespace fx
{
expect<Lexer::Literal>();
for (const auto& [identifer, mode] : constants::BlendFunc)
for (const auto& [identifer, mode] : Constants::BlendFunc)
{
if (asLiteral() == identifer)
return mode;
@ -1025,11 +1025,11 @@ namespace fx
*/
expect<Lexer::Open_Parenthesis>();
std::vector<fx::Types::Choice<SrcT>> choices;
std::vector<Fx::Types::Choice<SrcT>> choices;
while (!isNext<Lexer::Eof>())
{
fx::Types::Choice<SrcT> choice;
Fx::Types::Choice<SrcT> choice;
choice.mLabel = parseString();
expect<Lexer::Equal>();
choice.mValue = getUniformValue<SrcT, T>();

View File

@ -29,7 +29,7 @@ namespace VFS
class Manager;
}
namespace fx
namespace Fx
{
using FlagsType = size_t;
@ -85,7 +85,7 @@ namespace fx
}
// not safe to read/write in draw thread
std::shared_ptr<fx::Technique> mHandle = nullptr;
std::shared_ptr<Fx::Technique> mHandle = nullptr;
FlagsType mFlags = 0;

View File

@ -12,7 +12,7 @@
#include <components/sceneutil/depth.hpp>
#include <components/settings/shadermanager.hpp>
namespace fx
namespace Fx
{
namespace Types
{

View File

@ -6,7 +6,7 @@ namespace
{
template <class T, class WidgetT>
void createVectorWidget(
const std::shared_ptr<fx::Types::UniformBase>& uniform, MyGUI::Widget* client, fx::Widgets::UniformBase* base)
const std::shared_ptr<Fx::Types::UniformBase>& uniform, MyGUI::Widget* client, Fx::Widgets::UniformBase* base)
{
int height = client->getHeight();
base->setSize(base->getSize().width, (base->getSize().height - height) + (height * T::num_components));
@ -16,13 +16,13 @@ namespace
{
auto* widget = client->createWidget<WidgetT>(
"MW_ValueEditNumber", { 0, height * i, client->getWidth(), height }, MyGUI::Align::Default);
widget->setData(uniform, static_cast<fx::Widgets::Index>(i));
widget->setData(uniform, static_cast<Fx::Widgets::Index>(i));
base->addItem(widget);
}
}
}
namespace fx
namespace Fx
{
namespace Widgets
{
@ -127,7 +127,7 @@ namespace fx
mChoices->eventComboChangePosition += MyGUI::newDelegate(this, &EditChoice::notifyComboBoxChanged);
}
void UniformBase::init(const std::shared_ptr<fx::Types::UniformBase>& uniform)
void UniformBase::init(const std::shared_ptr<Fx::Types::UniformBase>& uniform)
{
if (uniform->mDisplayName.empty())
mLabel->setCaption(uniform->mName);

View File

@ -28,7 +28,7 @@ namespace Gui
class AutoSizedButton;
}
namespace fx
namespace Fx
{
namespace Widgets
{
@ -46,7 +46,7 @@ namespace fx
public:
virtual ~EditBase() = default;
void setData(const std::shared_ptr<fx::Types::UniformBase>& uniform, Index index = None)
void setData(const std::shared_ptr<Fx::Types::UniformBase>& uniform, Index index = None)
{
mUniform = uniform;
mIndex = index;
@ -57,7 +57,7 @@ namespace fx
virtual void toDefault() = 0;
protected:
std::shared_ptr<fx::Types::UniformBase> mUniform;
std::shared_ptr<Fx::Types::UniformBase> mUniform;
Index mIndex;
};
@ -268,7 +268,7 @@ namespace fx
MYGUI_RTTI_DERIVED(UniformBase)
public:
void init(const std::shared_ptr<fx::Types::UniformBase>& uniform);
void init(const std::shared_ptr<Fx::Types::UniformBase>& uniform);
void toDefault();

View File

@ -6,7 +6,7 @@
#include <components/debug/debuglog.hpp>
#include <components/vfs/manager.hpp>
namespace l10n
namespace L10n
{
void Manager::setPreferredLocales(const std::vector<std::string>& langs, bool gmstHasPriority)

View File

@ -10,7 +10,7 @@ namespace VFS
class Manager;
}
namespace l10n
namespace L10n
{
class Manager

View File

@ -7,7 +7,7 @@
#include <components/debug/debuglog.hpp>
namespace l10n
namespace L10n
{
MessageBundles::MessageBundles(const std::vector<icu::Locale>& preferredLocales, icu::Locale& fallbackLocale)
: mFallbackLocale(fallbackLocale)

View File

@ -10,7 +10,7 @@
#include <unicode/locid.h>
#include <unicode/msgfmt.h>
namespace l10n
namespace L10n
{
/**
* @brief A collection of Message Bundles

View File

@ -3,7 +3,7 @@
#include <QLibraryInfo>
#include <QLocale>
namespace l10n
namespace L10n
{
QTranslator AppTranslator{};
QTranslator ComponentsTranslator{};

View File

@ -4,7 +4,7 @@
#include <QApplication>
#include <QTranslator>
namespace l10n
namespace L10n
{
extern QTranslator AppTranslator;
extern QTranslator ComponentsTranslator;

View File

@ -55,7 +55,7 @@ namespace LuaUtil
// Find duplicates; only the last occurrence will be used (unless `sMerge` flag is used).
// Search for duplicates is case insensitive.
std::vector<bool> skip(cfg.mScripts.size(), false);
for (size_t i = 0; i < cfg.mScripts.size(); ++i)
for (int i = 0; i < static_cast<int>(cfg.mScripts.size()); ++i)
{
const ESM::LuaScriptCfg& script = cfg.mScripts[i];
bool global = script.mFlags & ESM::LuaScriptCfg::sGlobal;

View File

@ -8,7 +8,7 @@ namespace
{
struct L10nContext
{
std::shared_ptr<const l10n::MessageBundles> mData;
std::shared_ptr<const L10n::MessageBundles> mData;
};
void getICUArgs(std::string_view messageId, const sol::table& table, std::vector<icu::UnicodeString>& argNames,
@ -52,7 +52,7 @@ namespace sol
namespace LuaUtil
{
sol::function initL10nLoader(lua_State* L, l10n::Manager* manager)
sol::function initL10nLoader(lua_State* L, L10n::Manager* manager)
{
sol::state_view lua(L);
sol::usertype<L10nContext> ctxDef = lua.new_usertype<L10nContext>("L10nContext");

View File

@ -3,14 +3,14 @@
#include <sol/sol.hpp>
namespace l10n
namespace L10n
{
class Manager;
}
namespace LuaUtil
{
sol::function initL10nLoader(lua_State*, l10n::Manager* manager);
sol::function initL10nLoader(lua_State*, L10n::Manager* manager);
}
#endif // COMPONENTS_LUA_L10N_H

View File

@ -453,7 +453,7 @@ namespace LuaUtil
return call(sol::state_view(obj.lua_state())["tostring"], obj);
}
std::string internal::formatCastingError(const sol::object& obj, const std::type_info& t)
std::string Internal::formatCastingError(const sol::object& obj, const std::type_info& t)
{
const char* typeName = t.name();
if (t == typeid(int))

View File

@ -325,7 +325,7 @@ namespace LuaUtil
// String representation of a Lua object. Should be used for debugging/logging purposes only.
std::string toString(const sol::object&);
namespace internal
namespace Internal
{
std::string formatCastingError(const sol::object& obj, const std::type_info&);
}
@ -334,7 +334,7 @@ namespace LuaUtil
decltype(auto) cast(const sol::object& obj)
{
if (!obj.is<T>())
throw std::runtime_error(internal::formatCastingError(obj, typeid(T)));
throw std::runtime_error(Internal::formatCastingError(obj, typeid(T)));
return obj.as<T>();
}

View File

@ -5,7 +5,7 @@
#include "myguirendermanager.hpp"
namespace osgMyGUI
namespace MyGUIPlatform
{
AdditiveLayer::AdditiveLayer()

View File

@ -10,7 +10,7 @@ namespace osg
class StateSet;
}
namespace osgMyGUI
namespace MyGUIPlatform
{
/// @brief A Layer rendering with additive blend mode.

View File

@ -24,7 +24,7 @@ namespace
};
}
namespace osgMyGUI
namespace MyGUIPlatform
{
void DataManager::setResourcePath(const std::filesystem::path& path)

View File

@ -11,7 +11,7 @@ namespace VFS
class Manager;
}
namespace osgMyGUI
namespace MyGUIPlatform
{
class DataManager : public MyGUI::DataManager

View File

@ -4,7 +4,7 @@
#include <components/debug/debuglog.hpp>
namespace osgMyGUI
namespace MyGUIPlatform
{
void CustomLogListener::open()
{

View File

@ -10,7 +10,7 @@
#include <MyGUI_LevelLogFilter.h>
#include <MyGUI_LogSource.h>
namespace osgMyGUI
namespace MyGUIPlatform
{
/// \brief Custom MyGUI::ILogListener interface implementation

View File

@ -6,7 +6,7 @@
#include "components/files/conversion.hpp"
namespace osgMyGUI
namespace MyGUIPlatform
{
Platform::Platform(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ImageManager* imageManager,

View File

@ -26,7 +26,7 @@ namespace VFS
class Manager;
}
namespace osgMyGUI
namespace MyGUIPlatform
{
class RenderManager;

View File

@ -40,12 +40,12 @@
} \
} while (0)
namespace osgMyGUI
namespace MyGUIPlatform
{
class Drawable : public osg::Drawable
{
osgMyGUI::RenderManager* mParent;
MyGUIPlatform::RenderManager* mParent;
osg::ref_ptr<osg::StateSet> mStateSet;
public:
@ -58,12 +58,12 @@ namespace osgMyGUI
{
}
void setRenderManager(osgMyGUI::RenderManager* renderManager) { mRenderManager = renderManager; }
void setRenderManager(MyGUIPlatform::RenderManager* renderManager) { mRenderManager = renderManager; }
void operator()(osg::Node*, osg::NodeVisitor*) { mRenderManager->update(); }
private:
osgMyGUI::RenderManager* mRenderManager;
MyGUIPlatform::RenderManager* mRenderManager;
};
// Stage 1: collect draw calls. Run during the Cull traversal.
@ -75,12 +75,12 @@ namespace osgMyGUI
{
}
void setRenderManager(osgMyGUI::RenderManager* renderManager) { mRenderManager = renderManager; }
void setRenderManager(MyGUIPlatform::RenderManager* renderManager) { mRenderManager = renderManager; }
void operator()(osg::Node*, osg::NodeVisitor*) { mRenderManager->collectDrawCalls(); }
private:
osgMyGUI::RenderManager* mRenderManager;
MyGUIPlatform::RenderManager* mRenderManager;
};
// Stage 2: execute the draw calls. Run during the Draw traversal. May run in parallel with the update traversal
@ -162,7 +162,7 @@ namespace osgMyGUI
}
public:
Drawable(osgMyGUI::RenderManager* parent = nullptr)
Drawable(MyGUIPlatform::RenderManager* parent = nullptr)
: mParent(parent)
, mWriteTo(0)
, mReadFrom(0)

View File

@ -28,7 +28,7 @@ namespace osg
class StateSet;
}
namespace osgMyGUI
namespace MyGUIPlatform
{
class Drawable;

View File

@ -8,7 +8,7 @@
#include <components/debug/debuglog.hpp>
#include <components/resource/imagemanager.hpp>
namespace osgMyGUI
namespace MyGUIPlatform
{
OSGTexture::OSGTexture(const std::string& name, Resource::ImageManager* imageManager)

View File

@ -17,7 +17,7 @@ namespace Resource
class ImageManager;
}
namespace osgMyGUI
namespace MyGUIPlatform
{
class OSGTexture final : public MyGUI::ITexture

View File

@ -3,7 +3,7 @@
#include <MyGUI_RenderManager.h>
#include <algorithm>
namespace osgMyGUI
namespace MyGUIPlatform
{
/// @brief the ProxyRenderTarget allows to adjust the pixel scale and offset for a "source" render target.

View File

@ -3,7 +3,7 @@
#include <MyGUI_OverlappedLayer.h>
namespace osgMyGUI
namespace MyGUIPlatform
{
///@brief A Layer that lays out and renders widgets in screen-relative coordinates. The "Size" property determines

View File

@ -1568,6 +1568,9 @@ namespace NifOsg
}
rig->setBoneInfo(std::move(boneInfo));
rig->setInfluences(influences);
rig->setTransform(data->mTransform.toMatrix());
if (const Nif::NiAVObject* rootBone = skin->mRoot.getPtr())
rig->setRootBone(rootBone->mName);
drawable = rig;
}
@ -1683,7 +1686,7 @@ namespace NifOsg
if (hasColors)
colors.emplace_back(elem.mVertColor[0], elem.mVertColor[1], elem.mVertColor[2], elem.mVertColor[3]);
if (hasUV)
uvlist.emplace_back(halfToFloat(elem.mUV[0]), 1.0 - halfToFloat(elem.mUV[1]));
uvlist.emplace_back(halfToFloat(elem.mUV[0]), 1.0f - halfToFloat(elem.mUV[1]));
}
if (!vertices.empty())
@ -1729,6 +1732,8 @@ namespace NifOsg
}
rig->setBoneInfo(std::move(boneInfo));
rig->setInfluences(influences);
if (const Nif::NiAVObject* rootBone = skin->mRoot.getPtr())
rig->setRootBone(rootBone->mName);
drawable = rig;
}

View File

@ -7,6 +7,7 @@
#include <osgUtil/CullVisitor>
#include <components/debug/debuglog.hpp>
#include <components/misc/strings/algorithm.hpp>
#include <components/resource/scenemanager.hpp>
#include "skeleton.hpp"
@ -181,6 +182,12 @@ namespace SceneUtil
++boneInfo;
}
osg::Matrixf transform;
if (mSkinToSkelMatrix)
transform = (*mSkinToSkelMatrix) * mData->mTransform;
else
transform = mData->mTransform;
for (const auto& [influences, vertices] : mData->mInfluences)
{
osg::Matrixf resultMat(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
@ -196,8 +203,7 @@ namespace SceneUtil
*resultMatPtr += *boneMatPtr * weight;
}
if (mGeomToSkelMatrix)
resultMat *= (*mGeomToSkelMatrix);
resultMat *= transform;
for (unsigned short vertex : vertices)
{
@ -242,9 +248,14 @@ namespace SceneUtil
mSkeleton->updateBoneMatrices(nv->getTraversalNumber());
updateGeomToSkelMatrix(nv->getNodePath());
updateSkinToSkelMatrix(nv->getNodePath());
osg::BoundingBox box;
osg::Matrixf transform;
if (mSkinToSkelMatrix)
transform = (*mSkinToSkelMatrix) * mData->mTransform;
else
transform = mData->mTransform;
size_t index = 0;
for (const BoneInfo& info : mData->mBones)
@ -254,10 +265,7 @@ namespace SceneUtil
continue;
osg::BoundingSpheref bs = info.mBoundSphere;
if (mGeomToSkelMatrix)
transformBoundingSphere(bone->mMatrixInSkeletonSpace * (*mGeomToSkelMatrix), bs);
else
transformBoundingSphere(bone->mMatrixInSkeletonSpace, bs);
transformBoundingSphere(bone->mMatrixInSkeletonSpace * transform, bs);
box.expandBy(bs);
}
@ -280,31 +288,39 @@ namespace SceneUtil
}
}
void RigGeometry::updateGeomToSkelMatrix(const osg::NodePath& nodePath)
void RigGeometry::updateSkinToSkelMatrix(const osg::NodePath& nodePath)
{
bool foundSkel = false;
osg::RefMatrix* geomToSkelMatrix = mGeomToSkelMatrix;
if (geomToSkelMatrix)
geomToSkelMatrix->makeIdentity();
for (osg::NodePath::const_iterator it = nodePath.begin(); it != nodePath.end() - 1; ++it)
if (mSkinToSkelMatrix)
mSkinToSkelMatrix->makeIdentity();
auto skeletonRoot = std::find(nodePath.begin(), nodePath.end(), mSkeleton);
if (skeletonRoot == nodePath.end())
return;
skeletonRoot++;
auto skinRoot = nodePath.end();
if (!mData->mRootBone.empty())
skinRoot = std::find_if(skeletonRoot, nodePath.end(),
[&](const osg::Node* node) { return Misc::StringUtils::ciEqual(node->getName(), mData->mRootBone); });
if (skinRoot == nodePath.end())
{
osg::Node* node = *it;
if (!foundSkel)
// Failed to find skin root, cancel out everything up till the trishape.
// Our parent node is the trishape's transform
skinRoot = nodePath.end() - 2;
if ((*skinRoot)->getName() != getName()) // but maybe it can get optimized out
skinRoot++;
}
else
skinRoot++;
for (auto it = skeletonRoot; it != skinRoot; ++it)
{
const osg::Node* node = *it;
if (const osg::Transform* trans = node->asTransform())
{
if (node == mSkeleton)
foundSkel = true;
}
else
{
if (osg::Transform* trans = node->asTransform())
{
osg::MatrixTransform* matrixTrans = trans->asMatrixTransform();
if (matrixTrans && matrixTrans->getMatrix().isIdentity())
continue;
if (!geomToSkelMatrix)
geomToSkelMatrix = mGeomToSkelMatrix = new osg::RefMatrix;
trans->computeWorldToLocalMatrix(*geomToSkelMatrix, nullptr);
}
const osg::MatrixTransform* matrixTrans = trans->asMatrixTransform();
if (matrixTrans && matrixTrans->getMatrix().isIdentity())
continue;
if (!mSkinToSkelMatrix)
mSkinToSkelMatrix = new osg::RefMatrix;
trans->computeWorldToLocalMatrix(*mSkinToSkelMatrix, nullptr);
}
}
}
@ -346,12 +362,26 @@ namespace SceneUtil
std::map<BoneWeights, VertexList> influencesToVertices;
for (size_t i = 0; i < influences.size(); i++)
influencesToVertices[influences[i]].emplace_back(i);
influencesToVertices[influences[i]].emplace_back(static_cast<VertexList::value_type>(i));
mData->mInfluences.reserve(influencesToVertices.size());
mData->mInfluences.assign(influencesToVertices.begin(), influencesToVertices.end());
}
void RigGeometry::setTransform(osg::Matrixf&& transform)
{
if (!mData)
mData = new InfluenceData;
mData->mTransform = transform;
}
void RigGeometry::setRootBone(std::string_view name)
{
if (!mData)
mData = new InfluenceData;
mData->mRootBone = name;
}
void RigGeometry::accept(osg::NodeVisitor& nv)
{
if (!nv.validNodeMask(*this))

Some files were not shown because too many files have changed in this diff Show More