mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-29 19:06:41 +00:00
Add OpenMW commits up to 1 Dec 2019
# Conflicts: # CMakeLists.txt # apps/openmw/mwscript/aiextensions.cpp # apps/openmw/mwscript/statsextensions.cpp
This commit is contained in:
commit
9d6f3fdd09
35 changed files with 275 additions and 143 deletions
|
@ -74,6 +74,7 @@ Programmers
|
||||||
Fil Krynicki (filkry)
|
Fil Krynicki (filkry)
|
||||||
Finbar Crago (finbar-crago)
|
Finbar Crago (finbar-crago)
|
||||||
Florian Weber (Florianjw)
|
Florian Weber (Florianjw)
|
||||||
|
Gaëtan Dezeiraud (Brouilles)
|
||||||
Gašper Sedej
|
Gašper Sedej
|
||||||
Gijsbert ter Horst (Ghostbird)
|
Gijsbert ter Horst (Ghostbird)
|
||||||
Gohan1989
|
Gohan1989
|
||||||
|
|
|
@ -176,6 +176,9 @@
|
||||||
Bug #5209: Spellcasting ignores race height
|
Bug #5209: Spellcasting ignores race height
|
||||||
Bug #5210: AiActivate allows actors to open dialogue and inventory windows
|
Bug #5210: AiActivate allows actors to open dialogue and inventory windows
|
||||||
Bug #5211: Screen fades in if the first loaded save is in interior cell
|
Bug #5211: Screen fades in if the first loaded save is in interior cell
|
||||||
|
Bug #5213: SameFaction script function is broken
|
||||||
|
Bug #5218: Crash when disabling ToggleBorders
|
||||||
|
Bug #5220: GetLOS crashes when actor isn't loaded
|
||||||
Feature #1774: Handle AvoidNode
|
Feature #1774: Handle AvoidNode
|
||||||
Feature #2229: Improve pathfinding AI
|
Feature #2229: Improve pathfinding AI
|
||||||
Feature #3025: Analogue gamepad movement controls
|
Feature #3025: Analogue gamepad movement controls
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
brew update
|
brew update
|
||||||
brew outdated pkgconfig || brew upgrade pkgconfig
|
brew outdated pkgconfig || brew upgrade pkgconfig
|
||||||
|
brew install cmake
|
||||||
brew install qt
|
brew install qt
|
||||||
brew install ccache
|
brew install ccache
|
||||||
|
|
||||||
|
|
|
@ -332,6 +332,8 @@ IF(BOOST_STATIC)
|
||||||
set(Boost_USE_STATIC_LIBS ON)
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(Boost_NO_BOOST_CMAKE ON)
|
||||||
|
|
||||||
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
||||||
|
|
||||||
include_directories("."
|
include_directories("."
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QTranslator>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
@ -26,6 +27,13 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
// Internationalization
|
||||||
|
QString locale = QLocale::system().name().section('_', 0, 0);
|
||||||
|
|
||||||
|
QTranslator appTranslator;
|
||||||
|
appTranslator.load(":/translations/" + locale + ".qm");
|
||||||
|
app.installTranslator(&appTranslator);
|
||||||
|
|
||||||
// Now we make sure the current dir is set to application path
|
// Now we make sure the current dir is set to application path
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
QDir dir(QCoreApplication::applicationDirPath());
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,7 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
|
||||||
iconWidget->setFlow(QListView::LeftToRight);
|
iconWidget->setFlow(QListView::LeftToRight);
|
||||||
|
|
||||||
QPushButton *playButton = new QPushButton(tr("Play"));
|
QPushButton *playButton = new QPushButton(tr("Play"));
|
||||||
|
buttonBox->button(QDialogButtonBox::Close)->setText(tr("Close"));
|
||||||
buttonBox->addButton(playButton, QDialogButtonBox::AcceptRole);
|
buttonBox->addButton(playButton, QDialogButtonBox::AcceptRole);
|
||||||
|
|
||||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(close()));
|
connect(buttonBox, SIGNAL(rejected()), this, SLOT(close()));
|
||||||
|
|
|
@ -27,13 +27,13 @@ Launcher::SettingsPage::SettingsPage(Files::ConfigurationManager &cfg,
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
|
|
||||||
QStringList languages;
|
QStringList languages;
|
||||||
languages << QLatin1String("English")
|
languages << tr("English")
|
||||||
<< QLatin1String("French")
|
<< tr("French")
|
||||||
<< QLatin1String("German")
|
<< tr("German")
|
||||||
<< QLatin1String("Italian")
|
<< tr("Italian")
|
||||||
<< QLatin1String("Polish")
|
<< tr("Polish")
|
||||||
<< QLatin1String("Russian")
|
<< tr("Russian")
|
||||||
<< QLatin1String("Spanish");
|
<< tr("Spanish");
|
||||||
|
|
||||||
languageComboBox->addItems(languages);
|
languageComboBox->addItems(languages);
|
||||||
|
|
||||||
|
|
|
@ -266,5 +266,5 @@ endif (MSVC)
|
||||||
|
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION "." COMPONENT BUNDLE)
|
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION "." COMPONENT Bundle)
|
||||||
endif()
|
endif()
|
||||||
|
|
16
apps/openmw/mwbase/rotationflags.hpp
Normal file
16
apps/openmw/mwbase/rotationflags.hpp
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef GAME_MWBASE_ROTATIONFLAGS_H
|
||||||
|
#define GAME_MWBASE_ROTATIONFLAGS_H
|
||||||
|
|
||||||
|
namespace MWBase
|
||||||
|
{
|
||||||
|
using RotationFlags = unsigned short;
|
||||||
|
|
||||||
|
enum RotationFlag : RotationFlags
|
||||||
|
{
|
||||||
|
RotationFlag_none = 0,
|
||||||
|
RotationFlag_adjust = 1,
|
||||||
|
RotationFlag_inverseOrder = 1 << 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef GAME_MWBASE_WORLD_H
|
#ifndef GAME_MWBASE_WORLD_H
|
||||||
#define GAME_MWBASE_WORLD_H
|
#define GAME_MWBASE_WORLD_H
|
||||||
|
|
||||||
|
#include "rotationflags.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
@ -408,7 +410,8 @@ namespace MWBase
|
||||||
|
|
||||||
virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;
|
virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;
|
||||||
|
|
||||||
virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0;
|
virtual void rotateObject(const MWWorld::Ptr& ptr, float x, float y, float z,
|
||||||
|
RotationFlags flags = RotationFlag_inverseOrder) = 0;
|
||||||
|
|
||||||
virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0;
|
virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0;
|
||||||
///< Place an object. Makes a copy of the Ptr.
|
///< Place an object. Makes a copy of the Ptr.
|
||||||
|
|
|
@ -631,7 +631,8 @@ namespace MWGui
|
||||||
|
|
||||||
ESM::QuickKeys keys;
|
ESM::QuickKeys keys;
|
||||||
|
|
||||||
for (int i=0; i<10; ++i)
|
// NB: The quick key with index 9 always has Hand-to-Hand type and must not be saved
|
||||||
|
for (int i=0; i<9; ++i)
|
||||||
{
|
{
|
||||||
ItemWidget* button = mKey[i].button;
|
ItemWidget* button = mKey[i].button;
|
||||||
|
|
||||||
|
@ -680,7 +681,8 @@ namespace MWGui
|
||||||
int i=0;
|
int i=0;
|
||||||
for (ESM::QuickKeys::QuickKey& quickKey : keys.mKeys)
|
for (ESM::QuickKeys::QuickKey& quickKey : keys.mKeys)
|
||||||
{
|
{
|
||||||
if (i >= 10)
|
// NB: The quick key with index 9 always has Hand-to-Hand type and must not be loaded
|
||||||
|
if (i >= 9)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mSelected = &mKey[i];
|
mSelected = &mKey[i];
|
||||||
|
|
|
@ -1917,6 +1917,9 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
0, mAttackType+" min attack", mAttackType+" max attack", 0.999f, 0);
|
0, mAttackType+" min attack", mAttackType+" max attack", 0.999f, 0);
|
||||||
break;
|
break;
|
||||||
case UpperCharState_StartToMinAttack:
|
case UpperCharState_StartToMinAttack:
|
||||||
|
case UpperCharState_MaxAttackToMinHit:
|
||||||
|
{
|
||||||
|
if (mUpperBodyState == UpperCharState_StartToMinAttack)
|
||||||
{
|
{
|
||||||
// If actor is already stopped preparing attack, do not play the "min attack -> max attack" part.
|
// If actor is already stopped preparing attack, do not play the "min attack -> max attack" part.
|
||||||
// Happens if the player did not hold the attack button.
|
// Happens if the player did not hold the attack button.
|
||||||
|
@ -1932,8 +1935,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
}
|
}
|
||||||
playSwishSound(0.0f);
|
playSwishSound(0.0f);
|
||||||
}
|
}
|
||||||
// Fall-through
|
|
||||||
case UpperCharState_MaxAttackToMinHit:
|
|
||||||
if(mAttackType == "shoot")
|
if(mAttackType == "shoot")
|
||||||
{
|
{
|
||||||
start = mAttackType+" min hit";
|
start = mAttackType+" min hit";
|
||||||
|
@ -1946,6 +1948,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
}
|
}
|
||||||
mUpperBodyState = UpperCharState_MinHitToHit;
|
mUpperBodyState = UpperCharState_MinHitToHit;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case UpperCharState_MinHitToHit:
|
case UpperCharState_MinHitToHit:
|
||||||
if(mAttackType == "shoot")
|
if(mAttackType == "shoot")
|
||||||
{
|
{
|
||||||
|
|
|
@ -131,30 +131,21 @@ namespace MWMechanics
|
||||||
|
|
||||||
mPrev = pos;
|
mPrev = pos;
|
||||||
|
|
||||||
switch(mWalkState)
|
if (mWalkState != State_Evade)
|
||||||
{
|
|
||||||
case State_Norm:
|
|
||||||
{
|
|
||||||
if(!samePosition)
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
mWalkState = State_CheckStuck;
|
|
||||||
}
|
|
||||||
/* FALL THROUGH */
|
|
||||||
case State_CheckStuck:
|
|
||||||
{
|
{
|
||||||
if(!samePosition)
|
if(!samePosition)
|
||||||
{
|
{
|
||||||
mWalkState = State_Norm;
|
mWalkState = State_Norm;
|
||||||
mStuckDuration = 0;
|
mStuckDuration = 0;
|
||||||
break;
|
mEvadeDuration = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
mWalkState = State_CheckStuck;
|
||||||
mStuckDuration += duration;
|
mStuckDuration += duration;
|
||||||
// consider stuck only if position unchanges for a period
|
// consider stuck only if position unchanges for a period
|
||||||
if(mStuckDuration < DURATION_SAME_SPOT)
|
if(mStuckDuration < DURATION_SAME_SPOT)
|
||||||
break; // still checking, note duration added to timer
|
return; // still checking, note duration added to timer
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mStuckDuration = 0;
|
mStuckDuration = 0;
|
||||||
|
@ -162,10 +153,7 @@ namespace MWMechanics
|
||||||
chooseEvasionDirection();
|
chooseEvasionDirection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/* FALL THROUGH */
|
|
||||||
case State_Evade:
|
|
||||||
{
|
|
||||||
mEvadeDuration += duration;
|
mEvadeDuration += duration;
|
||||||
if(mEvadeDuration >= DURATION_TO_EVADE)
|
if(mEvadeDuration >= DURATION_TO_EVADE)
|
||||||
{
|
{
|
||||||
|
@ -174,9 +162,6 @@ namespace MWMechanics
|
||||||
mEvadeDuration = 0;
|
mEvadeDuration = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* NO DEFAULT CASE */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObstacleCheck::takeEvasiveAction(MWMechanics::Movement& actorMovement) const
|
void ObstacleCheck::takeEvasiveAction(MWMechanics::Movement& actorMovement) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -448,9 +448,11 @@ namespace MWScript
|
||||||
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPtr(actorID, true);
|
MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->searchPtr(actorID, true, false);
|
||||||
|
|
||||||
Interpreter::Type_Integer value = MWBase::Environment::get().getMechanicsManager()->isActorDetected(actor, observer);
|
Interpreter::Type_Integer value = 0;
|
||||||
|
if (!actor.isEmpty())
|
||||||
|
value = MWBase::Environment::get().getMechanicsManager()->isActorDetected(actor, observer);
|
||||||
|
|
||||||
runtime.push (value);
|
runtime.push (value);
|
||||||
}
|
}
|
||||||
|
@ -470,9 +472,9 @@ namespace MWScript
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
|
|
||||||
MWWorld::Ptr dest = MWBase::Environment::get().getWorld()->getPtr(actorID,true);
|
MWWorld::Ptr dest = MWBase::Environment::get().getWorld()->searchPtr(actorID, true, false);
|
||||||
bool value = false;
|
bool value = false;
|
||||||
if(dest != MWWorld::Ptr() && source.getClass().isActor() && dest.getClass().isActor())
|
if (!dest.isEmpty() && source.getClass().isActor() && dest.getClass().isActor())
|
||||||
{
|
{
|
||||||
value = MWBase::Environment::get().getWorld()->getLOS(source,dest);
|
value = MWBase::Environment::get().getWorld()->getLOS(source,dest);
|
||||||
}
|
}
|
||||||
|
@ -513,7 +515,7 @@ namespace MWScript
|
||||||
std::string targetID = runtime.getStringLiteral (runtime[0].mInteger);
|
std::string targetID = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(targetID, true);
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(targetID, true, false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
@ -521,11 +523,12 @@ namespace MWScript
|
||||||
Track whether this actor is already in combat with its target, to ensure we don't
|
Track whether this actor is already in combat with its target, to ensure we don't
|
||||||
send repetitive packets to the server
|
send repetitive packets to the server
|
||||||
*/
|
*/
|
||||||
bool alreadyInCombatWithTarget = actor.getClass().getCreatureStats(actor).getAiSequence().isInCombat(target);
|
bool alreadyInCombatWithTarget = !target.isEmpty() ? actor.getClass().getCreatureStats(actor).getAiSequence().isInCombat(target) : false;
|
||||||
/*
|
/*
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (!target.isEmpty())
|
||||||
MWBase::Environment::get().getMechanicsManager()->startCombat(actor, target);
|
MWBase::Environment::get().getMechanicsManager()->startCombat(actor, target);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -535,7 +538,7 @@ namespace MWScript
|
||||||
cell authority or not; the server can decide if it wants to comply with them by
|
cell authority or not; the server can decide if it wants to comply with them by
|
||||||
forwarding them to the cell authority
|
forwarding them to the cell authority
|
||||||
*/
|
*/
|
||||||
if (target && !alreadyInCombatWithTarget)
|
if (!target.isEmpty() && !alreadyInCombatWithTarget)
|
||||||
{
|
{
|
||||||
mwmp::ActorList *actorList = mwmp::Main::get().getNetworking()->getActorList();
|
mwmp::ActorList *actorList = mwmp::Main::get().getNetworking()->getActorList();
|
||||||
actorList->reset();
|
actorList->reset();
|
||||||
|
|
|
@ -269,7 +269,7 @@ namespace MWScript
|
||||||
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
||||||
|
|
||||||
player.getClass().getNpcStats (player).isInFaction(ptr.getClass().getPrimaryFaction(ptr));
|
runtime.push(player.getClass().getNpcStats (player).isInFaction(ptr.getClass().getPrimaryFaction(ptr)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1248,7 +1248,9 @@ namespace MWScript
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr (targetId, false);
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(targetId, false, false);
|
||||||
|
if (target.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
MWMechanics::CastSpell cast(ptr, target, false, true);
|
MWMechanics::CastSpell cast(ptr, target, false, true);
|
||||||
cast.playSpellCastingEffects(spell->mId, false);
|
cast.playSpellCastingEffects(spell->mId, false);
|
||||||
|
|
|
@ -496,16 +496,6 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
// Apply looping particles immediately for constant effects
|
// Apply looping particles immediately for constant effects
|
||||||
MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr);
|
MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr);
|
||||||
|
|
||||||
// The spell may have an instant effect which must be handled immediately.
|
|
||||||
for (const auto& effect : creatureStats.getSpells().getMagicEffects())
|
|
||||||
{
|
|
||||||
if (effect.second.getMagnitude() <= 0)
|
|
||||||
continue;
|
|
||||||
MWMechanics::CastSpell cast(ptr, ptr);
|
|
||||||
if (cast.applyInstantEffect(ptr, ptr, effect.first, effect.second.getMagnitude()))
|
|
||||||
creatureStats.getSpells().purgeEffect(effect.first.mId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -533,6 +523,16 @@ namespace MWScript
|
||||||
|
|
||||||
if (spells.hasSpell(id))
|
if (spells.hasSpell(id))
|
||||||
{
|
{
|
||||||
|
// The spell may have an instant effect which must be handled before the spell's removal.
|
||||||
|
for (const auto& effect : creatureStats.getSpells().getMagicEffects())
|
||||||
|
{
|
||||||
|
if (effect.second.getMagnitude() <= 0)
|
||||||
|
continue;
|
||||||
|
MWMechanics::CastSpell cast(ptr, ptr);
|
||||||
|
if (cast.applyInstantEffect(ptr, ptr, effect.first, effect.second.getMagnitude()))
|
||||||
|
creatureStats.getSpells().purgeEffect(effect.first.mId);
|
||||||
|
}
|
||||||
|
|
||||||
ptr.getClass().getCreatureStats(ptr).getSpells().remove(id);
|
ptr.getClass().getCreatureStats(ptr).getSpells().remove(id);
|
||||||
|
|
||||||
if (ptr == MWMechanics::getPlayer())
|
if (ptr == MWMechanics::getPlayer())
|
||||||
|
|
|
@ -344,6 +344,7 @@ namespace MWWorld
|
||||||
ContainerStoreIteratorBase& operator++ ();
|
ContainerStoreIteratorBase& operator++ ();
|
||||||
ContainerStoreIteratorBase operator++ (int);
|
ContainerStoreIteratorBase operator++ (int);
|
||||||
ContainerStoreIteratorBase& operator= (const ContainerStoreIteratorBase& rhs);
|
ContainerStoreIteratorBase& operator= (const ContainerStoreIteratorBase& rhs);
|
||||||
|
ContainerStoreIteratorBase (const ContainerStoreIteratorBase& rhs) = default;
|
||||||
|
|
||||||
int getType() const;
|
int getType() const;
|
||||||
const ContainerStore *getContainerStore() const;
|
const ContainerStore *getContainerStore() const;
|
||||||
|
|
|
@ -51,6 +51,8 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
using MWWorld::RotationOrder;
|
||||||
|
|
||||||
osg::Quat makeActorOsgQuat(const ESM::Position& position)
|
osg::Quat makeActorOsgQuat(const ESM::Position& position)
|
||||||
{
|
{
|
||||||
return osg::Quat(position.rot[2], osg::Vec3(0, 0, -1));
|
return osg::Quat(position.rot[2], osg::Vec3(0, 0, -1));
|
||||||
|
@ -78,7 +80,7 @@ namespace
|
||||||
* osg::Quat(xr, osg::Vec3(-1, 0, 0));
|
* osg::Quat(xr, osg::Vec3(-1, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setNodeRotation(const MWWorld::Ptr& ptr, MWRender::RenderingManager& rendering, const bool inverseRotationOrder)
|
void setNodeRotation(const MWWorld::Ptr& ptr, MWRender::RenderingManager& rendering, RotationOrder order)
|
||||||
{
|
{
|
||||||
if (!ptr.getRefData().getBaseNode())
|
if (!ptr.getRefData().getBaseNode())
|
||||||
return;
|
return;
|
||||||
|
@ -86,7 +88,7 @@ namespace
|
||||||
rendering.rotateObject(ptr,
|
rendering.rotateObject(ptr,
|
||||||
ptr.getClass().isActor()
|
ptr.getClass().isActor()
|
||||||
? makeActorOsgQuat(ptr.getRefData().getPosition())
|
? makeActorOsgQuat(ptr.getRefData().getPosition())
|
||||||
: (inverseRotationOrder
|
: (order == RotationOrder::inverse
|
||||||
? makeInversedOrderObjectOsgQuat(ptr.getRefData().getPosition())
|
? makeInversedOrderObjectOsgQuat(ptr.getRefData().getPosition())
|
||||||
: makeObjectOsgQuat(ptr.getRefData().getPosition()))
|
: makeObjectOsgQuat(ptr.getRefData().getPosition()))
|
||||||
);
|
);
|
||||||
|
@ -111,7 +113,7 @@ namespace
|
||||||
model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player
|
model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player
|
||||||
|
|
||||||
ptr.getClass().insertObjectRendering(ptr, model, rendering);
|
ptr.getClass().insertObjectRendering(ptr, model, rendering);
|
||||||
setNodeRotation(ptr, rendering, false);
|
setNodeRotation(ptr, rendering, RotationOrder::direct);
|
||||||
|
|
||||||
ptr.getClass().insertObject (ptr, model, physics);
|
ptr.getClass().insertObject (ptr, model, physics);
|
||||||
|
|
||||||
|
@ -190,9 +192,9 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateObjectRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
|
void updateObjectRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
|
||||||
MWRender::RenderingManager& rendering, bool inverseRotationOrder)
|
MWRender::RenderingManager& rendering, RotationOrder order)
|
||||||
{
|
{
|
||||||
setNodeRotation(ptr, rendering, inverseRotationOrder);
|
setNodeRotation(ptr, rendering, order);
|
||||||
physics.updateRotation(ptr);
|
physics.updateRotation(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,9 +291,9 @@ namespace
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
|
||||||
void Scene::updateObjectRotation (const Ptr& ptr, bool inverseRotationOrder)
|
void Scene::updateObjectRotation(const Ptr& ptr, RotationOrder order)
|
||||||
{
|
{
|
||||||
::updateObjectRotation(ptr, *mPhysics, mRendering, inverseRotationOrder);
|
::updateObjectRotation(ptr, *mPhysics, mRendering, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::updateObjectScale(const Ptr &ptr)
|
void Scene::updateObjectScale(const Ptr &ptr)
|
||||||
|
|
|
@ -51,6 +51,12 @@ namespace MWWorld
|
||||||
class CellStore;
|
class CellStore;
|
||||||
class CellPreloader;
|
class CellPreloader;
|
||||||
|
|
||||||
|
enum class RotationOrder
|
||||||
|
{
|
||||||
|
direct,
|
||||||
|
inverse
|
||||||
|
};
|
||||||
|
|
||||||
class Scene
|
class Scene
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -137,7 +143,7 @@ namespace MWWorld
|
||||||
void removeObjectFromScene (const Ptr& ptr);
|
void removeObjectFromScene (const Ptr& ptr);
|
||||||
///< Remove an object from the scene, but not from the world model.
|
///< Remove an object from the scene, but not from the world model.
|
||||||
|
|
||||||
void updateObjectRotation (const Ptr& ptr, bool inverseRotationOrder);
|
void updateObjectRotation(const Ptr& ptr, RotationOrder order);
|
||||||
void updateObjectScale(const Ptr& ptr);
|
void updateObjectScale(const Ptr& ptr);
|
||||||
|
|
||||||
bool isCellActive(const CellStore &cell);
|
bool isCellActive(const CellStore &cell);
|
||||||
|
|
|
@ -92,6 +92,8 @@ namespace MWWorld
|
||||||
: mIter(iter)
|
: mIter(iter)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
SharedIterator& operator=(const SharedIterator&) = default;
|
||||||
|
|
||||||
SharedIterator &operator++() {
|
SharedIterator &operator++() {
|
||||||
++mIter;
|
++mIter;
|
||||||
return *this;
|
return *this;
|
||||||
|
|
|
@ -1550,13 +1550,13 @@ namespace MWWorld
|
||||||
mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator;
|
mShouldUpdateNavigator = updateNavigatorObject(object) || mShouldUpdateNavigator;
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust)
|
void World::rotateObjectImp(const Ptr& ptr, const osg::Vec3f& rot, MWBase::RotationFlags flags)
|
||||||
{
|
{
|
||||||
const float pi = static_cast<float>(osg::PI);
|
const float pi = static_cast<float>(osg::PI);
|
||||||
|
|
||||||
ESM::Position pos = ptr.getRefData().getPosition();
|
ESM::Position pos = ptr.getRefData().getPosition();
|
||||||
float *objRot = pos.rot;
|
float *objRot = pos.rot;
|
||||||
if(adjust)
|
if (flags & MWBase::RotationFlag_adjust)
|
||||||
{
|
{
|
||||||
objRot[0] += rot.x();
|
objRot[0] += rot.x();
|
||||||
objRot[1] += rot.y();
|
objRot[1] += rot.y();
|
||||||
|
@ -1588,7 +1588,9 @@ namespace MWWorld
|
||||||
|
|
||||||
if(ptr.getRefData().getBaseNode() != 0)
|
if(ptr.getRefData().getBaseNode() != 0)
|
||||||
{
|
{
|
||||||
mWorldScene->updateObjectRotation(ptr, true);
|
const auto order = flags & MWBase::RotationFlag_inverseOrder
|
||||||
|
? RotationOrder::inverse : RotationOrder::direct;
|
||||||
|
mWorldScene->updateObjectRotation(ptr, order);
|
||||||
|
|
||||||
if (const auto object = mPhysics->getObject(ptr))
|
if (const auto object = mPhysics->getObject(ptr))
|
||||||
updateNavigatorObject(object);
|
updateNavigatorObject(object);
|
||||||
|
@ -1660,9 +1662,9 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust)
|
void World::rotateObject (const Ptr& ptr, float x, float y, float z, MWBase::RotationFlags flags)
|
||||||
{
|
{
|
||||||
rotateObjectImp(ptr, osg::Vec3f(x, y, z), adjust);
|
rotateObjectImp(ptr, osg::Vec3f(x, y, z), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::rotateWorldObject (const Ptr& ptr, osg::Quat rotate)
|
void World::rotateWorldObject (const Ptr& ptr, osg::Quat rotate)
|
||||||
|
@ -1868,7 +1870,7 @@ namespace MWWorld
|
||||||
|
|
||||||
float diff = duration * osg::DegreesToRadians(90.f);
|
float diff = duration * osg::DegreesToRadians(90.f);
|
||||||
float targetRot = std::min(std::max(minRot, oldRot + diff * (state == MWWorld::DoorState::Opening ? 1 : -1)), maxRot);
|
float targetRot = std::min(std::max(minRot, oldRot + diff * (state == MWWorld::DoorState::Opening ? 1 : -1)), maxRot);
|
||||||
rotateObject(door, objPos.rot[0], objPos.rot[1], targetRot);
|
rotateObject(door, objPos.rot[0], objPos.rot[1], targetRot, MWBase::RotationFlag_none);
|
||||||
|
|
||||||
bool reached = (targetRot == maxRot && state != MWWorld::DoorState::Idle) || targetRot == minRot;
|
bool reached = (targetRot == maxRot && state != MWWorld::DoorState::Idle) || targetRot == minRot;
|
||||||
|
|
||||||
|
@ -1912,11 +1914,9 @@ namespace MWWorld
|
||||||
MWBase::Environment::get().getSoundManager()->stopSound3D(door, closeSound);
|
MWBase::Environment::get().getSoundManager()->stopSound3D(door, closeSound);
|
||||||
}
|
}
|
||||||
|
|
||||||
rotateObject(door, objPos.rot[0], objPos.rot[1], oldRot);
|
rotateObject(door, objPos.rot[0], objPos.rot[1], oldRot, MWBase::RotationFlag_none);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the rotation order we want to use
|
|
||||||
mWorldScene->updateObjectRotation(door, false);
|
|
||||||
return reached;
|
return reached;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2771,7 +2771,7 @@ namespace MWWorld
|
||||||
player.getClass().getInventoryStore(player).setContListener(anim);
|
player.getClass().getInventoryStore(player).setContListener(anim);
|
||||||
|
|
||||||
scaleObject(player, player.getCellRef().getScale()); // apply race height
|
scaleObject(player, player.getCellRef().getScale()); // apply race height
|
||||||
rotateObject(player, 0.f, 0.f, 0.f, true);
|
rotateObject(player, 0.f, 0.f, 0.f, MWBase::RotationFlag_inverseOrder | MWBase::RotationFlag_adjust);
|
||||||
|
|
||||||
MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr());
|
MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr());
|
||||||
MWBase::Environment::get().getMechanicsManager()->watchActor(getPlayerPtr());
|
MWBase::Environment::get().getMechanicsManager()->watchActor(getPlayerPtr());
|
||||||
|
|
|
@ -126,7 +126,7 @@ namespace MWWorld
|
||||||
void updateWeather(float duration, bool paused = false);
|
void updateWeather(float duration, bool paused = false);
|
||||||
int getDaysPerMonth (int month) const;
|
int getDaysPerMonth (int month) const;
|
||||||
|
|
||||||
void rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, bool adjust);
|
void rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, MWBase::RotationFlags flags);
|
||||||
|
|
||||||
Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z, bool movePhysics=true, bool moveToActive=false);
|
Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z, bool movePhysics=true, bool moveToActive=false);
|
||||||
///< @return an updated Ptr in case the Ptr's cell changes
|
///< @return an updated Ptr in case the Ptr's cell changes
|
||||||
|
@ -507,7 +507,8 @@ namespace MWWorld
|
||||||
/// @note Rotations via this method use a different rotation order than the initial rotations in the CS. This
|
/// @note Rotations via this method use a different rotation order than the initial rotations in the CS. This
|
||||||
/// could be considered a bug, but is needed for MW compatibility.
|
/// could be considered a bug, but is needed for MW compatibility.
|
||||||
/// \param adjust indicates rotation should be set or adjusted
|
/// \param adjust indicates rotation should be set or adjusted
|
||||||
void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false) override;
|
void rotateObject (const Ptr& ptr, float x, float y, float z,
|
||||||
|
MWBase::RotationFlags flags = MWBase::RotationFlag_inverseOrder) override;
|
||||||
|
|
||||||
MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) override;
|
MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) override;
|
||||||
///< Place an object. Makes a copy of the Ptr.
|
///< Place an object. Makes a copy of the Ptr.
|
||||||
|
|
|
@ -361,9 +361,9 @@ namespace
|
||||||
);
|
);
|
||||||
const auto recastMesh = builder.create();
|
const auto recastMesh = builder.create();
|
||||||
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
EXPECT_EQ(recastMesh->getVertices(), std::vector<float>({
|
||||||
0.707107067108154296875, 0, -3.535533905029296875,
|
1.41421353816986083984375, 0, 1.1920928955078125e-07,
|
||||||
-0.70710659027099609375, 0, -3.535533905029296875,
|
-1.41421353816986083984375, 0, -1.1920928955078125e-07,
|
||||||
2.384185791015625e-07, 0, -4.24264049530029296875,
|
1.1920928955078125e-07, 0, -1.41421353816986083984375,
|
||||||
}));
|
}));
|
||||||
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
EXPECT_EQ(recastMesh->getIndices(), std::vector<int>({0, 1, 2}));
|
||||||
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
EXPECT_EQ(recastMesh->getAreaTypes(), std::vector<AreaType>({AreaType_ground}));
|
||||||
|
|
38
components/bullethelpers/transformboundingbox.hpp
Normal file
38
components/bullethelpers/transformboundingbox.hpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef OPENMW_COMPONENTS_BULLETHELPERS_TRANSFORMBOUNDINGBOX_H
|
||||||
|
#define OPENMW_COMPONENTS_BULLETHELPERS_TRANSFORMBOUNDINGBOX_H
|
||||||
|
|
||||||
|
#include <LinearMath/btVector3.h>
|
||||||
|
#include <LinearMath/btTransform.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace BulletHelpers
|
||||||
|
{
|
||||||
|
inline btVector3 min(const btVector3& a, const btVector3& b)
|
||||||
|
{
|
||||||
|
return btVector3(std::min(a.x(), b.x()), std::min(a.y(), b.y()), std::min(a.z(), b.z()));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline btVector3 max(const btVector3& a, const btVector3& b)
|
||||||
|
{
|
||||||
|
return btVector3(std::max(a.x(), b.x()), std::max(a.y(), b.y()), std::max(a.z(), b.z()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://dev.theomader.com/transform-bounding-boxes/
|
||||||
|
inline void transformBoundingBox(const btTransform& transform, btVector3& aabbMin, btVector3& aabbMax)
|
||||||
|
{
|
||||||
|
const btVector3 xa(transform.getBasis().getColumn(0) * aabbMin.x());
|
||||||
|
const btVector3 xb(transform.getBasis().getColumn(0) * aabbMax.x());
|
||||||
|
|
||||||
|
const btVector3 ya(transform.getBasis().getColumn(1) * aabbMin.y());
|
||||||
|
const btVector3 yb(transform.getBasis().getColumn(1) * aabbMax.y());
|
||||||
|
|
||||||
|
const btVector3 za(transform.getBasis().getColumn(2) * aabbMin.z());
|
||||||
|
const btVector3 zb(transform.getBasis().getColumn(2) * aabbMax.z());
|
||||||
|
|
||||||
|
aabbMin = min(xa, xb) + min(ya, yb) + min(za, zb) + transform.getOrigin();
|
||||||
|
aabbMax = max(xa, xb) + max(ya, yb) + max(za, zb) + transform.getOrigin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -97,9 +97,13 @@ int wrapApplication(int (*innerApplication)(int argc, char *argv[]), int argc, c
|
||||||
std::streambuf* cout_rdbuf = std::cout.rdbuf ();
|
std::streambuf* cout_rdbuf = std::cout.rdbuf ();
|
||||||
std::streambuf* cerr_rdbuf = std::cerr.rdbuf ();
|
std::streambuf* cerr_rdbuf = std::cerr.rdbuf ();
|
||||||
|
|
||||||
#if !(defined(_WIN32) && defined(_DEBUG))
|
#if defined(_WIN32) && defined(_DEBUG)
|
||||||
|
boost::iostreams::stream_buffer<Debug::DebugOutput> sb;
|
||||||
|
#else
|
||||||
boost::iostreams::stream_buffer<Debug::Tee> coutsb;
|
boost::iostreams::stream_buffer<Debug::Tee> coutsb;
|
||||||
boost::iostreams::stream_buffer<Debug::Tee> cerrsb;
|
boost::iostreams::stream_buffer<Debug::Tee> cerrsb;
|
||||||
|
std::ostream oldcout(cout_rdbuf);
|
||||||
|
std::ostream oldcerr(cerr_rdbuf);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const std::string logName = Misc::StringUtils::lowerCase(appName) + ".log";
|
const std::string logName = Misc::StringUtils::lowerCase(appName) + ".log";
|
||||||
|
@ -113,7 +117,6 @@ int wrapApplication(int (*innerApplication)(int argc, char *argv[]), int argc, c
|
||||||
|
|
||||||
#if defined(_WIN32) && defined(_DEBUG)
|
#if defined(_WIN32) && defined(_DEBUG)
|
||||||
// Redirect cout and cerr to VS debug output when running in debug mode
|
// Redirect cout and cerr to VS debug output when running in debug mode
|
||||||
boost::iostreams::stream_buffer<Debug::DebugOutput> sb;
|
|
||||||
sb.open(Debug::DebugOutput());
|
sb.open(Debug::DebugOutput());
|
||||||
std::cout.rdbuf (&sb);
|
std::cout.rdbuf (&sb);
|
||||||
std::cerr.rdbuf (&sb);
|
std::cerr.rdbuf (&sb);
|
||||||
|
@ -121,8 +124,6 @@ int wrapApplication(int (*innerApplication)(int argc, char *argv[]), int argc, c
|
||||||
// Redirect cout and cerr to the log file
|
// Redirect cout and cerr to the log file
|
||||||
logfile.open (boost::filesystem::path(cfgMgr.getLogPath() / logName));
|
logfile.open (boost::filesystem::path(cfgMgr.getLogPath() / logName));
|
||||||
|
|
||||||
std::ostream oldcout(cout_rdbuf);
|
|
||||||
std::ostream oldcerr(cerr_rdbuf);
|
|
||||||
coutsb.open (Debug::Tee(logfile, oldcout));
|
coutsb.open (Debug::Tee(logfile, oldcout));
|
||||||
cerrsb.open (Debug::Tee(logfile, oldcerr));
|
cerrsb.open (Debug::Tee(logfile, oldcerr));
|
||||||
|
|
||||||
|
|
|
@ -135,7 +135,7 @@ namespace DetourNavigator
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
Log(Debug::Error) << "AsyncNavMeshUpdater::process exception: ", e.what();
|
Log(Debug::Error) << "AsyncNavMeshUpdater::process exception: " << e.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log(Debug::Debug) << "Stop navigator jobs processing";
|
Log(Debug::Debug) << "Stop navigator jobs processing";
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "settingsutils.hpp"
|
#include "settingsutils.hpp"
|
||||||
#include "exceptions.hpp"
|
#include "exceptions.hpp"
|
||||||
|
|
||||||
|
#include <components/bullethelpers/transformboundingbox.hpp>
|
||||||
#include <components/bullethelpers/processtrianglecallback.hpp>
|
#include <components/bullethelpers/processtrianglecallback.hpp>
|
||||||
#include <components/misc/convert.hpp>
|
#include <components/misc/convert.hpp>
|
||||||
|
|
||||||
|
@ -13,6 +14,7 @@
|
||||||
#include <BulletCollision/CollisionShapes/btConcaveShape.h>
|
#include <BulletCollision/CollisionShapes/btConcaveShape.h>
|
||||||
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
|
||||||
#include <LinearMath/btTransform.h>
|
#include <LinearMath/btTransform.h>
|
||||||
|
#include <LinearMath/btAabbUtil2.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
@ -57,7 +59,7 @@ namespace DetourNavigator
|
||||||
return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* triangle, int, int)
|
return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* triangle, int, int)
|
||||||
{
|
{
|
||||||
for (std::size_t i = 3; i > 0; --i)
|
for (std::size_t i = 3; i > 0; --i)
|
||||||
addTriangleVertex(transform(triangle[i - 1]));
|
addTriangleVertex(triangle[i - 1]);
|
||||||
mAreaTypes.push_back(areaType);
|
mAreaTypes.push_back(areaType);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -68,7 +70,7 @@ namespace DetourNavigator
|
||||||
return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* triangle, int, int)
|
return addObject(shape, transform, makeProcessTriangleCallback([&] (btVector3* triangle, int, int)
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < 3; ++i)
|
for (std::size_t i = 0; i < 3; ++i)
|
||||||
addTriangleVertex(transform(triangle[i]));
|
addTriangleVertex(triangle[i]);
|
||||||
mAreaTypes.push_back(areaType);
|
mAreaTypes.push_back(areaType);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -131,8 +133,34 @@ namespace DetourNavigator
|
||||||
|
|
||||||
shape.getAabb(btTransform::getIdentity(), aabbMin, aabbMax);
|
shape.getAabb(btTransform::getIdentity(), aabbMin, aabbMax);
|
||||||
|
|
||||||
aabbMin = transform(aabbMin);
|
const btVector3 boundsMin(mBounds.mMin.x(), mBounds.mMin.y(),
|
||||||
aabbMax = transform(aabbMax);
|
-std::numeric_limits<btScalar>::max() * std::numeric_limits<btScalar>::epsilon());
|
||||||
|
const btVector3 boundsMax(mBounds.mMax.x(), mBounds.mMax.y(),
|
||||||
|
std::numeric_limits<btScalar>::max() * std::numeric_limits<btScalar>::epsilon());
|
||||||
|
|
||||||
|
auto wrapper = makeProcessTriangleCallback([&] (btVector3* triangle, int partId, int triangleIndex)
|
||||||
|
{
|
||||||
|
std::array<btVector3, 3> transformed;
|
||||||
|
for (std::size_t i = 0; i < 3; ++i)
|
||||||
|
transformed[i] = transform(triangle[i]);
|
||||||
|
if (TestTriangleAgainstAabb2(transformed.data(), boundsMin, boundsMax))
|
||||||
|
callback.processTriangle(transformed.data(), partId, triangleIndex);
|
||||||
|
});
|
||||||
|
|
||||||
|
shape.processAllTriangles(&wrapper, aabbMin, aabbMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecastMeshBuilder::addObject(const btHeightfieldTerrainShape& shape, const btTransform& transform,
|
||||||
|
btTriangleCallback&& callback)
|
||||||
|
{
|
||||||
|
using BulletHelpers::transformBoundingBox;
|
||||||
|
|
||||||
|
btVector3 aabbMin;
|
||||||
|
btVector3 aabbMax;
|
||||||
|
|
||||||
|
shape.getAabb(btTransform::getIdentity(), aabbMin, aabbMax);
|
||||||
|
|
||||||
|
transformBoundingBox(transform, aabbMin, aabbMax);
|
||||||
|
|
||||||
aabbMin.setX(std::max(mBounds.mMin.x(), aabbMin.x()));
|
aabbMin.setX(std::max(mBounds.mMin.x(), aabbMin.x()));
|
||||||
aabbMin.setX(std::min(mBounds.mMax.x(), aabbMin.x()));
|
aabbMin.setX(std::min(mBounds.mMax.x(), aabbMin.x()));
|
||||||
|
@ -144,20 +172,17 @@ namespace DetourNavigator
|
||||||
aabbMax.setY(std::max(mBounds.mMin.y(), aabbMax.y()));
|
aabbMax.setY(std::max(mBounds.mMin.y(), aabbMax.y()));
|
||||||
aabbMax.setY(std::min(mBounds.mMax.y(), aabbMax.y()));
|
aabbMax.setY(std::min(mBounds.mMax.y(), aabbMax.y()));
|
||||||
|
|
||||||
const auto inversedTransform = transform.inverse();
|
transformBoundingBox(transform.inverse(), aabbMin, aabbMax);
|
||||||
|
|
||||||
aabbMin = inversedTransform(aabbMin);
|
auto wrapper = makeProcessTriangleCallback([&] (btVector3* triangle, int partId, int triangleIndex)
|
||||||
aabbMax = inversedTransform(aabbMax);
|
{
|
||||||
|
std::array<btVector3, 3> transformed;
|
||||||
|
for (std::size_t i = 0; i < 3; ++i)
|
||||||
|
transformed[i] = transform(triangle[i]);
|
||||||
|
callback.processTriangle(transformed.data(), partId, triangleIndex);
|
||||||
|
});
|
||||||
|
|
||||||
aabbMin.setX(std::min(aabbMin.x(), aabbMax.x()));
|
shape.processAllTriangles(&wrapper, aabbMin, aabbMax);
|
||||||
aabbMin.setY(std::min(aabbMin.y(), aabbMax.y()));
|
|
||||||
aabbMin.setZ(std::min(aabbMin.z(), aabbMax.z()));
|
|
||||||
|
|
||||||
aabbMax.setX(std::max(aabbMin.x(), aabbMax.x()));
|
|
||||||
aabbMax.setY(std::max(aabbMin.y(), aabbMax.y()));
|
|
||||||
aabbMax.setZ(std::max(aabbMin.z(), aabbMax.z()));
|
|
||||||
|
|
||||||
shape.processAllTriangles(&callback, aabbMin, aabbMax);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecastMeshBuilder::addTriangleVertex(const btVector3& worldPosition)
|
void RecastMeshBuilder::addTriangleVertex(const btVector3& worldPosition)
|
||||||
|
|
|
@ -48,6 +48,8 @@ namespace DetourNavigator
|
||||||
|
|
||||||
void addObject(const btConcaveShape& shape, const btTransform& transform, btTriangleCallback&& callback);
|
void addObject(const btConcaveShape& shape, const btTransform& transform, btTriangleCallback&& callback);
|
||||||
|
|
||||||
|
void addObject(const btHeightfieldTerrainShape& shape, const btTransform& transform, btTriangleCallback&& callback);
|
||||||
|
|
||||||
void addTriangleVertex(const btVector3& worldPosition);
|
void addTriangleVertex(const btVector3& worldPosition);
|
||||||
|
|
||||||
void addVertex(const btVector3& worldPosition);
|
void addVertex(const btVector3& worldPosition);
|
||||||
|
|
|
@ -76,7 +76,14 @@ ParticleShooter::ParticleShooter()
|
||||||
ParticleShooter::ParticleShooter(const ParticleShooter ©, const osg::CopyOp ©op)
|
ParticleShooter::ParticleShooter(const ParticleShooter ©, const osg::CopyOp ©op)
|
||||||
: osgParticle::Shooter(copy, copyop)
|
: osgParticle::Shooter(copy, copyop)
|
||||||
{
|
{
|
||||||
*this = copy;
|
mMinSpeed = copy.mMinSpeed;
|
||||||
|
mMaxSpeed = copy.mMaxSpeed;
|
||||||
|
mHorizontalDir = copy.mHorizontalDir;
|
||||||
|
mHorizontalAngle = copy.mHorizontalAngle;
|
||||||
|
mVerticalDir = copy.mVerticalDir;
|
||||||
|
mVerticalAngle = copy.mVerticalAngle;
|
||||||
|
mLifetime = copy.mLifetime;
|
||||||
|
mLifetimeRandom = copy.mLifetimeRandom;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParticleShooter::shoot(osgParticle::Particle *particle) const
|
void ParticleShooter::shoot(osgParticle::Particle *particle) const
|
||||||
|
@ -112,7 +119,9 @@ GrowFadeAffector::GrowFadeAffector()
|
||||||
GrowFadeAffector::GrowFadeAffector(const GrowFadeAffector& copy, const osg::CopyOp& copyop)
|
GrowFadeAffector::GrowFadeAffector(const GrowFadeAffector& copy, const osg::CopyOp& copyop)
|
||||||
: osgParticle::Operator(copy, copyop)
|
: osgParticle::Operator(copy, copyop)
|
||||||
{
|
{
|
||||||
*this = copy;
|
mGrowTime = copy.mGrowTime;
|
||||||
|
mFadeTime = copy.mFadeTime;
|
||||||
|
mCachedDefaultSize = copy.mCachedDefaultSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrowFadeAffector::beginOperate(osgParticle::Program *program)
|
void GrowFadeAffector::beginOperate(osgParticle::Program *program)
|
||||||
|
@ -143,7 +152,7 @@ ParticleColorAffector::ParticleColorAffector()
|
||||||
ParticleColorAffector::ParticleColorAffector(const ParticleColorAffector ©, const osg::CopyOp ©op)
|
ParticleColorAffector::ParticleColorAffector(const ParticleColorAffector ©, const osg::CopyOp ©op)
|
||||||
: osgParticle::Operator(copy, copyop)
|
: osgParticle::Operator(copy, copyop)
|
||||||
{
|
{
|
||||||
*this = copy;
|
mData = copy.mData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* dt */)
|
void ParticleColorAffector::operate(osgParticle::Particle* particle, double /* dt */)
|
||||||
|
@ -172,7 +181,13 @@ GravityAffector::GravityAffector()
|
||||||
GravityAffector::GravityAffector(const GravityAffector ©, const osg::CopyOp ©op)
|
GravityAffector::GravityAffector(const GravityAffector ©, const osg::CopyOp ©op)
|
||||||
: osgParticle::Operator(copy, copyop)
|
: osgParticle::Operator(copy, copyop)
|
||||||
{
|
{
|
||||||
*this = copy;
|
mForce = copy.mForce;
|
||||||
|
mType = copy.mType;
|
||||||
|
mPosition = copy.mPosition;
|
||||||
|
mDirection = copy.mDirection;
|
||||||
|
mDecay = copy.mDecay;
|
||||||
|
mCachedWorldPosition = copy.mCachedWorldPosition;
|
||||||
|
mCachedWorldDirection = copy.mCachedWorldDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GravityAffector::beginOperate(osgParticle::Program* program)
|
void GravityAffector::beginOperate(osgParticle::Program* program)
|
||||||
|
|
|
@ -78,6 +78,8 @@ namespace NifOsg
|
||||||
ParticleShooter();
|
ParticleShooter();
|
||||||
ParticleShooter(const ParticleShooter& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
|
ParticleShooter(const ParticleShooter& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
|
||||||
|
|
||||||
|
ParticleShooter& operator=(const ParticleShooter&) = delete;
|
||||||
|
|
||||||
META_Object(NifOsg, ParticleShooter)
|
META_Object(NifOsg, ParticleShooter)
|
||||||
|
|
||||||
virtual void shoot(osgParticle::Particle* particle) const;
|
virtual void shoot(osgParticle::Particle* particle) const;
|
||||||
|
@ -135,6 +137,8 @@ namespace NifOsg
|
||||||
GrowFadeAffector();
|
GrowFadeAffector();
|
||||||
GrowFadeAffector(const GrowFadeAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
|
GrowFadeAffector(const GrowFadeAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
|
||||||
|
|
||||||
|
GrowFadeAffector& operator=(const GrowFadeAffector&) = delete;
|
||||||
|
|
||||||
META_Object(NifOsg, GrowFadeAffector)
|
META_Object(NifOsg, GrowFadeAffector)
|
||||||
|
|
||||||
virtual void beginOperate(osgParticle::Program* program);
|
virtual void beginOperate(osgParticle::Program* program);
|
||||||
|
@ -155,6 +159,8 @@ namespace NifOsg
|
||||||
ParticleColorAffector();
|
ParticleColorAffector();
|
||||||
ParticleColorAffector(const ParticleColorAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
|
ParticleColorAffector(const ParticleColorAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
|
||||||
|
|
||||||
|
ParticleColorAffector& operator=(const ParticleColorAffector&) = delete;
|
||||||
|
|
||||||
META_Object(NifOsg, ParticleColorAffector)
|
META_Object(NifOsg, ParticleColorAffector)
|
||||||
|
|
||||||
virtual void operate(osgParticle::Particle* particle, double dt);
|
virtual void operate(osgParticle::Particle* particle, double dt);
|
||||||
|
@ -170,6 +176,8 @@ namespace NifOsg
|
||||||
GravityAffector();
|
GravityAffector();
|
||||||
GravityAffector(const GravityAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
|
GravityAffector(const GravityAffector& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
|
||||||
|
|
||||||
|
GravityAffector& operator=(const GravityAffector&) = delete;
|
||||||
|
|
||||||
META_Object(NifOsg, GravityAffector)
|
META_Object(NifOsg, GravityAffector)
|
||||||
|
|
||||||
virtual void operate(osgParticle::Particle* particle, double dt);
|
virtual void operate(osgParticle::Particle* particle, double dt);
|
||||||
|
|
|
@ -91,8 +91,9 @@ void CellBorder::destroyCellBorderGeometry(int x, int y)
|
||||||
|
|
||||||
void CellBorder::destroyCellBorderGeometry()
|
void CellBorder::destroyCellBorderGeometry()
|
||||||
{
|
{
|
||||||
for (CellGrid::iterator it = mCellBorderNodes.begin(); it != mCellBorderNodes.end(); ++it)
|
for (const auto& v : mCellBorderNodes)
|
||||||
destroyCellBorderGeometry(it->first.first,it->first.second);
|
mRoot->removeChild(v.second);
|
||||||
|
mCellBorderNodes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,12 +176,12 @@ recast scale factor
|
||||||
|
|
||||||
:Type: floating point
|
:Type: floating point
|
||||||
:Range: > 0.0
|
:Range: > 0.0
|
||||||
:Default: 0.023529411764705882
|
:Default: 0.029411764705882353
|
||||||
|
|
||||||
Scale of nav mesh coordinates to world coordinates. Recastnavigation builds voxels for world geometry.
|
Scale of nav mesh coordinates to world coordinates. Recastnavigation builds voxels for world geometry.
|
||||||
Basically voxel size is 1 / "cell size". To reduce amount of voxels we apply scale factor, to make voxel size
|
Basically voxel size is 1 / "cell size". To reduce amount of voxels we apply scale factor, to make voxel size
|
||||||
"recast scale factor" / "cell size". Default value calculates by this equation:
|
"recast scale factor" / "cell size". Default value calculates by this equation:
|
||||||
sStepSizeUp * "recast scale factor" / "cell size" = 4 (max climb height should be equal to 4 voxels).
|
sStepSizeUp * "recast scale factor" / "cell size" = 5 (max climb height should be equal to 4 voxels).
|
||||||
Changing this value will change generated nav mesh. Some locations may become unavailable for NPC and creatures.
|
Changing this value will change generated nav mesh. Some locations may become unavailable for NPC and creatures.
|
||||||
Pay attention to slopes and roofs when change it. Increasing this value will reduce nav mesh update latency.
|
Pay attention to slopes and roofs when change it. Increasing this value will reduce nav mesh update latency.
|
||||||
|
|
||||||
|
|
2
extern/oics/ICSInputControlSystem.cpp
vendored
2
extern/oics/ICSInputControlSystem.cpp
vendored
|
@ -148,7 +148,7 @@ namespace ICS
|
||||||
float step = FromString<float>(xmlInterval->Attribute("step"));
|
float step = FromString<float>(xmlInterval->Attribute("step"));
|
||||||
|
|
||||||
ICS_LOG("Applying Bezier filter to channel [number="
|
ICS_LOG("Applying Bezier filter to channel [number="
|
||||||
+ ToString<int>(ch) + ", startX="
|
+ ToString<size_t>(ch) + ", startX="
|
||||||
+ ToString<float>(startX) + ", startY="
|
+ ToString<float>(startX) + ", startY="
|
||||||
+ ToString<float>(startY) + ", midX="
|
+ ToString<float>(startY) + ", midX="
|
||||||
+ ToString<float>(midX) + ", midY="
|
+ ToString<float>(midX) + ", midY="
|
||||||
|
|
|
@ -642,8 +642,8 @@ enable = true
|
||||||
# Scale of NavMesh coordinates to world coordinates (value > 0.0). Recastnavigation builds voxels for world geometry.
|
# Scale of NavMesh coordinates to world coordinates (value > 0.0). Recastnavigation builds voxels for world geometry.
|
||||||
# Basically voxel size is 1 / "cell size". To reduce amount of voxels we apply scale factor, to make voxel size
|
# Basically voxel size is 1 / "cell size". To reduce amount of voxels we apply scale factor, to make voxel size
|
||||||
# "recast scale factor" / "cell size". Default value calculates by this equation:
|
# "recast scale factor" / "cell size". Default value calculates by this equation:
|
||||||
# sStepSizeUp * "recast scale factor" / "cell size" = 4 (max climb height should be equal to 4 voxels)
|
# sStepSizeUp * "recast scale factor" / "cell size" = 5 (max climb height should be equal to 4 voxels)
|
||||||
recast scale factor = 0.023529411764705882
|
recast scale factor = 0.029411764705882353
|
||||||
|
|
||||||
# The z-axis cell size to use for fields. (value > 0.0)
|
# The z-axis cell size to use for fields. (value > 0.0)
|
||||||
# Defines voxel/grid/cell size. So their values have significant
|
# Defines voxel/grid/cell size. So their values have significant
|
||||||
|
@ -671,7 +671,7 @@ detail sample max error = 1.0
|
||||||
max simplification error = 1.3
|
max simplification error = 1.3
|
||||||
|
|
||||||
# The width and height of each tile. (value > 0)
|
# The width and height of each tile. (value > 0)
|
||||||
tile size = 64
|
tile size = 128
|
||||||
|
|
||||||
# The size of the non-navigable border around the heightfield. (value >= 0)
|
# The size of the non-navigable border around the heightfield. (value >= 0)
|
||||||
border size = 16
|
border size = 16
|
||||||
|
|
Loading…
Reference in a new issue