diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index c9fcdbc867..65596b752d 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -58,8 +58,8 @@ namespace CSVRender MouseState::MouseState(WorldspaceWidget *parent) : mParent(parent), mPhysics(parent->getPhysics()), mSceneManager(parent->getSceneManager()) , mCurrentObj(""), mMouseState(Mouse_Default), mOldCursorPos(0,0), mMouseEventTimer(0) - , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) - , mOldMousePos(Ogre::Vector3()), mPlane(0) + , mGrabbedSceneNode(""), mGrabbedRefId(""), mOrigObjPos(Ogre::Vector3()) + , mOrigMousePos(Ogre::Vector3()), mOldMousePos(Ogre::Vector3()), mPlane(0) , mColIndexPosX(0), mColIndexPosY(0), mColIndexPosZ(0), mIdTableModel(0) { const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); @@ -120,16 +120,13 @@ namespace CSVRender std::pair planeResult = mousePosOnPlane(event->pos(), *mPlane); if(planeResult.first) { - if(mGrabbedSceneNode != "") - { - Ogre::Vector3 pos = mOrigObjPos + (planeResult.second-mOrigMousePos); + Ogre::Vector3 pos = mOrigObjPos + (planeResult.second-mOrigMousePos); - mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos); - mPhysics->moveSceneNodes(mGrabbedSceneNode, pos); - updateSceneWidgets(); + mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos); + mPhysics->moveSceneNodes(mGrabbedSceneNode, pos); + updateSceneWidgets(); - mOldMousePos = planeResult.second; - } + mOldMousePos = planeResult.second; } } break; @@ -157,11 +154,18 @@ namespace CSVRender { if(event->buttons() & Qt::RightButton) { - std::pair result = objectUnderCursor(event->x(), event->y()); + // get object or pathgrid + std::pair result = underCursor(event->x(), event->y(), + CSVRender::Element_Reference|CSVRender::Element_Pathgrid); + if(result.first == "") break; - mGrabbedSceneNode = result.first; + mGrabbedSceneNode = mPhysics->refIdToSceneNode(result.first, mSceneManager); + if(!mSceneManager->hasSceneNode(mGrabbedSceneNode)) + break; + + mGrabbedRefId = result.first; // ray test agaist the plane to get a starting position of the // mouse in relation to the object position std::pair planeRes = planeAxis(); @@ -190,7 +194,9 @@ namespace CSVRender { case Mouse_Grab: { - std::pair result = objectUnderCursor(event->x(), event->y()); + std::pair result = underCursor(event->x(), event->y(), + CSVRender::Element_Reference|CSVRender::Element_Pathgrid); + if(result.first != "") { if(result.first == mCurrentObj) @@ -208,11 +214,7 @@ namespace CSVRender } //#if 0 // print some debug info - std::string referenceId = mPhysics->sceneNodeToRefId(result.first); - if(referenceId != "") - std::cout << "result grab release: " << referenceId << std::endl; - else - std::cout << "result grab release: " << result.first << std::endl; + std::cout << "result grab release: " << result.first << std::endl; std::cout << " hit pos "+ QString::number(result.second.x).toStdString() + ", " + QString::number(result.second.y).toStdString() + ", " + QString::number(result.second.z).toStdString() << std::endl; @@ -224,24 +226,21 @@ namespace CSVRender { // final placement std::pair planeResult = mousePosOnPlane(event->pos(), *mPlane); - if(planeResult.first && mGrabbedSceneNode != "") + if(planeResult.first) { Ogre::Vector3 pos = mOrigObjPos + (planeResult.second-mOrigMousePos); - // use the saved scene node name since the physics model has not moved yet - std::string referenceId = mPhysics->sceneNodeToRefId(mGrabbedSceneNode); - - if(QString(referenceId.c_str()).contains(QRegExp("^Pathgrid"))) + // use the saved reference Id since the physics model has not moved yet + if(QString(mGrabbedRefId.c_str()).contains(QRegExp("^Pathgrid"))) { // FIXME: move pathgrid point, but don't save yet (need pathgrid // table feature & its data structure to be completed) // Also need to signal PathgridPoint object of change std::pair result = mPhysics->distToClosest(pos, getCamera(), 600); // snap - std::string refId = mPhysics->sceneNodeToRefId(result.first); if(result.first != "" && // don't allow pathgrid points under the cursor - !QString(refId.c_str()).contains(QRegExp("^Pathgrid"))) + !QString(result.first.c_str()).contains(QRegExp("^Pathgrid"))) { pos.z -= result.second; pos.z += 2; // arbitrary number, lift up slightly (maybe change the nif?) @@ -251,7 +250,7 @@ namespace CSVRender // the object is a pathgrid point at the begging and set // a flag?) placeObject(mGrabbedSceneNode, pos); // result.second - mParent->pathgridMoved(referenceId, pos); // result.second + mParent->pathgridMoved(mGrabbedRefId, pos); // result.second } else cancelDrag(); // FIXME: does not allow editing if terrain not visible @@ -260,22 +259,23 @@ namespace CSVRender { mParent->mDocument.getUndoStack().beginMacro (QObject::tr("Move Object")); mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, - mIdTableModel->getModelIndex(referenceId, mColIndexPosX), pos.x)); + mIdTableModel->getModelIndex(mGrabbedRefId, mColIndexPosX), pos.x)); mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, - mIdTableModel->getModelIndex(referenceId, mColIndexPosY), pos.y)); + mIdTableModel->getModelIndex(mGrabbedRefId, mColIndexPosY), pos.y)); mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, - mIdTableModel->getModelIndex(referenceId, mColIndexPosZ), pos.z)); + mIdTableModel->getModelIndex(mGrabbedRefId, mColIndexPosZ), pos.z)); mParent->mDocument.getUndoStack().endMacro(); } // FIXME: highlight current object? - //mCurrentObj = mGrabbedSceneNode; // FIXME: doesn't work? + //mCurrentObj = mGrabbedRefId; // FIXME: doesn't work? mCurrentObj = ""; // whether the object is selected mMouseState = Mouse_Edit; // reset states - mGrabbedSceneNode = ""; // id of the object + mGrabbedRefId = ""; // id of the object + mGrabbedSceneNode = ""; mOrigMousePos = Ogre::Vector3(); // starting pos of mouse in world space mOrigObjPos = Ogre::Vector3(); // starting pos of object in world space mOldMousePos = Ogre::Vector3(); // mouse pos to use in wheel event @@ -287,7 +287,9 @@ namespace CSVRender case Mouse_Default: { // probably terrain, check - std::pair result = terrainUnderCursor(event->x(), event->y()); + std::pair result = underCursor(event->x(), event->y(), + CSVRender::Element_Terrain); + if(result.first != "") { // FIXME: terrain editing goes here @@ -354,9 +356,10 @@ namespace CSVRender mousePos = planeResult.second; } - // Find the final world position of the cursor + // Find the final world position of the object Ogre::Vector3 finalPos = mOrigObjPos + (mousePos-mOrigMousePos); + // update Ogre and Bullet mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(finalPos); mPhysics->moveSceneNodes(mGrabbedSceneNode, finalPos); updateSceneWidgets(); @@ -396,6 +399,7 @@ namespace CSVRender mOldMousePos = Ogre::Vector3(); mOrigMousePos = Ogre::Vector3(); mOrigObjPos = Ogre::Vector3(); + mGrabbedRefId = ""; mGrabbedSceneNode = ""; mCurrentObj = ""; mOldCursorPos = QPoint(0, 0); @@ -444,21 +448,6 @@ namespace CSVRender } } - // FIXME: castRay converts referenceId to scene node name only to be re-converted - // here - investigate whether refactoring required - std::pair MouseState::pgPointUnderCursor(const int mouseX, const int mouseY) - { - std::pair result = objectUnderCursor(mouseX, mouseY); - std::string referenceId = mPhysics->sceneNodeToRefId(result.first); - if(result.first != "" && - referenceId != "" && QString(referenceId.c_str()).contains(QRegExp("^Pathgrid"))) - { - return std::make_pair(referenceId, result.second); - } - - return std::make_pair("", Ogre::Vector3()); - } - std::pair MouseState::mousePosOnPlane(const QPoint &pos, const Ogre::Plane &plane) { // using a really small value seems to mess up with the projections @@ -476,47 +465,8 @@ namespace CSVRender return std::make_pair(false, Ogre::Vector3()); // should only happen if the plane is too small } - std::pair MouseState::terrainUnderCursor(const int mouseX, const int mouseY) - { - std::pair result = anyUnderCursor(mouseX, mouseY); - if(result.first != "") - { - // FIXME: is there a better way to distinguish terrain from objects? - QString name = QString(result.first.c_str()); - if(name.contains(QRegExp("^HeightField"))) - { - return result; - } - } - - return std::make_pair("", Ogre::Vector3()); - } - - // NOTE: also returns pathgrids - std::pair MouseState::objectUnderCursor(const int mouseX, const int mouseY) - { - std::pair result = anyUnderCursor(mouseX, mouseY); - if(result.first != "") - { - // NOTE: anything not terrain is assumed to be an object, e.g pathgrid points - QString name = QString(result.first.c_str()); - if(!name.contains(QRegExp("^HeightField"))) - { - uint32_t visibilityMask = getViewport()->getVisibilityMask(); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - bool ignorePathgrid = !(visibilityMask & (uint32_t)CSVRender::Element_Pathgrid); - - if((!ignoreObjects || !ignorePathgrid) && mSceneManager->hasSceneNode(result.first)) - { - return result; - } - } - } - - return std::make_pair("", Ogre::Vector3()); - } - - std::pair MouseState::anyUnderCursor(const int mouseX, const int mouseY) + std::pair MouseState::underCursor(const int mouseX, + const int mouseY, Ogre::uint32 elements) { if(!getViewport()) return std::make_pair("", Ogre::Vector3()); @@ -524,13 +474,7 @@ namespace CSVRender float x = (float) mouseX / getViewport()->getActualWidth(); float y = (float) mouseY / getViewport()->getActualHeight(); - std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); - if(result.first != "") - { - return result; - } - - return std::make_pair("", Ogre::Vector3()); + return mPhysics->castRay(x, y, mSceneManager, getCamera(), elements); } void MouseState::updateSceneWidgets() @@ -554,14 +498,12 @@ namespace CSVRender return mParent->getCamera()->getViewport(); } - void MouseState::placeObject(const std::string sceneNode, const Ogre::Vector3 &pos) + void MouseState::placeObject(const std::string sceneNodeName, const Ogre::Vector3 &pos) { - mSceneManager->getSceneNode(sceneNode)->setPosition(pos); + mSceneManager->getSceneNode(sceneNodeName)->setPosition(pos); // update physics - std::string refId = mPhysics->sceneNodeToRefId(sceneNode); - - mPhysics->replaceObject(sceneNode, 1, pos, Ogre::Quaternion::IDENTITY); + mPhysics->replaceObject(sceneNodeName, 1, pos, Ogre::Quaternion::IDENTITY); // update all SceneWidgets and their SceneManagers updateSceneWidgets(); diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp index d21735a78d..d55d5f6c30 100644 --- a/apps/opencs/view/render/mousestate.hpp +++ b/apps/opencs/view/render/mousestate.hpp @@ -49,6 +49,7 @@ namespace CSVRender QPoint mOldCursorPos; std::string mCurrentObj; std::string mGrabbedSceneNode; + std::string mGrabbedRefId; QElapsedTimer *mMouseEventTimer; Ogre::Plane *mPlane; Ogre::Vector3 mOrigObjPos; @@ -70,20 +71,19 @@ namespace CSVRender void mouseReleaseEvent (QMouseEvent *event); void mouseDoubleClickEvent (QMouseEvent *event); bool wheelEvent (QWheelEvent *event); - std::pair pgPointUnderCursor(const int mouseX, const int mouseY); - std::pair anyUnderCursor(const int mouseX, const int mouseY); + + std::pair underCursor(const int mouseX, + const int mouseY, Ogre::uint32 elements); void cancelDrag(); private: std::pair mousePosOnPlane(const QPoint &pos, const Ogre::Plane &plane); - std::pair terrainUnderCursor(const int mouseX, const int mouseY); - std::pair objectUnderCursor(const int mouseX, const int mouseY); std::pair planeAxis(); void updateSceneWidgets(); - void placeObject(const std::string sceneNode, const Ogre::Vector3 &pos); // FIXME + void placeObject(const std::string sceneNodeName, const Ogre::Vector3 &pos); // FIXME Ogre::Camera *getCamera(); // friend access Ogre::Viewport *getViewport(); // friend access diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 506fd54df9..bb856dbffd 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -334,10 +334,9 @@ CSVRender::Cell *CSVRender::PagedWorldspaceWidget::findCell(const std::string &c } // NOTE: allow placing pathgrid points above objects and terrain -void CSVRender::PagedWorldspaceWidget::pathgridInserted (const std::string &name, const Ogre::Vector3 &pos) +void CSVRender::PagedWorldspaceWidget::pathgridInserted (const std::string &referenceId, const Ogre::Vector3 &pos) { - QString id = QString(name.c_str()); - std::string referenceId = getPhysics()->sceneNodeToRefId(name); // FIXME: move back + QString id = QString(referenceId.c_str()); bool terrain = id.startsWith("HeightField_"); bool object = QString(referenceId.c_str()).startsWith("ref#"); diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index b5ca91880b..63f6caa60a 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -96,7 +96,7 @@ namespace CSVRender virtual void mouseDoubleClickEvent (QMouseEvent *event); // FIXME: temporary only until signals from the document is implemented - virtual void pathgridInserted (const std::string &terrain, const Ogre::Vector3 &pos); + virtual void pathgridInserted (const std::string &referenceId, const Ogre::Vector3 &pos); virtual void pathgridMoved (const std::string &pgName, const Ogre::Vector3 &pos); virtual void pathgridAboutToBeRemoved (const std::string &pgName); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 4f85f3a30c..54d0ce8e85 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -411,7 +411,9 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) else if(event->key() == Qt::Key_Delete) { QPoint p = this->mapFromGlobal(QCursor::pos()); - std::pair result = mMouse->pgPointUnderCursor(p.x(), p.y()); + std::pair result = + mMouse->underCursor(p.x(), p.y(), CSVRender::Element_Pathgrid); + if(result.first != "") { pathgridAboutToBeRemoved(result.first); @@ -422,7 +424,9 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) else if(event->key() == Qt::Key_Insert) { QPoint p = this->mapFromGlobal(QCursor::pos()); - std::pair result = mMouse->anyUnderCursor(p.x(), p.y()); + std::pair result = + mMouse->underCursor(p.x(), p.y(), CSVRender::Element_Reference|CSVRender::Element_Terrain); + if(result.first != "") { pathgridInserted(result.first, result.second); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 9ff945829a..9012a06c2c 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -211,15 +211,11 @@ namespace CSVWorld } } - // 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::SceneManager *sceneMgr, Ogre::Camera *camera) + float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera, + Ogre::uint32 elements) { // NOTE: there could be more than one camera for the scene manager // TODO: check whether camera belongs to sceneMgr @@ -241,10 +237,10 @@ namespace CSVWorld _from = btVector3(from.x, from.y, from.z); _to = btVector3(to.x, to.y, to.z); - uint32_t visibilityMask = camera->getViewport()->getVisibilityMask(); - bool ignoreHeightMap = !(visibilityMask & (uint32_t)CSVRender::Element_Terrain); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - bool ignorePathgrid = !(visibilityMask & (uint32_t)CSVRender::Element_Pathgrid); + Ogre::uint32 visibilityMask = camera->getViewport()->getVisibilityMask(); + bool ignoreHeightMap = !(visibilityMask & (Ogre::uint32)CSVRender::Element_Terrain); + bool ignoreObjects = !(visibilityMask & (Ogre::uint32)CSVRender::Element_Reference); + bool ignorePathgrid = !(visibilityMask & (Ogre::uint32)CSVRender::Element_Pathgrid); std::pair result = std::make_pair("", -1); short mask = OEngine::Physic::CollisionType_Raycasting; @@ -265,20 +261,18 @@ namespace CSVWorld } // result.first is the object's referenceId - if(result.first == "") - return std::make_pair("", Ogre::Vector3()); - else + if(result.first != "" && + ((elements & (Ogre::uint32)CSVRender::Element_Terrain && + QString(result.first.c_str()).contains(QRegExp("^Height"))) || + (elements & (Ogre::uint32)CSVRender::Element_Reference && + QString(result.first.c_str()).contains(QRegExp("^ref#"))) || + (elements & (Ogre::uint32)CSVRender::Element_Pathgrid && + QString(result.first.c_str()).contains(QRegExp("^Pathgrid"))))) { - // FIXME: maybe below logic belongs in the caller, i.e. terrainUnderCursor or - // objectUnderCursor - std::string name = refIdToSceneNode(result.first, sceneMgr); - if(name == "") - name = result.first; // prob terrain - else - name = refIdToSceneNode(result.first, sceneMgr); // prob object - - return std::make_pair(name, ray.getPoint(farClipDist*result.second)); + return std::make_pair(result.first, ray.getPoint(farClipDist*result.second)); } + else + return std::make_pair("", Ogre::Vector3()); } std::pair PhysicsSystem::distToGround(const Ogre::Vector3 &position, @@ -288,11 +282,11 @@ namespace CSVWorld _from = btVector3(position.x, position.y, position.z); _to = btVector3(position.x, position.y, position.z-limit); - uint32_t visibilityMask = camera->getViewport()->getVisibilityMask(); - bool ignoreHeightMap = !(visibilityMask & (uint32_t)CSVRender::Element_Terrain); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); + Ogre::uint32 visibilityMask = camera->getViewport()->getVisibilityMask(); + bool ignoreHeightMap = !(visibilityMask & (Ogre::uint32)CSVRender::Element_Terrain); + bool ignoreObjects = !(visibilityMask & (Ogre::uint32)CSVRender::Element_Reference); bool ignorePathgrid = ignorePgPoint || - !(visibilityMask & (uint32_t)CSVRender::Element_Pathgrid); + !(visibilityMask & (Ogre::uint32)CSVRender::Element_Pathgrid); std::pair result = std::make_pair("", -1); short mask = OEngine::Physic::CollisionType_Raycasting; diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 589dca9c5b..5543c84b96 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -4,6 +4,8 @@ #include #include +#include + namespace Ogre { class Vector3; @@ -71,7 +73,8 @@ namespace CSVWorld // return the object's SceneNode name and position for the given SceneManager std::pair castRay(float mouseX, - float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera); + float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera, + Ogre::uint32 elements = 0xFFFFFFFF); std::pair distToGround(const Ogre::Vector3 &position, Ogre::Camera *camera, const float limit = 300000, bool ignorePgPoint = false); @@ -79,7 +82,7 @@ namespace CSVWorld std::pair distToClosest(const Ogre::Vector3 &position, Ogre::Camera *camera, const float limit = 100.0f); - std::string sceneNodeToRefId(std::string sceneNodeName); + std::string refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr); // for multi-scene manager per physics engine std::map sceneWidgets(); @@ -91,7 +94,7 @@ namespace CSVWorld void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); - std::string refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr); + std::string sceneNodeToRefId(std::string sceneNodeName); Ogre::SceneManager *findSceneManager(std::string sceneNodeName); };