diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 5744ebb9b..99b83a5ac 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -837,8 +837,7 @@ namespace MWClass ptr.getRefData().setCount(1); // Reset to original position - ESM::Position& pos = ptr.getRefData().getPosition(); - pos = ptr.getCellRef().getPosition(); + ptr.getRefData().setPosition(ptr.getCellRef().getPosition()); ptr.getRefData().setCustomData(NULL); } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 5ec192ab2..6d5ff9f7f 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1325,8 +1325,7 @@ namespace MWClass ptr.getRefData().setCount(1); // Reset to original position - ESM::Position& pos = ptr.getRefData().getPosition(); - pos = ptr.getCellRef().getPosition(); + ptr.getRefData().setPosition(ptr.getCellRef().getPosition()); ptr.getRefData().setCustomData(NULL); } diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 85e56af8b..05723c575 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -88,7 +88,7 @@ bool AiSequence::canAddTarget(const ESM::Position& actorPos, float distToTarget) else { // add new target only if current target (player) is farther - ESM::Position &targetPos = combat->getTarget().getRefData().getPosition(); + const ESM::Position &targetPos = combat->getTarget().getRefData().getPosition(); float distToCurrTarget = (Ogre::Vector3(targetPos.pos) - Ogre::Vector3(actorPos.pos)).length(); return (distToCurrTarget > distToTarget); @@ -153,7 +153,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor,float duration) } else { - ESM::Position &targetPos = target.getRefData().getPosition(); + const ESM::Position &targetPos = target.getRefData().getPosition(); float distTo = (Ogre::Vector3(targetPos.pos) - vActorPos).length(); if (distTo < nearestDist) diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index c3fa0a662..4983a4a4f 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -100,6 +100,9 @@ namespace MWMechanics if(!cell) return false; + if(mIsGraphConstructed) + return true; + mCell = cell; mIsExterior = cell->isExterior(); mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*cell); @@ -107,8 +110,6 @@ namespace MWMechanics if(!mPathgrid) return false; - if(mIsGraphConstructed) - return true; mGraph.resize(mPathgrid->mPoints.size()); for(int i = 0; i < static_cast (mPathgrid->mEdges.size()); i++) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 74216c1de..64b5e48c3 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -165,7 +165,7 @@ void RippleSimulation::addImpulses() // for non-player actors this is done in updateObjectCell it->mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); } - float* _currentPos = it->mPtr.getRefData().getPosition().pos; + const float* _currentPos = it->mPtr.getRefData().getPosition().pos; Ogre::Vector3 currentPos (_currentPos[0], _currentPos[1], _currentPos[2]); if ( (currentPos - it->mLastEmitPosition).length() > 2 diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index a944a31b8..138326ff0 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -578,7 +578,7 @@ namespace MWScript Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); - float *objRot = ptr.getRefData().getPosition().rot; + const float *objRot = ptr.getRefData().getPosition().rot; float ax = Ogre::Radian(objRot[0]).valueDegrees(); float ay = Ogre::Radian(objRot[1]).valueDegrees(); @@ -613,9 +613,12 @@ namespace MWScript if (!ptr.isInCell()) return; - ptr.getRefData().getLocalRotation().rot[0] = 0; - ptr.getRefData().getLocalRotation().rot[1] = 0; - ptr.getRefData().getLocalRotation().rot[2] = 0; + MWWorld::LocalRotation rot; + rot.rot[0] = 0; + rot.rot[1] = 0; + rot.rot[2] = 0; + ptr.getRefData().setLocalRotation(rot); + MWBase::Environment::get().getWorld()->rotateObject(ptr, 0,0,0,true); MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().pos[0], ptr.getCellRef().getPosition().pos[1], ptr.getCellRef().getPosition().pos[2]); @@ -678,7 +681,7 @@ namespace MWScript Interpreter::Type_Float movement = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); - float *objPos = ptr.getRefData().getPosition().pos; + const float *objPos = ptr.getRefData().getPosition().pos; if (axis == "x") { diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 4db362b1e..689671c02 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -42,7 +42,8 @@ namespace MWWorld float getScale() const; void setScale(float scale); - // Position and rotation of this object within the cell + // The *original* position and rotation as it was given in the Construction Set. + // Current position and rotation of the object is stored in RefData. ESM::Position getPosition() const; void setPosition (const ESM::Position& position); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 63cdbfb1a..3e29a9cae 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -410,6 +410,9 @@ namespace MWWorld loadRefs (store, esm); mState = State_Loaded; + + // TODO: the pathgrid graph only needs to be loaded for active cells, so move this somewhere else. + // In a simple test, loading the graph for all cells in MW + expansions took 200 ms mPathgridGraph.load(mCell); } } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index c13ecfab5..446519b87 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -366,7 +366,7 @@ namespace MWWorld Class::copyToCell(const Ptr &ptr, CellStore &cell, const ESM::Position &pos) const { Ptr newPtr = copyToCell(ptr, cell); - newPtr.getRefData().getPosition() = pos; + newPtr.getRefData().setPosition(pos); return newPtr; } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 9913b888b..b88483bfe 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -44,8 +44,9 @@ namespace MWWorld cellRef.mRefID = "player"; mPlayer = LiveCellRef(cellRef, player); - float* playerPos = mPlayer.mData.getPosition().pos; - playerPos[0] = playerPos[1] = playerPos[2] = 0; + ESM::Position playerPos = mPlayer.mData.getPosition(); + playerPos.pos[0] = playerPos.pos[1] = playerPos.pos[2] = 0; + mPlayer.mData.setPosition(playerPos); } void Player::set(const ESM::NPC *player) diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 2e267b37c..3b7521e8d 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -188,15 +188,25 @@ namespace MWWorld mEnabled = false; } - ESM::Position& RefData::getPosition() + void RefData::setPosition(const ESM::Position& pos) { mChanged = true; + mPosition = pos; + } + + const ESM::Position& RefData::getPosition() + { return mPosition; } - LocalRotation& RefData::getLocalRotation() + void RefData::setLocalRotation(const LocalRotation& rot) { mChanged = true; + mLocalRotation = rot; + } + + const LocalRotation& RefData::getLocalRotation() + { return mLocalRotation; } diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index a8ffad684..fcd1437c9 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -100,9 +100,11 @@ namespace MWWorld void disable(); - ESM::Position& getPosition(); + void setPosition (const ESM::Position& pos); + const ESM::Position& getPosition(); - LocalRotation& getLocalRotation(); + void setLocalRotation (const LocalRotation& rotation); + const LocalRotation& getLocalRotation(); void setCustomData (CustomData *data); ///< Set custom data (potentially replacing old custom data). The ownership of \æ data is diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index f753ae1f4..b2faa1a01 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -22,6 +22,30 @@ namespace { + void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, + MWRender::RenderingManager& rendering) + { + if (ptr.getRefData().getBaseNode() != NULL) + { + Ogre::Quaternion worldRotQuat(Ogre::Radian(ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z); + if (!ptr.getClass().isActor()) + worldRotQuat = Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)* + Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y)* worldRotQuat; + + float x = ptr.getRefData().getLocalRotation().rot[0]; + float y = ptr.getRefData().getLocalRotation().rot[1]; + float z = ptr.getRefData().getLocalRotation().rot[2]; + + Ogre::Quaternion rot(Ogre::Radian(z), Ogre::Vector3::NEGATIVE_UNIT_Z); + if (!ptr.getClass().isActor()) + rot = Ogre::Quaternion(Ogre::Radian(x), Ogre::Vector3::NEGATIVE_UNIT_X)* + Ogre::Quaternion(Ogre::Radian(y), Ogre::Vector3::NEGATIVE_UNIT_Y)*rot; + + ptr.getRefData().getBaseNode()->setOrientation(worldRotQuat*rot); + physics.rotateObject(ptr); + } + } + struct InsertFunctor { MWWorld::CellStore& mCell; @@ -60,11 +84,7 @@ namespace mRendering.addObject (ptr); ptr.getClass().insertObject (ptr, mPhysics); - float ax = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[0]).valueDegrees(); - float ay = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[1]).valueDegrees(); - float az = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[2]).valueDegrees(); - MWBase::Environment::get().getWorld()->localRotateObject (ptr, ax, ay, az); - + updateObjectLocalRotation(ptr, mPhysics, mRendering); MWBase::Environment::get().getWorld()->scaleObject (ptr, ptr.getCellRef().getScale()); ptr.getClass().adjustPosition (ptr); } @@ -85,6 +105,20 @@ namespace namespace MWWorld { + void Scene::updateObjectLocalRotation (const Ptr& ptr) + { + ::updateObjectLocalRotation(ptr, *mPhysics, mRendering); + } + + void Scene::updateObjectRotation (const Ptr& ptr) + { + if(ptr.getRefData().getBaseNode() != 0) + { + mRendering.rotateObject(ptr); + mPhysics->rotateObject(ptr); + } + } + void Scene::update (float duration, bool paused) { if (mNeedMapUpdate) diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 449644754..e0eeee187 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -103,6 +103,10 @@ namespace MWWorld void removeObjectFromScene (const Ptr& ptr); ///< Remove an object from the scene, but not from the world model. + void updateObjectLocalRotation (const Ptr& ptr); + + void updateObjectRotation (const Ptr& ptr); + bool isCellActive(const CellStore &cell); Ptr searchPtrViaHandle (const std::string& handle); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6a18298f9..e6049c185 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -957,12 +957,14 @@ namespace MWWorld void World::moveObject(const Ptr &ptr, CellStore* newCell, float x, float y, float z) { - ESM::Position &pos = ptr.getRefData().getPosition(); + ESM::Position pos = ptr.getRefData().getPosition(); pos.pos[0] = x; pos.pos[1] = y; pos.pos[2] = z; + ptr.getRefData().setPosition(pos); + Ogre::Vector3 vec(x, y, z); CellStore *currCell = ptr.isInCell() ? ptr.getCell() : NULL; @@ -1068,7 +1070,8 @@ namespace MWWorld const float two_pi = Ogre::Math::TWO_PI; const float pi = Ogre::Math::PI; - float *objRot = ptr.getRefData().getPosition().rot; + ESM::Position pos = ptr.getRefData().getPosition(); + float *objRot = pos.rot; if(adjust) { objRot[0] += rot.x; @@ -1105,43 +1108,33 @@ namespace MWWorld while(objRot[2] < -pi) objRot[2] += two_pi; while(objRot[2] > pi) objRot[2] -= two_pi; - if(ptr.getRefData().getBaseNode() != 0) - { - mRendering->rotateObject(ptr); - mPhysics->rotateObject(ptr); - } + ptr.getRefData().setPosition(pos); + + mWorldScene->updateObjectRotation(ptr); } void World::localRotateObject (const Ptr& ptr, float x, float y, float z) { - if (ptr.getRefData().getBaseNode() != 0) { - - ptr.getRefData().getLocalRotation().rot[0]=Ogre::Degree(x).valueRadians(); - ptr.getRefData().getLocalRotation().rot[1]=Ogre::Degree(y).valueRadians(); - ptr.getRefData().getLocalRotation().rot[2]=Ogre::Degree(z).valueRadians(); - - wrap(ptr.getRefData().getLocalRotation().rot[0]); - wrap(ptr.getRefData().getLocalRotation().rot[1]); - wrap(ptr.getRefData().getLocalRotation().rot[2]); + if (ptr.getRefData().getBaseNode() != 0) + { + LocalRotation rot = ptr.getRefData().getLocalRotation(); + rot.rot[0]=Ogre::Degree(x).valueRadians(); + rot.rot[1]=Ogre::Degree(y).valueRadians(); + rot.rot[2]=Ogre::Degree(z).valueRadians(); - Ogre::Quaternion worldRotQuat(Ogre::Radian(ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z); - if (!ptr.getClass().isActor()) - worldRotQuat = Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)* - Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y)* worldRotQuat; + wrap(rot.rot[0]); + wrap(rot.rot[1]); + wrap(rot.rot[2]); - Ogre::Quaternion rot(Ogre::Degree(z), Ogre::Vector3::NEGATIVE_UNIT_Z); - if (!ptr.getClass().isActor()) - rot = Ogre::Quaternion(Ogre::Degree(x), Ogre::Vector3::NEGATIVE_UNIT_X)* - Ogre::Quaternion(Ogre::Degree(y), Ogre::Vector3::NEGATIVE_UNIT_Y)*rot; + ptr.getRefData().setLocalRotation(rot); - ptr.getRefData().getBaseNode()->setOrientation(worldRotQuat*rot); - mPhysics->rotateObject(ptr); + mWorldScene->updateObjectLocalRotation(ptr); } } void World::adjustPosition(const Ptr &ptr) { - Ogre::Vector3 pos (ptr.getRefData().getPosition().pos); + ESM::Position pos (ptr.getRefData().getPosition()); if(!ptr.getRefData().getBaseNode()) { @@ -1149,21 +1142,23 @@ namespace MWWorld return; } - float terrainHeight = mRendering->getTerrainHeightAt(pos); + float terrainHeight = mRendering->getTerrainHeightAt(Ogre::Vector3(pos.pos)); + + if (pos.pos[2] < terrainHeight) + pos.pos[2] = terrainHeight; - if (pos.z < terrainHeight) - pos.z = terrainHeight; + pos.pos[2] += 20; // place slightly above. will snap down to ground with code below - ptr.getRefData().getPosition().pos[2] = pos.z + 20; // place slightly above. will snap down to ground with code below + ptr.getRefData().setPosition(pos); if (!isFlying(ptr)) { Ogre::Vector3 traced = mPhysics->traceDown(ptr); - if (traced.z < pos.z) - pos.z = traced.z; + if (traced.z < pos.pos[2]) + pos.pos[2] = traced.z; } - moveObject(ptr, ptr.getCell(), pos.x, pos.y, pos.z); + moveObject(ptr, ptr.getCell(), pos.pos[0], pos.pos[1], pos.pos[2]); } void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) @@ -1429,7 +1424,7 @@ namespace MWWorld // cast a ray from player to sun to detect if the sun is visible // this is temporary until we find a better place to put this code // currently its here because we need to access the physics system - float* p = mPlayer->getPlayer().getRefData().getPosition().pos; + const float* p = mPlayer->getPlayer().getRefData().getPosition().pos; Vector3 sun = mRendering->getSkyManager()->getRealSunPos(); mRendering->getSkyManager()->setGlare(!mPhysics->castRay(Ogre::Vector3(p[0], p[1], p[2]), sun)); } @@ -1683,10 +1678,11 @@ namespace MWWorld object.getClass().copyToCell(object, *cell, pos); // Reset some position values that could be uninitialized if this item came from a container - LocalRotation& localRotation = dropped.getRefData().getLocalRotation(); + LocalRotation localRotation; localRotation.rot[0] = 0; localRotation.rot[1] = 0; localRotation.rot[2] = 0; + dropped.getRefData().setLocalRotation(localRotation); dropped.getCellRef().setPosition(pos); if (mWorldScene->isCellActive(*cell)) { @@ -1785,7 +1781,7 @@ namespace MWWorld bool World::isSubmerged(const MWWorld::Ptr &object) const { - float *fpos = object.getRefData().getPosition().pos; + const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); @@ -1798,7 +1794,7 @@ namespace MWWorld World::isSwimming(const MWWorld::Ptr &object) const { /// \todo add check ifActor() - only actors can swim - float *fpos = object.getRefData().getPosition().pos; + const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); /// \fixme 3/4ths submerged? @@ -2031,9 +2027,9 @@ namespace MWWorld if (!targetNpc.getRefData().isEnabled() || !npc.getRefData().isEnabled()) return false; // cannot get LOS unless both NPC's are enabled Ogre::Vector3 halfExt1 = mPhysEngine->getCharacter(npc.getRefData().getHandle())->getHalfExtents(); - float* pos1 = npc.getRefData().getPosition().pos; + const float* pos1 = npc.getRefData().getPosition().pos; Ogre::Vector3 halfExt2 = mPhysEngine->getCharacter(targetNpc.getRefData().getHandle())->getHalfExtents(); - float* pos2 = targetNpc.getRefData().getPosition().pos; + const float* pos2 = targetNpc.getRefData().getPosition().pos; btVector3 from(pos1[0],pos1[1],pos1[2]+halfExt1.z); btVector3 to(pos2[0],pos2[1],pos2[2]+halfExt2.z); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5b493efcc..8307d53a4 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -336,10 +336,11 @@ namespace MWWorld virtual void scaleObject (const Ptr& ptr, float scale); - /// Rotates object, uses degrees + /// World rotates object, uses degrees /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); + /// Local rotates object, uses degrees virtual void localRotateObject (const Ptr& ptr, float x, float y, float z); virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos);