mirror of
https://github.com/TES3MP/TES3MP.git
synced 2025-09-26 22:45:15 -04:00
Add OpenMW commits up to 14 Feb 2021
# Conflicts: # apps/openmw/mwclass/door.cpp # apps/openmw/mwscript/aiextensions.cpp
This commit is contained in:
commit
7e188f2dd6
@ -116,12 +116,13 @@ variables: &cs-targets
|
|||||||
- .\ActivateMSVC.ps1
|
- .\ActivateMSVC.ps1
|
||||||
- cmake --build . --config $config --target ($targets.Split(','))
|
- cmake --build . --config $config --target ($targets.Split(','))
|
||||||
- cd $config
|
- cd $config
|
||||||
|
- echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt
|
||||||
- |
|
- |
|
||||||
if (Get-ChildItem -Recurse *.pdb) {
|
if (Get-ChildItem -Recurse *.pdb) {
|
||||||
7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb'
|
7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' CI-ID.txt
|
||||||
Get-ChildItem -Recurse *.pdb | Remove-Item
|
Get-ChildItem -Recurse *.pdb | Remove-Item
|
||||||
}
|
}
|
||||||
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.zip '*'
|
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}.zip '*'
|
||||||
after_script:
|
after_script:
|
||||||
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
||||||
cache:
|
cache:
|
||||||
@ -206,12 +207,13 @@ Windows_Ninja_CS_RelWithDebInfo:
|
|||||||
- cd MSVC2019_64
|
- cd MSVC2019_64
|
||||||
- cmake --build . --config $config --target ($targets.Split(','))
|
- cmake --build . --config $config --target ($targets.Split(','))
|
||||||
- cd $config
|
- cd $config
|
||||||
|
- echo "CI_COMMIT_REF_NAME ${CI_COMMIT_REF_NAME}`nCI_JOB_ID ${CI_JOB_ID}`nCI_COMMIT_SHA ${CI_COMMIT_SHA}" | Out-File -Encoding UTF8 CI-ID.txt
|
||||||
- |
|
- |
|
||||||
if (Get-ChildItem -Recurse *.pdb) {
|
if (Get-ChildItem -Recurse *.pdb) {
|
||||||
7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb'
|
7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}_symbols.zip '*.pdb' CI-ID.txt
|
||||||
Get-ChildItem -Recurse *.pdb | Remove-Item
|
Get-ChildItem -Recurse *.pdb | Remove-Item
|
||||||
}
|
}
|
||||||
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}_${CI_JOB_ID}.zip '*'
|
- 7z a -tzip ..\..\OpenMW_MSVC2019_64_${config}_${CI_COMMIT_REF_NAME}.zip '*'
|
||||||
after_script:
|
after_script:
|
||||||
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
- Copy-Item C:\ProgramData\chocolatey\logs\chocolatey.log
|
||||||
cache:
|
cache:
|
||||||
|
@ -215,6 +215,7 @@ Programmers
|
|||||||
Yohaulticetl
|
Yohaulticetl
|
||||||
Yuri Krupenin
|
Yuri Krupenin
|
||||||
zelurker
|
zelurker
|
||||||
|
Noah Gooder
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
@ -98,6 +98,11 @@
|
|||||||
Bug #5758: Paralyzed actors behavior is inconsistent with vanilla
|
Bug #5758: Paralyzed actors behavior is inconsistent with vanilla
|
||||||
Bug #5762: Movement solver is insufficiently robust
|
Bug #5762: Movement solver is insufficiently robust
|
||||||
Bug #5821: NPCs from mods getting removed if mod order was changed
|
Bug #5821: NPCs from mods getting removed if mod order was changed
|
||||||
|
Bug #5835: OpenMW doesn't accept negative values for NPC's hello, alarm, fight, and flee
|
||||||
|
Bug #5836: OpenMW dialogue/greeting/voice filter doesn't accept negative Ai values for NPC's hello, alarm, fight, and flee
|
||||||
|
Bug #5838: Local map and other menus become blank in some locations while playing Wizards' Islands mod.
|
||||||
|
Bug #5840: GetSoundPlaying "Health Damage" doesn't play when NPC hits target with shield effect ( vanilla engine behavior )
|
||||||
|
Bug #5841: Can't Cast Zero Cost Spells When Magicka is < 0
|
||||||
Feature #390: 3rd person look "over the shoulder"
|
Feature #390: 3rd person look "over the shoulder"
|
||||||
Feature #1536: Show more information about level on menu
|
Feature #1536: Show more information about level on menu
|
||||||
Feature #2386: Distant Statics in the form of Object Paging
|
Feature #2386: Distant Statics in the form of Object Paging
|
||||||
@ -105,6 +110,7 @@
|
|||||||
Feature #2686: Timestamps in openmw.log
|
Feature #2686: Timestamps in openmw.log
|
||||||
Feature #3171: OpenMW-CS: Instance drag selection
|
Feature #3171: OpenMW-CS: Instance drag selection
|
||||||
Feature #4894: Consider actors as obstacles for pathfinding
|
Feature #4894: Consider actors as obstacles for pathfinding
|
||||||
|
Feature #4977: Use the "default icon.tga" when an item's icon is not found
|
||||||
Feature #5043: Head Bobbing
|
Feature #5043: Head Bobbing
|
||||||
Feature #5199: Improve Scene Colors
|
Feature #5199: Improve Scene Colors
|
||||||
Feature #5297: Add a search function to the "Datafiles" tab of the OpenMW launcher
|
Feature #5297: Add a search function to the "Datafiles" tab of the OpenMW launcher
|
||||||
@ -130,6 +136,7 @@
|
|||||||
Feature #5813: Instanced groundcover support
|
Feature #5813: Instanced groundcover support
|
||||||
Task #5480: Drop Qt4 support
|
Task #5480: Drop Qt4 support
|
||||||
Task #5520: Improve cell name autocompleter implementation
|
Task #5520: Improve cell name autocompleter implementation
|
||||||
|
Task #5844: Update 'toggle sneak' documentation
|
||||||
|
|
||||||
0.46.0
|
0.46.0
|
||||||
------
|
------
|
||||||
|
@ -218,6 +218,7 @@ namespace MWBase
|
|||||||
///
|
///
|
||||||
/// \note If cell==0, the cell the player is currently in will be used instead to
|
/// \note If cell==0, the cell the player is currently in will be used instead to
|
||||||
/// generate a name.
|
/// generate a name.
|
||||||
|
virtual std::string getCellName(const ESM::Cell* cell) const = 0;
|
||||||
|
|
||||||
virtual void removeRefScript (MWWorld::RefData *ref) = 0;
|
virtual void removeRefScript (MWWorld::RefData *ref) = 0;
|
||||||
//< Remove the script attached to ref from mLocalScripts
|
//< Remove the script attached to ref from mLocalScripts
|
||||||
|
@ -379,45 +379,31 @@ namespace MWClass
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Door::getDestination (const MWWorld::LiveCellRef<ESM::Door>& door)
|
std::string Door::getDestination(const MWWorld::LiveCellRef<ESM::Door>& door)
|
||||||
{
|
{
|
||||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
std::string dest;
|
std::string dest = door.mRef.getDestCell();
|
||||||
if (door.mRef.getDestCell() != "")
|
if (dest.empty())
|
||||||
{
|
|
||||||
// door leads to an interior, use interior name as tooltip
|
|
||||||
dest = door.mRef.getDestCell();
|
|
||||||
|
|
||||||
/*
|
|
||||||
Start of tes3mp change (major)
|
|
||||||
|
|
||||||
If there is a destination override in the mwmp::Worldstate for this door's original
|
|
||||||
destination, use it
|
|
||||||
*/
|
|
||||||
if (mwmp::Main::get().getNetworking()->getWorldstate()->destinationOverrides.count(dest) != 0)
|
|
||||||
dest = mwmp::Main::get().getNetworking()->getWorldstate()->destinationOverrides[dest];
|
|
||||||
/*
|
|
||||||
End of tes3mp change (major)
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// door leads to exterior, use cell name (if any), otherwise translated region name
|
// door leads to exterior, use cell name (if any), otherwise translated region name
|
||||||
int x,y;
|
int x, y;
|
||||||
MWBase::Environment::get().getWorld()->positionToIndex (door.mRef.getDoorDest().pos[0], door.mRef.getDoorDest().pos[1], x, y);
|
auto world = MWBase::Environment::get().getWorld();
|
||||||
const ESM::Cell* cell = store.get<ESM::Cell>().find(x,y);
|
world->positionToIndex(door.mRef.getDoorDest().pos[0], door.mRef.getDoorDest().pos[1], x, y);
|
||||||
if (cell->mName != "")
|
const ESM::Cell* cell = world->getStore().get<ESM::Cell>().search(x, y);
|
||||||
dest = cell->mName;
|
dest = world->getCellName(cell);
|
||||||
else
|
|
||||||
{
|
|
||||||
const ESM::Region* region =
|
|
||||||
store.get<ESM::Region>().find(cell->mRegion);
|
|
||||||
|
|
||||||
//name as is, not a token
|
|
||||||
return MyGUI::TextIterator::toTagsString(region->mName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
If there is a destination override in the mwmp::Worldstate for this door's original
|
||||||
|
destination, use it
|
||||||
|
*/
|
||||||
|
else if (mwmp::Main::get().getNetworking()->getWorldstate()->destinationOverrides.count(dest) != 0)
|
||||||
|
dest = mwmp::Main::get().getNetworking()->getWorldstate()->destinationOverrides[dest];
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
return "#{sCell=" + dest + "}";
|
return "#{sCell=" + dest + "}";
|
||||||
}
|
}
|
||||||
|
@ -435,10 +435,10 @@ namespace MWClass
|
|||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
const MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||||
|
|
||||||
std::string model = "meshes\\base_anim.nif";
|
std::string model = Settings::Manager::getString("baseanim", "Models");
|
||||||
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(ref->mBase->mRace);
|
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(ref->mBase->mRace);
|
||||||
if(race->mData.mFlags & ESM::Race::Beast)
|
if(race->mData.mFlags & ESM::Race::Beast)
|
||||||
model = "meshes\\base_animkna.nif";
|
model = Settings::Manager::getString("baseanimkna", "Models");
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
@ -448,12 +448,12 @@ namespace MWClass
|
|||||||
const MWWorld::LiveCellRef<ESM::NPC> *npc = ptr.get<ESM::NPC>();
|
const MWWorld::LiveCellRef<ESM::NPC> *npc = ptr.get<ESM::NPC>();
|
||||||
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().search(npc->mBase->mRace);
|
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().search(npc->mBase->mRace);
|
||||||
if(race && race->mData.mFlags & ESM::Race::Beast)
|
if(race && race->mData.mFlags & ESM::Race::Beast)
|
||||||
models.emplace_back("meshes\\base_animkna.nif");
|
models.emplace_back(Settings::Manager::getString("baseanimkna", "Models"));
|
||||||
|
|
||||||
// keep these always loaded just in case
|
// keep these always loaded just in case
|
||||||
models.emplace_back("meshes/xargonian_swimkna.nif");
|
models.emplace_back(Settings::Manager::getString("xargonianswimkna", "Models"));
|
||||||
models.emplace_back("meshes/xbase_anim_female.nif");
|
models.emplace_back(Settings::Manager::getString("xbaseanimfemale", "Models"));
|
||||||
models.emplace_back("meshes/xbase_anim.nif");
|
models.emplace_back(Settings::Manager::getString("xbaseanim", "Models"));
|
||||||
|
|
||||||
if (!npc->mBase->mModel.empty())
|
if (!npc->mBase->mModel.empty())
|
||||||
models.push_back("meshes/"+npc->mBase->mModel);
|
models.push_back("meshes/"+npc->mBase->mModel);
|
||||||
|
@ -316,7 +316,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
|
|||||||
case SelectWrapper::Function_AiSetting:
|
case SelectWrapper::Function_AiSetting:
|
||||||
|
|
||||||
return mActor.getClass().getCreatureStats (mActor).getAiSetting (
|
return mActor.getClass().getCreatureStats (mActor).getAiSetting (
|
||||||
(MWMechanics::CreatureStats::AiSetting)select.getArgument()).getModified();
|
(MWMechanics::CreatureStats::AiSetting)select.getArgument()).getModified(false);
|
||||||
|
|
||||||
case SelectWrapper::Function_PcAttribute:
|
case SelectWrapper::Function_PcAttribute:
|
||||||
|
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
#include <MyGUI_TextBox.h>
|
#include <MyGUI_TextBox.h>
|
||||||
|
|
||||||
// correctIconPath
|
// correctIconPath
|
||||||
|
#include <components/resource/resourcesystem.hpp>
|
||||||
|
#include <components/vfs/manager.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
@ -106,7 +109,10 @@ namespace MWGui
|
|||||||
std::string invIcon = ptr.getClass().getInventoryIcon(ptr);
|
std::string invIcon = ptr.getClass().getInventoryIcon(ptr);
|
||||||
if (invIcon.empty())
|
if (invIcon.empty())
|
||||||
invIcon = "default icon.tga";
|
invIcon = "default icon.tga";
|
||||||
setIcon(MWBase::Environment::get().getWindowManager()->correctIconPath(invIcon));
|
invIcon = MWBase::Environment::get().getWindowManager()->correctIconPath(invIcon);
|
||||||
|
if (!MWBase::Environment::get().getResourceSystem()->getVFS()->exists(invIcon))
|
||||||
|
invIcon = MWBase::Environment::get().getWindowManager()->correctIconPath("default icon.tga");
|
||||||
|
setIcon(invIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -996,29 +996,29 @@ namespace MWMechanics
|
|||||||
if (actor.getClass().hasInventoryStore(actor))
|
if (actor.getClass().hasInventoryStore(actor))
|
||||||
actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Poison);
|
actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Poison);
|
||||||
}
|
}
|
||||||
else if (effects.get(ESM::MagicEffect::CureParalyzation).getModifier() > 0)
|
if (effects.get(ESM::MagicEffect::CureParalyzation).getModifier() > 0)
|
||||||
{
|
{
|
||||||
creatureStats.getActiveSpells().purgeEffect(ESM::MagicEffect::Paralyze);
|
creatureStats.getActiveSpells().purgeEffect(ESM::MagicEffect::Paralyze);
|
||||||
creatureStats.getSpells().purgeEffect(ESM::MagicEffect::Paralyze);
|
creatureStats.getSpells().purgeEffect(ESM::MagicEffect::Paralyze);
|
||||||
if (actor.getClass().hasInventoryStore(actor))
|
if (actor.getClass().hasInventoryStore(actor))
|
||||||
actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Paralyze);
|
actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Paralyze);
|
||||||
}
|
}
|
||||||
else if (effects.get(ESM::MagicEffect::CureCommonDisease).getModifier() > 0)
|
if (effects.get(ESM::MagicEffect::CureCommonDisease).getModifier() > 0)
|
||||||
{
|
{
|
||||||
creatureStats.getSpells().purgeCommonDisease();
|
creatureStats.getSpells().purgeCommonDisease();
|
||||||
}
|
}
|
||||||
else if (effects.get(ESM::MagicEffect::CureBlightDisease).getModifier() > 0)
|
if (effects.get(ESM::MagicEffect::CureBlightDisease).getModifier() > 0)
|
||||||
{
|
{
|
||||||
creatureStats.getSpells().purgeBlightDisease();
|
creatureStats.getSpells().purgeBlightDisease();
|
||||||
}
|
}
|
||||||
else if (effects.get(ESM::MagicEffect::CureCorprusDisease).getModifier() > 0)
|
if (effects.get(ESM::MagicEffect::CureCorprusDisease).getModifier() > 0)
|
||||||
{
|
{
|
||||||
creatureStats.getActiveSpells().purgeCorprusDisease();
|
creatureStats.getActiveSpells().purgeCorprusDisease();
|
||||||
creatureStats.getSpells().purgeCorprusDisease();
|
creatureStats.getSpells().purgeCorprusDisease();
|
||||||
if (actor.getClass().hasInventoryStore(actor))
|
if (actor.getClass().hasInventoryStore(actor))
|
||||||
actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Corprus, true);
|
actor.getClass().getInventoryStore(actor).purgeEffect(ESM::MagicEffect::Corprus, true);
|
||||||
}
|
}
|
||||||
else if (effects.get(ESM::MagicEffect::RemoveCurse).getModifier() > 0)
|
if (effects.get(ESM::MagicEffect::RemoveCurse).getModifier() > 0)
|
||||||
{
|
{
|
||||||
creatureStats.getSpells().purgeCurses();
|
creatureStats.getSpells().purgeCurses();
|
||||||
}
|
}
|
||||||
|
@ -452,6 +452,8 @@ namespace MWMechanics
|
|||||||
MWMechanics::DynamicStat<float> health = attackerStats.getHealth();
|
MWMechanics::DynamicStat<float> health = attackerStats.getHealth();
|
||||||
health.setCurrent(health.getCurrent() - x);
|
health.setCurrent(health.getCurrent() - x);
|
||||||
attackerStats.setHealth(health);
|
attackerStats.setHealth(health);
|
||||||
|
|
||||||
|
MWBase::Environment::get().getSoundManager()->playSound3D(attacker, "Health Damage", 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ namespace MWMechanics
|
|||||||
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
||||||
return 100;
|
return 100;
|
||||||
|
|
||||||
if (checkMagicka && stats.getMagicka().getCurrent() < spell->mData.mCost)
|
if (checkMagicka && spell->mData.mCost > 0 && stats.getMagicka().getCurrent() < spell->mData.mCost)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (spell->mData.mFlags & ESM::Spell::F_Always)
|
if (spell->mData.mFlags & ESM::Spell::F_Always)
|
||||||
|
@ -18,8 +18,10 @@ namespace MWMechanics
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T Stat<T>::getModified() const
|
T Stat<T>::getModified(bool capped) const
|
||||||
{
|
{
|
||||||
|
if(!capped)
|
||||||
|
return mModified;
|
||||||
return std::max(static_cast<T>(0), mModified);
|
return std::max(static_cast<T>(0), mModified);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ namespace MWMechanics
|
|||||||
|
|
||||||
const T& getBase() const;
|
const T& getBase() const;
|
||||||
|
|
||||||
T getModified() const;
|
T getModified(bool capped = true) const;
|
||||||
T getCurrentModified() const;
|
T getCurrentModified() const;
|
||||||
T getModifier() const;
|
T getModifier() const;
|
||||||
T getCurrentModifier() const;
|
T getCurrentModifier() const;
|
||||||
|
@ -38,7 +38,7 @@ namespace MWPhysics
|
|||||||
ContactCollectionCallback(const btCollisionObject * me, osg::Vec3f velocity) : mMe(me)
|
ContactCollectionCallback(const btCollisionObject * me, osg::Vec3f velocity) : mMe(me)
|
||||||
{
|
{
|
||||||
m_collisionFilterGroup = me->getBroadphaseHandle()->m_collisionFilterGroup;
|
m_collisionFilterGroup = me->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||||
m_collisionFilterMask = me->getBroadphaseHandle()->m_collisionFilterMask;
|
m_collisionFilterMask = me->getBroadphaseHandle()->m_collisionFilterMask & ~CollisionType_Projectile;
|
||||||
mVelocity = Misc::Convert::toBullet(velocity);
|
mVelocity = Misc::Convert::toBullet(velocity);
|
||||||
}
|
}
|
||||||
btScalar addSingleResult(btManifoldPoint & contact, const btCollisionObjectWrapper * colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper * colObj1Wrap, int partId1, int index1) override
|
btScalar addSingleResult(btManifoldPoint & contact, const btCollisionObjectWrapper * colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper * colObj1Wrap, int partId1, int index1) override
|
||||||
|
@ -1500,7 +1500,7 @@ namespace MWRender
|
|||||||
MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
|
MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
|
||||||
if(ref->mBase->mFlags & ESM::Creature::Bipedal)
|
if(ref->mBase->mFlags & ESM::Creature::Bipedal)
|
||||||
{
|
{
|
||||||
defaultSkeleton = "meshes\\xbase_anim.nif";
|
defaultSkeleton = Settings::Manager::getString("xbaseanim", "Models");
|
||||||
inject = true;
|
inject = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,6 +184,9 @@ namespace MWRender
|
|||||||
osg::ref_ptr<osg::Texture2D> dummyTexture = new osg::Texture2D();
|
osg::ref_ptr<osg::Texture2D> dummyTexture = new osg::Texture2D();
|
||||||
dummyTexture->setInternalFormat(GL_RED);
|
dummyTexture->setInternalFormat(GL_RED);
|
||||||
dummyTexture->setTextureSize(1, 1);
|
dummyTexture->setTextureSize(1, 1);
|
||||||
|
// This might clash with a shadow map, so make sure it doesn't cast shadows
|
||||||
|
dummyTexture->setShadowComparison(true);
|
||||||
|
dummyTexture->setShadowCompareFunc(osg::Texture::ShadowCompareFunc::ALWAYS);
|
||||||
stateset->setTextureAttributeAndModes(7, dummyTexture, osg::StateAttribute::ON);
|
stateset->setTextureAttributeAndModes(7, dummyTexture, osg::StateAttribute::ON);
|
||||||
stateset->setTextureAttribute(7, noBlendAlphaEnv, osg::StateAttribute::ON);
|
stateset->setTextureAttribute(7, noBlendAlphaEnv, osg::StateAttribute::ON);
|
||||||
stateset->addUniform(new osg::Uniform("noAlpha", true));
|
stateset->addUniform(new osg::Uniform("noAlpha", true));
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
#include <components/sceneutil/visitor.hpp>
|
#include <components/sceneutil/visitor.hpp>
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
#include <components/sceneutil/skeleton.hpp>
|
#include <components/sceneutil/skeleton.hpp>
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
@ -35,7 +35,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr,
|
|||||||
setObjectRoot(model, false, false, true);
|
setObjectRoot(model, false, false, true);
|
||||||
|
|
||||||
if((ref->mBase->mFlags&ESM::Creature::Bipedal))
|
if((ref->mBase->mFlags&ESM::Creature::Bipedal))
|
||||||
addAnimSource("meshes\\xbase_anim.nif", model);
|
addAnimSource(Settings::Manager::getString("xbaseanim", "Models"), model);
|
||||||
addAnimSource(model, model);
|
addAnimSource(model, model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const
|
|||||||
|
|
||||||
if((ref->mBase->mFlags&ESM::Creature::Bipedal))
|
if((ref->mBase->mFlags&ESM::Creature::Bipedal))
|
||||||
{
|
{
|
||||||
addAnimSource("meshes\\xbase_anim.nif", model);
|
addAnimSource(Settings::Manager::getString("xbaseanim", "Models"), model);
|
||||||
}
|
}
|
||||||
addAnimSource(model, model);
|
addAnimSource(model, model);
|
||||||
|
|
||||||
|
@ -524,7 +524,7 @@ void NpcAnimation::updateNpcBase()
|
|||||||
|
|
||||||
if(!is1stPerson)
|
if(!is1stPerson)
|
||||||
{
|
{
|
||||||
const std::string base = "meshes\\xbase_anim.nif";
|
const std::string base = Settings::Manager::getString("xbaseanim", "Models");
|
||||||
if (smodel != base && !isWerewolf)
|
if (smodel != base && !isWerewolf)
|
||||||
addAnimSource(base, smodel);
|
addAnimSource(base, smodel);
|
||||||
|
|
||||||
@ -538,7 +538,7 @@ void NpcAnimation::updateNpcBase()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const std::string base = "meshes\\xbase_anim.1st.nif";
|
const std::string base = Settings::Manager::getString("xbaseanim1st", "Models");
|
||||||
if (smodel != base && !isWerewolf)
|
if (smodel != base && !isWerewolf)
|
||||||
addAnimSource(base, smodel);
|
addAnimSource(base, smodel);
|
||||||
|
|
||||||
|
@ -456,12 +456,15 @@ namespace MWRender
|
|||||||
mSky->listAssetsToPreload(workItem->mModels, workItem->mTextures);
|
mSky->listAssetsToPreload(workItem->mModels, workItem->mTextures);
|
||||||
mWater->listAssetsToPreload(workItem->mTextures);
|
mWater->listAssetsToPreload(workItem->mTextures);
|
||||||
|
|
||||||
const char* basemodels[] = {"xbase_anim", "xbase_anim.1st", "xbase_anim_female", "xbase_animkna"};
|
workItem->mModels.push_back(Settings::Manager::getString("xbaseanim", "Models"));
|
||||||
for (size_t i=0; i<sizeof(basemodels)/sizeof(basemodels[0]); ++i)
|
workItem->mModels.push_back(Settings::Manager::getString("xbaseanim1st", "Models"));
|
||||||
{
|
workItem->mModels.push_back(Settings::Manager::getString("xbaseanimfemale", "Models"));
|
||||||
workItem->mModels.push_back(std::string("meshes/") + basemodels[i] + ".nif");
|
workItem->mModels.push_back(Settings::Manager::getString("xargonianswimkna", "Models"));
|
||||||
workItem->mKeyframes.push_back(std::string("meshes/") + basemodels[i] + ".kf");
|
|
||||||
}
|
workItem->mKeyframes.push_back(Settings::Manager::getString("xbaseanimkf", "Models"));
|
||||||
|
workItem->mKeyframes.push_back(Settings::Manager::getString("xbaseanim1stkf", "Models"));
|
||||||
|
workItem->mKeyframes.push_back(Settings::Manager::getString("xbaseanimfemalekf", "Models"));
|
||||||
|
workItem->mKeyframes.push_back(Settings::Manager::getString("xargonianswimknakf", "Models"));
|
||||||
|
|
||||||
workItem->mTextures.emplace_back("textures/_land_default.dds");
|
workItem->mTextures.emplace_back("textures/_land_default.dds");
|
||||||
|
|
||||||
|
@ -255,7 +255,7 @@ namespace MWScript
|
|||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
MWWorld::Ptr ptr = R()(runtime);
|
||||||
|
|
||||||
runtime.push(ptr.getClass().getCreatureStats (ptr).getAiSetting (mIndex).getModified());
|
runtime.push(ptr.getClass().getCreatureStats (ptr).getAiSetting (mIndex).getModified(false));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<class R>
|
template<class R>
|
||||||
@ -290,20 +290,20 @@ namespace MWScript
|
|||||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
Interpreter::Type_Integer value = runtime[0].mInteger;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
MWMechanics::Stat<int> stat = ptr.getClass().getCreatureStats(ptr).getAiSetting(mIndex);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
||||||
Track the original stat value, to ensure we don't send repetitive packets to the server
|
Track the original stat value, to ensure we don't send repetitive packets to the server
|
||||||
about its changes
|
about its changes
|
||||||
*/
|
*/
|
||||||
|
MWMechanics::Stat<int> stat = ptr.getClass().getCreatureStats(ptr).getAiSetting(mIndex);
|
||||||
|
|
||||||
int initialValue = stat.getBase();
|
int initialValue = stat.getBase();
|
||||||
/*
|
/*
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
stat.setModified(value, 0);
|
ptr.getClass().getCreatureStats(ptr).setAiSetting(mIndex, value);
|
||||||
ptr.getClass().setBaseAISetting(ptr.getCellRef().getRefId(), mIndex, value);
|
ptr.getClass().setBaseAISetting(ptr.getCellRef().getRefId(), mIndex, value);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -198,6 +198,9 @@ namespace MWScript
|
|||||||
.getCreatureStats(ptr)
|
.getCreatureStats(ptr)
|
||||||
.getDynamic(mIndex)
|
.getDynamic(mIndex)
|
||||||
.getCurrent();
|
.getCurrent();
|
||||||
|
// GetMagicka shouldn't return negative values
|
||||||
|
if(mIndex == 1 && value < 0)
|
||||||
|
value = 0;
|
||||||
}
|
}
|
||||||
runtime.push (value);
|
runtime.push (value);
|
||||||
}
|
}
|
||||||
|
@ -723,13 +723,19 @@ namespace MWWorld
|
|||||||
{
|
{
|
||||||
if (!cell)
|
if (!cell)
|
||||||
cell = mWorldScene->getCurrentCell();
|
cell = mWorldScene->getCurrentCell();
|
||||||
|
return getCellName(cell->getCell());
|
||||||
|
}
|
||||||
|
|
||||||
if (!cell->getCell()->isExterior() || !cell->getCell()->mName.empty())
|
std::string World::getCellName(const ESM::Cell* cell) const
|
||||||
return cell->getCell()->mName;
|
{
|
||||||
|
if (cell)
|
||||||
if (const ESM::Region* region = mStore.get<ESM::Region>().search (cell->getCell()->mRegion))
|
{
|
||||||
return region->mName;
|
if (!cell->isExterior() || !cell->mName.empty())
|
||||||
|
return cell->mName;
|
||||||
|
|
||||||
|
if (const ESM::Region* region = mStore.get<ESM::Region>().search (cell->mRegion))
|
||||||
|
return region->mName;
|
||||||
|
}
|
||||||
return mStore.get<ESM::GameSetting>().find ("sDefaultCellname")->mValue.getString();
|
return mStore.get<ESM::GameSetting>().find ("sDefaultCellname")->mValue.getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3461,7 +3467,7 @@ namespace MWWorld
|
|||||||
// Check mana
|
// Check mana
|
||||||
bool godmode = (isPlayer && mGodMode);
|
bool godmode = (isPlayer && mGodMode);
|
||||||
MWMechanics::DynamicStat<float> magicka = stats.getMagicka();
|
MWMechanics::DynamicStat<float> magicka = stats.getMagicka();
|
||||||
if (magicka.getCurrent() < spell->mData.mCost && !godmode)
|
if (spell->mData.mCost > 0 && magicka.getCurrent() < spell->mData.mCost && !godmode)
|
||||||
{
|
{
|
||||||
message = "#{sMagicInsufficientSP}";
|
message = "#{sMagicInsufficientSP}";
|
||||||
fail = true;
|
fail = true;
|
||||||
|
@ -315,6 +315,7 @@ namespace MWWorld
|
|||||||
///
|
///
|
||||||
/// \note If cell==0, the cell the player is currently in will be used instead to
|
/// \note If cell==0, the cell the player is currently in will be used instead to
|
||||||
/// generate a name.
|
/// generate a name.
|
||||||
|
std::string getCellName(const ESM::Cell* cell) const override;
|
||||||
|
|
||||||
void removeRefScript (MWWorld::RefData *ref) override;
|
void removeRefScript (MWWorld::RefData *ref) override;
|
||||||
//< Remove the script attached to ref from mLocalScripts
|
//< Remove the script attached to ref from mLocalScripts
|
||||||
|
@ -15,6 +15,7 @@ if (GTEST_FOUND AND GMOCK_FOUND)
|
|||||||
esm/test_fixed_string.cpp
|
esm/test_fixed_string.cpp
|
||||||
|
|
||||||
misc/test_stringops.cpp
|
misc/test_stringops.cpp
|
||||||
|
misc/test_endianness.cpp
|
||||||
|
|
||||||
nifloader/testbulletnifloader.cpp
|
nifloader/testbulletnifloader.cpp
|
||||||
|
|
||||||
|
122
apps/openmw_test_suite/misc/test_endianness.cpp
Normal file
122
apps/openmw_test_suite/misc/test_endianness.cpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "components/misc/endianness.hpp"
|
||||||
|
|
||||||
|
struct EndiannessTest : public ::testing::Test {};
|
||||||
|
|
||||||
|
TEST_F(EndiannessTest, test_swap_endianness_inplace1)
|
||||||
|
{
|
||||||
|
uint8_t zero=0x00;
|
||||||
|
uint8_t ff=0xFF;
|
||||||
|
uint8_t fortytwo=0x42;
|
||||||
|
uint8_t half=128;
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(zero);
|
||||||
|
EXPECT_EQ(zero, 0x00);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(ff);
|
||||||
|
EXPECT_EQ(ff, 0xFF);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(fortytwo);
|
||||||
|
EXPECT_EQ(fortytwo, 0x42);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(half);
|
||||||
|
EXPECT_EQ(half, 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EndiannessTest, test_swap_endianness_inplace2)
|
||||||
|
{
|
||||||
|
uint16_t zero = 0x0000;
|
||||||
|
uint16_t ffff = 0xFFFF;
|
||||||
|
uint16_t n12 = 0x0102;
|
||||||
|
uint16_t fortytwo = 0x0042;
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(zero);
|
||||||
|
EXPECT_EQ(zero, 0x0000);
|
||||||
|
Misc::swapEndiannessInplace(zero);
|
||||||
|
EXPECT_EQ(zero, 0x0000);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(ffff);
|
||||||
|
EXPECT_EQ(ffff, 0xFFFF);
|
||||||
|
Misc::swapEndiannessInplace(ffff);
|
||||||
|
EXPECT_EQ(ffff, 0xFFFF);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(n12);
|
||||||
|
EXPECT_EQ(n12, 0x0201);
|
||||||
|
Misc::swapEndiannessInplace(n12);
|
||||||
|
EXPECT_EQ(n12, 0x0102);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(fortytwo);
|
||||||
|
EXPECT_EQ(fortytwo, 0x4200);
|
||||||
|
Misc::swapEndiannessInplace(fortytwo);
|
||||||
|
EXPECT_EQ(fortytwo, 0x0042);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EndiannessTest, test_swap_endianness_inplace4)
|
||||||
|
{
|
||||||
|
uint32_t zero = 0x00000000;
|
||||||
|
uint32_t n1234 = 0x01020304;
|
||||||
|
uint32_t ffff = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(zero);
|
||||||
|
EXPECT_EQ(zero, 0x00000000);
|
||||||
|
Misc::swapEndiannessInplace(zero);
|
||||||
|
EXPECT_EQ(zero, 0x00000000);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(n1234);
|
||||||
|
EXPECT_EQ(n1234, 0x04030201);
|
||||||
|
Misc::swapEndiannessInplace(n1234);
|
||||||
|
EXPECT_EQ(n1234, 0x01020304);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(ffff);
|
||||||
|
EXPECT_EQ(ffff, 0xFFFFFFFF);
|
||||||
|
Misc::swapEndiannessInplace(ffff);
|
||||||
|
EXPECT_EQ(ffff, 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EndiannessTest, test_swap_endianness_inplace8)
|
||||||
|
{
|
||||||
|
uint64_t zero = 0x0000'0000'0000'0000;
|
||||||
|
uint64_t n1234 = 0x0102'0304'0506'0708;
|
||||||
|
uint64_t ffff = 0xFFFF'FFFF'FFFF'FFFF;
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(zero);
|
||||||
|
EXPECT_EQ(zero, 0x0000'0000'0000'0000);
|
||||||
|
Misc::swapEndiannessInplace(zero);
|
||||||
|
EXPECT_EQ(zero, 0x0000'0000'0000'0000);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(ffff);
|
||||||
|
EXPECT_EQ(ffff, 0xFFFF'FFFF'FFFF'FFFF);
|
||||||
|
Misc::swapEndiannessInplace(ffff);
|
||||||
|
EXPECT_EQ(ffff, 0xFFFF'FFFF'FFFF'FFFF);
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(n1234);
|
||||||
|
EXPECT_EQ(n1234, 0x0807'0605'0403'0201);
|
||||||
|
Misc::swapEndiannessInplace(n1234);
|
||||||
|
EXPECT_EQ(n1234, 0x0102'0304'0506'0708);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EndiannessTest, test_swap_endianness_inplace_float)
|
||||||
|
{
|
||||||
|
const uint32_t original = 0x4023d70a;
|
||||||
|
const uint32_t expected = 0x0ad72340;
|
||||||
|
|
||||||
|
float number;
|
||||||
|
memcpy(&number, &original, sizeof(original));
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(number);
|
||||||
|
|
||||||
|
EXPECT_TRUE(!memcmp(&number, &expected, sizeof(expected)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EndiannessTest, test_swap_endianness_inplace_double)
|
||||||
|
{
|
||||||
|
const uint64_t original = 0x040047ae147ae147ul;
|
||||||
|
const uint64_t expected = 0x47e17a14ae470004ul;
|
||||||
|
|
||||||
|
double number;
|
||||||
|
memcpy(&number, &original, sizeof(original));
|
||||||
|
|
||||||
|
Misc::swapEndiannessInplace(number);
|
||||||
|
|
||||||
|
EXPECT_TRUE(!memcmp(&number, &expected, sizeof(expected)) );
|
||||||
|
}
|
@ -95,9 +95,9 @@ void Wizard::ExistingInstallationPage::on_browseButton_clicked()
|
|||||||
{
|
{
|
||||||
QString selectedFile = QFileDialog::getOpenFileName(
|
QString selectedFile = QFileDialog::getOpenFileName(
|
||||||
this,
|
this,
|
||||||
tr("Select master file"),
|
tr("Select Morrowind.esm (located in Data Files)"),
|
||||||
QDir::currentPath(),
|
QDir::currentPath(),
|
||||||
QString(tr("Morrowind master file (*.esm)")),
|
QString(tr("Morrowind master file (Morrowind.esm)")),
|
||||||
nullptr,
|
nullptr,
|
||||||
QFileDialog::DontResolveSymlinks);
|
QFileDialog::DontResolveSymlinks);
|
||||||
|
|
||||||
@ -110,7 +110,18 @@ void Wizard::ExistingInstallationPage::on_browseButton_clicked()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!mWizard->findFiles(QLatin1String("Morrowind"), info.absolutePath()))
|
if (!mWizard->findFiles(QLatin1String("Morrowind"), info.absolutePath()))
|
||||||
return; // No valid Morrowind installation found
|
{
|
||||||
|
QMessageBox msgBox;
|
||||||
|
msgBox.setWindowTitle(tr("Error detecting Morrowind files"));
|
||||||
|
msgBox.setIcon(QMessageBox::Warning);
|
||||||
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
|
msgBox.setText(QObject::tr(
|
||||||
|
"<b>Morrowind.bsa</b> is missing!<br>\
|
||||||
|
Make sure your Morrowind installation is complete."
|
||||||
|
));
|
||||||
|
msgBox.exec();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QString path(QDir::toNativeSeparators(info.absolutePath()));
|
QString path(QDir::toNativeSeparators(info.absolutePath()));
|
||||||
QList<QListWidgetItem*> items = installationsList->findItems(path, Qt::MatchExactly);
|
QList<QListWidgetItem*> items = installationsList->findItems(path, Qt::MatchExactly);
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
#define COMPONENTS_MISC_ENDIANNESS_H
|
#define COMPONENTS_MISC_ENDIANNESS_H
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace Misc
|
namespace Misc
|
||||||
{
|
{
|
||||||
@ -15,20 +17,26 @@ namespace Misc
|
|||||||
|
|
||||||
if constexpr (sizeof(T) == 2)
|
if constexpr (sizeof(T) == 2)
|
||||||
{
|
{
|
||||||
uint16_t& v16 = *reinterpret_cast<uint16_t*>(&v);
|
uint16_t v16;
|
||||||
|
std::memcpy(&v16, &v, sizeof(T));
|
||||||
v16 = (v16 >> 8) | (v16 << 8);
|
v16 = (v16 >> 8) | (v16 << 8);
|
||||||
|
std::memcpy(&v, &v16, sizeof(T));
|
||||||
}
|
}
|
||||||
if constexpr (sizeof(T) == 4)
|
if constexpr (sizeof(T) == 4)
|
||||||
{
|
{
|
||||||
uint32_t& v32 = *reinterpret_cast<uint32_t*>(&v);
|
uint32_t v32;
|
||||||
v32 = (v32 >> 24) | ((v32 >> 8) & 0xff00) | ((v32 & 0xff00) << 8) || v32 << 24;
|
std::memcpy(&v32, &v, sizeof(T));
|
||||||
|
v32 = (v32 >> 24) | ((v32 >> 8) & 0xff00) | ((v32 & 0xff00) << 8) | (v32 << 24);
|
||||||
|
std::memcpy(&v, &v32, sizeof(T));
|
||||||
}
|
}
|
||||||
if constexpr (sizeof(T) == 8)
|
if constexpr (sizeof(T) == 8)
|
||||||
{
|
{
|
||||||
uint64_t& v64 = *reinterpret_cast<uint64_t*>(&v);
|
uint64_t v64;
|
||||||
|
std::memcpy(&v64, &v, sizeof(T));
|
||||||
v64 = (v64 >> 56) | ((v64 & 0x00ff'0000'0000'0000) >> 40) | ((v64 & 0x0000'ff00'0000'0000) >> 24)
|
v64 = (v64 >> 56) | ((v64 & 0x00ff'0000'0000'0000) >> 40) | ((v64 & 0x0000'ff00'0000'0000) >> 24)
|
||||||
| ((v64 & 0x0000'00ff'0000'0000) >> 8) | ((v64 & 0x0000'0000'ff00'0000) << 8)
|
| ((v64 & 0x0000'00ff'0000'0000) >> 8) | ((v64 & 0x0000'0000'ff00'0000) << 8)
|
||||||
| ((v64 & 0x0000'0000'00ff'0000) << 24) | ((v64 & 0x0000'0000'0000'ff00) << 40) | (v64 << 56);
|
| ((v64 & 0x0000'0000'00ff'0000) << 24) | ((v64 & 0x0000'0000'0000'ff00) << 40) | (v64 << 56);
|
||||||
|
std::memcpy(&v, &v64, sizeof(T));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <BulletCollision/CollisionShapes/btTriangleMesh.h>
|
#include <BulletCollision/CollisionShapes/btTriangleMesh.h>
|
||||||
|
|
||||||
|
#include <components/sceneutil/visitor.hpp>
|
||||||
#include <components/vfs/manager.hpp>
|
#include <components/vfs/manager.hpp>
|
||||||
|
|
||||||
#include <components/nifbullet/bulletnifloader.hpp>
|
#include <components/nifbullet/bulletnifloader.hpp>
|
||||||
@ -86,7 +87,17 @@ public:
|
|||||||
return osg::ref_ptr<BulletShape>();
|
return osg::ref_ptr<BulletShape>();
|
||||||
|
|
||||||
osg::ref_ptr<BulletShape> shape (new BulletShape);
|
osg::ref_ptr<BulletShape> shape (new BulletShape);
|
||||||
shape->mCollisionShape = new TriangleMeshShape(mTriangleMesh.release(), true);
|
btBvhTriangleMeshShape* triangleMeshShape = new TriangleMeshShape(mTriangleMesh.release(), true);
|
||||||
|
btVector3 aabbMin = triangleMeshShape->getLocalAabbMin();
|
||||||
|
btVector3 aabbMax = triangleMeshShape->getLocalAabbMax();
|
||||||
|
shape->mCollisionBox.extents[0] = (aabbMax[0] - aabbMin[0]) / 2.0f;
|
||||||
|
shape->mCollisionBox.extents[1] = (aabbMax[1] - aabbMin[1]) / 2.0f;
|
||||||
|
shape->mCollisionBox.extents[2] = (aabbMax[2] - aabbMin[2]) / 2.0f;
|
||||||
|
shape->mCollisionBox.center = osg::Vec3f( (aabbMax[0] + aabbMin[0]) / 2.0f,
|
||||||
|
(aabbMax[1] + aabbMin[1]) / 2.0f,
|
||||||
|
(aabbMax[2] + aabbMin[2]) / 2.0f );
|
||||||
|
shape->mCollisionShape = triangleMeshShape;
|
||||||
|
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,11 +146,31 @@ osg::ref_ptr<const BulletShape> BulletShapeManager::getShape(const std::string &
|
|||||||
|
|
||||||
osg::ref_ptr<const osg::Node> constNode (mSceneManager->getTemplate(normalized));
|
osg::ref_ptr<const osg::Node> constNode (mSceneManager->getTemplate(normalized));
|
||||||
osg::ref_ptr<osg::Node> node (const_cast<osg::Node*>(constNode.get())); // const-trickery required because there is no const version of NodeVisitor
|
osg::ref_ptr<osg::Node> node (const_cast<osg::Node*>(constNode.get())); // const-trickery required because there is no const version of NodeVisitor
|
||||||
NodeToShapeVisitor visitor;
|
|
||||||
node->accept(visitor);
|
// Check first if there's a custom collision node
|
||||||
shape = visitor.getShape();
|
unsigned int visitAllNodesMask = 0xffffffff;
|
||||||
|
SceneUtil::FindByNameVisitor nameFinder("Collision");
|
||||||
|
nameFinder.setTraversalMask(visitAllNodesMask);
|
||||||
|
nameFinder.setNodeMaskOverride(visitAllNodesMask);
|
||||||
|
node->accept(nameFinder);
|
||||||
|
if (nameFinder.mFoundNode)
|
||||||
|
{
|
||||||
|
NodeToShapeVisitor visitor;
|
||||||
|
visitor.setTraversalMask(visitAllNodesMask);
|
||||||
|
visitor.setNodeMaskOverride(visitAllNodesMask);
|
||||||
|
nameFinder.mFoundNode->accept(visitor);
|
||||||
|
shape = visitor.getShape();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a collision shape from the mesh
|
||||||
if (!shape)
|
if (!shape)
|
||||||
return osg::ref_ptr<BulletShape>();
|
{
|
||||||
|
NodeToShapeVisitor visitor;
|
||||||
|
node->accept(visitor);
|
||||||
|
shape = visitor.getShape();
|
||||||
|
if (!shape)
|
||||||
|
return osg::ref_ptr<BulletShape>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mCache->addEntryToObjectCache(normalized, shape);
|
mCache->addEntryToObjectCache(normalized, shape);
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <components/nifosg/nifloader.hpp>
|
#include <components/nifosg/nifloader.hpp>
|
||||||
#include <components/sceneutil/keyframe.hpp>
|
#include <components/sceneutil/keyframe.hpp>
|
||||||
#include <components/sceneutil/osgacontroller.hpp>
|
#include <components/sceneutil/osgacontroller.hpp>
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include "animation.hpp"
|
#include "animation.hpp"
|
||||||
#include "objectcache.hpp"
|
#include "objectcache.hpp"
|
||||||
@ -17,11 +18,13 @@
|
|||||||
namespace Resource
|
namespace Resource
|
||||||
{
|
{
|
||||||
|
|
||||||
RetrieveAnimationsVisitor::RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr<osgAnimation::BasicAnimationManager> animationManager) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), mTarget(target), mAnimationManager(animationManager) {}
|
RetrieveAnimationsVisitor::RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr<osgAnimation::BasicAnimationManager> animationManager,
|
||||||
|
const std::string& normalized, const VFS::Manager* vfs) :
|
||||||
|
osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), mTarget(target), mAnimationManager(animationManager), mNormalized(normalized), mVFS(vfs) {}
|
||||||
|
|
||||||
void RetrieveAnimationsVisitor::apply(osg::Node& node)
|
void RetrieveAnimationsVisitor::apply(osg::Node& node)
|
||||||
{
|
{
|
||||||
if (node.libraryName() == std::string("osgAnimation") && node.className() == std::string("Bone") && node.getName() == std::string("bip01"))
|
if (node.libraryName() == std::string("osgAnimation") && node.className() == std::string("Bone") && Misc::StringUtils::lowerCase(node.getName()) == std::string("bip01"))
|
||||||
{
|
{
|
||||||
osg::ref_ptr<SceneUtil::OsgAnimationController> callback = new SceneUtil::OsgAnimationController();
|
osg::ref_ptr<SceneUtil::OsgAnimationController> callback = new SceneUtil::OsgAnimationController();
|
||||||
|
|
||||||
@ -38,27 +41,19 @@ namespace Resource
|
|||||||
|
|
||||||
osg::ref_ptr<Resource::Animation> mergedAnimationTrack = new Resource::Animation;
|
osg::ref_ptr<Resource::Animation> mergedAnimationTrack = new Resource::Animation;
|
||||||
std::string animationName = animation->getName();
|
std::string animationName = animation->getName();
|
||||||
std::string start = animationName + std::string(": start");
|
mergedAnimationTrack->setName(animationName);
|
||||||
std::string stop = animationName + std::string(": stop");
|
|
||||||
|
|
||||||
const osgAnimation::ChannelList& channels = animation->getChannels();
|
const osgAnimation::ChannelList& channels = animation->getChannels();
|
||||||
for (const auto& channel: channels)
|
for (const auto& channel: channels)
|
||||||
{
|
{
|
||||||
mergedAnimationTrack->addChannel(channel.get()->clone()); // is ->clone needed?
|
mergedAnimationTrack->addChannel(channel.get()->clone()); // is ->clone needed?
|
||||||
}
|
}
|
||||||
mergedAnimationTrack->setName(animation->getName());
|
|
||||||
callback->addMergedAnimationTrack(mergedAnimationTrack);
|
callback->addMergedAnimationTrack(mergedAnimationTrack);
|
||||||
|
|
||||||
float startTime = animation->getStartTime();
|
float startTime = animation->getStartTime();
|
||||||
float stopTime = startTime + animation->getDuration();
|
float stopTime = startTime + animation->getDuration();
|
||||||
|
|
||||||
// mTextKeys is a nif-thing, used by OpenMW's animation system
|
|
||||||
// Format is likely "AnimationName: [Keyword_optional] [Start OR Stop]"
|
|
||||||
// AnimationNames are keywords like idle2, idle3... AiPackages and various mechanics control which animations are played
|
|
||||||
// Keywords can be stuff like Loop, Equip, Unequip, Block, InventoryHandtoHand, InventoryWeaponOneHand, PickProbe, Slash, Thrust, Chop... even "Slash Small Follow"
|
|
||||||
mTarget.mTextKeys.emplace(startTime, std::move(start));
|
|
||||||
mTarget.mTextKeys.emplace(stopTime, std::move(stop));
|
|
||||||
|
|
||||||
SceneUtil::EmulatedAnimation emulatedAnimation;
|
SceneUtil::EmulatedAnimation emulatedAnimation;
|
||||||
emulatedAnimation.mStartTime = startTime;
|
emulatedAnimation.mStartTime = startTime;
|
||||||
emulatedAnimation.mStopTime = stopTime;
|
emulatedAnimation.mStopTime = stopTime;
|
||||||
@ -66,12 +61,61 @@ namespace Resource
|
|||||||
emulatedAnimations.emplace_back(emulatedAnimation);
|
emulatedAnimations.emplace_back(emulatedAnimation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mTextKeys is a nif-thing, used by OpenMW's animation system
|
||||||
|
// Format is likely "AnimationName: [Keyword_optional] [Start OR Stop]"
|
||||||
|
// AnimationNames are keywords like idle2, idle3... AiPackages and various mechanics control which animations are played
|
||||||
|
// Keywords can be stuff like Loop, Equip, Unequip, Block, InventoryHandtoHand, InventoryWeaponOneHand, PickProbe, Slash, Thrust, Chop... even "Slash Small Follow"
|
||||||
|
// osgAnimation formats should have a .txt file with the same name, each line holding a textkey and whitespace separated time value
|
||||||
|
// e.g. idle: start 0.0333
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Files::IStreamPtr textKeysFile = mVFS->get(changeFileExtension(mNormalized, "txt"));
|
||||||
|
std::string line;
|
||||||
|
while ( getline (*textKeysFile, line) )
|
||||||
|
{
|
||||||
|
mTarget.mTextKeys.emplace(parseTimeSignature(line), parseTextKey(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "No textkey file found for " << mNormalized;
|
||||||
|
}
|
||||||
|
|
||||||
callback->setEmulatedAnimations(emulatedAnimations);
|
callback->setEmulatedAnimations(emulatedAnimations);
|
||||||
mTarget.mKeyframeControllers.emplace(node.getName(), callback);
|
mTarget.mKeyframeControllers.emplace(node.getName(), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
traverse(node);
|
traverse(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string RetrieveAnimationsVisitor::parseTextKey(const std::string& line)
|
||||||
|
{
|
||||||
|
size_t spacePos = line.find_last_of(' ');
|
||||||
|
if (spacePos != std::string::npos)
|
||||||
|
return line.substr(0, spacePos);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
double RetrieveAnimationsVisitor::parseTimeSignature(const std::string& line)
|
||||||
|
{
|
||||||
|
size_t spacePos = line.find_last_of(' ');
|
||||||
|
double time = 0.0;
|
||||||
|
if (spacePos != std::string::npos && spacePos + 1 < line.size())
|
||||||
|
time = std::stod(line.substr(spacePos + 1));
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RetrieveAnimationsVisitor::changeFileExtension(const std::string file, const std::string ext)
|
||||||
|
{
|
||||||
|
size_t extPos = file.find_last_of('.');
|
||||||
|
if (extPos != std::string::npos && extPos+1 < file.size())
|
||||||
|
{
|
||||||
|
return file.substr(0, extPos + 1) + ext;
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Resource
|
namespace Resource
|
||||||
@ -109,7 +153,7 @@ namespace Resource
|
|||||||
osg::ref_ptr<osgAnimation::BasicAnimationManager> bam = dynamic_cast<osgAnimation::BasicAnimationManager*> (scene->getUpdateCallback());
|
osg::ref_ptr<osgAnimation::BasicAnimationManager> bam = dynamic_cast<osgAnimation::BasicAnimationManager*> (scene->getUpdateCallback());
|
||||||
if (bam)
|
if (bam)
|
||||||
{
|
{
|
||||||
Resource::RetrieveAnimationsVisitor rav(*loaded.get(), bam);
|
Resource::RetrieveAnimationsVisitor rav(*loaded.get(), bam, normalized, mVFS);
|
||||||
scene->accept(rav);
|
scene->accept(rav);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,21 @@ namespace Resource
|
|||||||
class RetrieveAnimationsVisitor : public osg::NodeVisitor
|
class RetrieveAnimationsVisitor : public osg::NodeVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr<osgAnimation::BasicAnimationManager> animationManager);
|
RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr<osgAnimation::BasicAnimationManager> animationManager,
|
||||||
|
const std::string& normalized, const VFS::Manager* vfs);
|
||||||
|
|
||||||
virtual void apply(osg::Node& node) override;
|
virtual void apply(osg::Node& node) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
std::string changeFileExtension(const std::string file, const std::string ext);
|
||||||
|
std::string parseTextKey(const std::string& line);
|
||||||
|
double parseTimeSignature(const std::string& line);
|
||||||
|
|
||||||
SceneUtil::KeyframeHolder& mTarget;
|
SceneUtil::KeyframeHolder& mTarget;
|
||||||
osg::ref_ptr<osgAnimation::BasicAnimationManager> mAnimationManager;
|
osg::ref_ptr<osgAnimation::BasicAnimationManager> mAnimationManager;
|
||||||
|
std::string mNormalized;
|
||||||
|
const VFS::Manager* mVFS;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <components/sceneutil/util.hpp>
|
#include <components/sceneutil/util.hpp>
|
||||||
#include <components/sceneutil/controller.hpp>
|
#include <components/sceneutil/controller.hpp>
|
||||||
#include <components/sceneutil/optimizer.hpp>
|
#include <components/sceneutil/optimizer.hpp>
|
||||||
|
#include <components/sceneutil/visitor.hpp>
|
||||||
|
|
||||||
#include <components/shader/shadervisitor.hpp>
|
#include <components/shader/shadervisitor.hpp>
|
||||||
#include <components/shader/shadermanager.hpp>
|
#include <components/shader/shadermanager.hpp>
|
||||||
@ -373,6 +374,14 @@ namespace Resource
|
|||||||
errormsg << "Error loading " << normalizedFilename << ": " << result.message() << " code " << result.status() << std::endl;
|
errormsg << "Error loading " << normalizedFilename << ": " << result.message() << " code " << result.status() << std::endl;
|
||||||
throw std::runtime_error(errormsg.str());
|
throw std::runtime_error(errormsg.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recognize and hide collision node
|
||||||
|
unsigned int hiddenNodeMask = 0;
|
||||||
|
SceneUtil::FindByNameVisitor nameFinder("Collision");
|
||||||
|
result.getNode()->accept(nameFinder);
|
||||||
|
if (nameFinder.mFoundNode)
|
||||||
|
nameFinder.mFoundNode->setNodeMask(hiddenNodeMask);
|
||||||
|
|
||||||
return result.getNode();
|
return result.getNode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -390,7 +399,8 @@ namespace Resource
|
|||||||
{
|
{
|
||||||
const char* reserved[] = {"Head", "Neck", "Chest", "Groin", "Right Hand", "Left Hand", "Right Wrist", "Left Wrist", "Shield Bone", "Right Forearm", "Left Forearm", "Right Upper Arm",
|
const char* reserved[] = {"Head", "Neck", "Chest", "Groin", "Right Hand", "Left Hand", "Right Wrist", "Left Wrist", "Shield Bone", "Right Forearm", "Left Forearm", "Right Upper Arm",
|
||||||
"Left Upper Arm", "Right Foot", "Left Foot", "Right Ankle", "Left Ankle", "Right Knee", "Left Knee", "Right Upper Leg", "Left Upper Leg", "Right Clavicle",
|
"Left Upper Arm", "Right Foot", "Left Foot", "Right Ankle", "Left Ankle", "Right Knee", "Left Knee", "Right Upper Leg", "Left Upper Leg", "Right Clavicle",
|
||||||
"Left Clavicle", "Weapon Bone", "Tail", "Bip01", "Root Bone", "BoneOffset", "AttachLight", "Arrow", "Camera"};
|
"Left Clavicle", "Weapon Bone", "Tail", "Bip01", "Root Bone", "BoneOffset", "AttachLight", "Arrow", "Camera", "Collision", "Right_Wrist", "Left_Wrist",
|
||||||
|
"Shield_Bone", "Right_Forearm", "Left_Forearm", "Right_Upper_Arm", "Left_Clavicle", "Weapon_Bone", "Root_Bone"};
|
||||||
|
|
||||||
reservedNames = std::vector<std::string>(reserved, reserved + sizeof(reserved)/sizeof(reserved[0]));
|
reservedNames = std::vector<std::string>(reserved, reserved + sizeof(reserved)/sizeof(reserved[0]));
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
namespace SceneUtil
|
namespace SceneUtil
|
||||||
{
|
{
|
||||||
std::string getActorSkeleton(bool firstPerson, bool isFemale, bool isBeast, bool isWerewolf)
|
std::string getActorSkeleton(bool firstPerson, bool isFemale, bool isBeast, bool isWerewolf)
|
||||||
@ -7,24 +9,24 @@ namespace SceneUtil
|
|||||||
if (!firstPerson)
|
if (!firstPerson)
|
||||||
{
|
{
|
||||||
if (isWerewolf)
|
if (isWerewolf)
|
||||||
return "meshes\\wolf\\skin.nif";
|
return Settings::Manager::getString("wolfskin", "Models");
|
||||||
else if (isBeast)
|
else if (isBeast)
|
||||||
return "meshes\\base_animkna.nif";
|
return Settings::Manager::getString("baseanimkna", "Models");
|
||||||
else if (isFemale)
|
else if (isFemale)
|
||||||
return "meshes\\base_anim_female.nif";
|
return Settings::Manager::getString("baseanimfemale", "Models");
|
||||||
else
|
else
|
||||||
return "meshes\\base_anim.nif";
|
return Settings::Manager::getString("baseanim", "Models");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (isWerewolf)
|
if (isWerewolf)
|
||||||
return "meshes\\wolf\\skin.1st.nif";
|
return Settings::Manager::getString("wolfskin1st", "Models");
|
||||||
else if (isBeast)
|
else if (isBeast)
|
||||||
return "meshes\\base_animkna.1st.nif";
|
return Settings::Manager::getString("baseanimkna1st", "Models");
|
||||||
else if (isFemale)
|
else if (isFemale)
|
||||||
return "meshes\\base_anim_female.1st.nif";
|
return Settings::Manager::getString("baseanimfemale1st", "Models");
|
||||||
else
|
else
|
||||||
return "meshes\\base_anim.1st.nif";
|
return Settings::Manager::getString("xbaseanim1st", "Models");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -997,9 +997,9 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 1. Traverse main scene graph
|
// 1. Traverse main scene graph
|
||||||
cv.pushStateSet( _shadowRecievingPlaceholderStateSet.get() );
|
auto* shadowReceiverStateSet = vdd->getStateSet(cv.getTraversalNumber());
|
||||||
|
shadowReceiverStateSet->clear();
|
||||||
osg::ref_ptr<osgUtil::StateGraph> decoratorStateGraph = cv.getCurrentStateGraph();
|
cv.pushStateSet(shadowReceiverStateSet);
|
||||||
|
|
||||||
cullShadowReceivingScene(&cv);
|
cullShadowReceivingScene(&cv);
|
||||||
|
|
||||||
@ -1426,7 +1426,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
|
|||||||
|
|
||||||
if (numValidShadows>0)
|
if (numValidShadows>0)
|
||||||
{
|
{
|
||||||
decoratorStateGraph->setStateSet(selectStateSetForRenderingShadow(*vdd, cv.getTraversalNumber()));
|
prepareStateSetForRenderingShadow(*vdd, cv.getTraversalNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
// OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()<<std::endl;
|
// OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()<<std::endl;
|
||||||
@ -3004,9 +3004,9 @@ void MWShadowTechnique::cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Ca
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::StateSet* MWShadowTechnique::selectStateSetForRenderingShadow(ViewDependentData& vdd, unsigned int traversalNumber) const
|
osg::StateSet* MWShadowTechnique::prepareStateSetForRenderingShadow(ViewDependentData& vdd, unsigned int traversalNumber) const
|
||||||
{
|
{
|
||||||
OSG_INFO<<" selectStateSetForRenderingShadow() "<<vdd.getStateSet(traversalNumber)<<std::endl;
|
OSG_INFO<<" prepareStateSetForRenderingShadow() "<<vdd.getStateSet(traversalNumber)<<std::endl;
|
||||||
|
|
||||||
osg::ref_ptr<osg::StateSet> stateset = vdd.getStateSet(traversalNumber);
|
osg::ref_ptr<osg::StateSet> stateset = vdd.getStateSet(traversalNumber);
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ namespace SceneUtil {
|
|||||||
|
|
||||||
virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const;
|
virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const;
|
||||||
|
|
||||||
virtual osg::StateSet* selectStateSetForRenderingShadow(ViewDependentData& vdd, unsigned int traversalNumber) const;
|
virtual osg::StateSet* prepareStateSetForRenderingShadow(ViewDependentData& vdd, unsigned int traversalNumber) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~MWShadowTechnique();
|
virtual ~MWShadowTechnique();
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include <osgAnimation/UpdateMatrixTransform>
|
#include <osgAnimation/UpdateMatrixTransform>
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
#include <components/resource/animation.hpp>
|
#include <components/resource/animation.hpp>
|
||||||
#include <components/sceneutil/controller.hpp>
|
#include <components/sceneutil/controller.hpp>
|
||||||
#include <components/sceneutil/keyframe.hpp>
|
#include <components/sceneutil/keyframe.hpp>
|
||||||
@ -83,7 +84,7 @@ namespace SceneUtil
|
|||||||
{
|
{
|
||||||
osgAnimation::UpdateMatrixTransform* umt = dynamic_cast<osgAnimation::UpdateMatrixTransform*>(cb);
|
osgAnimation::UpdateMatrixTransform* umt = dynamic_cast<osgAnimation::UpdateMatrixTransform*>(cb);
|
||||||
if (umt)
|
if (umt)
|
||||||
if (node.getName() != "bip01") link(umt);
|
if (Misc::StringUtils::lowerCase(node.getName()) != "bip01") link(umt);
|
||||||
cb = cb->getNestedCallback();
|
cb = cb->getNestedCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,10 +103,14 @@ namespace SceneUtil
|
|||||||
}
|
}
|
||||||
|
|
||||||
OsgAnimationController::OsgAnimationController(const OsgAnimationController ©, const osg::CopyOp ©op) : SceneUtil::KeyframeController(copy, copyop)
|
OsgAnimationController::OsgAnimationController(const OsgAnimationController ©, const osg::CopyOp ©op) : SceneUtil::KeyframeController(copy, copyop)
|
||||||
, mMergedAnimationTracks(copy.mMergedAnimationTracks)
|
|
||||||
, mEmulatedAnimations(copy.mEmulatedAnimations)
|
, mEmulatedAnimations(copy.mEmulatedAnimations)
|
||||||
{
|
{
|
||||||
mLinker = nullptr;
|
mLinker = nullptr;
|
||||||
|
for (const auto& mergedAnimationTrack : copy.mMergedAnimationTracks)
|
||||||
|
{
|
||||||
|
Resource::Animation* copiedAnimationTrack = static_cast<Resource::Animation*>(mergedAnimationTrack.get()->clone(copyop));
|
||||||
|
mMergedAnimationTracks.emplace_back(copiedAnimationTrack);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec3f OsgAnimationController::getTranslation(float time) const
|
osg::Vec3f OsgAnimationController::getTranslation(float time) const
|
||||||
|
@ -60,7 +60,20 @@ namespace SceneUtil
|
|||||||
void NodeMapVisitor::apply(osg::MatrixTransform& trans)
|
void NodeMapVisitor::apply(osg::MatrixTransform& trans)
|
||||||
{
|
{
|
||||||
// Take transformation for first found node in file
|
// Take transformation for first found node in file
|
||||||
const std::string nodeName = Misc::StringUtils::lowerCase(trans.getName());
|
std::string originalNodeName = Misc::StringUtils::lowerCase(trans.getName());
|
||||||
|
|
||||||
|
if (trans.libraryName() == std::string("osgAnimation"))
|
||||||
|
{
|
||||||
|
// Convert underscores to whitespaces as a workaround for Collada (OpenMW's animation system uses whitespace-separated names)
|
||||||
|
std::string underscore = "_";
|
||||||
|
std::size_t foundUnderscore = originalNodeName.find(underscore);
|
||||||
|
|
||||||
|
if (foundUnderscore != std::string::npos)
|
||||||
|
std::replace(originalNodeName.begin(), originalNodeName.end(), '_', ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string nodeName = originalNodeName;
|
||||||
|
|
||||||
mMap.emplace(nodeName, &trans);
|
mMap.emplace(nodeName, &trans);
|
||||||
|
|
||||||
traverse(trans);
|
traverse(trans);
|
||||||
|
@ -38,7 +38,7 @@ This setting causes the behavior of the sneak key (bound to Ctrl by default)
|
|||||||
to toggle sneaking on and off rather than requiring the key to be held down while sneaking.
|
to toggle sneaking on and off rather than requiring the key to be held down while sneaking.
|
||||||
Players that spend significant time sneaking may find the character easier to control with this option enabled.
|
Players that spend significant time sneaking may find the character easier to control with this option enabled.
|
||||||
|
|
||||||
This setting can only be configured by editing the settings configuration file.
|
This setting can be toggled in the launcher under "Advanced" -> "Game Mechanics" -> "Toggle sneak".
|
||||||
|
|
||||||
always run
|
always run
|
||||||
----------
|
----------
|
||||||
|
@ -955,6 +955,51 @@ defer aabb update = true
|
|||||||
# Loading arbitrary meshes is not advised and may cause instability.
|
# Loading arbitrary meshes is not advised and may cause instability.
|
||||||
load unsupported nif files = false
|
load unsupported nif files = false
|
||||||
|
|
||||||
|
# 3rd person base animation model that looks also for the corresponding kf-file
|
||||||
|
xbaseanim = meshes/xbase_anim.nif
|
||||||
|
|
||||||
|
# 3rd person base model with textkeys-data
|
||||||
|
baseanim = meshes/base_anim.nif
|
||||||
|
|
||||||
|
# 1st person base animation model that looks also for corresponding kf-file
|
||||||
|
xbaseanim1st = meshes/xbase_anim.1st.nif
|
||||||
|
|
||||||
|
# 3rd person beast race base model with textkeys-data
|
||||||
|
baseanimkna = meshes/base_animkna.nif
|
||||||
|
|
||||||
|
# 1st person beast race base animation model
|
||||||
|
baseanimkna1st = meshes/base_animkna.1st.nif
|
||||||
|
|
||||||
|
# 3rd person female base animation model
|
||||||
|
xbaseanimfemale = meshes/xbase_anim_female.nif
|
||||||
|
|
||||||
|
# 3rd person female base model with textkeys-data
|
||||||
|
baseanimfemale = meshes/base_anim_female.nif
|
||||||
|
|
||||||
|
# 1st person female base model with textkeys-data
|
||||||
|
baseanimfemale1st = meshes/base_anim_female.1st.nif
|
||||||
|
|
||||||
|
# 3rd person werewolf skin
|
||||||
|
wolfskin = meshes/wolf/skin.nif
|
||||||
|
|
||||||
|
# 1st person werewolf skin
|
||||||
|
wolfskin1st = meshes/wolf/skin.1st.nif
|
||||||
|
|
||||||
|
# Argonian smimkna
|
||||||
|
xargonianswimkna = meshes/xargonian_swimkna.nif
|
||||||
|
|
||||||
|
# File to load xbaseanim 3rd person animations
|
||||||
|
xbaseanimkf = meshes/xbase_anim.kf
|
||||||
|
|
||||||
|
# File to load xbaseanim 3rd person animations
|
||||||
|
xbaseanim1stkf = meshes/xbase_anim.1st.kf
|
||||||
|
|
||||||
|
# File to load xbaseanim animations from
|
||||||
|
xbaseanimfemalekf = meshes/xbase_anim_female.kf
|
||||||
|
|
||||||
|
# File to load xargonianswimkna animations from
|
||||||
|
xargonianswimknakf = meshes/xargonian_swimkna.kf
|
||||||
|
|
||||||
[Groundcover]
|
[Groundcover]
|
||||||
|
|
||||||
# enable separate groundcover handling
|
# enable separate groundcover handling
|
||||||
|
@ -13,22 +13,13 @@ void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 vie
|
|||||||
#ifndef GROUNDCOVER
|
#ifndef GROUNDCOVER
|
||||||
lambert = max(lambert, 0.0);
|
lambert = max(lambert, 0.0);
|
||||||
#else
|
#else
|
||||||
|
float eyeCosine = dot(normalize(viewPos), viewNormal.xyz);
|
||||||
|
if (lambert < 0.0)
|
||||||
{
|
{
|
||||||
float cosine = dot(normalize(viewPos), normalize(viewNormal.xyz));
|
lambert = -lambert;
|
||||||
if (lambert >= 0.0)
|
eyeCosine = -eyeCosine;
|
||||||
cosine = -cosine;
|
|
||||||
|
|
||||||
float mult = 1.0;
|
|
||||||
float divisor = 8.0;
|
|
||||||
|
|
||||||
if (cosine < 0.0 && cosine >= -1.0/divisor)
|
|
||||||
mult = mix(1.0, 0.3, -cosine*divisor);
|
|
||||||
else if (cosine < -1.0/divisor)
|
|
||||||
mult = 0.3;
|
|
||||||
|
|
||||||
lambert *= mult;
|
|
||||||
lambert = abs(lambert);
|
|
||||||
}
|
}
|
||||||
|
lambert *= clamp(-8.0 * (1.0 - 0.3) * eyeCosine + 1.0, 0.3, 1.0);
|
||||||
#endif
|
#endif
|
||||||
diffuseOut = gl_LightSource[lightIndex].diffuse.xyz * lambert;
|
diffuseOut = gl_LightSource[lightIndex].diffuse.xyz * lambert;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user