mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-05 03:41:32 +00:00
Merge branch 'master' into 'effective_magic'
# Conflicts: # CHANGELOG.md
This commit is contained in:
commit
2c8c36fe5d
44 changed files with 264 additions and 278 deletions
|
@ -229,6 +229,7 @@ Programmers
|
||||||
Yuri Krupenin
|
Yuri Krupenin
|
||||||
zelurker
|
zelurker
|
||||||
Noah Gooder
|
Noah Gooder
|
||||||
|
Andrew Appuhamy (andrew-app)
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
Bug #5596: Effects in constant spells should not be merged
|
Bug #5596: Effects in constant spells should not be merged
|
||||||
Bug #5621: Drained stats cannot be restored
|
Bug #5621: Drained stats cannot be restored
|
||||||
Bug #5755: Active grid object paging - disappearing textures
|
Bug #5755: Active grid object paging - disappearing textures
|
||||||
|
Bug #5766: Active grid object paging - disappearing textures
|
||||||
Bug #5788: Texture editing parses the selected indexes wrongly
|
Bug #5788: Texture editing parses the selected indexes wrongly
|
||||||
Bug #5801: A multi-effect spell with the intervention effects and recall always favors Almsivi intervention
|
Bug #5801: A multi-effect spell with the intervention effects and recall always favors Almsivi intervention
|
||||||
Bug #5842: GetDisposition adds temporary disposition change from different actors
|
Bug #5842: GetDisposition adds temporary disposition change from different actors
|
||||||
|
@ -40,6 +41,7 @@
|
||||||
Bug #6133: Cannot reliably sneak or steal in the sight of the NPCs siding with player
|
Bug #6133: Cannot reliably sneak or steal in the sight of the NPCs siding with player
|
||||||
Bug #6143: Capturing a screenshot makes engine to be a temporary unresponsive
|
Bug #6143: Capturing a screenshot makes engine to be a temporary unresponsive
|
||||||
Bug #6165: Paralyzed player character can pickup items when the inventory is open
|
Bug #6165: Paralyzed player character can pickup items when the inventory is open
|
||||||
|
Bug #6172: Some creatures can't open doors
|
||||||
Bug #6174: Spellmaking and Enchanting sliders differences from vanilla
|
Bug #6174: Spellmaking and Enchanting sliders differences from vanilla
|
||||||
Bug #6184: Command and Calm and Demoralize and Frenzy and Rally magic effects inconsistencies with vanilla
|
Bug #6184: Command and Calm and Demoralize and Frenzy and Rally magic effects inconsistencies with vanilla
|
||||||
Bug #6197: Infinite Casting Loop
|
Bug #6197: Infinite Casting Loop
|
||||||
|
@ -49,6 +51,7 @@
|
||||||
Bug #6283: Avis Dorsey follows you after her death
|
Bug #6283: Avis Dorsey follows you after her death
|
||||||
Bug #6289: Keyword search in dialogues expected the text to be all ASCII characters
|
Bug #6289: Keyword search in dialogues expected the text to be all ASCII characters
|
||||||
Bug #6302: Teleporting disabled actor breaks its disabled state
|
Bug #6302: Teleporting disabled actor breaks its disabled state
|
||||||
|
Bug #6307: Pathfinding in Infidelities quest from Tribunal addon is broken
|
||||||
Feature #890: OpenMW-CS: Column filtering
|
Feature #890: OpenMW-CS: Column filtering
|
||||||
Feature #2554: Modifying an object triggers the instances table to scroll to the corresponding record
|
Feature #2554: Modifying an object triggers the instances table to scroll to the corresponding record
|
||||||
Feature #2780: A way to see current OpenMW version in the console
|
Feature #2780: A way to see current OpenMW version in the console
|
||||||
|
@ -60,6 +63,7 @@
|
||||||
Feature #5198: Implement "Magic effect expired" event
|
Feature #5198: Implement "Magic effect expired" event
|
||||||
Feature #5454: Clear active spells from actor when he disappears from scene
|
Feature #5454: Clear active spells from actor when he disappears from scene
|
||||||
Feature #5489: MCP: Telekinesis fix for activators
|
Feature #5489: MCP: Telekinesis fix for activators
|
||||||
|
Feature #5737: Handle instance move from one cell to another
|
||||||
Feature #5996: Support Lua scripts in OpenMW
|
Feature #5996: Support Lua scripts in OpenMW
|
||||||
Feature #6017: Separate persistent and temporary cell references when saving
|
Feature #6017: Separate persistent and temporary cell references when saving
|
||||||
Feature #6032: Reverse-z depth buffer
|
Feature #6032: Reverse-z depth buffer
|
||||||
|
|
|
@ -653,7 +653,8 @@ namespace MWBase
|
||||||
|
|
||||||
virtual bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const = 0;
|
virtual bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const = 0;
|
||||||
|
|
||||||
virtual bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const = 0;
|
virtual bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius,
|
||||||
|
const MWWorld::ConstPtr& ignore, std::vector<MWWorld::Ptr>* occupyingActors = nullptr) const = 0;
|
||||||
|
|
||||||
virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0;
|
virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0;
|
||||||
|
|
||||||
|
|
|
@ -38,15 +38,15 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Activator::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated) const
|
void Activator::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
insertObjectPhysics(ptr, model, rotation, physics, skipAnimated);
|
insertObjectPhysics(ptr, model, rotation, physics);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Activator::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated) const
|
void Activator::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
if(!model.empty())
|
||||||
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World, skipAnimated);
|
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Activator::getModel(const MWWorld::ConstPtr &ptr) const
|
std::string Activator::getModel(const MWWorld::ConstPtr &ptr) const
|
||||||
|
|
|
@ -17,9 +17,9 @@ namespace MWClass
|
||||||
void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const override;
|
void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const override;
|
||||||
///< Add reference into a cell for rendering
|
///< Add reference into a cell for rendering
|
||||||
|
|
||||||
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated = false) const override;
|
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const override;
|
||||||
|
|
||||||
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated) const override;
|
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const override;
|
||||||
|
|
||||||
std::string getName (const MWWorld::ConstPtr& ptr) const override;
|
std::string getName (const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \return name or ID; can return an empty string.
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace MWClass
|
||||||
MWBase::Environment::get().getWorld()->adjustPosition(ptr, force);
|
MWBase::Environment::get().getWorld()->adjustPosition(ptr, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated) const
|
void Actor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if (!model.empty())
|
if (!model.empty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace MWClass
|
||||||
///< Adjust position to stand on ground. Must be called post model load
|
///< Adjust position to stand on ground. Must be called post model load
|
||||||
/// @param force do this even if the ptr is flying
|
/// @param force do this even if the ptr is flying
|
||||||
|
|
||||||
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated = false) const override;
|
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const override;
|
||||||
|
|
||||||
bool useAnim() const override;
|
bool useAnim() const override;
|
||||||
|
|
||||||
|
|
|
@ -106,15 +106,15 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated) const
|
void Container::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
insertObjectPhysics(ptr, model, rotation, physics, skipAnimated);
|
insertObjectPhysics(ptr, model, rotation, physics);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated) const
|
void Container::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
if(!model.empty())
|
||||||
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World, skipAnimated);
|
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Container::getModel(const MWWorld::ConstPtr &ptr) const
|
std::string Container::getModel(const MWWorld::ConstPtr &ptr) const
|
||||||
|
|
|
@ -42,8 +42,8 @@ namespace MWClass
|
||||||
void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const override;
|
void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const override;
|
||||||
///< Add reference into a cell for rendering
|
///< Add reference into a cell for rendering
|
||||||
|
|
||||||
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated = false) const override;
|
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const override;
|
||||||
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated = false) const override;
|
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const override;
|
||||||
|
|
||||||
std::string getName (const MWWorld::ConstPtr& ptr) const override;
|
std::string getName (const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \return name or ID; can return an empty string.
|
||||||
|
|
|
@ -55,9 +55,9 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Door::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated) const
|
void Door::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
insertObjectPhysics(ptr, model, rotation, physics, skipAnimated);
|
insertObjectPhysics(ptr, model, rotation, physics);
|
||||||
|
|
||||||
// Resume the door's opening/closing animation if it wasn't finished
|
// Resume the door's opening/closing animation if it wasn't finished
|
||||||
if (ptr.getRefData().getCustomData())
|
if (ptr.getRefData().getCustomData())
|
||||||
|
@ -70,10 +70,10 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Door::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated) const
|
void Door::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
if(!model.empty())
|
||||||
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_Door, skipAnimated);
|
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_Door);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Door::isDoor() const
|
bool Door::isDoor() const
|
||||||
|
|
|
@ -18,8 +18,8 @@ namespace MWClass
|
||||||
void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const override;
|
void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const override;
|
||||||
///< Add reference into a cell for rendering
|
///< Add reference into a cell for rendering
|
||||||
|
|
||||||
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated = false) const override;
|
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const override;
|
||||||
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated = false) const override;
|
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const override;
|
||||||
|
|
||||||
bool isDoor() const override;
|
bool isDoor() const override;
|
||||||
|
|
||||||
|
|
|
@ -33,13 +33,13 @@ namespace MWClass
|
||||||
renderingInterface.getObjects().insertModel(ptr, model, true, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault));
|
renderingInterface.getObjects().insertModel(ptr, model, true, !(ref->mBase->mData.mFlags & ESM::Light::OffDefault));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Light::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated) const
|
void Light::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Light> *ref =
|
MWWorld::LiveCellRef<ESM::Light> *ref =
|
||||||
ptr.get<ESM::Light>();
|
ptr.get<ESM::Light>();
|
||||||
assert (ref->mBase != nullptr);
|
assert (ref->mBase != nullptr);
|
||||||
|
|
||||||
insertObjectPhysics(ptr, model, rotation, physics, skipAnimated);
|
insertObjectPhysics(ptr, model, rotation, physics);
|
||||||
|
|
||||||
if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault))
|
if (!ref->mBase->mSound.empty() && !(ref->mBase->mData.mFlags & ESM::Light::OffDefault))
|
||||||
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0,
|
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0,
|
||||||
|
@ -47,11 +47,11 @@ namespace MWClass
|
||||||
MWSound::PlayMode::Loop);
|
MWSound::PlayMode::Loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Light::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated) const
|
void Light::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
// TODO: add option somewhere to enable collision for placeable objects
|
// TODO: add option somewhere to enable collision for placeable objects
|
||||||
if (!model.empty() && (ptr.get<ESM::Light>()->mBase->mData.mFlags & ESM::Light::Carry) == 0)
|
if (!model.empty() && (ptr.get<ESM::Light>()->mBase->mData.mFlags & ESM::Light::Carry) == 0)
|
||||||
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World, skipAnimated);
|
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Light::useAnim() const
|
bool Light::useAnim() const
|
||||||
|
|
|
@ -14,8 +14,8 @@ namespace MWClass
|
||||||
void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const override;
|
void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const override;
|
||||||
///< Add reference into a cell for rendering
|
///< Add reference into a cell for rendering
|
||||||
|
|
||||||
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated = false) const override;
|
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const override;
|
||||||
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated = false) const override;
|
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const override;
|
||||||
|
|
||||||
bool useAnim() const override;
|
bool useAnim() const override;
|
||||||
|
|
||||||
|
|
|
@ -23,15 +23,15 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Static::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated) const
|
void Static::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
insertObjectPhysics(ptr, model, rotation, physics, skipAnimated);
|
insertObjectPhysics(ptr, model, rotation, physics);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Static::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated) const
|
void Static::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
if(!model.empty())
|
if(!model.empty())
|
||||||
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World, skipAnimated);
|
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_World);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Static::getModel(const MWWorld::ConstPtr &ptr) const
|
std::string Static::getModel(const MWWorld::ConstPtr &ptr) const
|
||||||
|
|
|
@ -14,8 +14,8 @@ namespace MWClass
|
||||||
void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const override;
|
void insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const override;
|
||||||
///< Add reference into a cell for rendering
|
///< Add reference into a cell for rendering
|
||||||
|
|
||||||
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated = false) const override;
|
void insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const override;
|
||||||
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated = false) const override;
|
void insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const override;
|
||||||
|
|
||||||
std::string getName (const MWWorld::ConstPtr& ptr) const override;
|
std::string getName (const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \return name or ID; can return an empty string.
|
||||||
|
|
|
@ -99,8 +99,8 @@ namespace MWInput
|
||||||
// We keep track of our own mouse position, so that moving the mouse while in
|
// We keep track of our own mouse position, so that moving the mouse while in
|
||||||
// game mode does not move the position of the GUI cursor
|
// game mode does not move the position of the GUI cursor
|
||||||
float uiScale = MWBase::Environment::get().getWindowManager()->getScalingFactor();
|
float uiScale = MWBase::Environment::get().getWindowManager()->getScalingFactor();
|
||||||
float xMove = xAxis * dt * 1500.0f / uiScale;
|
float xMove = xAxis * dt * 1500.0f / uiScale * mGamepadCursorSpeed;
|
||||||
float yMove = yAxis * dt * 1500.0f / uiScale;
|
float yMove = yAxis * dt * 1500.0f / uiScale * mGamepadCursorSpeed;
|
||||||
|
|
||||||
float mouseWheelMove = -zAxis * dt * 1500.0f;
|
float mouseWheelMove = -zAxis * dt * 1500.0f;
|
||||||
if (xMove != 0 || yMove != 0 || mouseWheelMove != 0)
|
if (xMove != 0 || yMove != 0 || mouseWheelMove != 0)
|
||||||
|
|
|
@ -51,8 +51,8 @@ namespace MWLua
|
||||||
std::array<bool, MWWorld::InventoryStore::Slots> usedSlots;
|
std::array<bool, MWWorld::InventoryStore::Slots> usedSlots;
|
||||||
std::fill(usedSlots.begin(), usedSlots.end(), false);
|
std::fill(usedSlots.begin(), usedSlots.end(), false);
|
||||||
|
|
||||||
constexpr int anySlot = -1;
|
static constexpr int anySlot = -1;
|
||||||
auto tryEquipToSlot = [&actor, &store, &usedSlots, &worldView, anySlot](int slot, const Item& item) -> bool
|
auto tryEquipToSlot = [&actor, &store, &usedSlots, &worldView](int slot, const Item& item) -> bool
|
||||||
{
|
{
|
||||||
auto old_it = slot != anySlot ? store.getSlot(slot) : store.end();
|
auto old_it = slot != anySlot ? store.getSlot(slot) : store.end();
|
||||||
MWWorld::Ptr itemPtr;
|
MWWorld::Ptr itemPtr;
|
||||||
|
|
|
@ -47,8 +47,6 @@ namespace MWLua
|
||||||
return LObject(getId(r.mHitObject), worldView->getObjectRegistry());
|
return LObject(getId(r.mHitObject), worldView->getObjectRegistry());
|
||||||
});
|
});
|
||||||
|
|
||||||
constexpr int defaultCollisionType = MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap |
|
|
||||||
MWPhysics::CollisionType_Actor | MWPhysics::CollisionType_Door;
|
|
||||||
api["COLLISION_TYPE"] = LuaUtil::makeReadOnly(context.mLua->sol().create_table_with(
|
api["COLLISION_TYPE"] = LuaUtil::makeReadOnly(context.mLua->sol().create_table_with(
|
||||||
"World", MWPhysics::CollisionType_World,
|
"World", MWPhysics::CollisionType_World,
|
||||||
"Door", MWPhysics::CollisionType_Door,
|
"Door", MWPhysics::CollisionType_Door,
|
||||||
|
@ -56,12 +54,12 @@ namespace MWLua
|
||||||
"HeightMap", MWPhysics::CollisionType_HeightMap,
|
"HeightMap", MWPhysics::CollisionType_HeightMap,
|
||||||
"Projectile", MWPhysics::CollisionType_Projectile,
|
"Projectile", MWPhysics::CollisionType_Projectile,
|
||||||
"Water", MWPhysics::CollisionType_Water,
|
"Water", MWPhysics::CollisionType_Water,
|
||||||
"Default", defaultCollisionType));
|
"Default", MWPhysics::CollisionType_Default));
|
||||||
|
|
||||||
api["castRay"] = [defaultCollisionType](const osg::Vec3f& from, const osg::Vec3f& to, sol::optional<sol::table> options)
|
api["castRay"] = [](const osg::Vec3f& from, const osg::Vec3f& to, sol::optional<sol::table> options)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ignore;
|
MWWorld::Ptr ignore;
|
||||||
int collisionType = defaultCollisionType;
|
int collisionType = MWPhysics::CollisionType_Default;
|
||||||
float radius = 0;
|
float radius = 0;
|
||||||
if (options)
|
if (options)
|
||||||
{
|
{
|
||||||
|
@ -80,7 +78,7 @@ namespace MWLua
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// TODO: async raycasting
|
// TODO: async raycasting
|
||||||
/*api["asyncCastRay"] = [luaManager = context.mLuaManager, defaultCollisionType](
|
/*api["asyncCastRay"] = [luaManager = context.mLuaManager](
|
||||||
const Callback& luaCallback, const osg::Vec3f& from, const osg::Vec3f& to, sol::optional<sol::table> options)
|
const Callback& luaCallback, const osg::Vec3f& from, const osg::Vec3f& to, sol::optional<sol::table> options)
|
||||||
{
|
{
|
||||||
std::function<void(MWPhysics::RayCastingResult)> callback =
|
std::function<void(MWPhysics::RayCastingResult)> callback =
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation)
|
Actor::Actor(const MWWorld::Ptr &ptr, MWRender::Animation *animation)
|
||||||
|
: mPositionAdjusted(false)
|
||||||
{
|
{
|
||||||
mCharacterController.reset(new CharacterController(ptr, animation));
|
mCharacterController.reset(new CharacterController(ptr, animation));
|
||||||
}
|
}
|
||||||
|
@ -58,4 +59,14 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
mIsTurningToPlayer = turning;
|
mIsTurningToPlayer = turning;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Actor::setPositionAdjusted(bool adjusted)
|
||||||
|
{
|
||||||
|
mPositionAdjusted = adjusted;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Actor::getPositionAdjusted() const
|
||||||
|
{
|
||||||
|
return mPositionAdjusted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,9 @@ namespace MWMechanics
|
||||||
return mEngageCombat.update(duration);
|
return mEngageCombat.update(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setPositionAdjusted(bool adjusted);
|
||||||
|
bool getPositionAdjusted() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<CharacterController> mCharacterController;
|
std::unique_ptr<CharacterController> mCharacterController;
|
||||||
int mGreetingTimer{0};
|
int mGreetingTimer{0};
|
||||||
|
@ -55,6 +58,7 @@ namespace MWMechanics
|
||||||
GreetingState mGreetingState{Greet_None};
|
GreetingState mGreetingState{Greet_None};
|
||||||
bool mIsTurningToPlayer{false};
|
bool mIsTurningToPlayer{false};
|
||||||
Misc::DeviatingPeriodicTimer mEngageCombat{1.0f, 0.25f, Misc::Rng::deviate(0, 0.25f)};
|
Misc::DeviatingPeriodicTimer mEngageCombat{1.0f, 0.25f, Misc::Rng::deviate(0, 0.25f)};
|
||||||
|
bool mPositionAdjusted;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1608,7 +1608,14 @@ namespace MWMechanics
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (!isPlayer)
|
else if (!isPlayer)
|
||||||
|
{
|
||||||
iter->first.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Actor);
|
iter->first.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Actor);
|
||||||
|
if (!iter->second->getPositionAdjusted())
|
||||||
|
{
|
||||||
|
iter->first.getClass().adjustPosition(iter->first, false);
|
||||||
|
iter->second->setPositionAdjusted(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const bool isDead = iter->first.getClass().getCreatureStats(iter->first).isDead();
|
const bool isDead = iter->first.getClass().getCreatureStats(iter->first).isDead();
|
||||||
if (!isDead && (!godmode || !isPlayer) && iter->first.getClass().getCreatureStats(iter->first).isParalyzed())
|
if (!isDead && (!godmode || !isPlayer) && iter->first.getClass().getCreatureStats(iter->first).isParalyzed())
|
||||||
|
|
|
@ -34,6 +34,11 @@ namespace
|
||||||
const float actorTolerance = 2 * speed * duration + 1.2 * std::max(halfExtents.x(), halfExtents.y());
|
const float actorTolerance = 2 * speed * duration + 1.2 * std::max(halfExtents.x(), halfExtents.y());
|
||||||
return std::max(MWMechanics::MIN_TOLERANCE, actorTolerance);
|
return std::max(MWMechanics::MIN_TOLERANCE, actorTolerance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool canOpenDoors(const MWWorld::Ptr& ptr)
|
||||||
|
{
|
||||||
|
return ptr.getClass().isBipedal(ptr) || ptr.getClass().hasInventoryStore(ptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::AiPackage::AiPackage(AiPackageTypeId typeId, const Options& options) :
|
MWMechanics::AiPackage::AiPackage(AiPackageTypeId typeId, const Options& options) :
|
||||||
|
@ -118,7 +123,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
|
||||||
|
|
||||||
if (!isDestReached && timerStatus == Misc::TimerStatus::Elapsed)
|
if (!isDestReached && timerStatus == Misc::TimerStatus::Elapsed)
|
||||||
{
|
{
|
||||||
if (actor.getClass().isBipedal(actor))
|
if (canOpenDoors(actor))
|
||||||
openDoors(actor);
|
openDoors(actor);
|
||||||
|
|
||||||
const bool wasShortcutting = mIsShortcutting;
|
const bool wasShortcutting = mIsShortcutting;
|
||||||
|
@ -232,7 +237,7 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor)
|
||||||
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
|
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
|
||||||
|
|
||||||
const MWWorld::Ptr door = getNearbyDoor(actor, distance);
|
const MWWorld::Ptr door = getNearbyDoor(actor, distance);
|
||||||
if (!door.isEmpty() && actor.getClass().isBipedal(actor))
|
if (!door.isEmpty() && canOpenDoors(actor))
|
||||||
{
|
{
|
||||||
openDoors(actor);
|
openDoors(actor);
|
||||||
}
|
}
|
||||||
|
@ -443,9 +448,13 @@ DetourNavigator::Flags MWMechanics::AiPackage::getNavigatorFlags(const MWWorld::
|
||||||
result |= DetourNavigator::Flag_swim;
|
result |= DetourNavigator::Flag_swim;
|
||||||
|
|
||||||
if (actorClass.canWalk(actor) && actor.getClass().getWalkSpeed(actor) > 0)
|
if (actorClass.canWalk(actor) && actor.getClass().getWalkSpeed(actor) > 0)
|
||||||
|
{
|
||||||
result |= DetourNavigator::Flag_walk;
|
result |= DetourNavigator::Flag_walk;
|
||||||
|
if (getTypeId() == AiPackageTypeId::Travel)
|
||||||
|
result |= DetourNavigator::Flag_usePathgrid;
|
||||||
|
}
|
||||||
|
|
||||||
if (actorClass.isBipedal(actor) && getTypeId() != AiPackageTypeId::Wander)
|
if (canOpenDoors(actor) && getTypeId() != AiPackageTypeId::Wander)
|
||||||
result |= DetourNavigator::Flag_openDoor;
|
result |= DetourNavigator::Flag_openDoor;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -457,20 +466,31 @@ DetourNavigator::AreaCosts MWMechanics::AiPackage::getAreaCosts(const MWWorld::P
|
||||||
const DetourNavigator::Flags flags = getNavigatorFlags(actor);
|
const DetourNavigator::Flags flags = getNavigatorFlags(actor);
|
||||||
const MWWorld::Class& actorClass = actor.getClass();
|
const MWWorld::Class& actorClass = actor.getClass();
|
||||||
|
|
||||||
if (flags & DetourNavigator::Flag_swim)
|
const float swimSpeed = (flags & DetourNavigator::Flag_swim) == 0
|
||||||
costs.mWater = divOrMax(costs.mWater, actorClass.getSwimSpeed(actor));
|
? 0.0f
|
||||||
|
: actorClass.getSwimSpeed(actor);
|
||||||
|
|
||||||
if (flags & DetourNavigator::Flag_walk)
|
const float walkSpeed = [&]
|
||||||
{
|
{
|
||||||
float walkCost;
|
if ((flags & DetourNavigator::Flag_walk) == 0)
|
||||||
|
return 0.0f;
|
||||||
if (getTypeId() == AiPackageTypeId::Wander)
|
if (getTypeId() == AiPackageTypeId::Wander)
|
||||||
walkCost = divOrMax(1.0, actorClass.getWalkSpeed(actor));
|
return actorClass.getWalkSpeed(actor);
|
||||||
else
|
return actorClass.getRunSpeed(actor);
|
||||||
walkCost = divOrMax(1.0, actorClass.getRunSpeed(actor));
|
} ();
|
||||||
costs.mDoor = costs.mDoor * walkCost;
|
|
||||||
costs.mPathgrid = costs.mPathgrid * walkCost;
|
const float maxSpeed = std::max(swimSpeed, walkSpeed);
|
||||||
costs.mGround = costs.mGround * walkCost;
|
|
||||||
}
|
if (maxSpeed == 0)
|
||||||
|
return costs;
|
||||||
|
|
||||||
|
const float swimFactor = swimSpeed / maxSpeed;
|
||||||
|
const float walkFactor = walkSpeed / maxSpeed;
|
||||||
|
|
||||||
|
costs.mWater = divOrMax(costs.mWater, swimFactor);
|
||||||
|
costs.mDoor = divOrMax(costs.mDoor, walkFactor);
|
||||||
|
costs.mPathgrid = divOrMax(costs.mPathgrid, walkFactor);
|
||||||
|
costs.mGround = divOrMax(costs.mGround, walkFactor);
|
||||||
|
|
||||||
return costs;
|
return costs;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "aitravel.hpp"
|
#include "aitravel.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <components/esm/aisequence.hpp>
|
#include <components/esm/aisequence.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -23,6 +25,11 @@ bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2)
|
||||||
return (pos1 - pos2).length2() <= 7168*7168;
|
return (pos1 - pos2).length2() <= 7168*7168;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float getActorRadius(const MWWorld::ConstPtr& actor)
|
||||||
|
{
|
||||||
|
const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor);
|
||||||
|
return std::max(halfExtents.x(), std::max(halfExtents.y(), halfExtents.z()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
|
@ -70,16 +77,24 @@ namespace MWMechanics
|
||||||
|
|
||||||
// Unfortunately, with vanilla assets destination is sometimes blocked by other actor.
|
// Unfortunately, with vanilla assets destination is sometimes blocked by other actor.
|
||||||
// If we got close to target, check for actors nearby. If they are, finish AI package.
|
// If we got close to target, check for actors nearby. If they are, finish AI package.
|
||||||
int destinationTolerance = 64;
|
if (mDestinationCheck.update(duration) == Misc::TimerStatus::Elapsed)
|
||||||
if (distance(actorPos, targetPos) <= destinationTolerance)
|
|
||||||
{
|
{
|
||||||
std::vector<MWWorld::Ptr> targetActors;
|
std::vector<MWWorld::Ptr> occupyingActors;
|
||||||
std::pair<MWWorld::Ptr, osg::Vec3f> result = MWBase::Environment::get().getWorld()->getHitContact(actor, destinationTolerance, targetActors);
|
if (isAreaOccupiedByOtherActor(actor, targetPos, &occupyingActors))
|
||||||
|
|
||||||
if (!result.first.isEmpty())
|
|
||||||
{
|
{
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
const float actorRadius = getActorRadius(actor);
|
||||||
return true;
|
const float distanceToTarget = distance(actorPos, targetPos);
|
||||||
|
for (const MWWorld::Ptr& other : occupyingActors)
|
||||||
|
{
|
||||||
|
const float otherRadius = getActorRadius(other);
|
||||||
|
const auto [minRadius, maxRadius] = std::minmax(actorRadius, otherRadius);
|
||||||
|
constexpr float toleranceFactor = 1.25;
|
||||||
|
if (minRadius * toleranceFactor + maxRadius > distanceToTarget)
|
||||||
|
{
|
||||||
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,8 @@ namespace MWMechanics
|
||||||
const float mZ;
|
const float mZ;
|
||||||
|
|
||||||
const bool mHidden;
|
const bool mHidden;
|
||||||
|
|
||||||
|
AiReactionTimer mDestinationCheck;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AiInternalTravel final : public AiTravel
|
struct AiInternalTravel final : public AiTravel
|
||||||
|
|
|
@ -85,14 +85,6 @@ namespace MWMechanics
|
||||||
return MWBase::Environment::get().getWorld()->castRay(position, visibleDestination, mask, actor);
|
return MWBase::Environment::get().getWorld()->castRay(position, visibleDestination, mask, actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAreaOccupiedByOtherActor(const MWWorld::ConstPtr &actor, const osg::Vec3f& destination)
|
|
||||||
{
|
|
||||||
const auto world = MWBase::Environment::get().getWorld();
|
|
||||||
const osg::Vec3f halfExtents = world->getPathfindingHalfExtents(actor);
|
|
||||||
const auto maxHalfExtent = std::max(halfExtents.x(), std::max(halfExtents.y(), halfExtents.z()));
|
|
||||||
return world->isAreaOccupiedByOtherActor(destination, 2 * maxHalfExtent, actor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void stopMovement(const MWWorld::Ptr& actor)
|
void stopMovement(const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[0] = 0;
|
actor.getClass().getMovementSettings(actor).mPosition[0] = 0;
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
|
||||||
|
@ -72,6 +74,15 @@ namespace MWMechanics
|
||||||
return MWWorld::Ptr(); // none found
|
return MWWorld::Ptr(); // none found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isAreaOccupiedByOtherActor(const MWWorld::ConstPtr& actor, const osg::Vec3f& destination,
|
||||||
|
std::vector<MWWorld::Ptr>* occupyingActors)
|
||||||
|
{
|
||||||
|
const auto world = MWBase::Environment::get().getWorld();
|
||||||
|
const osg::Vec3f halfExtents = world->getPathfindingHalfExtents(actor);
|
||||||
|
const auto maxHalfExtent = std::max(halfExtents.x(), std::max(halfExtents.y(), halfExtents.z()));
|
||||||
|
return world->isAreaOccupiedByOtherActor(destination, 2 * maxHalfExtent, actor, occupyingActors);
|
||||||
|
}
|
||||||
|
|
||||||
ObstacleCheck::ObstacleCheck()
|
ObstacleCheck::ObstacleCheck()
|
||||||
: mWalkState(WalkState::Initial)
|
: mWalkState(WalkState::Initial)
|
||||||
, mStateDuration(0)
|
, mStateDuration(0)
|
||||||
|
|
|
@ -3,9 +3,12 @@
|
||||||
|
|
||||||
#include <osg/Vec3f>
|
#include <osg/Vec3f>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class Ptr;
|
class Ptr;
|
||||||
|
class ConstPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
|
@ -21,6 +24,9 @@ namespace MWMechanics
|
||||||
/** \return Pointer to the door, or empty pointer if none exists **/
|
/** \return Pointer to the door, or empty pointer if none exists **/
|
||||||
const MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist);
|
const MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist);
|
||||||
|
|
||||||
|
bool isAreaOccupiedByOtherActor(const MWWorld::ConstPtr& actor, const osg::Vec3f& destination,
|
||||||
|
std::vector<MWWorld::Ptr>* occupyingActors = nullptr);
|
||||||
|
|
||||||
class ObstacleCheck
|
class ObstacleCheck
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -397,7 +397,7 @@ namespace MWMechanics
|
||||||
mPath.clear();
|
mPath.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status != DetourNavigator::Status::NavMeshNotFound && mPath.empty())
|
if (status != DetourNavigator::Status::NavMeshNotFound && mPath.empty() && (flags & DetourNavigator::Flag_usePathgrid) == 0)
|
||||||
{
|
{
|
||||||
status = buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents,
|
status = buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents,
|
||||||
flags | DetourNavigator::Flag_usePathgrid, areaCosts, endTolerance, pathType, std::back_inserter(mPath));
|
flags | DetourNavigator::Flag_usePathgrid, areaCosts, endTolerance, pathType, std::back_inserter(mPath));
|
||||||
|
|
|
@ -22,28 +22,36 @@ namespace MWPhysics
|
||||||
return nearest.distance(position) < radius;
|
return nearest.distance(position) < radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class OnCollision>
|
||||||
class HasSphereCollisionCallback final : public btBroadphaseAabbCallback
|
class HasSphereCollisionCallback final : public btBroadphaseAabbCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HasSphereCollisionCallback(const btVector3& position, const btScalar radius, btCollisionObject* object,
|
HasSphereCollisionCallback(const btVector3& position, const btScalar radius, btCollisionObject* object,
|
||||||
const int mask, const int group)
|
const int mask, const int group, OnCollision* onCollision)
|
||||||
: mPosition(position),
|
: mPosition(position),
|
||||||
mRadius(radius),
|
mRadius(radius),
|
||||||
mCollisionObject(object),
|
mCollisionObject(object),
|
||||||
mCollisionFilterMask(mask),
|
mCollisionFilterMask(mask),
|
||||||
mCollisionFilterGroup(group)
|
mCollisionFilterGroup(group),
|
||||||
|
mOnCollision(onCollision)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool process(const btBroadphaseProxy* proxy) override
|
bool process(const btBroadphaseProxy* proxy) override
|
||||||
{
|
{
|
||||||
if (mResult)
|
if (mResult && mOnCollision == nullptr)
|
||||||
return false;
|
return false;
|
||||||
const auto collisionObject = static_cast<btCollisionObject*>(proxy->m_clientObject);
|
const auto collisionObject = static_cast<btCollisionObject*>(proxy->m_clientObject);
|
||||||
if (collisionObject == mCollisionObject)
|
if (collisionObject == mCollisionObject
|
||||||
|
|| !needsCollision(*proxy)
|
||||||
|
|| !testAabbAgainstSphere(proxy->m_aabbMin, proxy->m_aabbMax, mPosition, mRadius))
|
||||||
return true;
|
return true;
|
||||||
if (needsCollision(*proxy))
|
mResult = true;
|
||||||
mResult = testAabbAgainstSphere(proxy->m_aabbMin, proxy->m_aabbMax, mPosition, mRadius);
|
if (mOnCollision != nullptr)
|
||||||
|
{
|
||||||
|
(*mOnCollision)(collisionObject);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return !mResult;
|
return !mResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +66,7 @@ namespace MWPhysics
|
||||||
btCollisionObject* mCollisionObject;
|
btCollisionObject* mCollisionObject;
|
||||||
int mCollisionFilterMask;
|
int mCollisionFilterMask;
|
||||||
int mCollisionFilterGroup;
|
int mCollisionFilterGroup;
|
||||||
|
OnCollision* mOnCollision;
|
||||||
bool mResult = false;
|
bool mResult = false;
|
||||||
|
|
||||||
bool needsCollision(const btBroadphaseProxy& proxy) const
|
bool needsCollision(const btBroadphaseProxy& proxy) const
|
||||||
|
|
|
@ -492,7 +492,7 @@ namespace MWPhysics
|
||||||
return heightField->second.get();
|
return heightField->second.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh, osg::Quat rotation, int collisionType, bool skipAnimated)
|
void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh, osg::Quat rotation, int collisionType)
|
||||||
{
|
{
|
||||||
if (ptr.mRef->mData.mPhysicsPostponed)
|
if (ptr.mRef->mData.mPhysicsPostponed)
|
||||||
return;
|
return;
|
||||||
|
@ -500,9 +500,6 @@ namespace MWPhysics
|
||||||
if (!shapeInstance || !shapeInstance->getCollisionShape())
|
if (!shapeInstance || !shapeInstance->getCollisionShape())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (skipAnimated && shapeInstance->isAnimated())
|
|
||||||
return;
|
|
||||||
|
|
||||||
assert(!getObject(ptr));
|
assert(!getObject(ptr));
|
||||||
|
|
||||||
auto obj = std::make_shared<Object>(ptr, shapeInstance, rotation, collisionType, mTaskScheduler.get());
|
auto obj = std::make_shared<Object>(ptr, shapeInstance, rotation, collisionType, mTaskScheduler.get());
|
||||||
|
@ -923,7 +920,8 @@ namespace MWPhysics
|
||||||
CollisionType_Actor|CollisionType_Projectile);
|
CollisionType_Actor|CollisionType_Projectile);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsSystem::isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const
|
bool PhysicsSystem::isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius,
|
||||||
|
const MWWorld::ConstPtr& ignore, std::vector<MWWorld::Ptr>* occupyingActors) const
|
||||||
{
|
{
|
||||||
btCollisionObject* object = nullptr;
|
btCollisionObject* object = nullptr;
|
||||||
const auto it = mActors.find(ignore.mRef);
|
const auto it = mActors.find(ignore.mRef);
|
||||||
|
@ -934,7 +932,19 @@ namespace MWPhysics
|
||||||
const auto aabbMax = bulletPosition + btVector3(radius, radius, radius);
|
const auto aabbMax = bulletPosition + btVector3(radius, radius, radius);
|
||||||
const int mask = MWPhysics::CollisionType_Actor;
|
const int mask = MWPhysics::CollisionType_Actor;
|
||||||
const int group = 0xff;
|
const int group = 0xff;
|
||||||
HasSphereCollisionCallback callback(bulletPosition, radius, object, mask, group);
|
if (occupyingActors == nullptr)
|
||||||
|
{
|
||||||
|
HasSphereCollisionCallback callback(bulletPosition, radius, object, mask, group,
|
||||||
|
static_cast<void (*)(const btCollisionObject*)>(nullptr));
|
||||||
|
mTaskScheduler->aabbTest(aabbMin, aabbMax, callback);
|
||||||
|
return callback.getResult();
|
||||||
|
}
|
||||||
|
const auto onCollision = [&] (const btCollisionObject* object)
|
||||||
|
{
|
||||||
|
if (PtrHolder* holder = static_cast<PtrHolder*>(object->getUserPointer()))
|
||||||
|
occupyingActors->push_back(holder->getPtr());
|
||||||
|
};
|
||||||
|
HasSphereCollisionCallback callback(bulletPosition, radius, object, mask, group, &onCollision);
|
||||||
mTaskScheduler->aabbTest(aabbMin, aabbMax, callback);
|
mTaskScheduler->aabbTest(aabbMin, aabbMax, callback);
|
||||||
return callback.getResult();
|
return callback.getResult();
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,7 +128,7 @@ namespace MWPhysics
|
||||||
void setWaterHeight(float height);
|
void setWaterHeight(float height);
|
||||||
void disableWater();
|
void disableWater();
|
||||||
|
|
||||||
void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, osg::Quat rotation, int collisionType = CollisionType_World, bool skipAnimated = false);
|
void addObject (const MWWorld::Ptr& ptr, const std::string& mesh, osg::Quat rotation, int collisionType = CollisionType_World);
|
||||||
void addActor (const MWWorld::Ptr& ptr, const std::string& mesh);
|
void addActor (const MWWorld::Ptr& ptr, const std::string& mesh);
|
||||||
|
|
||||||
int addProjectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius);
|
int addProjectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, const std::string& mesh, bool computeRadius);
|
||||||
|
@ -252,7 +252,8 @@ namespace MWPhysics
|
||||||
std::for_each(mAnimatedObjects.begin(), mAnimatedObjects.end(), function);
|
std::for_each(mAnimatedObjects.begin(), mAnimatedObjects.end(), function);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const;
|
bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius,
|
||||||
|
const MWWorld::ConstPtr& ignore, std::vector<MWWorld::Ptr>* occupyingActors) const;
|
||||||
|
|
||||||
void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
|
void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
|
||||||
void reportCollision(const btVector3& position, const btVector3& normal);
|
void reportCollision(const btVector3& position, const btVector3& normal);
|
||||||
|
|
|
@ -486,6 +486,7 @@ namespace MWRender
|
||||||
defaultMat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1));
|
defaultMat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1));
|
||||||
defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f));
|
defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f));
|
||||||
sceneRoot->getOrCreateStateSet()->setAttribute(defaultMat);
|
sceneRoot->getOrCreateStateSet()->setAttribute(defaultMat);
|
||||||
|
sceneRoot->getOrCreateStateSet()->addUniform(new osg::Uniform("emissiveMult", 1.f));
|
||||||
|
|
||||||
mFog.reset(new FogManager());
|
mFog.reset(new FogManager());
|
||||||
|
|
||||||
|
|
|
@ -25,16 +25,6 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ListObjectsVisitor
|
|
||||||
{
|
|
||||||
std::vector<MWWorld::Ptr> mObjects;
|
|
||||||
|
|
||||||
bool operator() (const MWWorld::Ptr& ptr)
|
|
||||||
{
|
|
||||||
mObjects.push_back (ptr);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,12 +30,12 @@ namespace MWWorld
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Class::insertObject(const Ptr& ptr, const std::string& mesh, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated) const
|
void Class::insertObject(const Ptr& ptr, const std::string& mesh, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Class::insertObjectPhysics(const Ptr& ptr, const std::string& mesh, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated) const
|
void Class::insertObjectPhysics(const Ptr& ptr, const std::string& mesh, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool Class::apply (const MWWorld::Ptr& ptr, const std::string& id, const MWWorld::Ptr& actor) const
|
bool Class::apply (const MWWorld::Ptr& ptr, const std::string& id, const MWWorld::Ptr& actor) const
|
||||||
|
|
|
@ -78,9 +78,9 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const;
|
virtual void insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const;
|
||||||
virtual void insertObject(const Ptr& ptr, const std::string& mesh, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated = false) const;
|
virtual void insertObject(const Ptr& ptr, const std::string& mesh, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const;
|
||||||
///< Add reference into a cell for rendering (default implementation: don't render anything).
|
///< Add reference into a cell for rendering (default implementation: don't render anything).
|
||||||
virtual void insertObjectPhysics(const Ptr& ptr, const std::string& mesh, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics, bool skipAnimated = false) const;
|
virtual void insertObjectPhysics(const Ptr& ptr, const std::string& mesh, const osg::Quat& rotation, MWPhysics::PhysicsSystem& physics) const;
|
||||||
|
|
||||||
virtual std::string getName (const ConstPtr& ptr) const = 0;
|
virtual std::string getName (const ConstPtr& ptr) const = 0;
|
||||||
///< \return name or ID; can return an empty string.
|
///< \return name or ID; can return an empty string.
|
||||||
|
|
|
@ -104,7 +104,7 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
|
void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
|
||||||
MWRender::RenderingManager& rendering, std::set<ESM::RefNum>& pagedRefs, bool onlyPhysics)
|
MWRender::RenderingManager& rendering, std::set<ESM::RefNum>& pagedRefs)
|
||||||
{
|
{
|
||||||
if (ptr.getRefData().getBaseNode() || physics.getActor(ptr))
|
if (ptr.getRefData().getBaseNode() || physics.getActor(ptr))
|
||||||
{
|
{
|
||||||
|
@ -114,12 +114,6 @@ namespace
|
||||||
|
|
||||||
std::string model = getModel(ptr, rendering.getResourceSystem()->getVFS());
|
std::string model = getModel(ptr, rendering.getResourceSystem()->getVFS());
|
||||||
const auto rotation = makeNodeRotation(ptr, RotationOrder::direct);
|
const auto rotation = makeNodeRotation(ptr, RotationOrder::direct);
|
||||||
if (onlyPhysics && !physics.getObject(ptr) && !ptr.getClass().isActor())
|
|
||||||
{
|
|
||||||
// When we preload physics object we need to skip animated objects. They are dependant on the scene graph which doesn't yet exist.
|
|
||||||
ptr.getClass().insertObject (ptr, model, rotation, physics, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ESM::RefNum& refnum = ptr.getCellRef().getRefNum();
|
const ESM::RefNum& refnum = ptr.getCellRef().getRefNum();
|
||||||
if (!refnum.hasContentFile() || pagedRefs.find(refnum) == pagedRefs.end())
|
if (!refnum.hasContentFile() || pagedRefs.find(refnum) == pagedRefs.end())
|
||||||
|
@ -137,8 +131,7 @@ namespace
|
||||||
// Restore effect particles
|
// Restore effect particles
|
||||||
MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr);
|
MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr);
|
||||||
|
|
||||||
if (!physics.getObject(ptr))
|
ptr.getClass().insertObject (ptr, model, rotation, physics);
|
||||||
ptr.getClass().insertObject (ptr, model, rotation, physics);
|
|
||||||
|
|
||||||
MWBase::Environment::get().getLuaManager()->objectAddedToScene(ptr);
|
MWBase::Environment::get().getLuaManager()->objectAddedToScene(ptr);
|
||||||
}
|
}
|
||||||
|
@ -201,11 +194,10 @@ namespace
|
||||||
{
|
{
|
||||||
MWWorld::CellStore& mCell;
|
MWWorld::CellStore& mCell;
|
||||||
Loading::Listener* mLoadingListener;
|
Loading::Listener* mLoadingListener;
|
||||||
bool mOnlyObjects;
|
|
||||||
|
|
||||||
std::vector<MWWorld::Ptr> mToInsert;
|
std::vector<MWWorld::Ptr> mToInsert;
|
||||||
|
|
||||||
InsertVisitor (MWWorld::CellStore& cell, Loading::Listener* loadingListener, bool onlyObjects);
|
InsertVisitor (MWWorld::CellStore& cell, Loading::Listener* loadingListener);
|
||||||
|
|
||||||
bool operator() (const MWWorld::Ptr& ptr);
|
bool operator() (const MWWorld::Ptr& ptr);
|
||||||
|
|
||||||
|
@ -213,8 +205,8 @@ namespace
|
||||||
void insert(AddObject&& addObject);
|
void insert(AddObject&& addObject);
|
||||||
};
|
};
|
||||||
|
|
||||||
InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, Loading::Listener* loadingListener, bool onlyObjects)
|
InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, Loading::Listener* loadingListener)
|
||||||
: mCell(cell), mLoadingListener(loadingListener), mOnlyObjects(onlyObjects)
|
: mCell(cell), mLoadingListener(loadingListener)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool InsertVisitor::operator() (const MWWorld::Ptr& ptr)
|
bool InsertVisitor::operator() (const MWWorld::Ptr& ptr)
|
||||||
|
@ -230,7 +222,7 @@ namespace
|
||||||
{
|
{
|
||||||
for (MWWorld::Ptr& ptr : mToInsert)
|
for (MWWorld::Ptr& ptr : mToInsert)
|
||||||
{
|
{
|
||||||
if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled() && (!mOnlyObjects || !ptr.getClass().isActor()))
|
if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -248,16 +240,6 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PositionVisitor
|
|
||||||
{
|
|
||||||
bool operator() (const MWWorld::Ptr& ptr)
|
|
||||||
{
|
|
||||||
if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled())
|
|
||||||
ptr.getClass().adjustPosition (ptr, false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
int getCellPositionDistanceToOrigin(const std::pair<int, int>& cellPosition)
|
int getCellPositionDistanceToOrigin(const std::pair<int, int>& cellPosition)
|
||||||
{
|
{
|
||||||
return std::abs(cellPosition.first) + std::abs(cellPosition.second);
|
return std::abs(cellPosition.first) + std::abs(cellPosition.second);
|
||||||
|
@ -324,39 +306,12 @@ namespace MWWorld
|
||||||
mRendering.update (duration, paused);
|
mRendering.update (duration, paused);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::unloadInactiveCell (CellStore* cell)
|
void Scene::unloadCell(CellStore* cell)
|
||||||
{
|
{
|
||||||
assert(mActiveCells.find(cell) == mActiveCells.end());
|
|
||||||
assert(mInactiveCells.find(cell) != mInactiveCells.end());
|
|
||||||
|
|
||||||
Log(Debug::Info) << "Unloading cell " << cell->getCell()->getDescription();
|
|
||||||
|
|
||||||
ListObjectsVisitor visitor;
|
|
||||||
|
|
||||||
cell->forEach(visitor);
|
|
||||||
for (const auto& ptr : visitor.mObjects)
|
|
||||||
{
|
|
||||||
mPhysics->remove(ptr);
|
|
||||||
ptr.mRef->mData.mPhysicsPostponed = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cell->getCell()->isExterior())
|
|
||||||
{
|
|
||||||
const auto cellX = cell->getCell()->getGridX();
|
|
||||||
const auto cellY = cell->getCell()->getGridY();
|
|
||||||
mPhysics->removeHeightField(cellX, cellY);
|
|
||||||
}
|
|
||||||
|
|
||||||
mInactiveCells.erase(cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scene::deactivateCell(CellStore* cell)
|
|
||||||
{
|
|
||||||
assert(mInactiveCells.find(cell) != mInactiveCells.end());
|
|
||||||
if (mActiveCells.find(cell) == mActiveCells.end())
|
if (mActiveCells.find(cell) == mActiveCells.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Log(Debug::Info) << "Deactivate cell " << cell->getCell()->getDescription();
|
Log(Debug::Info) << "Unloading cell " << cell->getCell()->getDescription();
|
||||||
|
|
||||||
ListAndResetObjectsVisitor visitor;
|
ListAndResetObjectsVisitor visitor;
|
||||||
|
|
||||||
|
@ -367,8 +322,8 @@ namespace MWWorld
|
||||||
if (const auto object = mPhysics->getObject(ptr))
|
if (const auto object = mPhysics->getObject(ptr))
|
||||||
{
|
{
|
||||||
mNavigator.removeObject(DetourNavigator::ObjectId(object));
|
mNavigator.removeObject(DetourNavigator::ObjectId(object));
|
||||||
if (object->isAnimated())
|
mPhysics->remove(ptr);
|
||||||
mPhysics->remove(ptr);
|
ptr.mRef->mData.mPhysicsPostponed = false;
|
||||||
}
|
}
|
||||||
else if (mPhysics->getActor(ptr))
|
else if (mPhysics->getActor(ptr))
|
||||||
{
|
{
|
||||||
|
@ -386,6 +341,8 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
if (mPhysics->getHeightField(cellX, cellY) != nullptr)
|
if (mPhysics->getHeightField(cellX, cellY) != nullptr)
|
||||||
mNavigator.removeHeightfield(osg::Vec2i(cellX, cellY));
|
mNavigator.removeHeightfield(osg::Vec2i(cellX, cellY));
|
||||||
|
|
||||||
|
mPhysics->removeHeightField(cellX, cellY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cell->getCell()->hasWater())
|
if (cell->getCell()->hasWater())
|
||||||
|
@ -408,12 +365,11 @@ namespace MWWorld
|
||||||
mActiveCells.erase(cell);
|
mActiveCells.erase(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::activateCell(CellStore *cell, Loading::Listener* loadingListener, bool respawn)
|
void Scene::loadCell(CellStore *cell, Loading::Listener* loadingListener, bool respawn)
|
||||||
{
|
{
|
||||||
using DetourNavigator::HeightfieldShape;
|
using DetourNavigator::HeightfieldShape;
|
||||||
|
|
||||||
assert(mActiveCells.find(cell) == mActiveCells.end());
|
assert(mActiveCells.find(cell) == mActiveCells.end());
|
||||||
assert(mInactiveCells.find(cell) != mInactiveCells.end());
|
|
||||||
mActiveCells.insert(cell);
|
mActiveCells.insert(cell);
|
||||||
|
|
||||||
Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription();
|
Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription();
|
||||||
|
@ -425,13 +381,25 @@ namespace MWWorld
|
||||||
|
|
||||||
if (cell->getCell()->isExterior())
|
if (cell->getCell()->isExterior())
|
||||||
{
|
{
|
||||||
|
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
|
||||||
|
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
|
||||||
|
const float verts = ESM::Land::LAND_SIZE;
|
||||||
|
const float worldsize = ESM::Land::REAL_SIZE;
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
mPhysics->addHeightField (data->mHeights, cellX, cellY, worldsize / (verts-1), verts, data->mMinHeight, data->mMaxHeight, land.get());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static std::vector<float> defaultHeight;
|
||||||
|
defaultHeight.resize(verts*verts, ESM::Land::DEFAULT_HEIGHT);
|
||||||
|
mPhysics->addHeightField (&defaultHeight[0], cellX, cellY, worldsize / (verts-1), verts, ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get());
|
||||||
|
}
|
||||||
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
|
||||||
{
|
{
|
||||||
const osg::Vec2i cellPosition(cellX, cellY);
|
const osg::Vec2i cellPosition(cellX, cellY);
|
||||||
const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin();
|
const btVector3& origin = heightField->getCollisionObject()->getWorldTransform().getOrigin();
|
||||||
const osg::Vec3f shift(origin.x(), origin.y(), origin.z());
|
const osg::Vec3f shift(origin.x(), origin.y(), origin.z());
|
||||||
const osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
|
|
||||||
const ESM::Land::LandData* const data = land == nullptr ? nullptr : land->getData(ESM::Land::DATA_VHGT);
|
|
||||||
const HeightfieldShape shape = [&] () -> HeightfieldShape
|
const HeightfieldShape shape = [&] () -> HeightfieldShape
|
||||||
{
|
{
|
||||||
if (data == nullptr)
|
if (data == nullptr)
|
||||||
|
@ -462,7 +430,7 @@ namespace MWWorld
|
||||||
if (respawn)
|
if (respawn)
|
||||||
cell->respawn();
|
cell->respawn();
|
||||||
|
|
||||||
insertCell(*cell, loadingListener, false);
|
insertCell(*cell, loadingListener);
|
||||||
|
|
||||||
mRendering.addCell(cell);
|
mRendering.addCell(cell);
|
||||||
|
|
||||||
|
@ -511,49 +479,14 @@ namespace MWWorld
|
||||||
mPreloader->notifyLoaded(cell);
|
mPreloader->notifyLoaded(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::loadInactiveCell(CellStore *cell, Loading::Listener* loadingListener)
|
|
||||||
{
|
|
||||||
assert(mActiveCells.find(cell) == mActiveCells.end());
|
|
||||||
assert(mInactiveCells.find(cell) == mInactiveCells.end());
|
|
||||||
mInactiveCells.insert(cell);
|
|
||||||
|
|
||||||
Log(Debug::Info) << "Loading inactive cell " << cell->getCell()->getDescription();
|
|
||||||
|
|
||||||
if (cell->getCell()->isExterior())
|
|
||||||
{
|
|
||||||
float verts = ESM::Land::LAND_SIZE;
|
|
||||||
float worldsize = ESM::Land::REAL_SIZE;
|
|
||||||
|
|
||||||
const int cellX = cell->getCell()->getGridX();
|
|
||||||
const int cellY = cell->getCell()->getGridY();
|
|
||||||
|
|
||||||
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
|
|
||||||
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr;
|
|
||||||
if (data)
|
|
||||||
{
|
|
||||||
mPhysics->addHeightField (data->mHeights, cellX, cellY, worldsize / (verts-1), verts, data->mMinHeight, data->mMaxHeight, land.get());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static std::vector<float> defaultHeight;
|
|
||||||
defaultHeight.resize(verts*verts, ESM::Land::DEFAULT_HEIGHT);
|
|
||||||
mPhysics->addHeightField (&defaultHeight[0], cellX, cellY, worldsize / (verts-1), verts, ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
insertCell(*cell, loadingListener, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scene::clear()
|
void Scene::clear()
|
||||||
{
|
{
|
||||||
for (auto iter = mInactiveCells.begin(); iter!=mInactiveCells.end(); )
|
for (auto iter = mActiveCells.begin(); iter!=mActiveCells.end(); )
|
||||||
{
|
{
|
||||||
auto* cell = *iter++;
|
auto* cell = *iter++;
|
||||||
deactivateCell(cell);
|
unloadCell (cell);
|
||||||
unloadInactiveCell (cell);
|
|
||||||
}
|
}
|
||||||
assert(mActiveCells.empty());
|
assert(mActiveCells.empty());
|
||||||
assert(mInactiveCells.empty());
|
|
||||||
mCurrentCell = nullptr;
|
mCurrentCell = nullptr;
|
||||||
|
|
||||||
mPreloader->clear();
|
mPreloader->clear();
|
||||||
|
@ -595,7 +528,7 @@ namespace MWWorld
|
||||||
|
|
||||||
void Scene::changeCellGrid (const osg::Vec3f &pos, int playerCellX, int playerCellY, bool changeEvent)
|
void Scene::changeCellGrid (const osg::Vec3f &pos, int playerCellX, int playerCellY, bool changeEvent)
|
||||||
{
|
{
|
||||||
for (auto iter = mInactiveCells.begin(); iter != mInactiveCells.end(); )
|
for (auto iter = mActiveCells.begin(); iter != mActiveCells.end(); )
|
||||||
{
|
{
|
||||||
auto* cell = *iter++;
|
auto* cell = *iter++;
|
||||||
if (cell->getCell()->isExterior())
|
if (cell->getCell()->isExterior())
|
||||||
|
@ -603,16 +536,10 @@ namespace MWWorld
|
||||||
const auto dx = std::abs(playerCellX - cell->getCell()->getGridX());
|
const auto dx = std::abs(playerCellX - cell->getCell()->getGridX());
|
||||||
const auto dy = std::abs(playerCellY - cell->getCell()->getGridY());
|
const auto dy = std::abs(playerCellY - cell->getCell()->getGridY());
|
||||||
if (dx > mHalfGridSize || dy > mHalfGridSize)
|
if (dx > mHalfGridSize || dy > mHalfGridSize)
|
||||||
deactivateCell(cell);
|
unloadCell(cell);
|
||||||
|
|
||||||
if (dx > mHalfGridSize+1 || dy > mHalfGridSize+1)
|
|
||||||
unloadInactiveCell(cell);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
unloadCell (cell);
|
||||||
deactivateCell(cell);
|
|
||||||
unloadInactiveCell(cell);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY);
|
mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY);
|
||||||
|
@ -662,7 +589,6 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cellsPositionsToLoad = cellsToLoad(mActiveCells,mHalfGridSize);
|
auto cellsPositionsToLoad = cellsToLoad(mActiveCells,mHalfGridSize);
|
||||||
auto cellsPositionsToLoadInactive = cellsToLoad(mInactiveCells,mHalfGridSize+1);
|
|
||||||
|
|
||||||
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
|
||||||
Loading::ScopedLoad load(loadingListener);
|
Loading::ScopedLoad load(loadingListener);
|
||||||
|
@ -685,26 +611,12 @@ namespace MWWorld
|
||||||
return getCellPositionPriority(lhs) < getCellPositionPriority(rhs);
|
return getCellPositionPriority(lhs) < getCellPositionPriority(rhs);
|
||||||
});
|
});
|
||||||
|
|
||||||
std::sort(cellsPositionsToLoadInactive.begin(), cellsPositionsToLoadInactive.end(),
|
|
||||||
[&] (const std::pair<int, int>& lhs, const std::pair<int, int>& rhs) {
|
|
||||||
return getCellPositionPriority(lhs) < getCellPositionPriority(rhs);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Load cells
|
|
||||||
for (const auto& [x,y] : cellsPositionsToLoadInactive)
|
|
||||||
{
|
|
||||||
if (!isCellInCollection(x, y, mInactiveCells))
|
|
||||||
{
|
|
||||||
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y);
|
|
||||||
loadInactiveCell (cell, loadingListener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const auto& [x,y] : cellsPositionsToLoad)
|
for (const auto& [x,y] : cellsPositionsToLoad)
|
||||||
{
|
{
|
||||||
if (!isCellInCollection(x, y, mActiveCells))
|
if (!isCellInCollection(x, y, mActiveCells))
|
||||||
{
|
{
|
||||||
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y);
|
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y);
|
||||||
activateCell (cell, loadingListener, changeEvent);
|
loadCell (cell, loadingListener, changeEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -737,17 +649,15 @@ namespace MWWorld
|
||||||
loadingListener->setLabel("Testing exterior cells ("+std::to_string(i)+"/"+std::to_string(cells.getExtSize())+")...");
|
loadingListener->setLabel("Testing exterior cells ("+std::to_string(i)+"/"+std::to_string(cells.getExtSize())+")...");
|
||||||
|
|
||||||
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(it->mData.mX, it->mData.mY);
|
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(it->mData.mX, it->mData.mY);
|
||||||
loadInactiveCell(cell, nullptr);
|
loadCell(cell, nullptr, false);
|
||||||
activateCell(cell, nullptr, false);
|
|
||||||
|
|
||||||
auto iter = mInactiveCells.begin();
|
auto iter = mActiveCells.begin();
|
||||||
while (iter != mInactiveCells.end())
|
while (iter != mActiveCells.end())
|
||||||
{
|
{
|
||||||
if (it->isExterior() && it->mData.mX == (*iter)->getCell()->getGridX() &&
|
if (it->isExterior() && it->mData.mX == (*iter)->getCell()->getGridX() &&
|
||||||
it->mData.mY == (*iter)->getCell()->getGridY())
|
it->mData.mY == (*iter)->getCell()->getGridY())
|
||||||
{
|
{
|
||||||
deactivateCell(*iter);
|
unloadCell(*iter);
|
||||||
unloadInactiveCell(*iter);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,18 +695,16 @@ namespace MWWorld
|
||||||
loadingListener->setLabel("Testing interior cells ("+std::to_string(i)+"/"+std::to_string(cells.getIntSize())+")...");
|
loadingListener->setLabel("Testing interior cells ("+std::to_string(i)+"/"+std::to_string(cells.getIntSize())+")...");
|
||||||
|
|
||||||
CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(it->mName);
|
CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(it->mName);
|
||||||
loadInactiveCell(cell, nullptr);
|
loadCell(cell, nullptr, false);
|
||||||
activateCell(cell, nullptr, false);
|
|
||||||
|
|
||||||
auto iter = mInactiveCells.begin();
|
auto iter = mActiveCells.begin();
|
||||||
while (iter != mInactiveCells.end())
|
while (iter != mActiveCells.end())
|
||||||
{
|
{
|
||||||
assert (!(*iter)->getCell()->isExterior());
|
assert (!(*iter)->getCell()->isExterior());
|
||||||
|
|
||||||
if (it->mName == (*iter)->getCell()->mName)
|
if (it->mName == (*iter)->getCell()->mName)
|
||||||
{
|
{
|
||||||
deactivateCell(*iter);
|
unloadCell(*iter);
|
||||||
unloadInactiveCell(*iter);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -915,21 +823,18 @@ namespace MWWorld
|
||||||
Log(Debug::Info) << "Changing to interior";
|
Log(Debug::Info) << "Changing to interior";
|
||||||
|
|
||||||
// unload
|
// unload
|
||||||
for (auto iter = mInactiveCells.begin(); iter!=mInactiveCells.end(); )
|
for (auto iter = mActiveCells.begin(); iter!=mActiveCells.end(); )
|
||||||
{
|
{
|
||||||
auto* cellToUnload = *iter++;
|
auto* cellToUnload = *iter++;
|
||||||
deactivateCell(cellToUnload);
|
unloadCell(cellToUnload);
|
||||||
unloadInactiveCell(cellToUnload);
|
|
||||||
}
|
}
|
||||||
assert(mActiveCells.empty());
|
assert(mActiveCells.empty());
|
||||||
assert(mInactiveCells.empty());
|
|
||||||
|
|
||||||
loadingListener->setProgressRange(cell->count());
|
loadingListener->setProgressRange(cell->count());
|
||||||
|
|
||||||
// Load cell.
|
// Load cell.
|
||||||
mPagedRefs.clear();
|
mPagedRefs.clear();
|
||||||
loadInactiveCell (cell, loadingListener);
|
loadCell(cell, loadingListener, changeEvent);
|
||||||
activateCell (cell, loadingListener, changeEvent);
|
|
||||||
|
|
||||||
changePlayerCell(cell, position, adjustPlayerPos);
|
changePlayerCell(cell, position, adjustPlayerPos);
|
||||||
|
|
||||||
|
@ -979,26 +884,19 @@ namespace MWWorld
|
||||||
mCellChanged = false;
|
mCellChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::insertCell (CellStore &cell, Loading::Listener* loadingListener, bool onlyObjects)
|
void Scene::insertCell (CellStore &cell, Loading::Listener* loadingListener)
|
||||||
{
|
{
|
||||||
InsertVisitor insertVisitor(cell, loadingListener, onlyObjects);
|
InsertVisitor insertVisitor(cell, loadingListener);
|
||||||
cell.forEach (insertVisitor);
|
cell.forEach (insertVisitor);
|
||||||
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering, mPagedRefs, onlyObjects); });
|
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering, mPagedRefs); });
|
||||||
if (!onlyObjects)
|
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mNavigator); });
|
||||||
{
|
|
||||||
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mNavigator); });
|
|
||||||
|
|
||||||
// do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
|
|
||||||
PositionVisitor posVisitor;
|
|
||||||
cell.forEach (posVisitor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::addObjectToScene (const Ptr& ptr)
|
void Scene::addObjectToScene (const Ptr& ptr)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
addObject(ptr, *mPhysics, mRendering, mPagedRefs, false);
|
addObject(ptr, *mPhysics, mRendering, mPagedRefs);
|
||||||
addObject(ptr, *mPhysics, mNavigator);
|
addObject(ptr, *mPhysics, mNavigator);
|
||||||
MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale());
|
MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale());
|
||||||
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
|
|
|
@ -77,7 +77,6 @@ namespace MWWorld
|
||||||
|
|
||||||
CellStore* mCurrentCell; // the cell the player is in
|
CellStore* mCurrentCell; // the cell the player is in
|
||||||
CellStoreCollection mActiveCells;
|
CellStoreCollection mActiveCells;
|
||||||
CellStoreCollection mInactiveCells;
|
|
||||||
bool mCellChanged;
|
bool mCellChanged;
|
||||||
MWPhysics::PhysicsSystem *mPhysics;
|
MWPhysics::PhysicsSystem *mPhysics;
|
||||||
MWRender::RenderingManager& mRendering;
|
MWRender::RenderingManager& mRendering;
|
||||||
|
@ -100,7 +99,7 @@ namespace MWWorld
|
||||||
|
|
||||||
std::vector<osg::ref_ptr<SceneUtil::WorkItem>> mWorkItems;
|
std::vector<osg::ref_ptr<SceneUtil::WorkItem>> mWorkItems;
|
||||||
|
|
||||||
void insertCell(CellStore &cell, Loading::Listener* loadingListener, bool onlyObjects);
|
void insertCell(CellStore &cell, Loading::Listener* loadingListener);
|
||||||
osg::Vec2i mCurrentGridCenter;
|
osg::Vec2i mCurrentGridCenter;
|
||||||
|
|
||||||
// Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center
|
// Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center
|
||||||
|
@ -116,10 +115,8 @@ namespace MWWorld
|
||||||
osg::Vec4i gridCenterToBounds(const osg::Vec2i ¢erCell) const;
|
osg::Vec4i gridCenterToBounds(const osg::Vec2i ¢erCell) const;
|
||||||
osg::Vec2i getNewGridCenter(const osg::Vec3f &pos, const osg::Vec2i *currentGridCenter = nullptr) const;
|
osg::Vec2i getNewGridCenter(const osg::Vec3f &pos, const osg::Vec2i *currentGridCenter = nullptr) const;
|
||||||
|
|
||||||
void unloadInactiveCell(CellStore* cell);
|
void unloadCell(CellStore* cell);
|
||||||
void deactivateCell(CellStore* cell);
|
void loadCell(CellStore *cell, Loading::Listener* loadingListener, bool respawn);
|
||||||
void activateCell(CellStore *cell, Loading::Listener* loadingListener, bool respawn);
|
|
||||||
void loadInactiveCell(CellStore *cell, Loading::Listener* loadingListener);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|
|
@ -3923,9 +3923,10 @@ namespace MWWorld
|
||||||
return btRayAabb(localFrom, localTo, aabbMin, aabbMax, hitDistance, hitNormal);
|
return btRayAabb(localFrom, localTo, aabbMin, aabbMax, hitDistance, hitNormal);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool World::isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const
|
bool World::isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius,
|
||||||
|
const MWWorld::ConstPtr& ignore, std::vector<MWWorld::Ptr>* occupyingActors) const
|
||||||
{
|
{
|
||||||
return mPhysics->isAreaOccupiedByOtherActor(position, radius, ignore);
|
return mPhysics->isAreaOccupiedByOtherActor(position, radius, ignore, occupyingActors);
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::reportStats(unsigned int frameNumber, osg::Stats& stats) const
|
void World::reportStats(unsigned int frameNumber, osg::Stats& stats) const
|
||||||
|
|
|
@ -735,7 +735,8 @@ namespace MWWorld
|
||||||
|
|
||||||
bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override;
|
bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override;
|
||||||
|
|
||||||
bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const override;
|
bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius,
|
||||||
|
const MWWorld::ConstPtr& ignore, std::vector<MWWorld::Ptr>* occupyingActors) const override;
|
||||||
|
|
||||||
void reportStats(unsigned int frameNumber, osg::Stats& stats) const override;
|
void reportStats(unsigned int frameNumber, osg::Stats& stats) const override;
|
||||||
|
|
||||||
|
|
|
@ -328,6 +328,12 @@ namespace LuaUtil
|
||||||
std::make_heap(mHoursTimersQueue.begin(), mHoursTimersQueue.end());
|
std::make_heap(mHoursTimersQueue.begin(), mHoursTimersQueue.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScriptsContainer::~ScriptsContainer()
|
||||||
|
{
|
||||||
|
for (auto& [_, script] : mScripts)
|
||||||
|
script.mHiddenData[ScriptId::KEY] = sol::nil;
|
||||||
|
}
|
||||||
|
|
||||||
void ScriptsContainer::removeAllScripts()
|
void ScriptsContainer::removeAllScripts()
|
||||||
{
|
{
|
||||||
for (auto& [_, script] : mScripts)
|
for (auto& [_, script] : mScripts)
|
||||||
|
|
|
@ -75,7 +75,7 @@ namespace LuaUtil
|
||||||
ScriptsContainer(LuaUtil::LuaState* lua, std::string_view namePrefix);
|
ScriptsContainer(LuaUtil::LuaState* lua, std::string_view namePrefix);
|
||||||
ScriptsContainer(const ScriptsContainer&) = delete;
|
ScriptsContainer(const ScriptsContainer&) = delete;
|
||||||
ScriptsContainer(ScriptsContainer&&) = delete;
|
ScriptsContainer(ScriptsContainer&&) = delete;
|
||||||
virtual ~ScriptsContainer() { removeAllScripts(); }
|
virtual ~ScriptsContainer();
|
||||||
|
|
||||||
// Adds package that will be available (via `require`) for all scripts in the container.
|
// Adds package that will be available (via `require`) for all scripts in the container.
|
||||||
// Automatically applies LuaUtil::makeReadOnly to the package.
|
// Automatically applies LuaUtil::makeReadOnly to the package.
|
||||||
|
|
|
@ -1134,8 +1134,6 @@ namespace NifOsg
|
||||||
trans->addChild(toAttach);
|
trans->addChild(toAttach);
|
||||||
parentNode->addChild(trans);
|
parentNode->addChild(trans);
|
||||||
}
|
}
|
||||||
// create partsys stateset in order to pass in ShaderVisitor like all other Drawables
|
|
||||||
partsys->getOrCreateStateSet();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleNiGeometryData(osg::Geometry *geometry, const Nif::NiGeometryData* data, const std::vector<unsigned int>& boundTextures, const std::string& name)
|
void handleNiGeometryData(osg::Geometry *geometry, const Nif::NiGeometryData* data, const std::vector<unsigned int>& boundTextures, const std::string& name)
|
||||||
|
@ -1923,8 +1921,6 @@ namespace NifOsg
|
||||||
void applyDrawableProperties(osg::Node* node, const std::vector<const Nif::Property*>& properties, SceneUtil::CompositeStateSetUpdater* composite,
|
void applyDrawableProperties(osg::Node* node, const std::vector<const Nif::Property*>& properties, SceneUtil::CompositeStateSetUpdater* composite,
|
||||||
bool hasVertexColors, int animflags)
|
bool hasVertexColors, int animflags)
|
||||||
{
|
{
|
||||||
osg::StateSet* stateset = node->getOrCreateStateSet();
|
|
||||||
|
|
||||||
// Specular lighting is enabled by default, but there's a quirk...
|
// Specular lighting is enabled by default, but there's a quirk...
|
||||||
bool specEnabled = true;
|
bool specEnabled = true;
|
||||||
osg::ref_ptr<osg::Material> mat (new osg::Material);
|
osg::ref_ptr<osg::Material> mat (new osg::Material);
|
||||||
|
@ -2006,15 +2002,15 @@ namespace NifOsg
|
||||||
if (blendFunc->getDestination() == GL_DST_ALPHA)
|
if (blendFunc->getDestination() == GL_DST_ALPHA)
|
||||||
blendFunc->setDestination(GL_ONE);
|
blendFunc->setDestination(GL_ONE);
|
||||||
blendFunc = shareAttribute(blendFunc);
|
blendFunc = shareAttribute(blendFunc);
|
||||||
stateset->setAttributeAndModes(blendFunc, osg::StateAttribute::ON);
|
node->getOrCreateStateSet()->setAttributeAndModes(blendFunc, osg::StateAttribute::ON);
|
||||||
|
|
||||||
bool noSort = (alphaprop->flags>>13)&1;
|
bool noSort = (alphaprop->flags>>13)&1;
|
||||||
if (!noSort)
|
if (!noSort)
|
||||||
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
node->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||||
else
|
else
|
||||||
stateset->setRenderBinToInherit();
|
node->getOrCreateStateSet()->setRenderBinToInherit();
|
||||||
}
|
}
|
||||||
else
|
else if (osg::StateSet* stateset = node->getStateSet())
|
||||||
{
|
{
|
||||||
stateset->removeAttribute(osg::StateAttribute::BLENDFUNC);
|
stateset->removeAttribute(osg::StateAttribute::BLENDFUNC);
|
||||||
stateset->removeMode(GL_BLEND);
|
stateset->removeMode(GL_BLEND);
|
||||||
|
@ -2025,9 +2021,9 @@ namespace NifOsg
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::AlphaFunc> alphaFunc (new osg::AlphaFunc(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f));
|
osg::ref_ptr<osg::AlphaFunc> alphaFunc (new osg::AlphaFunc(getTestMode((alphaprop->flags>>10)&0x7), alphaprop->data.threshold/255.f));
|
||||||
alphaFunc = shareAttribute(alphaFunc);
|
alphaFunc = shareAttribute(alphaFunc);
|
||||||
stateset->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON);
|
node->getOrCreateStateSet()->setAttributeAndModes(alphaFunc, osg::StateAttribute::ON);
|
||||||
}
|
}
|
||||||
else
|
else if (osg::StateSet* stateset = node->getStateSet())
|
||||||
{
|
{
|
||||||
stateset->removeAttribute(osg::StateAttribute::ALPHAFUNC);
|
stateset->removeAttribute(osg::StateAttribute::ALPHAFUNC);
|
||||||
stateset->removeMode(GL_ALPHA_TEST);
|
stateset->removeMode(GL_ALPHA_TEST);
|
||||||
|
@ -2083,8 +2079,10 @@ namespace NifOsg
|
||||||
|
|
||||||
mat = shareAttribute(mat);
|
mat = shareAttribute(mat);
|
||||||
|
|
||||||
|
osg::StateSet* stateset = node->getOrCreateStateSet();
|
||||||
stateset->setAttributeAndModes(mat, osg::StateAttribute::ON);
|
stateset->setAttributeAndModes(mat, osg::StateAttribute::ON);
|
||||||
stateset->addUniform(new osg::Uniform("emissiveMult", emissiveMult));
|
if (emissiveMult != 1.f)
|
||||||
|
stateset->addUniform(new osg::Uniform("emissiveMult", emissiveMult));
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -116,7 +116,6 @@ namespace Shader
|
||||||
, mImageManager(imageManager)
|
, mImageManager(imageManager)
|
||||||
, mDefaultShaderPrefix(defaultShaderPrefix)
|
, mDefaultShaderPrefix(defaultShaderPrefix)
|
||||||
{
|
{
|
||||||
mRequirements.emplace_back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderVisitor::setForceShaders(bool force)
|
void ShaderVisitor::setForceShaders(bool force)
|
||||||
|
@ -421,7 +420,10 @@ namespace Shader
|
||||||
|
|
||||||
void ShaderVisitor::pushRequirements(osg::Node& node)
|
void ShaderVisitor::pushRequirements(osg::Node& node)
|
||||||
{
|
{
|
||||||
mRequirements.push_back(mRequirements.back());
|
if (mRequirements.empty())
|
||||||
|
mRequirements.emplace_back();
|
||||||
|
else
|
||||||
|
mRequirements.push_back(mRequirements.back());
|
||||||
mRequirements.back().mNode = &node;
|
mRequirements.back().mNode = &node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ Savegames
|
||||||
+--------------+-----------------------------------------------------------------------------------------------------+
|
+--------------+-----------------------------------------------------------------------------------------------------+
|
||||||
| OS | Location |
|
| OS | Location |
|
||||||
+==============+=====================================================================================================+
|
+==============+=====================================================================================================+
|
||||||
| Linux | ``$HOME/.local/share/openmw/saves`` |
|
| Linux | ``$HOME/.local/share/openmw/saves`` |
|
||||||
+--------------+-----------------------------------------------------------------------------------------------------+
|
+--------------+-----------------------------------------------------------------------------------------------------+
|
||||||
| Mac | ``$HOME/Library/Application\ Support/openmw/saves`` |
|
| Mac | ``$HOME/Library/Application\ Support/openmw/saves`` |
|
||||||
+--------------+---------------+-------------------------------------------------------------------------------------+
|
+--------------+---------------+-------------------------------------------------------------------------------------+
|
||||||
|
|
Loading…
Reference in a new issue