Merge branch 'stand' into 'master'

Don't adjust actor position until all objects are loader (#5379)

See merge request OpenMW/openmw!546
pull/3044/head
psi29a 3 years ago
commit 64b4472efa

@ -43,6 +43,7 @@
Bug #5367: Selecting a spell on an enchanted item per hotkey always plays the equip sound Bug #5367: Selecting a spell on an enchanted item per hotkey always plays the equip sound
Bug #5369: Spawnpoint in the Grazelands doesn't produce oversized creatures Bug #5369: Spawnpoint in the Grazelands doesn't produce oversized creatures
Bug #5370: Opening an unlocked but trapped door uses the key Bug #5370: Opening an unlocked but trapped door uses the key
Bug #5379: Wandering NPCs falling through cantons
Bug #5384: openmw-cs: deleting an instance requires reload of scene window to show in editor Bug #5384: openmw-cs: deleting an instance requires reload of scene window to show in editor
Bug #5387: Move/MoveWorld don't update the object's cell properly Bug #5387: Move/MoveWorld don't update the object's cell properly
Bug #5391: Races Redone 1.2 bodies don't show on the inventory Bug #5391: Races Redone 1.2 bodies don't show on the inventory

@ -38,10 +38,10 @@ namespace MWClass
} }
} }
void Activator::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const void Activator::insertObject(const MWWorld::Ptr& ptr, const std::string& model, osg::Quat rotation, MWPhysics::PhysicsSystem& physics) const
{ {
if(!model.empty()) if(!model.empty())
physics.addObject(ptr, model); physics.addObject(ptr, model, rotation);
} }
std::string Activator::getModel(const MWWorld::ConstPtr &ptr) const std::string Activator::getModel(const MWWorld::ConstPtr &ptr) const

@ -17,7 +17,7 @@ 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, MWPhysics::PhysicsSystem& physics) const override; void insertObject(const MWWorld::Ptr& ptr, const std::string& model, 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.

@ -17,16 +17,12 @@
namespace MWClass namespace MWClass
{ {
Actor::Actor() {}
Actor::~Actor() {}
void Actor::adjustPosition(const MWWorld::Ptr& ptr, bool force) const void Actor::adjustPosition(const MWWorld::Ptr& ptr, bool force) const
{ {
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, MWPhysics::PhysicsSystem& physics) const void Actor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, osg::Quat rotation, MWPhysics::PhysicsSystem& physics) const
{ {
if (!model.empty()) if (!model.empty())
{ {

@ -15,16 +15,16 @@ namespace MWClass
{ {
protected: protected:
Actor(); Actor() = default;
public: public:
virtual ~Actor(); ~Actor() override = default;
void adjustPosition(const MWWorld::Ptr& ptr, bool force) const override; void adjustPosition(const MWWorld::Ptr& ptr, bool force) const override;
///< 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, MWPhysics::PhysicsSystem& physics) const override; void insertObject(const MWWorld::Ptr& ptr, const std::string& model, osg::Quat rotation, MWPhysics::PhysicsSystem& physics) const override;
bool useAnim() const override; bool useAnim() const override;
@ -46,8 +46,8 @@ namespace MWClass
float getCurrentSpeed(const MWWorld::Ptr& ptr) const override; float getCurrentSpeed(const MWWorld::Ptr& ptr) const override;
// not implemented // not implemented
Actor(const Actor&); Actor(const Actor&) = delete;
Actor& operator= (const Actor&); Actor& operator= (const Actor&) = delete;
}; };
} }

@ -26,11 +26,6 @@ namespace MWClass
} }
} }
void Apparatus::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
{
// TODO: add option somewhere to enable collision for placeable objects
}
std::string Apparatus::getModel(const MWWorld::ConstPtr &ptr) const std::string Apparatus::getModel(const MWWorld::ConstPtr &ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Apparatus> *ref = ptr.get<ESM::Apparatus>(); const MWWorld::LiveCellRef<ESM::Apparatus> *ref = ptr.get<ESM::Apparatus>();

@ -17,8 +17,6 @@ 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, 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.

@ -34,11 +34,6 @@ namespace MWClass
} }
} }
void Armor::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
{
// TODO: add option somewhere to enable collision for placeable objects
}
std::string Armor::getModel(const MWWorld::ConstPtr &ptr) const std::string Armor::getModel(const MWWorld::ConstPtr &ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>(); const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();

@ -16,8 +16,6 @@ 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, 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,10 +22,6 @@ namespace MWClass
} }
} }
void BodyPart::insertObject(const MWWorld::Ptr &ptr, const std::string &model, MWPhysics::PhysicsSystem &physics) const
{
}
std::string BodyPart::getName(const MWWorld::ConstPtr &ptr) const std::string BodyPart::getName(const MWWorld::ConstPtr &ptr) const
{ {
return std::string(); return std::string();

@ -15,8 +15,6 @@ 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, 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.

@ -31,11 +31,6 @@ namespace MWClass
} }
} }
void Book::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
{
// TODO: add option somewhere to enable collision for placeable objects
}
std::string Book::getModel(const MWWorld::ConstPtr &ptr) const std::string Book::getModel(const MWWorld::ConstPtr &ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Book> *ref = ptr.get<ESM::Book>(); const MWWorld::LiveCellRef<ESM::Book> *ref = ptr.get<ESM::Book>();

@ -14,8 +14,6 @@ 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, 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.

@ -29,11 +29,6 @@ namespace MWClass
} }
} }
void Clothing::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
{
// TODO: add option somewhere to enable collision for placeable objects
}
std::string Clothing::getModel(const MWWorld::ConstPtr &ptr) const std::string Clothing::getModel(const MWWorld::ConstPtr &ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Clothing> *ref = ptr.get<ESM::Clothing>(); const MWWorld::LiveCellRef<ESM::Clothing> *ref = ptr.get<ESM::Clothing>();

@ -14,8 +14,6 @@ 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, 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.

@ -111,10 +111,10 @@ namespace MWClass
} }
} }
void Container::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const void Container::insertObject(const MWWorld::Ptr& ptr, const std::string& model, osg::Quat rotation, MWPhysics::PhysicsSystem& physics) const
{ {
if(!model.empty()) if(!model.empty())
physics.addObject(ptr, model); physics.addObject(ptr, model, rotation);
} }
std::string Container::getModel(const MWWorld::ConstPtr &ptr) const std::string Container::getModel(const MWWorld::ConstPtr &ptr) const

