diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index c5712c7e8..ee6630eac 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -66,7 +66,7 @@ namespace CSVRender mOverlaySystem = OverlaySystem::instance().get(); mSceneMgr->addRenderQueueListener(mOverlaySystem); - CSVWorld::PhysicsSystem::instance()->setSceneManager(mSceneMgr); + CSVWorld::PhysicsSystem::instance()->addSceneManager(mSceneMgr); QTimer *timer = new QTimer (this); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index d11a9bb60..655a2e026 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -716,8 +716,8 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) // debug drawer. Hence only the first subview that creates the debug drawer // can view the debug lines. Will need to keep a map in OEngine if multiple // subviews are to be supported. - CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); - CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(); + //CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); + CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(getSceneManager()); flagAsModified(); } } @@ -840,7 +840,7 @@ std::pair CSVRender::WorldspaceWidget::terrainUnderC float y = (float) mouseY / getCamera()->getViewport()->getActualHeight(); std::pair result = - CSVWorld::PhysicsSystem::instance()->castRay(x, y, NULL, NULL, getCamera()); + CSVWorld::PhysicsSystem::instance()->castRay(x, y, getSceneManager(), getCamera()); if(result.first != "") { // FIXME: is there a better way to distinguish terrain from objects? @@ -863,7 +863,7 @@ std::pair CSVRender::WorldspaceWidget::objectUnderCu float y = (float) mouseY / getCamera()->getViewport()->getActualHeight(); std::pair result = - CSVWorld::PhysicsSystem::instance()->castRay(x, y, NULL, NULL, getCamera()); + CSVWorld::PhysicsSystem::instance()->castRay(x, y, getSceneManager(), getCamera()); if(result.first != "") { // NOTE: anything not terrain is assumed to be an object diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 0e3790d93..02775801c 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -15,7 +15,7 @@ namespace CSVWorld { PhysicsSystem *PhysicsSystem::mPhysicsSystemInstance = 0; - PhysicsSystem::PhysicsSystem(Ogre::SceneManager *sceneMgr) : mSceneMgr(sceneMgr) + PhysicsSystem::PhysicsSystem() : mSceneMgr(0) { assert(!mPhysicsSystemInstance); mPhysicsSystemInstance = this; @@ -36,20 +36,37 @@ namespace CSVWorld return mPhysicsSystemInstance; } + // FIXME: looks up the scene manager based on the scene node name (highly inefficient) + // NOTE: referenceId is assumed to be unique per document + // NOTE: searching is done here rather than after rayTest, so slower to load but + // faster to find (not verified w/ perf test) void PhysicsSystem::addObject(const std::string &mesh, const std::string &sceneNodeName, const std::string &referenceId, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) { - // NOTE: referenceId may not be unique when editing multiple documents concurrently - mSceneNodeToRefId[sceneNodeName] = referenceId; - mSceneNodeToMesh[sceneNodeName] = mesh; - - mEngine->createAndAdjustRigidBody(mesh, - sceneNodeName, scale, position, rotation, - 0, // scaledBoxTranslation - 0, // boxRotation - true, // raycasting - placeable); + bool foundSceneManager = false; + std::list::const_iterator iter = mSceneManagers.begin(); + for(; iter != mSceneManagers.end(); ++iter) + { + if((*iter)->hasSceneNode(sceneNodeName)) + { + mSceneNodeToRefId[sceneNodeName] = referenceId; + mRefIdToSceneNode[referenceId][*iter] = sceneNodeName; + mSceneNodeToMesh[sceneNodeName] = mesh; + foundSceneManager = true; + break; + } + } + + if(foundSceneManager) + { + mEngine->createAndAdjustRigidBody(mesh, + referenceId, scale, position, rotation, + 0, // scaledBoxTranslation + 0, // boxRotation + true, // raycasting + placeable); + } } void PhysicsSystem::removeObject(const std::string &sceneNodeName) @@ -76,13 +93,21 @@ namespace CSVWorld mEngine->removeHeightField(x, y); } + // sceneMgr: to lookup the scene node name from the object's referenceId + // camera: primarily used to get the visibility mask for the viewport + // + // returns the found object's scene node name and its position in the world space + // + // WARNING: far clip distance is a global setting, if it changes in future + // this method will need to be updated std::pair PhysicsSystem::castRay(float mouseX, - float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) + float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera) { - if(!mSceneMgr || !camera || !camera->getViewport()) + // NOTE: there could be more than one camera for the scene manager + // TODO: check whether camera belongs to sceneMgr + if(!sceneMgr || !camera || !camera->getViewport()) return std::make_pair("", Ogre::Vector3(0,0,0)); // FIXME: this should be an exception - // using a really small value seems to mess up with the projections float nearClipDistance = camera->getNearClipDistance(); // save existing camera->setNearClipDistance(10.0f); // arbitrary number @@ -102,14 +127,20 @@ namespace CSVWorld bool ignoreHeightMap = !(visibilityMask & (uint32_t)CSVRender::Element_Terrain); bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - Ogre::Vector3 norm; + Ogre::Vector3 norm; // not used std::pair result = mEngine->rayTest(_from, _to, !ignoreObjects, ignoreHeightMap, &norm); + // result.first is the object's referenceId if(result.first == "") return std::make_pair("", Ogre::Vector3(0,0,0)); else - return std::make_pair(result.first, ray.getPoint(farClipDist*result.second)); + return std::make_pair(refIdToSceneNode(result.first, sceneMgr), ray.getPoint(farClipDist*result.second)); + } + + std::string PhysicsSystem::refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr) + { + return mRefIdToSceneNode[referenceId][sceneMgr]; } std::string PhysicsSystem::sceneNodeToRefId(std::string sceneNodeName) @@ -122,17 +153,19 @@ namespace CSVWorld return mSceneNodeToMesh[sceneNodeName]; } - void PhysicsSystem::setSceneManager(Ogre::SceneManager *sceneMgr) + void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr) { - mSceneMgr = sceneMgr; - mEngine->setSceneManager(sceneMgr); // needed for toggleDebugRendering() + mSceneManagers.push_back(sceneMgr); } - void PhysicsSystem::toggleDebugRendering() + void PhysicsSystem::toggleDebugRendering(Ogre::SceneManager *sceneMgr) { + // FIXME: should check if sceneMgr is in the list if(!mSceneMgr) return; // FIXME: maybe this should be an exception + mEngine->setSceneManager(sceneMgr); + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); if(!(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false)) { diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 5cf568784..616bd13e6 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Ogre { @@ -27,19 +27,21 @@ namespace CSVWorld { static PhysicsSystem *mPhysicsSystemInstance; std::map mSceneNodeToRefId; + std::map > mRefIdToSceneNode; std::map mSceneNodeToMesh; + std::list mSceneManagers; // FIXME: change to list per OEngine OEngine::Physic::PhysicEngine* mEngine; Ogre::SceneManager *mSceneMgr; public: - PhysicsSystem(Ogre::SceneManager *sceneMgr = NULL); + PhysicsSystem(); ~PhysicsSystem(); static PhysicsSystem *instance(); - void setSceneManager(Ogre::SceneManager *sceneMgr); + void addSceneManager(Ogre::SceneManager *sceneMgr); void addObject(const std::string &mesh, const std::string &sceneNodeName, const std::string &referenceId, float scale, @@ -56,10 +58,11 @@ namespace CSVWorld void removeHeightField(int x, int y); - void toggleDebugRendering(); + void toggleDebugRendering(Ogre::SceneManager *sceneMgr); + // return the object's SceneNode name and position for the given SceneManager std::pair castRay(float mouseX, - float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera); + float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera); std::string sceneNodeToRefId(std::string sceneNodeName); std::string sceneNodeToMesh(std::string sceneNodeName); @@ -67,6 +70,7 @@ namespace CSVWorld private: void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); + std::string refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr); }; }