From 84e9d346efdd2fb3b4c2ca55af01381361f95992 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Feb 2016 16:47:33 +0100 Subject: [PATCH 01/13] Remove duplicate include --- apps/openmw/mwrender/water.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 0a379e50ac..340c077854 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include From fc3de3302e7b99d9a1bb695441f3f35b56845bd0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Feb 2016 16:47:41 +0100 Subject: [PATCH 02/13] Create a collision shape for the default terrain --- apps/openmw/mwworld/scene.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 63bb4758a3..65348763a3 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -268,6 +268,13 @@ namespace MWWorld mPhysics->addHeightField (data->mHeights, cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), verts); } + else + { + static std::vector defaultHeight; + defaultHeight.resize(verts*verts, -2048.f); + mPhysics->addHeightField (&defaultHeight[0], cell->getCell()->getGridX(), cell->getCell()->getGridY(), + worldsize / (verts-1), verts); + } } // register local scripts From 27577ce765d18e82098847901e3155524a5794e6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Feb 2016 16:49:18 +0100 Subject: [PATCH 03/13] Add ESM::Land::DEFAULT_HEIGHT --- apps/openmw/mwworld/scene.cpp | 2 +- components/esm/loadland.hpp | 3 +++ components/esmterrain/storage.cpp | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 65348763a3..ba28294690 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -271,7 +271,7 @@ namespace MWWorld else { static std::vector defaultHeight; - defaultHeight.resize(verts*verts, -2048.f); + defaultHeight.resize(verts*verts, ESM::Land::DEFAULT_HEIGHT); mPhysics->addHeightField (&defaultHeight[0], cell->getCell()->getGridX(), cell->getCell()->getGridY(), worldsize / (verts-1), verts); } diff --git a/components/esm/loadland.hpp b/components/esm/loadland.hpp index 8a8d6fdd2f..a2bf1573e9 100644 --- a/components/esm/loadland.hpp +++ b/components/esm/loadland.hpp @@ -46,6 +46,9 @@ struct Land DATA_VTEX = 16 }; + // default height to use in case there is no Land record + static const int DEFAULT_HEIGHT = -2048; + // number of vertices per side static const int LAND_SIZE = 65; diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index 68b32cf2a1..86d1e08e64 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -16,7 +16,7 @@ namespace ESMTerrain { - const float defaultHeight = -2048; + const float defaultHeight = ESM::Land::DEFAULT_HEIGHT; Storage::Storage(const VFS::Manager *vfs, const std::string& normalMapPattern, bool autoUseNormalMaps, const std::string& specularMapPattern, bool autoUseSpecularMaps) : mVFS(vfs) From 04d51d58713aa8e3294d3f3c023a524592c112ff Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Feb 2016 13:25:09 +0100 Subject: [PATCH 04/13] Always update the ingredient icons (Fixes #3220) --- apps/openmw/mwgui/alchemywindow.cpp | 43 +++++++++-------------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 3299846b7e..61a0efc460 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -67,46 +67,29 @@ namespace MWGui { MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getCaption ()); - if (result == MWMechanics::Alchemy::Result_NoName) + switch (result) { + case MWMechanics::Alchemy::Result_NoName: MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage37}"); - return; - } - - // check if mortar & pestle is available (always needed) - if (result == MWMechanics::Alchemy::Result_NoMortarAndPestle) - { + break; + case MWMechanics::Alchemy::Result_NoMortarAndPestle: MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage45}"); - return; - } - - // make sure 2 or more ingredients were selected - if (result == MWMechanics::Alchemy::Result_LessThanTwoIngredients) - { + break; + case MWMechanics::Alchemy::Result_LessThanTwoIngredients: MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage6a}"); - return; - } - - if (result == MWMechanics::Alchemy::Result_NoEffects) - { - MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage8}"); - MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); - return; - } - - if (result == MWMechanics::Alchemy::Result_Success) - { + break; + case MWMechanics::Alchemy::Result_Success: MWBase::Environment::get().getWindowManager()->messageBox("#{sPotionSuccess}"); MWBase::Environment::get().getSoundManager()->playSound("potion success", 1.f, 1.f); - } - else if (result == MWMechanics::Alchemy::Result_RandomFailure) - { - // potion failed + break; + case MWMechanics::Alchemy::Result_NoEffects: + case MWMechanics::Alchemy::Result_RandomFailure: MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage8}"); MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); + break; } - // reduce count of the ingredients + // remove ingredient slots that have been fully used up for (int i=0; i<4; ++i) if (mIngredients[i]->isUserString("ToolTipType")) { From be2f20f564e1c27537dc693464b377887e71b997 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Feb 2016 16:54:00 +0100 Subject: [PATCH 05/13] PlaceAt: attempt to select a safe spawn location (Fixes #2515, Fixes #1384, Fixes #2925) --- .../mwscript/transformationextensions.cpp | 75 ++++++++++++------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 95e2deee9b..9c950c8ff8 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -492,6 +492,15 @@ namespace MWScript { public: + osg::Vec3f getSpawnPosition(const osg::Vec3f& origin, const osg::Quat& orientation, int direction, float distance) + { + if(direction == 0) return origin + (orientation * osg::Vec3f(0,1,0)) * distance; + else if(direction == 1) return origin - (orientation * osg::Vec3f(0,1,0)) * distance; + else if(direction == 2) return origin - (orientation * osg::Vec3f(1,0,0)) * distance; + else if(direction == 3) return origin + (orientation * osg::Vec3f(1,0,0)) * distance; + else return origin; + } + virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr actor = pc @@ -514,40 +523,52 @@ namespace MWScript if (!actor.isInCell()) throw std::runtime_error ("actor is not in a cell"); + ESM::Position ipos = actor.getRefData().getPosition(); + osg::Vec3f pos(ipos.asVec3()); + osg::Quat rot(ipos.rot[2], osg::Vec3f(0,0,-1)); + + for (int i=0; i<4; ++i) + { + // check if spawn point is safe, fall back to another direction if not + osg::Vec3f spawnPoint = getSpawnPosition(ipos.asVec3(), rot, direction, distance); + spawnPoint.z() += 30; // move up a little to account for slopes, will snap down later + + if (!MWBase::Environment::get().getWorld()->castRay(spawnPoint.x(), spawnPoint.y(), spawnPoint.z(), + pos.x(), pos.y(), pos.z() + 20)) + { + // safe + ipos.pos[0] = spawnPoint.x(); + ipos.pos[1] = spawnPoint.y(); + ipos.pos[2] = spawnPoint.z(); + break; + } + direction = (direction+1) % 4; + } + + if (actor.getClass().isActor()) + { + // TODO: should this depend on the 'direction' parameter? + ipos.rot[0] = 0; + ipos.rot[1] = 0; + ipos.rot[2] = 0; + } + else + { + ipos.rot[0] = actor.getRefData().getPosition().rot[0]; + ipos.rot[1] = actor.getRefData().getPosition().rot[1]; + ipos.rot[2] = actor.getRefData().getPosition().rot[2]; + } + + for (int i=0; igetStore(), itemID, 1); ref.getPtr().getCellRef().setPosition(ipos); - MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + placed.getClass().adjustPosition(placed, true); // snap to ground } } }; From 11f00e3aa961fb9f9554df406e1840f0fe87b05c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Feb 2016 17:05:18 +0100 Subject: [PATCH 06/13] Rename safePlaceObject to placeObject --- apps/openmw/mwbase/world.hpp | 2 +- apps/openmw/mwclass/creaturelevlist.cpp | 2 +- apps/openmw/mwmechanics/summoning.cpp | 2 +- apps/openmw/mwscript/transformationextensions.cpp | 6 +++--- apps/openmw/mwworld/worldimp.cpp | 4 ++-- apps/openmw/mwworld/worldimp.hpp | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 99cbe96541..566853fc74 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -278,7 +278,7 @@ namespace MWBase virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0; - virtual MWWorld::Ptr safePlaceObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0; + virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0; ///< place an object in a "safe" location (ie not in the void, etc). virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) diff --git a/apps/openmw/mwclass/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index cd55d31a12..e0e890b604 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -120,7 +120,7 @@ namespace MWClass const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); MWWorld::ManualRef ref(store, id); ref.getPtr().getCellRef().setPosition(ptr.getCellRef().getPosition()); - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().getPosition()); + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().getPosition()); customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId(); customData.mSpawn = false; } diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 636e199074..7c4d077e61 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -147,7 +147,7 @@ namespace MWMechanics summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); creatureActorId = summonedCreatureStats.getActorId(); - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(),store,ipos); MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed); if (anim) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 9c950c8ff8..7d9877168a 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -434,7 +434,7 @@ namespace MWScript pos.rot[2] = osg::DegreesToRadians(zRotDegrees); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); ref.getPtr().getCellRef().setPosition(pos); - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(),store,pos); placed.getClass().adjustPosition(placed, true); } } @@ -482,7 +482,7 @@ namespace MWScript pos.rot[2] = osg::DegreesToRadians(zRotDegrees); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); ref.getPtr().getCellRef().setPosition(pos); - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(),store,pos); placed.getClass().adjustPosition(placed, true); } }; @@ -567,7 +567,7 @@ namespace MWScript MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), itemID, 1); ref.getPtr().getCellRef().setPosition(ipos); - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos); + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(),store,ipos); placed.getClass().adjustPosition(placed, true); // snap to ground } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e6b8f25a2c..3a4b0109c7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1325,7 +1325,7 @@ namespace MWWorld rotateObjectImp(ptr, osg::Vec3f(x, y, z), adjust); } - MWWorld::Ptr World::safePlaceObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) + MWWorld::Ptr World::placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) { return copyObjectToCell(ptr,cell,pos,ptr.getRefData().getCount(),false); } @@ -3041,7 +3041,7 @@ namespace MWWorld MWWorld::ManualRef ref(getStore(), selectedCreature, 1); ref.getPtr().getCellRef().setPosition(ipos); - safePlaceObject(ref.getPtr(), cell, ipos); + placeObject(ref.getPtr(), cell, ipos); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index ce5aa417ed..9f21135e54 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -367,8 +367,8 @@ namespace MWWorld /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); - virtual MWWorld::Ptr safePlaceObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos); - ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. + virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos); + ///< place an object. Makes a copy of the Ptr. virtual float getMaxActivationDistance(); From 6df71f6250f7a06c4dfc93d18d91025ce27d3526 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Feb 2016 17:16:33 +0100 Subject: [PATCH 07/13] Factor out safePlaceObject function --- apps/openmw/mwbase/world.hpp | 6 ++- .../mwscript/transformationextensions.cpp | 51 +------------------ apps/openmw/mwworld/worldimp.cpp | 37 ++++++++++++++ apps/openmw/mwworld/worldimp.hpp | 6 ++- 4 files changed, 48 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 566853fc74..de5f15d64f 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -279,7 +279,11 @@ namespace MWBase virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0; virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0; - ///< place an object in a "safe" location (ie not in the void, etc). + ///< Place an object. Makes a copy of the Ptr. + + virtual MWWorld::Ptr safePlaceObject (const MWWorld::ConstPtr& ptr, const MWWorld::ConstPtr& referenceObject, MWWorld::CellStore* referenceCell, int direction, float distance) = 0; + ///< Place an object in a safe place next to \a referenceObject. \a direction and \a distance specify the wanted placement + /// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is obstructed). virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const = 0; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 7d9877168a..e9e13e74f6 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -492,15 +492,6 @@ namespace MWScript { public: - osg::Vec3f getSpawnPosition(const osg::Vec3f& origin, const osg::Quat& orientation, int direction, float distance) - { - if(direction == 0) return origin + (orientation * osg::Vec3f(0,1,0)) * distance; - else if(direction == 1) return origin - (orientation * osg::Vec3f(0,1,0)) * distance; - else if(direction == 2) return origin - (orientation * osg::Vec3f(1,0,0)) * distance; - else if(direction == 3) return origin + (orientation * osg::Vec3f(1,0,0)) * distance; - else return origin; - } - virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr actor = pc @@ -523,52 +514,12 @@ namespace MWScript if (!actor.isInCell()) throw std::runtime_error ("actor is not in a cell"); - ESM::Position ipos = actor.getRefData().getPosition(); - osg::Vec3f pos(ipos.asVec3()); - osg::Quat rot(ipos.rot[2], osg::Vec3f(0,0,-1)); - - for (int i=0; i<4; ++i) - { - // check if spawn point is safe, fall back to another direction if not - osg::Vec3f spawnPoint = getSpawnPosition(ipos.asVec3(), rot, direction, distance); - spawnPoint.z() += 30; // move up a little to account for slopes, will snap down later - - if (!MWBase::Environment::get().getWorld()->castRay(spawnPoint.x(), spawnPoint.y(), spawnPoint.z(), - pos.x(), pos.y(), pos.z() + 20)) - { - // safe - ipos.pos[0] = spawnPoint.x(); - ipos.pos[1] = spawnPoint.y(); - ipos.pos[2] = spawnPoint.z(); - break; - } - direction = (direction+1) % 4; - } - - if (actor.getClass().isActor()) - { - // TODO: should this depend on the 'direction' parameter? - ipos.rot[0] = 0; - ipos.rot[1] = 0; - ipos.rot[2] = 0; - } - else - { - ipos.rot[0] = actor.getRefData().getPosition().rot[0]; - ipos.rot[1] = actor.getRefData().getPosition().rot[1]; - ipos.rot[2] = actor.getRefData().getPosition().rot[2]; - } - - for (int i=0; igetStore(), itemID, 1); - ref.getPtr().getCellRef().setPosition(ipos); - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(),store,ipos); - placed.getClass().adjustPosition(placed, true); // snap to ground + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), actor, actor.getCell(), direction, distance); } } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3a4b0109c7..be2baf7374 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1330,6 +1330,43 @@ namespace MWWorld return copyObjectToCell(ptr,cell,pos,ptr.getRefData().getCount(),false); } + MWWorld::Ptr World::safePlaceObject(const ConstPtr &ptr, const ConstPtr &referenceObject, MWWorld::CellStore* referenceCell, int direction, float distance) + { + ESM::Position ipos = referenceObject.getRefData().getPosition(); + osg::Vec3f pos(ipos.asVec3()); + osg::Quat orientation(ipos.rot[2], osg::Vec3f(0,0,-1)); + + for (int i=0; i<4; ++i) + { + // check if spawn point is safe, fall back to another direction if not + osg::Vec3f spawnPoint = pos; + if (direction == 0) spawnPoint = pos + (orientation * osg::Vec3f(0,1,0)) * distance; + else if(direction == 1) spawnPoint = pos - (orientation * osg::Vec3f(0,1,0)) * distance; + else if(direction == 2) spawnPoint = pos - (orientation * osg::Vec3f(1,0,0)) * distance; + else if(direction == 3) spawnPoint = pos + (orientation * osg::Vec3f(1,0,0)) * distance; + spawnPoint.z() += 30; // move up a little to account for slopes, will snap down later + + if (!castRay(spawnPoint.x(), spawnPoint.y(), spawnPoint.z(), + pos.x(), pos.y(), pos.z() + 20)) + { + // safe + ipos.pos[0] = spawnPoint.x(); + ipos.pos[1] = spawnPoint.y(); + ipos.pos[2] = spawnPoint.z(); + break; + } + direction = (direction+1) % 4; + } + + ipos.rot[0] = referenceObject.getRefData().getPosition().rot[0]; + ipos.rot[1] = referenceObject.getRefData().getPosition().rot[1]; + ipos.rot[2] = referenceObject.getRefData().getPosition().rot[2]; + + MWWorld::Ptr placed = copyObjectToCell(ptr, referenceCell, ipos, ptr.getRefData().getCount(), false); + placed.getClass().adjustPosition(placed, true); // snap to ground + return placed; + } + void World::indexToPosition (int cellX, int cellY, float &x, float &y, bool centre) const { const int cellSize = 8192; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9f21135e54..d1298a39be 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -368,7 +368,11 @@ namespace MWWorld virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos); - ///< place an object. Makes a copy of the Ptr. + ///< Place an object. Makes a copy of the Ptr. + + virtual MWWorld::Ptr safePlaceObject (const MWWorld::ConstPtr& ptr, const MWWorld::ConstPtr& referenceObject, MWWorld::CellStore* referenceCell, int direction, float distance); + ///< Place an object in a safe place next to \a referenceObject. \a direction and \a distance specify the wanted placement + /// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is obstructed). virtual float getMaxActivationDistance(); From be62ae758a706bcbabf847424686bf1c7894987d Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Feb 2016 17:26:52 +0100 Subject: [PATCH 08/13] Fall back to sides first --- apps/openmw/mwworld/worldimp.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index be2baf7374..6d7ceee432 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1336,8 +1336,11 @@ namespace MWWorld osg::Vec3f pos(ipos.asVec3()); osg::Quat orientation(ipos.rot[2], osg::Vec3f(0,0,-1)); + int fallbackDirections[4] = {direction, (direction+3)%4, (direction+2)%4, (direction+1)%4}; + for (int i=0; i<4; ++i) { + direction = fallbackDirections[i]; // check if spawn point is safe, fall back to another direction if not osg::Vec3f spawnPoint = pos; if (direction == 0) spawnPoint = pos + (orientation * osg::Vec3f(0,1,0)) * distance; @@ -1355,7 +1358,6 @@ namespace MWWorld ipos.pos[2] = spawnPoint.z(); break; } - direction = (direction+1) % 4; } ipos.rot[0] = referenceObject.getRefData().getPosition().rot[0]; From 7485abe5c311a7e66f05c2382debdb888a57c8fb Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Feb 2016 17:27:07 +0100 Subject: [PATCH 09/13] Use safePlaceObject for summoned creature spawning --- apps/openmw/mwmechanics/summoning.cpp | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 7c4d077e61..cf77714855 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -114,31 +114,16 @@ namespace MWMechanics bool found = creatureMap.find(std::make_pair(it->first, it->second)) != creatureMap.end(); if (!found) { - ESM::Position ipos = mActor.getRefData().getPosition(); - osg::Vec3f pos(ipos.asVec3()); - - osg::Quat rot (-ipos.rot[2], osg::Vec3f(0,0,1)); - const float distance = 50; - pos = pos + (rot * osg::Vec3f(0,1,0)) * distance; - ipos.pos[0] = pos.x(); - ipos.pos[1] = pos.y(); - ipos.pos[2] = pos.z(); - ipos.rot[0] = 0; - ipos.rot[1] = 0; - ipos.rot[2] = 0; - const std::string& creatureGmst = summonMap[it->first]; std::string creatureID = MWBase::Environment::get().getWorld()->getStore().get().find(creatureGmst)->getString(); if (!creatureID.empty()) { - MWWorld::CellStore* store = mActor.getCell(); int creatureActorId = -1; try { MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), creatureID, 1); - ref.getPtr().getCellRef().setPosition(ipos); MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr()); @@ -147,7 +132,7 @@ namespace MWMechanics summonedCreatureStats.getAiSequence().stack(package, ref.getPtr()); creatureActorId = summonedCreatureStats.getActorId(); - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(),store,ipos); + MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), mActor, mActor.getCell(), 0, 120.f); MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(placed); if (anim) From 36bb255bc0da04bdac805b61a2126330d1a25cdd Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Feb 2016 17:30:38 +0100 Subject: [PATCH 10/13] Use safePlaceObject in spawnRandomCreature --- apps/openmw/mwworld/worldimp.cpp | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6d7ceee432..2ab027cd63 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3064,23 +3064,9 @@ namespace MWWorld if (selectedCreature.empty()) return; - ESM::Position ipos = mPlayer->getPlayer().getRefData().getPosition(); - osg::Vec3f pos(ipos.asVec3()); - osg::Quat rot(-ipos.rot[2], osg::Vec3f(0,0,1)); - const float distance = 50; - pos = pos + (rot * osg::Vec3f(0,1,0)) * distance; - ipos.pos[0] = pos.x(); - ipos.pos[1] = pos.y(); - ipos.pos[2] = pos.z(); - ipos.rot[0] = 0; - ipos.rot[1] = 0; - ipos.rot[2] = 0; - - MWWorld::CellStore* cell = mPlayer->getPlayer().getCell(); MWWorld::ManualRef ref(getStore(), selectedCreature, 1); - ref.getPtr().getCellRef().setPosition(ipos); - placeObject(ref.getPtr(), cell, ipos); + safePlaceObject(ref.getPtr(), getPlayerPtr(), getPlayerPtr().getCell(), 0, 220.f); } } From 1e5b4bea0ac53cb544ec3a351c4a0f48ed3c5511 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Feb 2016 17:50:18 +0100 Subject: [PATCH 11/13] Don't create an unnecessary osg::Group when copying over a rig --- components/sceneutil/attach.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index d8cfa428a2..38330901d3 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -56,9 +56,18 @@ namespace SceneUtil CopyRigVisitor copyVisitor(handle, filter); toAttach->accept(copyVisitor); - master->asGroup()->addChild(handle); - - return handle; + if (handle->getNumChildren() == 1) + { + osg::ref_ptr newHandle = handle->getChild(0); + handle->removeChild(newHandle); + master->asGroup()->addChild(newHandle); + return newHandle; + } + else + { + master->asGroup()->addChild(handle); + return handle; + } } else { From 8791063110e140f1eadd06a1c2ea191944882804 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Feb 2016 18:20:56 +0100 Subject: [PATCH 12/13] Fix "RigGeometry rendering with no skeleton" warnings in rare cases --- components/sceneutil/skeleton.cpp | 11 ++++++++++- components/sceneutil/skeleton.hpp | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index d1299c0587..f311de2469 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -38,6 +38,8 @@ Skeleton::Skeleton() , mNeedToUpdateBoneMatrices(true) , mActive(true) , mLastFrameNumber(0) + , mTraversedEvenFrame(false) + , mTraversedOddFrame(false) { } @@ -48,6 +50,8 @@ Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op) , mNeedToUpdateBoneMatrices(true) , mActive(copy.mActive) , mLastFrameNumber(0) + , mTraversedEvenFrame(false) + , mTraversedOddFrame(false) { } @@ -111,6 +115,11 @@ void Skeleton::updateBoneMatrices(osg::NodeVisitor* nv) mLastFrameNumber = nv->getTraversalNumber(); + if (mLastFrameNumber % 2 == 0) + mTraversedEvenFrame = true; + else + mTraversedOddFrame = true; + if (mNeedToUpdateBoneMatrices) { if (mRootBone.get()) @@ -140,7 +149,7 @@ void Skeleton::traverse(osg::NodeVisitor& nv) if (!getActive() && nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR // need to process at least 2 frames before shutting off update, since we need to have both frame-alternating RigGeometries initialized // this would be more naturally handled if the double-buffering was implemented in RigGeometry itself rather than in a FrameSwitch decorator node - && mLastFrameNumber != 0 && mLastFrameNumber+2 <= nv.getTraversalNumber()) + && mLastFrameNumber != 0 && mTraversedEvenFrame && mTraversedOddFrame) return; osg::Group::traverse(nv); } diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index d98d367518..9ca1dd49da 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -69,6 +69,8 @@ namespace SceneUtil bool mActive; unsigned int mLastFrameNumber; + bool mTraversedEvenFrame; + bool mTraversedOddFrame; }; } From 87871d7d54260b4df53a0f3fc99c46cdcda5f041 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 29 Feb 2016 20:23:19 +0100 Subject: [PATCH 13/13] Don't add RotateController to an uncontrolled node --- apps/openmw/mwrender/animation.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 0418e34fdc..7f7183b9e0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1353,9 +1353,24 @@ namespace MWRender if (found != getNodeMap().end()) { osg::MatrixTransform* node = found->second; - mHeadController = new RotateController(mObjectRoot.get()); - node->addUpdateCallback(mHeadController); - mActiveControllers.insert(std::make_pair(node, mHeadController)); + + bool foundKeyframeCtrl = false; + osg::Callback* cb = node->getUpdateCallback(); + while (cb) + { + if (dynamic_cast(cb)) + { + foundKeyframeCtrl = true; + break; + } + } + + if (foundKeyframeCtrl) + { + mHeadController = new RotateController(mObjectRoot.get()); + node->addUpdateCallback(mHeadController); + mActiveControllers.insert(std::make_pair(node, mHeadController)); + } } } }