@ -44,7 +44,7 @@ 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, MWPhysics::PhysicsSystem& physics) const override; void insertObject(const MWWorld::Ptr& ptr, const std::string& model, 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.

@ -62,10 +62,10 @@ namespace MWClass
} }
} }
void Door::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const void Door::insertObject(const MWWorld::Ptr& ptr, const std::string& model, osg::Quat rotation, MWPhysics::PhysicsSystem& physics) const
{ {
if(!model.empty()) if(!model.empty())
physics.addObject(ptr, model, MWPhysics::CollisionType_Door); physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_Door);
// 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())

@ -18,7 +18,7 @@ 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, MWPhysics::PhysicsSystem& physics) const override; void insertObject(const MWWorld::Ptr& ptr, const std::string& model, osg::Quat rotation, MWPhysics::PhysicsSystem& physics) const override;
bool isDoor() const override; bool isDoor() const override;

@ -28,11 +28,6 @@ namespace MWClass
} }
} }
void Ingredient::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
{
// TODO: add option somewhere to enable collision for placeable objects
}
std::string Ingredient::getModel(const MWWorld::ConstPtr &ptr) const std::string Ingredient::getModel(const MWWorld::ConstPtr &ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Ingredient> *ref = ptr.get<ESM::Ingredient>(); const MWWorld::LiveCellRef<ESM::Ingredient> *ref = ptr.get<ESM::Ingredient>();

@ -14,8 +14,6 @@ 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, 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.

@ -33,7 +33,7 @@ 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, MWPhysics::PhysicsSystem& physics) const void Light::insertObject(const MWWorld::Ptr& ptr, const std::string& model, 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>();
@ -41,7 +41,7 @@ namespace MWClass
// TODO: add option somewhere to enable collision for placeable objects // TODO: add option somewhere to enable collision for placeable objects
if (!model.empty() && (ref->mBase->mData.mFlags & ESM::Light::Carry) == 0) if (!model.empty() && (ref->mBase->mData.mFlags & ESM::Light::Carry) == 0)
physics.addObject(ptr, model); physics.addObject(ptr, model, rotation);
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,

@ -14,7 +14,7 @@ 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, MWPhysics::PhysicsSystem& physics) const override; void insertObject(const MWWorld::Ptr& ptr, const std::string& model, osg::Quat rotation, MWPhysics::PhysicsSystem& physics) const override;
bool useAnim() const override; bool useAnim() const override;

@ -28,11 +28,6 @@ namespace MWClass
} }
} }
void Lockpick::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
{
// TODO: add option somewhere to enable collision for placeable objects
}
std::string Lockpick::getModel(const MWWorld::ConstPtr &ptr) const std::string Lockpick::getModel(const MWWorld::ConstPtr &ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Lockpick> *ref = ptr.get<ESM::Lockpick>(); const MWWorld::LiveCellRef<ESM::Lockpick> *ref = ptr.get<ESM::Lockpick>();

@ -14,8 +14,6 @@ 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, 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.

@ -37,11 +37,6 @@ namespace MWClass
} }
} }
void Miscellaneous::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
{
// TODO: add option somewhere to enable collision for placeable objects
}
std::string Miscellaneous::getModel(const MWWorld::ConstPtr &ptr) const std::string Miscellaneous::getModel(const MWWorld::ConstPtr &ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>(); const MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = ptr.get<ESM::Miscellaneous>();

@ -14,8 +14,6 @@ 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, 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.

@ -30,11 +30,6 @@ namespace MWClass
} }
} }
void Potion::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
{
// TODO: add option somewhere to enable collision for placeable objects
}
std::string Potion::getModel(const MWWorld::ConstPtr &ptr) const std::string Potion::getModel(const MWWorld::ConstPtr &ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Potion> *ref = ptr.get<ESM::Potion>(); const MWWorld::LiveCellRef<ESM::Potion> *ref = ptr.get<ESM::Potion>();

@ -14,8 +14,6 @@ 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, 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.

@ -28,11 +28,6 @@ namespace MWClass
} }
} }
void Probe::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
{
// TODO: add option somewhere to enable collision for placeable objects
}
std::string Probe::getModel(const MWWorld::ConstPtr &ptr) const std::string Probe::getModel(const MWWorld::ConstPtr &ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Probe> *ref = ptr.get<ESM::Probe>(); const MWWorld::LiveCellRef<ESM::Probe> *ref = ptr.get<ESM::Probe>();

@ -14,8 +14,6 @@ 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, 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.

@ -25,11 +25,6 @@ namespace MWClass
} }
} }
void Repair::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
{
// TODO: add option somewhere to enable collision for placeable objects
}
std::string Repair::getModel(const MWWorld::ConstPtr &ptr) const std::string Repair::getModel(const MWWorld::ConstPtr &ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Repair> *ref = ptr.get<ESM::Repair>(); const MWWorld::LiveCellRef<ESM::Repair> *ref = ptr.get<ESM::Repair>();

@ -14,8 +14,6 @@ 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, 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.

@ -23,10 +23,10 @@ namespace MWClass
} }
} }
void Static::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const void Static::insertObject(const MWWorld::Ptr& ptr, const std::string& model, osg::Quat rotation, MWPhysics::PhysicsSystem& physics) const
{ {
if(!model.empty()) if(!model.empty())
physics.addObject(ptr, model); physics.addObject(ptr, model, rotation);
} }
std::string Static::getModel(const MWWorld::ConstPtr &ptr) const std::string Static::getModel(const MWWorld::ConstPtr &ptr) const
@ -63,4 +63,9 @@ namespace MWClass
return MWWorld::Ptr(cell.insert(ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
bool Static::isStatic() const
{
return true;
}
} }

@ -14,7 +14,7 @@ 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, MWPhysics::PhysicsSystem& physics) const override; void insertObject(const MWWorld::Ptr& ptr, const std::string& model, 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.
@ -25,6 +25,8 @@ namespace MWClass
static void registerSelf(); static void registerSelf();
std::string getModel(const MWWorld::ConstPtr &ptr) const override; std::string getModel(const MWWorld::ConstPtr &ptr) const override;
bool isStatic() const override;
}; };
} }

