From a4d0068e2980800a3454ac83168e33d16b892b0e Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 2 Nov 2014 15:35:14 +0100 Subject: [PATCH 01/15] Make forcegreeting no-op for disabled references (Fixes #2093) --- apps/openmw/mwscript/dialogueextensions.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index a88c5a101..563a9dde3 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -125,6 +125,9 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); + if (!ptr.getRefData().isEnabled()) + return; + MWBase::Environment::get().getDialogueManager()->startDialogue (ptr); } }; From 140013820ba858ac9d46df3f2e78ec1c9237ac87 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 2 Nov 2014 15:40:08 +0100 Subject: [PATCH 02/15] Fix invalidated iterator --- apps/openmw/mwmechanics/spells.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 681f01f04..a1b73bc47 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -70,11 +70,13 @@ namespace MWMechanics if (mPermanentSpellEffects.find(lower) != mPermanentSpellEffects.end()) { MagicEffects & effects = mPermanentSpellEffects[lower]; - for (MagicEffects::Collection::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt) + for (MagicEffects::Collection::const_iterator effectIt = effects.begin(); effectIt != effects.end();) { const ESM::MagicEffect * magicEffect = MWBase::Environment::get().getWorld()->getStore().get().find(effectIt->first.mId); if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) - effects.remove(effectIt->first); + effects.remove((effectIt++)->first); + else + ++effectIt; } } mCorprusSpells.erase(corprusIt); From 0e70315f91ce6a3630f5bc8ca836702c4aeb0c4b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 4 Nov 2014 20:43:04 +1100 Subject: [PATCH 03/15] Experimental, compiles and runs but crashes in some exit scenarios. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/render/mousestate.cpp | 4 +++- apps/opencs/view/world/physicsmanager.cpp | 3 +++ apps/opencs/view/world/physicssystem.cpp | 25 +++++++++-------------- apps/opencs/view/world/physicssystem.hpp | 12 +++-------- 5 files changed, 20 insertions(+), 26 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index ec6f802cf..b6c24e190 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -68,7 +68,7 @@ opencs_units (view/world opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate - scripthighlighter idvalidator dialoguecreator physicssystem physicsmanager + scripthighlighter idvalidator dialoguecreator physicssystem physicsmanager physicsengine ) opencs_units (view/widget diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index af835d0a5..94ab9bc0b 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -266,7 +266,9 @@ namespace CSVRender void MouseState::mouseDoubleClickEvent (QMouseEvent *event) { - event->ignore(); + //event->ignore(); + mPhysics->toggleDebugRendering(mSceneManager); + mParent->flagAsModified(); } bool MouseState::wheelEvent (QWheelEvent *event) diff --git a/apps/opencs/view/world/physicsmanager.cpp b/apps/opencs/view/world/physicsmanager.cpp index f8e022e5d..2d8dcd95a 100644 --- a/apps/opencs/view/world/physicsmanager.cpp +++ b/apps/opencs/view/world/physicsmanager.cpp @@ -74,6 +74,9 @@ namespace CSVWorld throw std::runtime_error("No physics system found for the given document."); } + // deprecated by removeDocument() and may be deleted in future code updates + // however there may be some value in removing the deleted scene widgets from the + // list so that the list does not grow forever void PhysicsManager::removeSceneWidget(CSVRender::WorldspaceWidget *widget) { CSVRender::SceneWidget *sceneWidget = static_cast(widget); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 73063b6be..98e3a71e9 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include "physicsengine.hpp" #include #include "../../model/settings/usersettings.hpp" #include "../render/elements.hpp" @@ -15,17 +15,12 @@ namespace CSVWorld { PhysicsSystem::PhysicsSystem() { - // Create physics. shapeLoader is deleted by the physic engine - NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); - mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); + mEngine = new PhysicsEngine(); } PhysicsSystem::~PhysicsSystem() { - // FIXME: OEngine does not behave well when multiple instances are created - // and deleted, sometimes resulting in crashes. Skip the deletion until the physics - // code is moved out of OEngine. - //delete mEngine; + delete mEngine; } // looks up the scene manager based on the scene node name (inefficient) @@ -56,8 +51,6 @@ namespace CSVWorld { mEngine->createAndAdjustRigidBody(mesh, referenceId, scale, position, rotation, - 0, // scaledBoxTranslation - 0, // boxRotation true, // raycasting placeable); } @@ -146,7 +139,7 @@ namespace CSVWorld // create a new physics object mEngine->createAndAdjustRigidBody(mesh, referenceId, scale, position, rotation, - 0, 0, true, placeable); + true, placeable); // update other scene managers if they have the referenceId // FIXME: rotation or scale not updated @@ -278,6 +271,8 @@ namespace CSVWorld void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget *sceneWidget) { mSceneWidgets[sceneMgr] = sceneWidget; + + mEngine->createDebugDraw(sceneMgr); } std::map PhysicsSystem::sceneWidgets() @@ -287,6 +282,8 @@ namespace CSVWorld void PhysicsSystem::removeSceneManager(Ogre::SceneManager *sceneMgr) { + mEngine->removeDebugDraw(sceneMgr); + mSceneWidgets.erase(sceneMgr); } @@ -310,8 +307,6 @@ namespace CSVWorld if(!sceneMgr) return; - mEngine->setSceneManager(sceneMgr); - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); if(!(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false)) { @@ -319,7 +314,7 @@ namespace CSVWorld return; } - mEngine->toggleDebugRendering(); - mEngine->stepSimulation(0.0167); // DebugDrawer::step() not directly accessible + mEngine->toggleDebugRendering(sceneMgr); + mEngine->stepDebug(sceneMgr); } } diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 0036bf769..731e527b1 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -12,14 +12,6 @@ namespace Ogre class Camera; } -namespace OEngine -{ - namespace Physic - { - class PhysicEngine; - } -} - namespace CSVRender { class SceneWidget; @@ -27,13 +19,15 @@ namespace CSVRender namespace CSVWorld { + class PhysicsEngine; + class PhysicsSystem { std::map mSceneNodeToRefId; std::map > mRefIdToSceneNode; std::map mSceneNodeToMesh; std::map mSceneWidgets; - OEngine::Physic::PhysicEngine* mEngine; + PhysicsEngine* mEngine; std::multimap mTerrain; public: From 70b5d6857a182de419fc2faf63a0f7e177da8f7f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 4 Nov 2014 20:52:28 +1100 Subject: [PATCH 04/15] Add missing files. --- apps/opencs/view/world/physicsengine.cpp | 441 +++++++++++++++++++++++ apps/opencs/view/world/physicsengine.hpp | 253 +++++++++++++ 2 files changed, 694 insertions(+) create mode 100644 apps/opencs/view/world/physicsengine.cpp create mode 100644 apps/opencs/view/world/physicsengine.hpp diff --git a/apps/opencs/view/world/physicsengine.cpp b/apps/opencs/view/world/physicsengine.cpp new file mode 100644 index 000000000..cdfc818a5 --- /dev/null +++ b/apps/opencs/view/world/physicsengine.cpp @@ -0,0 +1,441 @@ +#include "physicsengine.hpp" + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +// PLEASE NOTE: +// +// This file is based on libs/openengine/bullet/physic.cpp. The commit history and +// credits for the code below stem from that file. + +namespace CSVWorld +{ + RigidBody::RigidBody(btRigidBody::btRigidBodyConstructionInfo &CI, + const std::string &referenceId) : btRigidBody(CI) , mReferenceId(referenceId) + { + } + + RigidBody::~RigidBody() + { + delete getMotionState(); + } + + // In OpenCS one document has one PhysicsSystem. Each PhysicsSystem contains one + // PhysicsEngine. One document can have 0..n SceneWidgets, each with its own + // Ogre::SceneManager. + // + // These relationships are managed by the PhysicsManager. + // + // - When a view is created its document is registered with the PhysicsManager in + // View's constructor. If the document is new a PhysicSystem is created and + // associated with that document. A null list of SceneWidgets are assigned to + // that document. + // + // - When all views for a given document is closed, ViewManager will notify the + // PhysicsManager to destroy the PhysicsSystem associated with the document. + // + // - Each time a WorldspaceWidget (or its subclass) is created, it gets the + // PhysicsSystem associates with the widget's document from the PhysicsManager. + // The list of widgets are then maintained, but is not necessary and may be + // removed in future code updates. + // + // Each WorldspaceWidget can have objects (References) and terrain (Land) loaded + // from its document. There may be several views of the object, however there + // is only one corresponding physics object. i.e. each Reference can have 1..n + // SceneNodes + // + // These relationships are managed by the PhysicsSystem for the document. + // + // - Each time a WorldspaceWidget (or its subclass) is created, it registers + // itself and its Ogre::SceneManager with the PhysicsSystem assigned by the + // PhysicsManager. + // + // - Each time an object is added, the object's Ogre::SceneNode name is registered + // with the PhysicsSystem. Ogre itself maintains which SceneNode belongs to + // which SceneManager. + // + // - Each time an terrain is added, its cell coordinates and the SceneManager is + // registered with the PhysicsSystem. + // + PhysicsEngine::PhysicsEngine() + { + // Set up the collision configuration and dispatcher + mCollisionConfiguration = new btDefaultCollisionConfiguration(); + mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); + + // The actual physics solver + mSolver = new btSequentialImpulseConstraintSolver; + + mBroadphase = new btDbvtBroadphase(); + + // The world. + mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher, + mBroadphase, mSolver, mCollisionConfiguration); + + // Don't update AABBs of all objects every frame. Most objects in MW are static, + // so we don't need this. Should a "static" object ever be moved, we have to + // update its AABB manually using DynamicsWorld::updateSingleAabb. + mDynamicsWorld->setForceUpdateAllAabbs(false); + + mDynamicsWorld->setGravity(btVector3(0, 0, -10)); + + if(OEngine::Physic::BulletShapeManager::getSingletonPtr() == NULL) + { + new OEngine::Physic::BulletShapeManager(); + } + + mShapeLoader = new NifBullet::ManualBulletShapeLoader(); + } + + PhysicsEngine::~PhysicsEngine() + { + HeightFieldContainer::iterator hf_it = mHeightFieldMap.begin(); + for(; hf_it != mHeightFieldMap.end(); ++hf_it) + { + mDynamicsWorld->removeRigidBody(hf_it->second.mBody); + delete hf_it->second.mShape; + delete hf_it->second.mBody; + } + + RigidBodyContainer::iterator rb_it = mCollisionObjectMap.begin(); + for(; rb_it != mCollisionObjectMap.end(); ++rb_it) + { + if (rb_it->second != NULL) + { + mDynamicsWorld->removeRigidBody(rb_it->second); + + delete rb_it->second; + rb_it->second = NULL; + } + } + + rb_it = mRaycastingObjectMap.begin(); + for (; rb_it != mRaycastingObjectMap.end(); ++rb_it) + { + if (rb_it->second != NULL) + { + mDynamicsWorld->removeRigidBody(rb_it->second); + + delete rb_it->second; + rb_it->second = NULL; + } + } + + delete mDynamicsWorld; // FIXME: need to reference count?? + delete mSolver; + delete mCollisionConfiguration; + delete mDispatcher; + delete mBroadphase; + delete mShapeLoader; + + delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); // FIXME: need to reference count + } + + int PhysicsEngine::toggleDebugRendering(Ogre::SceneManager *sceneMgr) + { + if(!sceneMgr) + return 0; + + std::map::iterator iter = + mDebugDrawers.find(sceneMgr); + if(iter != mDebugDrawers.end()) // found scene manager + { + if((*iter).second) + { + // set a new drawer each time (maybe with a different scene manager) + mDynamicsWorld->setDebugDrawer(mDebugDrawers[sceneMgr]); + if(!mDebugDrawers[sceneMgr]->getDebugMode()) + mDebugDrawers[sceneMgr]->setDebugMode(1 /*mDebugDrawFlags*/); + else + mDebugDrawers[sceneMgr]->setDebugMode(0); + + mDynamicsWorld->debugDrawWorld(); // FIXME: call this now? + return mDebugDrawers[sceneMgr]->getDebugMode(); + } + } + return 0; + } + + void PhysicsEngine::stepDebug(Ogre::SceneManager *sceneMgr) + { + if(!sceneMgr) + return; + + std::map::iterator iter = + mDebugDrawers.find(sceneMgr); + if(iter != mDebugDrawers.end()) // found scene manager + { + if((*iter).second) + (*iter).second->step(); + else + return; + } + } + + void PhysicsEngine::createDebugDraw(Ogre::SceneManager *sceneMgr) + { + if(mDebugDrawers.find(sceneMgr) == mDebugDrawers.end()) + { + mDebugSceneNodes[sceneMgr] = sceneMgr->getRootSceneNode()->createChildSceneNode(); + mDebugDrawers[sceneMgr] = new BtOgre::DebugDrawer(mDebugSceneNodes[sceneMgr], mDynamicsWorld); + mDebugDrawers[sceneMgr]->setDebugMode(0); + } + } + + void PhysicsEngine::removeDebugDraw(Ogre::SceneManager *sceneMgr) + { + std::map::iterator iter = + mDebugDrawers.find(sceneMgr); + if(iter != mDebugDrawers.end()) + { + delete (*iter).second; + mDebugDrawers.erase(iter); + } + + std::map::iterator it = + mDebugSceneNodes.find(sceneMgr); + if(it != mDebugSceneNodes.end()) + { + std::string sceneNodeName = (*it).second->getName(); + if(sceneMgr->hasSceneNode(sceneNodeName)) + sceneMgr->destroySceneNode(sceneNodeName); + } + } + + void PhysicsEngine::addHeightField(float* heights, + int x, int y, float yoffset, + float triSize, float sqrtVerts) + { + const std::string name = "HeightField_" + + boost::lexical_cast(x) + "_" + + boost::lexical_cast(y); + + // find the minimum and maximum heights (needed for bullet) + float minh = heights[0]; + float maxh = heights[0]; + for (int i=0; imaxh) maxh = h; + if (hsetUseDiamondSubdivision(true); + + btVector3 scl(triSize, triSize, 1); + hfShape->setLocalScaling(scl); + + btRigidBody::btRigidBodyConstructionInfo CI = + btRigidBody::btRigidBodyConstructionInfo(0,0,hfShape); + RigidBody* body = new RigidBody(CI, name); + body->getWorldTransform().setOrigin(btVector3( + (x+0.5)*triSize*(sqrtVerts-1), + (y+0.5)*triSize*(sqrtVerts-1), + (maxh+minh)/2.f)); + + HeightField hf; + hf.mBody = body; + hf.mShape = hfShape; + + mHeightFieldMap [name] = hf; + + mDynamicsWorld->addRigidBody(body, CollisionType_HeightMap, + CollisionType_Actor|CollisionType_Raycasting|CollisionType_Projectile); + } + + void PhysicsEngine::removeHeightField(int x, int y) + { + const std::string name = "HeightField_" + + boost::lexical_cast(x) + "_" + + boost::lexical_cast(y); + + HeightField hf = mHeightFieldMap [name]; + + mDynamicsWorld->removeRigidBody(hf.mBody); + delete hf.mShape; + delete hf.mBody; + + mHeightFieldMap.erase(name); + } + + void PhysicsEngine::adjustRigidBody(RigidBody* body, + const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) + { + btTransform tr; + //Ogre::Quaternion boxrot = rotation * boxRotation; + Ogre::Quaternion boxrot = rotation * Ogre::Quaternion::IDENTITY; + //Ogre::Vector3 transrot = boxrot * scaledBoxTranslation; + Ogre::Vector3 transrot = boxrot * Ogre::Vector3::ZERO; + Ogre::Vector3 newPosition = transrot + position; + + tr.setOrigin(btVector3(newPosition.x, newPosition.y, newPosition.z)); + tr.setRotation(btQuaternion(boxrot.x,boxrot.y,boxrot.z,boxrot.w)); + body->setWorldTransform(tr); + } + + RigidBody* PhysicsEngine::createAndAdjustRigidBody(const std::string &mesh, + const std::string &name, // referenceId, assumed unique per OpenCS document + float scale, + const Ogre::Vector3 &position, + const Ogre::Quaternion &rotation, + bool raycasting, + bool placeable) // indicates whether the object can be picked up by the player + { + std::string sid = (boost::format("%07.3f") % scale).str(); + std::string outputstring = mesh + sid; + + //get the shape from the .nif + mShapeLoader->load(outputstring, "General"); + OEngine::Physic::BulletShapeManager::getSingletonPtr()->load(outputstring, "General"); + OEngine::Physic::BulletShapePtr shape = + OEngine::Physic::BulletShapeManager::getSingleton().getByName(outputstring, "General"); + + if (placeable && !raycasting && shape->mCollisionShape && !shape->mHasCollisionNode) + return NULL; + + if (!shape->mCollisionShape && !raycasting) + return NULL; + + if (!shape->mRaycastingShape && raycasting) + return NULL; + + btCollisionShape* collisionShape = raycasting ? shape->mRaycastingShape : shape->mCollisionShape; + collisionShape->setLocalScaling(btVector3(scale, scale, scale)); + + //create the real body + btRigidBody::btRigidBodyConstructionInfo CI = + btRigidBody::btRigidBodyConstructionInfo(0, 0, collisionShape); + + RigidBody* body = new RigidBody(CI, name); + + adjustRigidBody(body, position, rotation); + + if (!raycasting) + { + assert (mCollisionObjectMap.find(name) == mCollisionObjectMap.end()); + mCollisionObjectMap[name] = body; + mDynamicsWorld->addRigidBody(body, + CollisionType_World, CollisionType_Actor|CollisionType_HeightMap); + } + else + { + assert (mRaycastingObjectMap.find(name) == mRaycastingObjectMap.end()); + mRaycastingObjectMap[name] = body; + mDynamicsWorld->addRigidBody(body, + CollisionType_Raycasting, CollisionType_Raycasting|CollisionType_Projectile); + } + + return body; + } + + void PhysicsEngine::removeRigidBody(const std::string &name) + { + RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); + if (it != mCollisionObjectMap.end() ) + { + RigidBody* body = it->second; + if(body != NULL) + { + mDynamicsWorld->removeRigidBody(body); + } + } + + it = mRaycastingObjectMap.find(name); + if (it != mRaycastingObjectMap.end() ) + { + RigidBody* body = it->second; + if(body != NULL) + { + mDynamicsWorld->removeRigidBody(body); + } + } + } + + void PhysicsEngine::deleteRigidBody(const std::string &name) + { + RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); + if (it != mCollisionObjectMap.end() ) + { + RigidBody* body = it->second; + + if(body != NULL) + { + delete body; + } + mCollisionObjectMap.erase(it); + } + + it = mRaycastingObjectMap.find(name); + if (it != mRaycastingObjectMap.end() ) + { + RigidBody* body = it->second; + + if(body != NULL) + { + delete body; + } + mRaycastingObjectMap.erase(it); + } + } + + RigidBody* PhysicsEngine::getRigidBody(const std::string &name, bool raycasting) + { + RigidBodyContainer* map = raycasting ? &mRaycastingObjectMap : &mCollisionObjectMap; + RigidBodyContainer::iterator it = map->find(name); + if (it != map->end() ) + { + RigidBody* body = (*map)[name]; + return body; + } + else + { + return NULL; + } + } + + std::pair PhysicsEngine::rayTest(const btVector3 &from, + const btVector3 &to, bool raycastingObjectOnly, bool ignoreHeightMap, Ogre::Vector3* normal) + { + std::string referenceId = ""; + float d = -1; + + btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); + resultCallback1.m_collisionFilterGroup = 0xff; + + if(raycastingObjectOnly) + resultCallback1.m_collisionFilterMask = CollisionType_Raycasting|CollisionType_Actor; + else + resultCallback1.m_collisionFilterMask = CollisionType_World; + + if(!ignoreHeightMap) + resultCallback1.m_collisionFilterMask = resultCallback1.m_collisionFilterMask | CollisionType_HeightMap; + + mDynamicsWorld->rayTest(from, to, resultCallback1); + if (resultCallback1.hasHit()) + { + referenceId = static_cast(*resultCallback1.m_collisionObject).getReferenceId(); + d = resultCallback1.m_closestHitFraction; + if (normal) + *normal = Ogre::Vector3(resultCallback1.m_hitNormalWorld.x(), + resultCallback1.m_hitNormalWorld.y(), + resultCallback1.m_hitNormalWorld.z()); + } + + return std::pair(referenceId, d); + } +} diff --git a/apps/opencs/view/world/physicsengine.hpp b/apps/opencs/view/world/physicsengine.hpp new file mode 100644 index 000000000..9d60fe5f1 --- /dev/null +++ b/apps/opencs/view/world/physicsengine.hpp @@ -0,0 +1,253 @@ +#ifndef CSV_WORLD_PHYSICSENGINE_H +#define CSV_WORLD_PHYSICSENGINE_H + +//#include +#include + +#include +//#include "BulletCollision/CollisionDispatch/btGhostObject.h" +//#include +//#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" +//#include +#include +#include // needs Ogre::SceneNode defined + +//#include +//#include + +//class btRigidBody; +class btBroadphaseInterface; +class btDefaultCollisionConfiguration; +class btSequentialImpulseConstraintSolver; +class btCollisionDispatcher; +class btDiscreteDynamicsWorld; +class btHeightfieldTerrainShape; +//class btCollisionObject; + +namespace BtOgre +{ + class DebugDrawer; +} + +namespace Ogre +{ + class Vector3; + class SceneNode; + class SceneManager; + class Quaternion; +} + +namespace OEngine +{ + namespace Physic + { + class BulletShapeLoader; + } +} + +namespace CSVWorld +{ + + // enum btIDebugDraw::DebugDrawModes + // { + // DBG_NoDebug=0, + // DBG_DrawWireframe = 1, + // DBG_DrawAabb=2, + // DBG_DrawFeaturesText=4, + // DBG_DrawContactPoints=8, + // DBG_NoDeactivation=16, + // DBG_NoHelpText = 32, + // DBG_DrawText=64, + // DBG_ProfileTimings = 128, + // DBG_EnableSatComparison = 256, + // DBG_DisableBulletLCP = 512, + // DBG_EnableCCD = 1024, + // DBG_DrawConstraints = (1 << 11), + // DBG_DrawConstraintLimits = (1 << 12), + // DBG_FastWireframe = (1<<13), + // DBG_DrawNormals = (1<<14), + // DBG_MAX_DEBUG_DRAW_MODE + // }; + // +#if 0 + class CSVDebugDrawer : public BtOgre::DebugDrawer + { + BtOgre::DebugDrawer *mDebugDrawer; + Ogre::SceneManager *mSceneMgr; + Ogre::SceneNode *mSceneNode; + int mDebugMode; + + public: + + CSVDebugDrawer(Ogre::SceneManager *sceneMgr, btDiscreteDynamicsWorld *dynamicsWorld); + ~CSVDebugDrawer(); + + void setDebugMode(int mode); + bool toggleDebugRendering(); + }; +#endif + + // This class is just an extension of normal btRigidBody in order to add extra info. + // When bullet give back a btRigidBody, you can just do a static_cast to RigidBody, + // so one never should use btRigidBody directly! + class RigidBody: public btRigidBody + { + std::string mReferenceId; + + public: + + RigidBody(btRigidBody::btRigidBodyConstructionInfo &CI, const std::string &referenceId); + virtual ~RigidBody(); + + std::string getReferenceId() const { return mReferenceId; } + }; + + struct HeightField + { + btHeightfieldTerrainShape* mShape; + RigidBody* mBody; + }; + + /** + * The PhysicsEngine class contain everything which is needed for Physic. + * It's needed that Ogre Resources are set up before the PhysicsEngine is created. + * Note:deleting it WILL NOT delete the RigidBody! + * TODO:unload unused resources? + */ + class PhysicsEngine + { + //Bullet Stuff + btBroadphaseInterface *mBroadphase; + btDefaultCollisionConfiguration *mCollisionConfiguration; + btSequentialImpulseConstraintSolver *mSolver; + btCollisionDispatcher *mDispatcher; + btDiscreteDynamicsWorld *mDynamicsWorld; + + //the NIF file loader. + OEngine::Physic::BulletShapeLoader *mShapeLoader; + + typedef std::map HeightFieldContainer; + HeightFieldContainer mHeightFieldMap; + + typedef std::map RigidBodyContainer; + RigidBodyContainer mCollisionObjectMap; + + RigidBodyContainer mRaycastingObjectMap; + + std::map mDebugDrawers; + std::map mDebugSceneNodes; + +#if 0 + // from bullet + enum CollisionFilterGroups + { + DefaultFilter = 1, + StaticFilter = 2, + KinematicFilter = 4, + DebrisFilter = 8, + SensorTrigger = 16, + CharacterFilter = 32, + AllFilter = -1 //all bits sets: DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorTrigger + }; +#endif + + enum CollisionType { + CollisionType_Nothing = 0, // rayTest(const btVector3 &from, + const btVector3 &to, bool raycastingObjectOnly = true, + bool ignoreHeightMap = false, Ogre::Vector3* normal = NULL); + + private: + + PhysicsEngine(const PhysicsEngine&); + PhysicsEngine& operator=(const PhysicsEngine&); + + // Create a debug rendering. It is called by setDebgRenderingMode if it's + // not created yet. + // Important Note: this will crash if the Render is not yet initialised! + void createDebugRendering(); + + // Set the debug rendering mode. 0 to turn it off. + // Important Note: this will crash if the Render is not yet initialised! + void setDebugRenderingMode(int mode); +#if 0 + void getObjectAABB(const std::string &mesh, + float scale, btVector3 &min, btVector3 &max); + + /** + * Return all objects hit by a ray. + */ + std::vector< std::pair > rayTest2(const btVector3 &from, const btVector3 &to, int filterGroup=0xff); + + std::pair sphereCast (float radius, btVector3 &from, btVector3 &to); + ///< @return (hit, relative distance) + + std::vector getCollisions(const std::string &name, int collisionGroup, int collisionMask); + + // Get the nearest object that's inside the given object, filtering out objects of the + // provided name + std::pair getFilteredContact(const std::string &filter, + const btVector3 &origin, + btCollisionObject *object); +#endif + }; +} +#endif // CSV_WORLD_PHYSICSENGINE_H From 37a050873c2aa289a96206dda95657a004effa6b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 4 Nov 2014 21:46:35 +1100 Subject: [PATCH 05/15] Fix crash when multiple scenewidgets were closed. BtOgre was destroying resources each time. --- apps/opencs/view/world/physicsengine.cpp | 13 +++++++++++++ apps/opencs/view/world/physicsengine.hpp | 2 -- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/physicsengine.cpp b/apps/opencs/view/world/physicsengine.cpp index cdfc818a5..7e7078a0f 100644 --- a/apps/opencs/view/world/physicsengine.cpp +++ b/apps/opencs/view/world/physicsengine.cpp @@ -11,6 +11,8 @@ #include #include +#include +#include // needs Ogre::SceneNode defined // PLEASE NOTE: // @@ -199,6 +201,17 @@ namespace CSVWorld { delete (*iter).second; mDebugDrawers.erase(iter); + + // BtOgre::DebugDrawer destroys the resources leading to crashes in some + // situations. Workaround by recreating them each time. + if (!Ogre::ResourceGroupManager::getSingleton().resourceGroupExists("BtOgre")) + Ogre::ResourceGroupManager::getSingleton().createResourceGroup("BtOgre"); + if (!Ogre::MaterialManager::getSingleton().resourceExists("BtOgre/DebugLines")) + { + Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create("BtOgre/DebugLines", "BtOgre"); + mat->setReceiveShadows(false); + mat->setSelfIllumination(1,1,1); + } } std::map::iterator it = diff --git a/apps/opencs/view/world/physicsengine.hpp b/apps/opencs/view/world/physicsengine.hpp index 9d60fe5f1..b14d35820 100644 --- a/apps/opencs/view/world/physicsengine.hpp +++ b/apps/opencs/view/world/physicsengine.hpp @@ -9,8 +9,6 @@ //#include //#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" //#include -#include -#include // needs Ogre::SceneNode defined //#include //#include From 7d133d508d4ec7db1cf33bcd64bb65f4159d4c4c Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 5 Nov 2014 07:10:14 +1100 Subject: [PATCH 06/15] Remove unused code. Move the cleanup of global resources used by the PhysicsEngine to PhysicsManager. --- apps/opencs/view/render/mousestate.cpp | 8 +- apps/opencs/view/world/physicsengine.cpp | 16 ++-- apps/opencs/view/world/physicsengine.hpp | 101 +--------------------- apps/opencs/view/world/physicsmanager.cpp | 15 ++++ 4 files changed, 32 insertions(+), 108 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 94ab9bc0b..45e846f74 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -255,7 +255,7 @@ namespace CSVRender std::pair result = terrainUnderCursor(event->x(), event->y()); if(result.first != "") { - // FIXME: terrain editing + // FIXME: terrain editing goes here } break; } @@ -266,9 +266,9 @@ namespace CSVRender void MouseState::mouseDoubleClickEvent (QMouseEvent *event) { - //event->ignore(); - mPhysics->toggleDebugRendering(mSceneManager); - mParent->flagAsModified(); + event->ignore(); + //mPhysics->toggleDebugRendering(mSceneManager); + //mParent->flagAsModified(); } bool MouseState::wheelEvent (QWheelEvent *event) diff --git a/apps/opencs/view/world/physicsengine.cpp b/apps/opencs/view/world/physicsengine.cpp index 7e7078a0f..05dcc3426 100644 --- a/apps/opencs/view/world/physicsengine.cpp +++ b/apps/opencs/view/world/physicsengine.cpp @@ -16,8 +16,9 @@ // PLEASE NOTE: // -// This file is based on libs/openengine/bullet/physic.cpp. The commit history and -// credits for the code below stem from that file. +// This file is based on libs/openengine/bullet/physic.cpp. Please see the commit +// history and credits for the code below, which is mostly copied from there and +// adapted for use with OpenCS. namespace CSVWorld { @@ -132,14 +133,17 @@ namespace CSVWorld } } - delete mDynamicsWorld; // FIXME: need to reference count?? + + delete mDynamicsWorld; delete mSolver; delete mCollisionConfiguration; delete mDispatcher; delete mBroadphase; delete mShapeLoader; - delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); // FIXME: need to reference count + // NOTE: the global resources such as "BtOgre/DebugLines" and the + // BulletShapeManager singleton need to be deleted only when all physics + // engines are deleted in PhysicsManager::removeDocument() } int PhysicsEngine::toggleDebugRendering(Ogre::SceneManager *sceneMgr) @@ -159,8 +163,8 @@ namespace CSVWorld mDebugDrawers[sceneMgr]->setDebugMode(1 /*mDebugDrawFlags*/); else mDebugDrawers[sceneMgr]->setDebugMode(0); + mDynamicsWorld->debugDrawWorld(); - mDynamicsWorld->debugDrawWorld(); // FIXME: call this now? return mDebugDrawers[sceneMgr]->getDebugMode(); } } @@ -290,9 +294,7 @@ namespace CSVWorld const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) { btTransform tr; - //Ogre::Quaternion boxrot = rotation * boxRotation; Ogre::Quaternion boxrot = rotation * Ogre::Quaternion::IDENTITY; - //Ogre::Vector3 transrot = boxrot * scaledBoxTranslation; Ogre::Vector3 transrot = boxrot * Ogre::Vector3::ZERO; Ogre::Vector3 newPosition = transrot + position; diff --git a/apps/opencs/view/world/physicsengine.hpp b/apps/opencs/view/world/physicsengine.hpp index b14d35820..d960abdff 100644 --- a/apps/opencs/view/world/physicsengine.hpp +++ b/apps/opencs/view/world/physicsengine.hpp @@ -1,26 +1,16 @@ #ifndef CSV_WORLD_PHYSICSENGINE_H #define CSV_WORLD_PHYSICSENGINE_H -//#include #include #include -//#include "BulletCollision/CollisionDispatch/btGhostObject.h" -//#include -//#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" -//#include -//#include -//#include - -//class btRigidBody; class btBroadphaseInterface; class btDefaultCollisionConfiguration; class btSequentialImpulseConstraintSolver; class btCollisionDispatcher; class btDiscreteDynamicsWorld; class btHeightfieldTerrainShape; -//class btCollisionObject; namespace BtOgre { @@ -45,46 +35,6 @@ namespace OEngine namespace CSVWorld { - - // enum btIDebugDraw::DebugDrawModes - // { - // DBG_NoDebug=0, - // DBG_DrawWireframe = 1, - // DBG_DrawAabb=2, - // DBG_DrawFeaturesText=4, - // DBG_DrawContactPoints=8, - // DBG_NoDeactivation=16, - // DBG_NoHelpText = 32, - // DBG_DrawText=64, - // DBG_ProfileTimings = 128, - // DBG_EnableSatComparison = 256, - // DBG_DisableBulletLCP = 512, - // DBG_EnableCCD = 1024, - // DBG_DrawConstraints = (1 << 11), - // DBG_DrawConstraintLimits = (1 << 12), - // DBG_FastWireframe = (1<<13), - // DBG_DrawNormals = (1<<14), - // DBG_MAX_DEBUG_DRAW_MODE - // }; - // -#if 0 - class CSVDebugDrawer : public BtOgre::DebugDrawer - { - BtOgre::DebugDrawer *mDebugDrawer; - Ogre::SceneManager *mSceneMgr; - Ogre::SceneNode *mSceneNode; - int mDebugMode; - - public: - - CSVDebugDrawer(Ogre::SceneManager *sceneMgr, btDiscreteDynamicsWorld *dynamicsWorld); - ~CSVDebugDrawer(); - - void setDebugMode(int mode); - bool toggleDebugRendering(); - }; -#endif - // This class is just an extension of normal btRigidBody in order to add extra info. // When bullet give back a btRigidBody, you can just do a static_cast to RigidBody, // so one never should use btRigidBody directly! @@ -106,12 +56,9 @@ namespace CSVWorld RigidBody* mBody; }; - /** - * The PhysicsEngine class contain everything which is needed for Physic. - * It's needed that Ogre Resources are set up before the PhysicsEngine is created. - * Note:deleting it WILL NOT delete the RigidBody! - * TODO:unload unused resources? - */ + // The PhysicsEngine class contain everything which is needed for Physic. + // It's needed that Ogre Resources are set up before the PhysicsEngine is created. + // Note:deleting it WILL NOT delete the RigidBody! class PhysicsEngine { //Bullet Stuff @@ -135,20 +82,6 @@ namespace CSVWorld std::map mDebugDrawers; std::map mDebugSceneNodes; -#if 0 - // from bullet - enum CollisionFilterGroups - { - DefaultFilter = 1, - StaticFilter = 2, - KinematicFilter = 4, - DebrisFilter = 8, - SensorTrigger = 16, - CharacterFilter = 32, - AllFilter = -1 //all bits sets: DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorTrigger - }; -#endif - enum CollisionType { CollisionType_Nothing = 0, // > rayTest2(const btVector3 &from, const btVector3 &to, int filterGroup=0xff); - - std::pair sphereCast (float radius, btVector3 &from, btVector3 &to); - ///< @return (hit, relative distance) - - std::vector getCollisions(const std::string &name, int collisionGroup, int collisionMask); - - // Get the nearest object that's inside the given object, filtering out objects of the - // provided name - std::pair getFilteredContact(const std::string &filter, - const btVector3 &origin, - btCollisionObject *object); -#endif }; } #endif // CSV_WORLD_PHYSICSENGINE_H diff --git a/apps/opencs/view/world/physicsmanager.cpp b/apps/opencs/view/world/physicsmanager.cpp index 2d8dcd95a..ce5748e8d 100644 --- a/apps/opencs/view/world/physicsmanager.cpp +++ b/apps/opencs/view/world/physicsmanager.cpp @@ -2,6 +2,9 @@ #include +#include +#include + #include "../render/worldspacewidget.hpp" #include "physicssystem.hpp" @@ -54,6 +57,18 @@ namespace CSVWorld { mSceneWidgets.erase(it); } + + // cleanup global resources + if(mPhysics.empty()) + { + // delete the extra resources created in removeDebugDraw + if (Ogre::MaterialManager::getSingleton().resourceExists("BtOgre/DebugLines")) + Ogre::MaterialManager::getSingleton().remove("BtOgre/DebugLines"); + if (Ogre::ResourceGroupManager::getSingleton().resourceGroupExists("BtOgre")) + Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup("BtOgre"); + + delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); + } } // called from CSVRender::WorldspaceWidget() to get widgets' association with Document& From 03abd69b4fed09706c70e34e53c0095f2dc8cb35 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 5 Nov 2014 07:20:20 +1100 Subject: [PATCH 07/15] Include string header for gcc. --- apps/opencs/view/world/physicsengine.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/world/physicsengine.hpp b/apps/opencs/view/world/physicsengine.hpp index d960abdff..58dbf6525 100644 --- a/apps/opencs/view/world/physicsengine.hpp +++ b/apps/opencs/view/world/physicsengine.hpp @@ -1,6 +1,7 @@ #ifndef CSV_WORLD_PHYSICSENGINE_H #define CSV_WORLD_PHYSICSENGINE_H +#include #include #include From 5909fa4368aec785e2d09a9e807936ea520d624f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 5 Nov 2014 21:18:43 +0100 Subject: [PATCH 08/15] new version number and updated changelog --- CMakeLists.txt | 2 +- readme.txt | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4efb19719..b3ec6cf6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 33) -set(OPENMW_VERSION_RELEASE 0) +set(OPENMW_VERSION_RELEASE 1) set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_TAGHASH "") diff --git a/readme.txt b/readme.txt index cb533e9fb..810a0e055 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind OpenMW is an attempt at recreating the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work. -Version: 0.33.0 +Version: 0.33.1 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org @@ -98,6 +98,10 @@ Allowed options: CHANGELOG +0.33.1 + +Bug #2108: OpenCS fails to build + 0.33.0 Bug #371: If console assigned to ` (probably to any symbolic key), "`" symbol will be added to console every time it closed From f051fb65ff99707f9443fe1feb52b10a752d70ad Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 6 Nov 2014 08:35:24 +1100 Subject: [PATCH 09/15] Fix memory leak when multiple documents in 3D edit. Support multiple physics engine per document. --- apps/opencs/view/world/physicsmanager.cpp | 9 +-- apps/opencs/view/world/physicssystem.cpp | 10 ++- apps/opencs/view/world/physicssystem.hpp | 12 +++- apps/openmw/mwworld/physicssystem.cpp | 2 + libs/openengine/bullet/BtOgreExtras.h | 6 +- libs/openengine/bullet/physic.cpp | 76 ++++++++++++++++++++++- libs/openengine/bullet/physic.hpp | 9 +++ 7 files changed, 106 insertions(+), 18 deletions(-) diff --git a/apps/opencs/view/world/physicsmanager.cpp b/apps/opencs/view/world/physicsmanager.cpp index ce5748e8d..fa8db9e1e 100644 --- a/apps/opencs/view/world/physicsmanager.cpp +++ b/apps/opencs/view/world/physicsmanager.cpp @@ -2,7 +2,6 @@ #include -#include #include #include "../render/worldspacewidget.hpp" @@ -58,15 +57,9 @@ namespace CSVWorld mSceneWidgets.erase(it); } - // cleanup global resources + // cleanup global resources used by OEngine if(mPhysics.empty()) { - // delete the extra resources created in removeDebugDraw - if (Ogre::MaterialManager::getSingleton().resourceExists("BtOgre/DebugLines")) - Ogre::MaterialManager::getSingleton().remove("BtOgre/DebugLines"); - if (Ogre::ResourceGroupManager::getSingleton().resourceGroupExists("BtOgre")) - Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup("BtOgre"); - delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); } } diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 98e3a71e9..57909f4d3 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -6,7 +6,7 @@ #include #include -#include "physicsengine.hpp" +#include #include #include "../../model/settings/usersettings.hpp" #include "../render/elements.hpp" @@ -15,7 +15,9 @@ namespace CSVWorld { PhysicsSystem::PhysicsSystem() { - mEngine = new PhysicsEngine(); + // Create physics. shapeLoader is deleted by the physic engine + NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); + mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); } PhysicsSystem::~PhysicsSystem() @@ -51,6 +53,8 @@ namespace CSVWorld { mEngine->createAndAdjustRigidBody(mesh, referenceId, scale, position, rotation, + 0, // scaledBoxTranslation + 0, // boxRotation true, // raycasting placeable); } @@ -139,7 +143,7 @@ namespace CSVWorld // create a new physics object mEngine->createAndAdjustRigidBody(mesh, referenceId, scale, position, rotation, - true, placeable); + 0, 0, true, placeable); // update other scene managers if they have the referenceId // FIXME: rotation or scale not updated diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 731e527b1..0036bf769 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -12,6 +12,14 @@ namespace Ogre class Camera; } +namespace OEngine +{ + namespace Physic + { + class PhysicEngine; + } +} + namespace CSVRender { class SceneWidget; @@ -19,15 +27,13 @@ namespace CSVRender namespace CSVWorld { - class PhysicsEngine; - class PhysicsSystem { std::map mSceneNodeToRefId; std::map > mRefIdToSceneNode; std::map mSceneNodeToMesh; std::map mSceneWidgets; - PhysicsEngine* mEngine; + OEngine::Physic::PhysicEngine* mEngine; std::multimap mTerrain; public: diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index aba120baa..80cccd063 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -498,6 +499,7 @@ namespace MWWorld if (mWaterCollisionObject.get()) mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get()); delete mEngine; + delete OEngine::Physic::BulletShapeManager::getSingletonPtr(); } OEngine::Physic::PhysicEngine* PhysicsSystem::getEngine() diff --git a/libs/openengine/bullet/BtOgreExtras.h b/libs/openengine/bullet/BtOgreExtras.h index 9572b8a7b..f8c1fe41d 100644 --- a/libs/openengine/bullet/BtOgreExtras.h +++ b/libs/openengine/bullet/BtOgreExtras.h @@ -212,8 +212,10 @@ public: ~DebugDrawer() { - Ogre::MaterialManager::getSingleton().remove("BtOgre/DebugLines"); - Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup("BtOgre"); + if (Ogre::MaterialManager::getSingleton().resourceExists("BtOgre/DebugLines")) + Ogre::MaterialManager::getSingleton().remove("BtOgre/DebugLines"); + if (Ogre::ResourceGroupManager::getSingleton().resourceGroupExists("BtOgre")) + Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup("BtOgre"); delete mLineDrawer; } diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 0c61253bf..d7db81595 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -114,7 +114,7 @@ namespace Physic { mEngine->mDynamicsWorld->removeRigidBody(mBody); delete mBody; - } + } } void PhysicActor::enableCollisionMode(bool collision) @@ -356,7 +356,8 @@ namespace Physic delete broadphase; delete mShapeLoader; - delete BulletShapeManager::getSingletonPtr(); + // Moved the cleanup to mwworld/physicssystem + //delete BulletShapeManager::getSingletonPtr(); } void PhysicEngine::addHeightField(float* heights, @@ -863,5 +864,76 @@ namespace Physic } } + int PhysicEngine::toggleDebugRendering(Ogre::SceneManager *sceneMgr) + { + if(!sceneMgr) + return 0; + + std::map::iterator iter = + mDebugDrawers.find(sceneMgr); + if(iter != mDebugDrawers.end()) // found scene manager + { + if((*iter).second) + { + // set a new drawer each time (maybe with a different scene manager) + mDynamicsWorld->setDebugDrawer(mDebugDrawers[sceneMgr]); + if(!mDebugDrawers[sceneMgr]->getDebugMode()) + mDebugDrawers[sceneMgr]->setDebugMode(1 /*mDebugDrawFlags*/); + else + mDebugDrawers[sceneMgr]->setDebugMode(0); + mDynamicsWorld->debugDrawWorld(); + + return mDebugDrawers[sceneMgr]->getDebugMode(); + } + } + return 0; + } + + void PhysicEngine::stepDebug(Ogre::SceneManager *sceneMgr) + { + if(!sceneMgr) + return; + + std::map::iterator iter = + mDebugDrawers.find(sceneMgr); + if(iter != mDebugDrawers.end()) // found scene manager + { + if((*iter).second) + (*iter).second->step(); + else + return; + } + } + + void PhysicEngine::createDebugDraw(Ogre::SceneManager *sceneMgr) + { + if(mDebugDrawers.find(sceneMgr) == mDebugDrawers.end()) + { + mDebugSceneNodes[sceneMgr] = sceneMgr->getRootSceneNode()->createChildSceneNode(); + mDebugDrawers[sceneMgr] = new BtOgre::DebugDrawer(mDebugSceneNodes[sceneMgr], mDynamicsWorld); + mDebugDrawers[sceneMgr]->setDebugMode(0); + } + } + + void PhysicEngine::removeDebugDraw(Ogre::SceneManager *sceneMgr) + { + std::map::iterator iter = + mDebugDrawers.find(sceneMgr); + if(iter != mDebugDrawers.end()) + { + delete (*iter).second; + mDebugDrawers.erase(iter); + } + + std::map::iterator it = + mDebugSceneNodes.find(sceneMgr); + if(it != mDebugSceneNodes.end()) + { + std::string sceneNodeName = (*it).second->getName(); + if(sceneMgr->hasSceneNode(sceneNodeName)) + sceneMgr->destroySceneNode(sceneNodeName); + } + } + } } diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index a77b60ab6..fb6ae0ceb 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -348,6 +348,15 @@ namespace Physic bool isDebugCreated; bool mDebugActive; + // for OpenCS with multiple engines per document + std::map mDebugDrawers; + std::map mDebugSceneNodes; + + int toggleDebugRendering(Ogre::SceneManager *sceneMgr); + void stepDebug(Ogre::SceneManager *sceneMgr); + void createDebugDraw(Ogre::SceneManager *sceneMgr); + void removeDebugDraw(Ogre::SceneManager *sceneMgr); + private: PhysicEngine(const PhysicEngine&); PhysicEngine& operator=(const PhysicEngine&); From a3a06821388493c8466898eb48fb4ade20ff03ed Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 6 Nov 2014 11:16:17 +1100 Subject: [PATCH 10/15] Remove files no longer used, reverting to OEngine. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/view/world/physicsengine.cpp | 456 ----------------------- apps/opencs/view/world/physicsengine.hpp | 159 -------- 3 files changed, 1 insertion(+), 616 deletions(-) delete mode 100644 apps/opencs/view/world/physicsengine.cpp delete mode 100644 apps/opencs/view/world/physicsengine.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index b6c24e190..ec6f802cf 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -68,7 +68,7 @@ opencs_units (view/world opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate - scripthighlighter idvalidator dialoguecreator physicssystem physicsmanager physicsengine + scripthighlighter idvalidator dialoguecreator physicssystem physicsmanager ) opencs_units (view/widget diff --git a/apps/opencs/view/world/physicsengine.cpp b/apps/opencs/view/world/physicsengine.cpp deleted file mode 100644 index 05dcc3426..000000000 --- a/apps/opencs/view/world/physicsengine.cpp +++ /dev/null @@ -1,456 +0,0 @@ -#include "physicsengine.hpp" - -#include -#include - -#include -#include -#include - -#include - -#include -#include -#include -#include // needs Ogre::SceneNode defined - -// PLEASE NOTE: -// -// This file is based on libs/openengine/bullet/physic.cpp. Please see the commit -// history and credits for the code below, which is mostly copied from there and -// adapted for use with OpenCS. - -namespace CSVWorld -{ - RigidBody::RigidBody(btRigidBody::btRigidBodyConstructionInfo &CI, - const std::string &referenceId) : btRigidBody(CI) , mReferenceId(referenceId) - { - } - - RigidBody::~RigidBody() - { - delete getMotionState(); - } - - // In OpenCS one document has one PhysicsSystem. Each PhysicsSystem contains one - // PhysicsEngine. One document can have 0..n SceneWidgets, each with its own - // Ogre::SceneManager. - // - // These relationships are managed by the PhysicsManager. - // - // - When a view is created its document is registered with the PhysicsManager in - // View's constructor. If the document is new a PhysicSystem is created and - // associated with that document. A null list of SceneWidgets are assigned to - // that document. - // - // - When all views for a given document is closed, ViewManager will notify the - // PhysicsManager to destroy the PhysicsSystem associated with the document. - // - // - Each time a WorldspaceWidget (or its subclass) is created, it gets the - // PhysicsSystem associates with the widget's document from the PhysicsManager. - // The list of widgets are then maintained, but is not necessary and may be - // removed in future code updates. - // - // Each WorldspaceWidget can have objects (References) and terrain (Land) loaded - // from its document. There may be several views of the object, however there - // is only one corresponding physics object. i.e. each Reference can have 1..n - // SceneNodes - // - // These relationships are managed by the PhysicsSystem for the document. - // - // - Each time a WorldspaceWidget (or its subclass) is created, it registers - // itself and its Ogre::SceneManager with the PhysicsSystem assigned by the - // PhysicsManager. - // - // - Each time an object is added, the object's Ogre::SceneNode name is registered - // with the PhysicsSystem. Ogre itself maintains which SceneNode belongs to - // which SceneManager. - // - // - Each time an terrain is added, its cell coordinates and the SceneManager is - // registered with the PhysicsSystem. - // - PhysicsEngine::PhysicsEngine() - { - // Set up the collision configuration and dispatcher - mCollisionConfiguration = new btDefaultCollisionConfiguration(); - mDispatcher = new btCollisionDispatcher(mCollisionConfiguration); - - // The actual physics solver - mSolver = new btSequentialImpulseConstraintSolver; - - mBroadphase = new btDbvtBroadphase(); - - // The world. - mDynamicsWorld = new btDiscreteDynamicsWorld(mDispatcher, - mBroadphase, mSolver, mCollisionConfiguration); - - // Don't update AABBs of all objects every frame. Most objects in MW are static, - // so we don't need this. Should a "static" object ever be moved, we have to - // update its AABB manually using DynamicsWorld::updateSingleAabb. - mDynamicsWorld->setForceUpdateAllAabbs(false); - - mDynamicsWorld->setGravity(btVector3(0, 0, -10)); - - if(OEngine::Physic::BulletShapeManager::getSingletonPtr() == NULL) - { - new OEngine::Physic::BulletShapeManager(); - } - - mShapeLoader = new NifBullet::ManualBulletShapeLoader(); - } - - PhysicsEngine::~PhysicsEngine() - { - HeightFieldContainer::iterator hf_it = mHeightFieldMap.begin(); - for(; hf_it != mHeightFieldMap.end(); ++hf_it) - { - mDynamicsWorld->removeRigidBody(hf_it->second.mBody); - delete hf_it->second.mShape; - delete hf_it->second.mBody; - } - - RigidBodyContainer::iterator rb_it = mCollisionObjectMap.begin(); - for(; rb_it != mCollisionObjectMap.end(); ++rb_it) - { - if (rb_it->second != NULL) - { - mDynamicsWorld->removeRigidBody(rb_it->second); - - delete rb_it->second; - rb_it->second = NULL; - } - } - - rb_it = mRaycastingObjectMap.begin(); - for (; rb_it != mRaycastingObjectMap.end(); ++rb_it) - { - if (rb_it->second != NULL) - { - mDynamicsWorld->removeRigidBody(rb_it->second); - - delete rb_it->second; - rb_it->second = NULL; - } - } - - - delete mDynamicsWorld; - delete mSolver; - delete mCollisionConfiguration; - delete mDispatcher; - delete mBroadphase; - delete mShapeLoader; - - // NOTE: the global resources such as "BtOgre/DebugLines" and the - // BulletShapeManager singleton need to be deleted only when all physics - // engines are deleted in PhysicsManager::removeDocument() - } - - int PhysicsEngine::toggleDebugRendering(Ogre::SceneManager *sceneMgr) - { - if(!sceneMgr) - return 0; - - std::map::iterator iter = - mDebugDrawers.find(sceneMgr); - if(iter != mDebugDrawers.end()) // found scene manager - { - if((*iter).second) - { - // set a new drawer each time (maybe with a different scene manager) - mDynamicsWorld->setDebugDrawer(mDebugDrawers[sceneMgr]); - if(!mDebugDrawers[sceneMgr]->getDebugMode()) - mDebugDrawers[sceneMgr]->setDebugMode(1 /*mDebugDrawFlags*/); - else - mDebugDrawers[sceneMgr]->setDebugMode(0); - mDynamicsWorld->debugDrawWorld(); - - return mDebugDrawers[sceneMgr]->getDebugMode(); - } - } - return 0; - } - - void PhysicsEngine::stepDebug(Ogre::SceneManager *sceneMgr) - { - if(!sceneMgr) - return; - - std::map::iterator iter = - mDebugDrawers.find(sceneMgr); - if(iter != mDebugDrawers.end()) // found scene manager - { - if((*iter).second) - (*iter).second->step(); - else - return; - } - } - - void PhysicsEngine::createDebugDraw(Ogre::SceneManager *sceneMgr) - { - if(mDebugDrawers.find(sceneMgr) == mDebugDrawers.end()) - { - mDebugSceneNodes[sceneMgr] = sceneMgr->getRootSceneNode()->createChildSceneNode(); - mDebugDrawers[sceneMgr] = new BtOgre::DebugDrawer(mDebugSceneNodes[sceneMgr], mDynamicsWorld); - mDebugDrawers[sceneMgr]->setDebugMode(0); - } - } - - void PhysicsEngine::removeDebugDraw(Ogre::SceneManager *sceneMgr) - { - std::map::iterator iter = - mDebugDrawers.find(sceneMgr); - if(iter != mDebugDrawers.end()) - { - delete (*iter).second; - mDebugDrawers.erase(iter); - - // BtOgre::DebugDrawer destroys the resources leading to crashes in some - // situations. Workaround by recreating them each time. - if (!Ogre::ResourceGroupManager::getSingleton().resourceGroupExists("BtOgre")) - Ogre::ResourceGroupManager::getSingleton().createResourceGroup("BtOgre"); - if (!Ogre::MaterialManager::getSingleton().resourceExists("BtOgre/DebugLines")) - { - Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create("BtOgre/DebugLines", "BtOgre"); - mat->setReceiveShadows(false); - mat->setSelfIllumination(1,1,1); - } - } - - std::map::iterator it = - mDebugSceneNodes.find(sceneMgr); - if(it != mDebugSceneNodes.end()) - { - std::string sceneNodeName = (*it).second->getName(); - if(sceneMgr->hasSceneNode(sceneNodeName)) - sceneMgr->destroySceneNode(sceneNodeName); - } - } - - void PhysicsEngine::addHeightField(float* heights, - int x, int y, float yoffset, - float triSize, float sqrtVerts) - { - const std::string name = "HeightField_" - + boost::lexical_cast(x) + "_" - + boost::lexical_cast(y); - - // find the minimum and maximum heights (needed for bullet) - float minh = heights[0]; - float maxh = heights[0]; - for (int i=0; imaxh) maxh = h; - if (hsetUseDiamondSubdivision(true); - - btVector3 scl(triSize, triSize, 1); - hfShape->setLocalScaling(scl); - - btRigidBody::btRigidBodyConstructionInfo CI = - btRigidBody::btRigidBodyConstructionInfo(0,0,hfShape); - RigidBody* body = new RigidBody(CI, name); - body->getWorldTransform().setOrigin(btVector3( - (x+0.5)*triSize*(sqrtVerts-1), - (y+0.5)*triSize*(sqrtVerts-1), - (maxh+minh)/2.f)); - - HeightField hf; - hf.mBody = body; - hf.mShape = hfShape; - - mHeightFieldMap [name] = hf; - - mDynamicsWorld->addRigidBody(body, CollisionType_HeightMap, - CollisionType_Actor|CollisionType_Raycasting|CollisionType_Projectile); - } - - void PhysicsEngine::removeHeightField(int x, int y) - { - const std::string name = "HeightField_" - + boost::lexical_cast(x) + "_" - + boost::lexical_cast(y); - - HeightField hf = mHeightFieldMap [name]; - - mDynamicsWorld->removeRigidBody(hf.mBody); - delete hf.mShape; - delete hf.mBody; - - mHeightFieldMap.erase(name); - } - - void PhysicsEngine::adjustRigidBody(RigidBody* body, - const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) - { - btTransform tr; - Ogre::Quaternion boxrot = rotation * Ogre::Quaternion::IDENTITY; - Ogre::Vector3 transrot = boxrot * Ogre::Vector3::ZERO; - Ogre::Vector3 newPosition = transrot + position; - - tr.setOrigin(btVector3(newPosition.x, newPosition.y, newPosition.z)); - tr.setRotation(btQuaternion(boxrot.x,boxrot.y,boxrot.z,boxrot.w)); - body->setWorldTransform(tr); - } - - RigidBody* PhysicsEngine::createAndAdjustRigidBody(const std::string &mesh, - const std::string &name, // referenceId, assumed unique per OpenCS document - float scale, - const Ogre::Vector3 &position, - const Ogre::Quaternion &rotation, - bool raycasting, - bool placeable) // indicates whether the object can be picked up by the player - { - std::string sid = (boost::format("%07.3f") % scale).str(); - std::string outputstring = mesh + sid; - - //get the shape from the .nif - mShapeLoader->load(outputstring, "General"); - OEngine::Physic::BulletShapeManager::getSingletonPtr()->load(outputstring, "General"); - OEngine::Physic::BulletShapePtr shape = - OEngine::Physic::BulletShapeManager::getSingleton().getByName(outputstring, "General"); - - if (placeable && !raycasting && shape->mCollisionShape && !shape->mHasCollisionNode) - return NULL; - - if (!shape->mCollisionShape && !raycasting) - return NULL; - - if (!shape->mRaycastingShape && raycasting) - return NULL; - - btCollisionShape* collisionShape = raycasting ? shape->mRaycastingShape : shape->mCollisionShape; - collisionShape->setLocalScaling(btVector3(scale, scale, scale)); - - //create the real body - btRigidBody::btRigidBodyConstructionInfo CI = - btRigidBody::btRigidBodyConstructionInfo(0, 0, collisionShape); - - RigidBody* body = new RigidBody(CI, name); - - adjustRigidBody(body, position, rotation); - - if (!raycasting) - { - assert (mCollisionObjectMap.find(name) == mCollisionObjectMap.end()); - mCollisionObjectMap[name] = body; - mDynamicsWorld->addRigidBody(body, - CollisionType_World, CollisionType_Actor|CollisionType_HeightMap); - } - else - { - assert (mRaycastingObjectMap.find(name) == mRaycastingObjectMap.end()); - mRaycastingObjectMap[name] = body; - mDynamicsWorld->addRigidBody(body, - CollisionType_Raycasting, CollisionType_Raycasting|CollisionType_Projectile); - } - - return body; - } - - void PhysicsEngine::removeRigidBody(const std::string &name) - { - RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); - if (it != mCollisionObjectMap.end() ) - { - RigidBody* body = it->second; - if(body != NULL) - { - mDynamicsWorld->removeRigidBody(body); - } - } - - it = mRaycastingObjectMap.find(name); - if (it != mRaycastingObjectMap.end() ) - { - RigidBody* body = it->second; - if(body != NULL) - { - mDynamicsWorld->removeRigidBody(body); - } - } - } - - void PhysicsEngine::deleteRigidBody(const std::string &name) - { - RigidBodyContainer::iterator it = mCollisionObjectMap.find(name); - if (it != mCollisionObjectMap.end() ) - { - RigidBody* body = it->second; - - if(body != NULL) - { - delete body; - } - mCollisionObjectMap.erase(it); - } - - it = mRaycastingObjectMap.find(name); - if (it != mRaycastingObjectMap.end() ) - { - RigidBody* body = it->second; - - if(body != NULL) - { - delete body; - } - mRaycastingObjectMap.erase(it); - } - } - - RigidBody* PhysicsEngine::getRigidBody(const std::string &name, bool raycasting) - { - RigidBodyContainer* map = raycasting ? &mRaycastingObjectMap : &mCollisionObjectMap; - RigidBodyContainer::iterator it = map->find(name); - if (it != map->end() ) - { - RigidBody* body = (*map)[name]; - return body; - } - else - { - return NULL; - } - } - - std::pair PhysicsEngine::rayTest(const btVector3 &from, - const btVector3 &to, bool raycastingObjectOnly, bool ignoreHeightMap, Ogre::Vector3* normal) - { - std::string referenceId = ""; - float d = -1; - - btCollisionWorld::ClosestRayResultCallback resultCallback1(from, to); - resultCallback1.m_collisionFilterGroup = 0xff; - - if(raycastingObjectOnly) - resultCallback1.m_collisionFilterMask = CollisionType_Raycasting|CollisionType_Actor; - else - resultCallback1.m_collisionFilterMask = CollisionType_World; - - if(!ignoreHeightMap) - resultCallback1.m_collisionFilterMask = resultCallback1.m_collisionFilterMask | CollisionType_HeightMap; - - mDynamicsWorld->rayTest(from, to, resultCallback1); - if (resultCallback1.hasHit()) - { - referenceId = static_cast(*resultCallback1.m_collisionObject).getReferenceId(); - d = resultCallback1.m_closestHitFraction; - if (normal) - *normal = Ogre::Vector3(resultCallback1.m_hitNormalWorld.x(), - resultCallback1.m_hitNormalWorld.y(), - resultCallback1.m_hitNormalWorld.z()); - } - - return std::pair(referenceId, d); - } -} diff --git a/apps/opencs/view/world/physicsengine.hpp b/apps/opencs/view/world/physicsengine.hpp deleted file mode 100644 index 58dbf6525..000000000 --- a/apps/opencs/view/world/physicsengine.hpp +++ /dev/null @@ -1,159 +0,0 @@ -#ifndef CSV_WORLD_PHYSICSENGINE_H -#define CSV_WORLD_PHYSICSENGINE_H - -#include -#include - -#include - -class btBroadphaseInterface; -class btDefaultCollisionConfiguration; -class btSequentialImpulseConstraintSolver; -class btCollisionDispatcher; -class btDiscreteDynamicsWorld; -class btHeightfieldTerrainShape; - -namespace BtOgre -{ - class DebugDrawer; -} - -namespace Ogre -{ - class Vector3; - class SceneNode; - class SceneManager; - class Quaternion; -} - -namespace OEngine -{ - namespace Physic - { - class BulletShapeLoader; - } -} - -namespace CSVWorld -{ - // This class is just an extension of normal btRigidBody in order to add extra info. - // When bullet give back a btRigidBody, you can just do a static_cast to RigidBody, - // so one never should use btRigidBody directly! - class RigidBody: public btRigidBody - { - std::string mReferenceId; - - public: - - RigidBody(btRigidBody::btRigidBodyConstructionInfo &CI, const std::string &referenceId); - virtual ~RigidBody(); - - std::string getReferenceId() const { return mReferenceId; } - }; - - struct HeightField - { - btHeightfieldTerrainShape* mShape; - RigidBody* mBody; - }; - - // The PhysicsEngine class contain everything which is needed for Physic. - // It's needed that Ogre Resources are set up before the PhysicsEngine is created. - // Note:deleting it WILL NOT delete the RigidBody! - class PhysicsEngine - { - //Bullet Stuff - btBroadphaseInterface *mBroadphase; - btDefaultCollisionConfiguration *mCollisionConfiguration; - btSequentialImpulseConstraintSolver *mSolver; - btCollisionDispatcher *mDispatcher; - btDiscreteDynamicsWorld *mDynamicsWorld; - - //the NIF file loader. - OEngine::Physic::BulletShapeLoader *mShapeLoader; - - typedef std::map HeightFieldContainer; - HeightFieldContainer mHeightFieldMap; - - typedef std::map RigidBodyContainer; - RigidBodyContainer mCollisionObjectMap; - - RigidBodyContainer mRaycastingObjectMap; - - std::map mDebugDrawers; - std::map mDebugSceneNodes; - - enum CollisionType { - CollisionType_Nothing = 0, // rayTest(const btVector3 &from, - const btVector3 &to, bool raycastingObjectOnly = true, - bool ignoreHeightMap = false, Ogre::Vector3* normal = NULL); - - private: - - PhysicsEngine(const PhysicsEngine&); - PhysicsEngine& operator=(const PhysicsEngine&); - - // Create a debug rendering. It is called by setDebgRenderingMode if it's - // not created yet. - // Important Note: this will crash if the Render is not yet initialised! - void createDebugRendering(); - - // Set the debug rendering mode. 0 to turn it off. - // Important Note: this will crash if the Render is not yet initialised! - void setDebugRenderingMode(int mode); - }; -} -#endif // CSV_WORLD_PHYSICSENGINE_H From bebb59ef1165d65f25be8e25d8c596b4b66acf45 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Thu, 6 Nov 2014 10:51:32 +0100 Subject: [PATCH 11/15] Removed sending of travis notifications to my email. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c35d29201..233117718 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,6 @@ after_script: - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi notifications: recipients: - - lgromanowski+travis.ci@gmail.com - corrmage+travis-ci@gmail.com email: on_success: change From 0fd33e319881f18a1fd039d52c377a3cbfcbb7a3 Mon Sep 17 00:00:00 2001 From: hasufell Date: Thu, 6 Nov 2014 22:27:35 +0100 Subject: [PATCH 12/15] Fix morrowind data files detection for custom install locations --- files/openmw.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/openmw.cfg b/files/openmw.cfg index e105b6304..b60c1ba72 100644 --- a/files/openmw.cfg +++ b/files/openmw.cfg @@ -1,5 +1,5 @@ -data="?global?data" data="?mw?Data Files" +data=${MORROWIND_DATA_FILES} data-local="?userdata?data" resources=${OPENMW_RESOURCE_FILES} script-blacklist=Museum From b8d5a9486ac04270034126df753fe7e69d198b41 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 2 Nov 2014 18:01:12 +0100 Subject: [PATCH 13/15] Make Restore/Damage Attribute/Skill effects continuous --- apps/openmw/mwmechanics/actors.cpp | 12 +++++++++--- apps/openmw/mwmechanics/actors.hpp | 2 +- apps/openmw/mwmechanics/stat.hpp | 8 ++++---- components/esm/statstate.hpp | 14 ++++++++++---- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 02594258d..2e835d57e 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -369,7 +369,7 @@ namespace MWMechanics void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration) { updateDrowning(ptr, duration); - calculateNpcStatModifiers(ptr); + calculateNpcStatModifiers(ptr, duration); updateEquippedLight(ptr, duration); } @@ -499,6 +499,9 @@ namespace MWMechanics effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).getMagnitude()); + stat.damage(effects.get(EffectKey(ESM::MagicEffect::DamageAttribute, i)).getMagnitude() * duration * 1.5); + stat.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreAttribute, i)).getMagnitude() * duration * 1.5); + creatureStats.setAttribute(i, stat); } @@ -855,7 +858,7 @@ namespace MWMechanics } } - void Actors::calculateNpcStatModifiers (const MWWorld::Ptr& ptr) + void Actors::calculateNpcStatModifiers (const MWWorld::Ptr& ptr, float duration) { NpcStats &npcStats = ptr.getClass().getNpcStats(ptr); const MagicEffects &effects = npcStats.getMagicEffects(); @@ -867,6 +870,9 @@ namespace MWMechanics skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).getMagnitude() - effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).getMagnitude()); + + skill.damage(effects.get(EffectKey(ESM::MagicEffect::DamageSkill, i)).getMagnitude() * duration * 1.5); + skill.restore(effects.get(EffectKey(ESM::MagicEffect::RestoreSkill, i)).getMagnitude() * duration * 1.5); } } @@ -1534,6 +1540,6 @@ namespace MWMechanics adjustMagicEffects(ptr); calculateCreatureStatModifiers(ptr, 0.f); if (ptr.getClass().isNpc()) - calculateNpcStatModifiers(ptr); + calculateNpcStatModifiers(ptr, 0.f); } } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 55f1719f6..0ccfaad78 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -34,7 +34,7 @@ namespace MWMechanics void calculateDynamicStats (const MWWorld::Ptr& ptr); void calculateCreatureStatModifiers (const MWWorld::Ptr& ptr, float duration); - void calculateNpcStatModifiers (const MWWorld::Ptr& ptr); + void calculateNpcStatModifiers (const MWWorld::Ptr& ptr, float duration); void calculateRestoration (const MWWorld::Ptr& ptr, float duration); diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 0fb4c5732..1c33db0fd 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -236,20 +236,20 @@ namespace MWMechanics { int mBase; int mModifier; - int mDamage; + float mDamage; // needs to be float to allow continuous damage public: AttributeValue() : mBase(0), mModifier(0), mDamage(0) {} - int getModified() const { return std::max(0, mBase - mDamage + mModifier); } + int getModified() const { return std::max(0, mBase - (int) mDamage + mModifier); } int getBase() const { return mBase; } int getModifier() const { return mModifier; } void setBase(int base) { mBase = std::max(0, base); } void setModifier(int mod) { mModifier = mod; } - void damage(int damage) { mDamage += damage; } - void restore(int amount) { mDamage -= std::min(mDamage, amount); } + void damage(float damage) { mDamage += damage; } + void restore(float amount) { mDamage -= std::min(mDamage, amount); } int getDamage() const { return mDamage; } void writeState (ESM::StatState& state) const; diff --git a/components/esm/statstate.hpp b/components/esm/statstate.hpp index f1a3b4d79..801d0ce82 100644 --- a/components/esm/statstate.hpp +++ b/components/esm/statstate.hpp @@ -15,7 +15,7 @@ namespace ESM T mMod; // Note: can either be the modifier, or the modified value. // A bit inconsistent, but we can't fix this without breaking compatibility. T mCurrent; - T mDamage; + float mDamage; float mProgress; StatState(); @@ -36,8 +36,14 @@ namespace ESM esm.getHNOT (mMod, "STMO"); mCurrent = 0; esm.getHNOT (mCurrent, "STCU"); - mDamage = 0; - esm.getHNOT (mDamage, "STDA"); + + // mDamage was changed to a float; ensure backwards compatibility + T oldDamage = 0; + esm.getHNOT(oldDamage, "STDA"); + mDamage = oldDamage; + + esm.getHNOT (mDamage, "STDF"); + mProgress = 0; esm.getHNOT (mProgress, "STPR"); } @@ -54,7 +60,7 @@ namespace ESM esm.writeHNT ("STCU", mCurrent); if (mDamage) - esm.writeHNT ("STDA", mDamage); + esm.writeHNT ("STDF", mDamage); if (mProgress) esm.writeHNT ("STPR", mProgress); From fe385214e4d45969ababbebe76d419f4af6e602a Mon Sep 17 00:00:00 2001 From: Evgenii Babinets Date: Mon, 10 Nov 2014 02:42:44 -0500 Subject: [PATCH 14/15] Added proper slow fall effect mechanics. --- apps/openmw/mwworld/physicssystem.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 80cccd063..eecc4a02d 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -472,10 +472,9 @@ namespace MWWorld physicActor->setInertialForce(Ogre::Vector3(0.0f)); else { - float diff = time*-627.2f; + inertia.z += time * -627.2f; if (inertia.z < 0) - diff *= slowFall; - inertia.z += diff; + inertia.z *= slowFall; physicActor->setInertialForce(inertia); } physicActor->setOnGround(isOnGround); @@ -865,8 +864,8 @@ namespace MWWorld continue; physicActor->setCanWaterWalk(waterCollision); - // 100 points of slowfall reduce gravity by 90% (this is just a guess) - float slowFall = 1-std::min(std::max(0.f, (effects.get(ESM::MagicEffect::SlowFall).getMagnitude() / 100.f) * 0.9f), 0.9f); + // Slow fall reduces fall speed by a factor of (effect magnitude / 200) + float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f)); Ogre::Vector3 newpos = MovementSolver::move(iter->first, iter->second, mTimeAccum, world->isFlying(iter->first), From 3828e3fae506d71488dd0065061815291067ff21 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 10 Nov 2014 16:37:31 +0100 Subject: [PATCH 15/15] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index 10065b44d..d7fe230c7 100644 --- a/credits.txt +++ b/credits.txt @@ -46,6 +46,7 @@ Jannik Heller (scrawl) Jason Hooks (jhooks) jeaye Jeffrey Haines (Jyby) +Jengerer Joel Graff (graffy) John Blomberg (fstp) Jordan Ayers