@ -34,11 +34,6 @@ namespace MWClass
} }
} }
void Weapon::insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const
{
// TODO: add option somewhere to enable collision for placeable objects
}
std::string Weapon::getModel(const MWWorld::ConstPtr &ptr) const std::string Weapon::getModel(const MWWorld::ConstPtr &ptr) const
{ {
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>(); const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();

@ -15,8 +15,6 @@ 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, 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.

@ -67,7 +67,7 @@ Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, Physic
updateScale(); updateScale();
if(!mRotationallyInvariant) if(!mRotationallyInvariant)
updateRotation(); setRotation(mPtr.getRefData().getBaseNode()->getAttitude());
updatePosition(); updatePosition();
addCollisionMask(getCollisionMask()); addCollisionMask(getCollisionMask());
@ -197,10 +197,10 @@ osg::Vec3f Actor::getPreviousPosition() const
return mPreviousPosition; return mPreviousPosition;
} }
void Actor::updateRotation () void Actor::setRotation(osg::Quat quat)
{ {
std::scoped_lock lock(mPositionMutex); std::scoped_lock lock(mPositionMutex);
mRotation = mPtr.getRefData().getBaseNode()->getAttitude(); mRotation = quat;
} }
bool Actor::isRotationallyInvariant() const bool Actor::isRotationallyInvariant() const

@ -49,7 +49,7 @@ namespace MWPhysics
void enableCollisionBody(bool collision); void enableCollisionBody(bool collision);
void updateScale(); void updateScale();
void updateRotation(); void setRotation(osg::Quat quat);
/** /**
* Return true if the collision shape looks the same no matter how its Z rotated. * Return true if the collision shape looks the same no matter how its Z rotated.

@ -14,7 +14,7 @@
namespace MWPhysics namespace MWPhysics
{ {
Object::Object(const MWWorld::Ptr& ptr, osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance, int collisionType, PhysicsTaskScheduler* scheduler) Object::Object(const MWWorld::Ptr& ptr, osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance, osg::Quat rotation, int collisionType, PhysicsTaskScheduler* scheduler)
: mShapeInstance(shapeInstance) : mShapeInstance(shapeInstance)
, mSolid(true) , mSolid(true)
, mTaskScheduler(scheduler) , mTaskScheduler(scheduler)
@ -27,7 +27,7 @@ namespace MWPhysics
mCollisionObject->setUserPointer(this); mCollisionObject->setUserPointer(this);
setScale(ptr.getCellRef().getScale()); setScale(ptr.getCellRef().getScale());
setRotation(Misc::Convert::toBullet(ptr.getRefData().getBaseNode()->getAttitude())); setRotation(rotation);
setOrigin(Misc::Convert::toBullet(ptr.getRefData().getPosition().asVec3())); setOrigin(Misc::Convert::toBullet(ptr.getRefData().getPosition().asVec3()));
commitPositionChange(); commitPositionChange();
@ -51,10 +51,10 @@ namespace MWPhysics
mScaleUpdatePending = true; mScaleUpdatePending = true;
} }
void Object::setRotation(const btQuaternion& quat) void Object::setRotation(osg::Quat quat)
{ {
std::unique_lock<std::mutex> lock(mPositionMutex); std::unique_lock<std::mutex> lock(mPositionMutex);
mLocalTransform.setRotation(quat); mLocalTransform.setRotation(Misc::Convert::toBullet(quat));
mTransformUpdatePending = true; mTransformUpdatePending = true;
} }
@ -116,6 +116,9 @@ namespace MWPhysics
if (mShapeInstance->mAnimatedShapes.empty()) if (mShapeInstance->mAnimatedShapes.empty())
return false; return false;
if (mPtr.getRefData().getBaseNode() == nullptr)
return true;
assert (mShapeInstance->getCollisionShape()->isCompound()); assert (mShapeInstance->getCollisionShape()->isCompound());
btCompoundShape* compound = static_cast<btCompoundShape*>(mShapeInstance->getCollisionShape()); btCompoundShape* compound = static_cast<btCompoundShape*>(mShapeInstance->getCollisionShape());

@ -26,12 +26,12 @@ namespace MWPhysics
class Object final : public PtrHolder class Object final : public PtrHolder
{ {
public: public:
Object(const MWWorld::Ptr& ptr, osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance, int collisionType, PhysicsTaskScheduler* scheduler); Object(const MWWorld::Ptr& ptr, osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance, osg::Quat rotation, int collisionType, PhysicsTaskScheduler* scheduler);
~Object() override; ~Object() override;
const Resource::BulletShapeInstance* getShapeInstance() const; const Resource::BulletShapeInstance* getShapeInstance() const;
void setScale(float scale); void setScale(float scale);
void setRotation(const btQuaternion& quat); void setRotation(osg::Quat quat);
void setOrigin(const btVector3& vec); void setOrigin(const btVector3& vec);
void commitPositionChange(); void commitPositionChange();
btCollisionObject* getCollisionObject(); btCollisionObject* getCollisionObject();

@ -456,20 +456,20 @@ namespace MWPhysics
return heightField->second.get(); return heightField->second.get();
} }
void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh, int collisionType) void PhysicsSystem::addObject (const MWWorld::Ptr& ptr, const std::string& mesh, osg::Quat rotation, int collisionType)
{ {
osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance = mShapeManager->getInstance(mesh); osg::ref_ptr<Resource::BulletShapeInstance> shapeInstance = mShapeManager->getInstance(mesh);
if (!shapeInstance || !shapeInstance->getCollisionShape()) if (!shapeInstance || !shapeInstance->getCollisionShape())
return; return;
auto obj = std::make_shared<Object>(ptr, shapeInstance, collisionType, mTaskScheduler.get()); auto obj = std::make_shared<Object>(ptr, shapeInstance, rotation, collisionType, mTaskScheduler.get());
mObjects.emplace(ptr, obj); mObjects.emplace(ptr, obj);
if (obj->isAnimated()) if (obj->isAnimated())
mAnimatedObjects.insert(obj.get()); mAnimatedObjects.insert(obj.get());
} }
void PhysicsSystem::remove(const MWWorld::Ptr &ptr) void PhysicsSystem::remove(const MWWorld::Ptr &ptr, bool keepObject)
{ {
ObjectMap::iterator found = mObjects.find(ptr); ObjectMap::iterator found = mObjects.find(ptr);
if (found != mObjects.end()) if (found != mObjects.end())
@ -479,7 +479,8 @@ namespace MWPhysics
mAnimatedObjects.erase(found->second.get()); mAnimatedObjects.erase(found->second.get());
mObjects.erase(found); if (!keepObject)
mObjects.erase(found);
} }
ActorMap::iterator foundActor = mActors.find(ptr); ActorMap::iterator foundActor = mActors.find(ptr);
@ -621,12 +622,12 @@ namespace MWPhysics
mTaskScheduler->updateSingleAabb(foundProjectile->second); mTaskScheduler->updateSingleAabb(foundProjectile->second);
} }
void PhysicsSystem::updateRotation(const MWWorld::Ptr &ptr) void PhysicsSystem::updateRotation(const MWWorld::Ptr &ptr, osg::Quat rotate)
{ {
ObjectMap::iterator found = mObjects.find(ptr); ObjectMap::iterator found = mObjects.find(ptr);
if (found != mObjects.end()) if (found != mObjects.end())
{ {
found->second->setRotation(Misc::Convert::toBullet(ptr.getRefData().getBaseNode()->getAttitude())); found->second->setRotation(rotate);
mTaskScheduler->updateSingleAabb(found->second); mTaskScheduler->updateSingleAabb(found->second);
return; return;
} }
@ -635,7 +636,7 @@ namespace MWPhysics
{ {
if (!foundActor->second->isRotationallyInvariant()) if (!foundActor->second->isRotationallyInvariant())
{ {
foundActor->second->updateRotation(); foundActor->second->setRotation(rotate);
mTaskScheduler->updateSingleAabb(foundActor->second); mTaskScheduler->updateSingleAabb(foundActor->second);
} }
return; return;

@ -121,7 +121,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, int collisionType = CollisionType_World); 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, float radius, bool canTraverseWater); int addProjectile(const MWWorld::Ptr& caster, const osg::Vec3f& position, float radius, bool canTraverseWater);
@ -138,10 +138,10 @@ namespace MWPhysics
Projectile* getProjectile(int projectileId) const; Projectile* getProjectile(int projectileId) const;
// Object or Actor // Object or Actor
void remove (const MWWorld::Ptr& ptr); void remove (const MWWorld::Ptr& ptr, bool keepObject = false);
void updateScale (const MWWorld::Ptr& ptr); void updateScale (const MWWorld::Ptr& ptr);
void updateRotation (const MWWorld::Ptr& ptr); void updateRotation (const MWWorld::Ptr& ptr, osg::Quat rotate);
void updatePosition (const MWWorld::Ptr& ptr); void updatePosition (const MWWorld::Ptr& ptr);
void addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject); void addHeightField (const float* heights, int x, int y, float triSize, float sqrtVerts, float minH, float maxH, const osg::Object* holdObject);

@ -18,12 +18,23 @@ namespace MWWorld
if (ptr.getRefData().getBaseNode()) if (ptr.getRefData().getBaseNode())
{ {
ptr.getRefData().setBaseNode(nullptr); ptr.getRefData().setBaseNode(nullptr);
mObjects.push_back (ptr);
} }
mObjects.push_back (ptr);
return true; return true;
} }
}; };
struct ListObjectsVisitor
{
std::vector<MWWorld::Ptr> mObjects;
bool operator() (MWWorld::Ptr ptr)
{
mObjects.push_back (ptr);
return true;
}
};
} }
#endif #endif

@ -25,16 +25,12 @@ namespace MWWorld
{ {
std::map<std::string, std::shared_ptr<Class> > Class::sClasses; std::map<std::string, std::shared_ptr<Class> > Class::sClasses;
Class::Class() {}
Class::~Class() {}
void Class::insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const void Class::insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const
{ {
} }
void Class::insertObject(const Ptr& ptr, const std::string& mesh, MWPhysics::PhysicsSystem& physics) const void Class::insertObject(const Ptr& ptr, const std::string& mesh, osg::Quat rotation, MWPhysics::PhysicsSystem& physics) const
{ {
} }

@ -6,6 +6,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <osg/Quat>
#include <osg/Vec4f> #include <osg/Vec4f>
#include "ptr.hpp" #include "ptr.hpp"
@ -57,13 +58,9 @@ namespace MWWorld
std::string mTypeName; std::string mTypeName;
// not implemented
Class (const Class&);
Class& operator= (const Class&);
protected: protected:
Class(); Class() = default;
std::shared_ptr<Action> defaultItemActivate(const Ptr &ptr, const Ptr &actor) const; std::shared_ptr<Action> defaultItemActivate(const Ptr &ptr, const Ptr &actor) const;
///< Generate default action for activating inventory items ///< Generate default action for activating inventory items
@ -72,14 +69,16 @@ namespace MWWorld
public: public:
virtual ~Class(); virtual ~Class() = default;
Class (const Class&) = delete;
Class& operator= (const Class&) = delete;
const std::string& getTypeName() const { const std::string& getTypeName() const {
return mTypeName; return mTypeName;
} }
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, MWPhysics::PhysicsSystem& physics) const; virtual void insertObject(const Ptr& ptr, const std::string& mesh, 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 std::string getName (const ConstPtr& ptr) const = 0; virtual std::string getName (const ConstPtr& ptr) const = 0;
@ -319,6 +318,10 @@ namespace MWWorld
return false; return false;
} }
virtual bool isStatic() const {
return false;
}
virtual bool isBipedal(const MWWorld::ConstPtr& ptr) const; virtual bool isBipedal(const MWWorld::ConstPtr& ptr) const;
virtual bool canFly(const MWWorld::ConstPtr& ptr) const; virtual bool canFly(const MWWorld::ConstPtr& ptr) const;
virtual bool canSwim(const MWWorld::ConstPtr& ptr) const; virtual bool canSwim(const MWWorld::ConstPtr& ptr) const;

@ -75,18 +75,20 @@ 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, RotationOrder order) osg::Quat makeNodeRotation(const MWWorld::Ptr& ptr, RotationOrder order)
{ {
if (!ptr.getRefData().getBaseNode()) const auto pos = ptr.getRefData().getPosition();
return;
const auto rot = ptr.getClass().isActor() ? makeActorOsgQuat(pos)
: (order == RotationOrder::inverse ? makeInversedOrderObjectOsgQuat(pos) : makeObjectOsgQuat(pos));
rendering.rotateObject(ptr, return rot;
ptr.getClass().isActor() }
? makeActorOsgQuat(ptr.getRefData().getPosition())
: (order == RotationOrder::inverse void setNodeRotation(const MWWorld::Ptr& ptr, MWRender::RenderingManager& rendering, osg::Quat rotation)
? makeInversedOrderObjectOsgQuat(ptr.getRefData().getPosition()) {
: makeObjectOsgQuat(ptr.getRefData().getPosition())) if (ptr.getRefData().getBaseNode())
); rendering.rotateObject(ptr, rotation);
} }
std::string getModel(const MWWorld::Ptr &ptr, const VFS::Manager *vfs) std::string getModel(const MWWorld::Ptr &ptr, const VFS::Manager *vfs)
@ -103,7 +105,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) MWRender::RenderingManager& rendering, std::set<ESM::RefNum>& pagedRefs, bool onlyPhysics)
{ {
if (ptr.getRefData().getBaseNode() || physics.getActor(ptr)) if (ptr.getRefData().getBaseNode() || physics.getActor(ptr))
{ {
@ -111,26 +113,29 @@ namespace
return; return;
} }
bool useAnim = ptr.getClass().useAnim();
std::string model = getModel(ptr, rendering.getResourceSystem()->getVFS()); std::string model = getModel(ptr, rendering.getResourceSystem()->getVFS());
const auto rotation = makeNodeRotation(ptr, RotationOrder::direct);
if (!onlyPhysics)
{
bool useAnim = ptr.getClass().useAnim();
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())
ptr.getClass().insertObjectRendering(ptr, model, rendering); ptr.getClass().insertObjectRendering(ptr, model, rendering);
else
ptr.getRefData().setBaseNode(new SceneUtil::PositionAttitudeTransform); // FIXME remove this when physics code is fixed not to depend on basenode
setNodeRotation(ptr, rendering, RotationOrder::direct);
ptr.getClass().insertObject (ptr, model, physics); setNodeRotation(ptr, rendering, rotation);
if (useAnim) if (useAnim)
MWBase::Environment::get().getMechanicsManager()->add(ptr); MWBase::Environment::get().getMechanicsManager()->add(ptr);
if (ptr.getClass().isActor()) if (ptr.getClass().isActor())
rendering.addWaterRippleEmitter(ptr); rendering.addWaterRippleEmitter(ptr);
// 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);
} }
void addObject(const MWWorld::Ptr& ptr, const MWPhysics::PhysicsSystem& physics, DetourNavigator::Navigator& navigator) void addObject(const MWWorld::Ptr& ptr, const MWPhysics::PhysicsSystem& physics, DetourNavigator::Navigator& navigator)
@ -201,11 +206,12 @@ namespace
{ {
MWWorld::CellStore& mCell; MWWorld::CellStore& mCell;
Loading::Listener& mLoadingListener; Loading::Listener& mLoadingListener;
bool mOnlyStatics;
bool mTest; bool mTest;
std::vector<MWWorld::Ptr> mToInsert; std::vector<MWWorld::Ptr> mToInsert;
InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool test); InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool onlyStatics, bool test);
bool operator() (const MWWorld::Ptr& ptr); bool operator() (const MWWorld::Ptr& ptr);
@ -213,8 +219,8 @@ namespace
void insert(AddObject&& addObject); void insert(AddObject&& addObject);
}; };
InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool test) InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool onlyStatics, bool test)
: mCell (cell), mLoadingListener (loadingListener), mTest(test) : mCell (cell), mLoadingListener (loadingListener), mOnlyStatics(onlyStatics), mTest(test)
{} {}
bool InsertVisitor::operator() (const MWWorld::Ptr& ptr) bool InsertVisitor::operator() (const MWWorld::Ptr& ptr)
@ -230,7 +236,7 @@ namespace
{ {
for (MWWorld::Ptr& ptr : mToInsert) for (MWWorld::Ptr& ptr : mToInsert)
{ {
if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled()) if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled() && ((mOnlyStatics && ptr.getClass().isStatic()) || !mOnlyStatics))
{ {
try try
{ {
@ -263,6 +269,16 @@ namespace
return std::abs(cellPosition.first) + std::abs(cellPosition.second); return std::abs(cellPosition.first) + std::abs(cellPosition.second);
} }
bool isCellInCollection(int x, int y, MWWorld::Scene::CellStoreCollection& collection)
{
for (auto *cell : collection)
{
assert(cell->getCell()->isExterior());
if (x == cell->getCell()->getGridX() && y == cell->getCell()->getGridY())
return true;
}
return false;
}
} }
@ -276,7 +292,7 @@ namespace MWWorld
{ {
if (!ptr.getRefData().getBaseNode()) return; if (!ptr.getRefData().getBaseNode()) return;
ptr.getClass().insertObjectRendering(ptr, getModel(ptr, mRendering.getResourceSystem()->getVFS()), mRendering); ptr.getClass().insertObjectRendering(ptr, getModel(ptr, mRendering.getResourceSystem()->getVFS()), mRendering);
setNodeRotation(ptr, mRendering, RotationOrder::direct); setNodeRotation(ptr, mRendering, makeNodeRotation(ptr, RotationOrder::direct));
reloadTerrain(); reloadTerrain();
} }
} }
@ -292,8 +308,9 @@ namespace MWWorld
void Scene::updateObjectRotation(const Ptr &ptr, RotationOrder order) void Scene::updateObjectRotation(const Ptr &ptr, RotationOrder order)
{ {
setNodeRotation(ptr, mRendering, order); const auto rot = makeNodeRotation(ptr, order);
mPhysics->updateRotation(ptr); setNodeRotation(ptr, mRendering, rot);
mPhysics->updateRotation(ptr, rot);
} }
void Scene::updateObjectScale(const Ptr &ptr) void Scene::updateObjectScale(const Ptr &ptr)
@ -313,15 +330,41 @@ namespace MWWorld
mRendering.update (duration, paused); mRendering.update (duration, paused);
} }
void Scene::unloadCell (CellStoreCollection::iterator iter, bool test) void Scene::unloadInactiveCell (CellStore* cell, bool test)
{
assert(mActiveCells.find(cell) == mActiveCells.end());
assert(mInactiveCells.find(cell) != mInactiveCells.end());
if (!test)
Log(Debug::Info) << "Unloading cell " << cell->getCell()->getDescription();
ListObjectsVisitor visitor;
cell->forEach(visitor);
for (const auto& ptr : visitor.mObjects)
mPhysics->remove(ptr);
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, bool test)
{ {
assert(mInactiveCells.find(cell) != mInactiveCells.end());
if (mActiveCells.find(cell) == mActiveCells.end())
return;
if (!test) if (!test)
Log(Debug::Info) << "Unloading cell " << (*iter)->getCell()->getDescription(); Log(Debug::Info) << "Deactivate cell " << cell->getCell()->getDescription();
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator(); const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
ListAndResetObjectsVisitor visitor; ListAndResetObjectsVisitor visitor;
(*iter)->forEach(visitor); cell->forEach(visitor);
const auto world = MWBase::Environment::get().getWorld(); const auto world = MWBase::Environment::get().getWorld();
for (const auto& ptr : visitor.mObjects) for (const auto& ptr : visitor.mObjects)
{ {
@ -332,140 +375,157 @@ namespace MWWorld
navigator->removeAgent(world->getPathfindingHalfExtents(ptr)); navigator->removeAgent(world->getPathfindingHalfExtents(ptr));
mRendering.removeActorPath(ptr); mRendering.removeActorPath(ptr);
} }
mPhysics->remove(ptr); mPhysics->remove(ptr, ptr.getClass().isStatic());
} }
const auto cellX = (*iter)->getCell()->getGridX(); const auto cellX = cell->getCell()->getGridX();
const auto cellY = (*iter)->getCell()->getGridY(); const auto cellY = cell->getCell()->getGridY();
if ((*iter)->getCell()->isExterior()) if (cell->getCell()->isExterior())
{ {
if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
navigator->removeObject(DetourNavigator::ObjectId(heightField)); navigator->removeObject(DetourNavigator::ObjectId(heightField));
mPhysics->removeHeightField(cellX, cellY);
} }
if ((*iter)->getCell()->hasWater()) if (cell->getCell()->hasWater())
navigator->removeWater(osg::Vec2i(cellX, cellY)); navigator->removeWater(osg::Vec2i(cellX, cellY));
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*(*iter)->getCell())) if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell->getCell()))
navigator->removePathgrid(*pathgrid); navigator->removePathgrid(*pathgrid);
const auto player = world->getPlayerPtr(); const auto player = world->getPlayerPtr();
navigator->update(player.getRefData().getPosition().asVec3()); navigator->update(player.getRefData().getPosition().asVec3());
MWBase::Environment::get().getMechanicsManager()->drop (*iter); MWBase::Environment::get().getMechanicsManager()->drop (cell);
mRendering.removeCell(*iter); mRendering.removeCell(cell);
MWBase::Environment::get().getWindowManager()->removeCell(*iter); MWBase::Environment::get().getWindowManager()->removeCell(cell);
MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (cell);
MWBase::Environment::get().getSoundManager()->stopSound (*iter); MWBase::Environment::get().getSoundManager()->stopSound (cell);
mActiveCells.erase(*iter); mActiveCells.erase(cell);
} }
void Scene::loadCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test) void Scene::activateCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test)
{ {
std::pair<CellStoreCollection::iterator, bool> result = mActiveCells.insert(cell); assert(mActiveCells.find(cell) == mActiveCells.end());
assert(mInactiveCells.find(cell) != mInactiveCells.end());
mActiveCells.insert(cell);
if(result.second) if (test)
Log(Debug::Info) << "Testing cell " << cell->getCell()->getDescription();
else
Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription();
const auto world = MWBase::Environment::get().getWorld();
const auto navigator = world->getNavigator();
const int cellX = cell->getCell()->getGridX();
const int cellY = cell->getCell()->getGridY();
if (!test && cell->getCell()->isExterior())
{ {
if (test) if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
Log(Debug::Info) << "Testing cell " << cell->getCell()->getDescription(); navigator->addObject(DetourNavigator::ObjectId(heightField), *heightField->getShape(),
else heightField->getCollisionObject()->getWorldTransform());
Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription(); }
float verts = ESM::Land::LAND_SIZE; if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell->getCell()))
float worldsize = ESM::Land::REAL_SIZE; navigator->addPathgrid(*cell->getCell(), *pathgrid);
const auto world = MWBase::Environment::get().getWorld(); // register local scripts
const auto navigator = world->getNavigator(); // do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice
MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell);
const int cellX = cell->getCell()->getGridX(); if (respawn)
const int cellY = cell->getCell()->getGridY(); cell->respawn();
insertCell (*cell, loadingListener, false, test);
// Load terrain physics first... mRendering.addCell(cell);
if (!test && cell->getCell()->isExterior()) if (!test)
{
MWBase::Environment::get().getWindowManager()->addCell(cell);
bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior();
float waterLevel = cell->getWaterLevel();
mRendering.setWaterEnabled(waterEnabled);
if (waterEnabled)
{ {
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY); mPhysics->enableWater(waterLevel);
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : nullptr; mRendering.setWaterHeight(waterLevel);
if (data)
if (cell->getCell()->isExterior())
{ {
mPhysics->addHeightField (data->mHeights, cellX, cellY, worldsize / (verts-1), verts, data->mMinHeight, data->mMaxHeight, land.get()); if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
navigator->addWater(osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE,
cell->getWaterLevel(), heightField->getCollisionObject()->getWorldTransform());
} }
else else
{ {
static std::vector<float> defaultHeight; navigator->addWater(osg::Vec2i(cellX, cellY), std::numeric_limits<int>::max(),
defaultHeight.resize(verts*verts, ESM::Land::DEFAULT_HEIGHT); cell->getWaterLevel(), btTransform::getIdentity());
mPhysics->addHeightField (&defaultHeight[0], cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), verts, ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get());
} }
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
navigator->addObject(DetourNavigator::ObjectId(heightField), *heightField->getShape(),
heightField->getCollisionObject()->getWorldTransform());
} }
else
mPhysics->disableWater();
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell->getCell())) const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
navigator->addPathgrid(*cell->getCell(), *pathgrid); navigator->update(player.getRefData().getPosition().asVec3());
// register local scripts
// do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice
MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell);
if (respawn) if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
cell->respawn(); mRendering.configureAmbient(cell->getCell());
}
// ... then references. This is important for adjustPosition to work correctly. mPreloader->notifyLoaded(cell);
insertCell (*cell, loadingListener, test); }
mRendering.addCell(cell); void Scene::loadInactiveCell (CellStore *cell, Loading::Listener* loadingListener, bool test)
if (!test) {
{ assert(mActiveCells.find(cell) == mActiveCells.end());
MWBase::Environment::get().getWindowManager()->addCell(cell); assert(mInactiveCells.find(cell) == mInactiveCells.end());
bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior(); mInactiveCells.insert(cell);
float waterLevel = cell->getWaterLevel();
mRendering.setWaterEnabled(waterEnabled);
if (waterEnabled)
{
mPhysics->enableWater(waterLevel);
mRendering.setWaterHeight(waterLevel);
if (cell->getCell()->isExterior()) if (test)
{ Log(Debug::Info) << "Testing inactive cell " << cell->getCell()->getDescription();
if (const auto heightField = mPhysics->getHeightField(cellX, cellY)) else
navigator->addWater(osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE, Log(Debug::Info) << "Loading inactive cell " << cell->getCell()->getDescription();
cell->getWaterLevel(), heightField->getCollisionObject()->getWorldTransform());
}
else
{
navigator->addWater(osg::Vec2i(cellX, cellY), std::numeric_limits<int>::max(),
cell->getWaterLevel(), btTransform::getIdentity());
}
}
else
mPhysics->disableWater();
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr(); if (!test && cell->getCell()->isExterior())
navigator->update(player.getRefData().getPosition().asVec3()); {
float verts = ESM::Land::LAND_SIZE;
float worldsize = ESM::Land::REAL_SIZE;
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) const int cellX = cell->getCell()->getGridX();
{ const int cellY = cell->getCell()->getGridY();
mRendering.configureAmbient(cell->getCell()); 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], cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), verts, ESM::Land::DEFAULT_HEIGHT, ESM::Land::DEFAULT_HEIGHT, land.get());
} }
} }
mPreloader->notifyLoaded(cell); insertCell (*cell, loadingListener, true, test);
} }
void Scene::clear() void Scene::clear()
{ {
CellStoreCollection::iterator active = mActiveCells.begin(); for (auto iter = mInactiveCells.begin(); iter!=mInactiveCells.end(); )
while (active!=mActiveCells.end()) {
unloadCell (active++); auto* cell = *iter++;
deactivateCell(cell);
unloadInactiveCell (cell);
}
assert(mActiveCells.empty()); assert(mActiveCells.empty());
assert(mInactiveCells.empty());
mCurrentCell = nullptr; mCurrentCell = nullptr;
mPreloader->clear(); mPreloader->clear();
@ -508,20 +568,24 @@ 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)
{ {
CellStoreCollection::iterator active = mActiveCells.begin(); for (auto iter = mInactiveCells.begin(); iter != mInactiveCells.end(); )
while (active!=mActiveCells.end())
{ {
if ((*active)->getCell()->isExterior()) auto* cell = *iter++;
if (cell->getCell()->isExterior())
{ {
if (std::abs (playerCellX-(*active)->getCell()->getGridX())<=mHalfGridSize && const auto dx = std::abs(playerCellX - cell->getCell()->getGridX());
std::abs (playerCellY-(*active)->getCell()->getGridY())<=mHalfGridSize) const auto dy = std::abs(playerCellY - cell->getCell()->getGridY());
{ if (dx > mHalfGridSize || dy > mHalfGridSize)
// keep cells within the new grid deactivateCell(cell);
++active;
continue; if (dx > mHalfGridSize+1 || dy > mHalfGridSize+1)
} unloadInactiveCell(cell);
}
else
{
deactivateCell(cell);
unloadInactiveCell(cell);
} }
unloadCell (active++);
} }
mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY); mCurrentGridCenter = osg::Vec2i(playerCellX, playerCellY);
@ -533,32 +597,24 @@ namespace MWWorld
mRendering.getPagedRefnums(newGrid, mPagedRefs); mRendering.getPagedRefnums(newGrid, mPagedRefs);
std::size_t refsToLoad = 0; std::size_t refsToLoad = 0;
std::vector<std::pair<int, int>> cellsPositionsToLoad; const auto cellsToLoad = [&playerCellX,&playerCellY,&refsToLoad](CellStoreCollection& collection, int range) -> std::vector<std::pair<int,int>>
// get the number of refs to load
for (int x = playerCellX - mHalfGridSize; x <= playerCellX + mHalfGridSize; ++x)
{ {
for (int y = playerCellY - mHalfGridSize; y <= playerCellY + mHalfGridSize; ++y) std::vector<std::pair<int, int>> cellsPositionsToLoad;
for (int x = playerCellX - range; x <= playerCellX + range; ++x)
{ {
CellStoreCollection::iterator iter = mActiveCells.begin(); for (int y = playerCellY - range; y <= playerCellY + range; ++y)
while (iter!=mActiveCells.end())
{ {
assert ((*iter)->getCell()->isExterior()); if (!isCellInCollection(x, y, collection))
{
if (x==(*iter)->getCell()->getGridX() && refsToLoad += MWBase::Environment::get().getWorld()->getExterior(x, y)->count();
y==(*iter)->getCell()->getGridY()) cellsPositionsToLoad.emplace_back(x, y);
break; }
++iter;
}
if (iter==mActiveCells.end())
{
refsToLoad += MWBase::Environment::get().getWorld()->getExterior(x, y)->count();
cellsPositionsToLoad.emplace_back(x, y);
} }
} }
} return cellsPositionsToLoad;
};
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);
@ -582,30 +638,26 @@ 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 // Load cells
for (const auto& cellPosition : cellsPositionsToLoad) for (const auto& [x,y] : cellsPositionsToLoadInactive)
{ {
const auto x = cellPosition.first; if (!isCellInCollection(x, y, mInactiveCells))
const auto y = cellPosition.second;
CellStoreCollection::iterator iter = mActiveCells.begin();
while (iter != mActiveCells.end())
{ {
assert ((*iter)->getCell()->isExterior()); CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(x, y);
loadInactiveCell (cell, loadingListener);
if (x == (*iter)->getCell()->getGridX() &&
y == (*iter)->getCell()->getGridY())
break;
++iter;
} }
}
if (iter == mActiveCells.end()) for (const auto& [x,y] : cellsPositionsToLoad)
{
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);
} }
} }
@ -638,7 +690,8 @@ namespace MWWorld
CellStoreCollection::iterator iter = mActiveCells.begin(); CellStoreCollection::iterator iter = mActiveCells.begin();
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);
loadCell (cell, loadingListener, false, true); loadInactiveCell (cell, loadingListener, true);
activateCell (cell, loadingListener, false, true);
iter = mActiveCells.begin(); iter = mActiveCells.begin();
while (iter != mActiveCells.end()) while (iter != mActiveCells.end())
@ -646,7 +699,8 @@ namespace MWWorld
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())
{ {
unloadCell(iter, true); deactivateCell(*iter, true);
unloadInactiveCell (*iter, true);
break; break;
} }
@ -684,7 +738,8 @@ 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);
loadCell (cell, loadingListener, false, true); loadInactiveCell (cell, loadingListener, true);
activateCell (cell, loadingListener, false, true);
CellStoreCollection::iterator iter = mActiveCells.begin(); CellStoreCollection::iterator iter = mActiveCells.begin();
while (iter != mActiveCells.end()) while (iter != mActiveCells.end())
@ -693,7 +748,8 @@ namespace MWWorld
if (it->mName == (*iter)->getCell()->mName) if (it->mName == (*iter)->getCell()->mName)
{ {
unloadCell(iter, true); deactivateCell(*iter, true);
unloadInactiveCell (*iter, true);
break; break;
} }
@ -816,15 +872,21 @@ namespace MWWorld
Log(Debug::Info) << "Changing to interior"; Log(Debug::Info) << "Changing to interior";
// unload // unload
CellStoreCollection::iterator active = mActiveCells.begin(); for (auto iter = mInactiveCells.begin(); iter!=mInactiveCells.end(); )
while (active!=mActiveCells.end()) {
unloadCell (active++); auto* cell = *iter++;
deactivateCell(cell);
unloadInactiveCell(cell);
}
assert(mActiveCells.empty());
assert(mInactiveCells.empty());
loadingListener->setProgressRange(cell->count()); loadingListener->setProgressRange(cell->count());
// Load cell. // Load cell.
mPagedRefs.clear(); mPagedRefs.clear();
loadCell (cell, loadingListener, changeEvent); loadInactiveCell (cell, loadingListener);
activateCell (cell, loadingListener, changeEvent);
changePlayerCell(cell, position, adjustPlayerPos); changePlayerCell(cell, position, adjustPlayerPos);
@ -872,23 +934,26 @@ namespace MWWorld
mCellChanged = false; mCellChanged = false;
} }
void Scene::insertCell (CellStore &cell, Loading::Listener* loadingListener, bool test) void Scene::insertCell (CellStore &cell, Loading::Listener* loadingListener, bool onlyStatics, bool test)
{ {
InsertVisitor insertVisitor (cell, *loadingListener, test); InsertVisitor insertVisitor (cell, *loadingListener, onlyStatics, test);
cell.forEach (insertVisitor); cell.forEach (insertVisitor);
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering, mPagedRefs); }); insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering, mPagedRefs, onlyStatics); });
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mNavigator); }); if (!onlyStatics)
{
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 // do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
PositionVisitor posVisitor; PositionVisitor posVisitor;
cell.forEach (posVisitor); cell.forEach (posVisitor);
}
} }
void Scene::addObjectToScene (const Ptr& ptr) void Scene::addObjectToScene (const Ptr& ptr)
{ {
try try
{ {
addObject(ptr, *mPhysics, mRendering, mPagedRefs); addObject(ptr, *mPhysics, mRendering, mPagedRefs, false);
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 navigator = MWBase::Environment::get().getWorld()->getNavigator(); const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();

@ -65,13 +65,13 @@ namespace MWWorld
class Scene class Scene
{ {
public: public:
using CellStoreCollection = std::set<CellStore *>;
typedef std::set<CellStore *> CellStoreCollection;
private: private:
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;
@ -92,7 +92,7 @@ namespace MWWorld
std::set<ESM::RefNum> mPagedRefs; std::set<ESM::RefNum> mPagedRefs;
void insertCell (CellStore &cell, Loading::Listener* loadingListener, bool test = false); void insertCell (CellStore &cell, Loading::Listener* loadingListener, bool onlyStatics, bool test = false);
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
@ -108,6 +108,11 @@ namespace MWWorld
osg::Vec4i gridCenterToBounds(const osg::Vec2i &centerCell) const; osg::Vec4i gridCenterToBounds(const osg::Vec2i &centerCell) 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, bool test = false);
void deactivateCell (CellStore* cell, bool test = false);
void activateCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test = false);
void loadInactiveCell (CellStore *cell, Loading::Listener* loadingListener, bool test = false);
public: public:
Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics, Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics,
@ -119,10 +124,6 @@ namespace MWWorld
void preloadTerrain(const osg::Vec3f& pos, bool sync=false); void preloadTerrain(const osg::Vec3f& pos, bool sync=false);
void reloadTerrain(); void reloadTerrain();
void unloadCell (CellStoreCollection::iterator iter, bool test = false);
void loadCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test = false);
void playerMoved (const osg::Vec3f& pos); void playerMoved (const osg::Vec3f& pos);
void changePlayerCell (CellStore* newCell, const ESM::Position& position, bool adjustPlayerPos); void changePlayerCell (CellStore* newCell, const ESM::Position& position, bool adjustPlayerPos);

@ -1407,7 +1407,7 @@ namespace MWWorld
mWorldScene->removeFromPagedRefs(ptr); mWorldScene->removeFromPagedRefs(ptr);
mRendering->rotateObject(ptr, rotate); mRendering->rotateObject(ptr, rotate);
mPhysics->updateRotation(ptr); mPhysics->updateRotation(ptr, rotate);
if (const auto object = mPhysics->getObject(ptr)) if (const auto object = mPhysics->getObject(ptr))
updateNavigatorObject(object); updateNavigatorObject(object);

Loading…
Cancel
Save