From f2ff2f298888d32d5dcdb7ae5a18e47f2b07fe6b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 8 Nov 2014 15:51:45 +1100 Subject: [PATCH 01/29] Render pathgrid points and edges. Can move the points but the edges are not updated. Visibility mask does not work properly because pathgrid points are considered as objects by the physics engine. --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/editor.cpp | 3 + apps/opencs/view/render/cell.cpp | 120 ++++++++++++++++++++++ apps/opencs/view/render/cell.hpp | 14 +++ apps/opencs/view/render/mousestate.cpp | 85 ++++++++++----- apps/opencs/view/render/mousestate.hpp | 2 + apps/opencs/view/render/pathgridpoint.cpp | 38 +++++++ apps/opencs/view/render/pathgridpoint.hpp | 35 +++++++ files/materials/pathgrid_pt.nif | Bin 0 -> 1683 bytes 9 files changed, 272 insertions(+), 26 deletions(-) create mode 100644 apps/opencs/view/render/pathgridpoint.cpp create mode 100644 apps/opencs/view/render/pathgridpoint.hpp create mode 100644 files/materials/pathgrid_pt.nif diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index ec6f802cf..29f93e566 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -83,6 +83,7 @@ opencs_units (view/render opencs_units_noqt (view/render navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight lightingbright object cell terrainstorage textoverlay overlaymask overlaysystem mousestate + pathgridpoint ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 591667ebb..beab0b607 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -308,6 +308,9 @@ std::auto_ptr CS::Editor::setupGraphics() // for font used in overlays Ogre::Root::getSingleton().addResourceLocation ((mResources / "mygui").string(), "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); + // for pathgrid point nif + Ogre::Root::getSingleton().addResourceLocation ((mResources / "materials").string(), + "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); if (!boost::filesystem::exists (mCfgMgr.getCachePath())) boost::filesystem::create_directories (mCfgMgr.getCachePath()); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 75e11cc10..6979a4042 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -10,10 +11,60 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" +#include "../../model/world/pathgrid.hpp" #include "../world/physicssystem.hpp" #include "elements.hpp" #include "terrainstorage.hpp" +#include "pathgridpoint.hpp" + +// FIXME: redraw edges when pathgrid points are moved, added and deleted +namespace CSVRender +{ + // PLEASE NOTE: pathgrid edge code copied and adapted from mwrender/debugging + static const std::string PG_LINE_MATERIAL = "pathgridLineMaterial"; + static const int POINT_MESH_BASE = 35; + static const std::string DEBUGGING_GROUP = "debugging"; +} + +void CSVRender::Cell::createGridMaterials() +{ + if(Ogre::MaterialManager::getSingleton().getByName(PG_LINE_MATERIAL, DEBUGGING_GROUP).isNull()) + { + Ogre::MaterialPtr lineMatPtr = + Ogre::MaterialManager::getSingleton().create(PG_LINE_MATERIAL, DEBUGGING_GROUP); + lineMatPtr->setReceiveShadows(false); + lineMatPtr->getTechnique(0)->setLightingEnabled(true); + lineMatPtr->getTechnique(0)->getPass(0)->setDiffuse(1,1,0,0); + lineMatPtr->getTechnique(0)->getPass(0)->setAmbient(1,1,0); + lineMatPtr->getTechnique(0)->getPass(0)->setSelfIllumination(1,1,0); + } +} + +void CSVRender::Cell::destroyGridMaterials() +{ + if(!Ogre::MaterialManager::getSingleton().getByName(PG_LINE_MATERIAL, DEBUGGING_GROUP).isNull()) + Ogre::MaterialManager::getSingleton().remove(PG_LINE_MATERIAL); +} + +Ogre::ManualObject *CSVRender::Cell::createPathgridEdge(const std::string &name, + const Ogre::Vector3 &start, const Ogre::Vector3 &end) +{ + Ogre::ManualObject *result = mSceneMgr->createManualObject(name); + + result->begin(PG_LINE_MATERIAL, Ogre::RenderOperation::OT_LINE_LIST); + + Ogre::Vector3 direction = (end - start); + Ogre::Vector3 lineDisplacement = direction.crossProduct(Ogre::Vector3::UNIT_Z).normalisedCopy(); + // move lines up a little, so they will be less covered by meshes/landscape + lineDisplacement = lineDisplacement * POINT_MESH_BASE + Ogre::Vector3(0, 0, 10); + result->position(start + lineDisplacement); + result->position(end + lineDisplacement); + + result->end(); + + return result; +} bool CSVRender::Cell::removeObject (const std::string& id) { @@ -94,10 +145,28 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts); } } + + addPathgrid(); } CSVRender::Cell::~Cell() { + // destroy manual objects + for(std::map, std::string>::iterator iter = mPgEdges.begin(); + iter != mPgEdges.end(); ++iter) + { + if(mSceneMgr->hasManualObject((*iter).second)) + mSceneMgr->destroyManualObject((*iter).second); + } + destroyGridMaterials(); + Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(DEBUGGING_GROUP); + + for(std::map::iterator iter (mPgPoints.begin()); + iter!=mPgPoints.end(); ++iter) + { + delete iter->second; + } + mPhysics->removeHeightField(mSceneMgr, mX, mY); for (std::map::iterator iter (mObjects.begin()); @@ -236,3 +305,54 @@ float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const else return -std::numeric_limits::max(); } + +void CSVRender::Cell::addPathgrid() +{ + if(!Ogre::ResourceGroupManager::getSingleton().resourceGroupExists(DEBUGGING_GROUP)) + Ogre::ResourceGroupManager::getSingleton().createResourceGroup(DEBUGGING_GROUP); + createGridMaterials(); + + float worldsize = ESM::Land::REAL_SIZE; + + CSMWorld::SubCellCollection& pathgridCollection = mData.getPathgrids(); + int index = pathgridCollection.searchId(mId); + if(index != -1) + { + const CSMWorld::Pathgrid pathgrid = pathgridCollection.getRecord(index).get(); + + std::vector::const_iterator iter = pathgrid.mPoints.begin(); + for(index = 0; iter != pathgrid.mPoints.end(); ++iter, ++index) + { + std::ostringstream stream; + stream << "Pathgrid_" << mId << "_" << index; + std::string name = stream.str(); + + Ogre::Vector3 pos = + Ogre::Vector3(worldsize*mX+(*iter).mX, worldsize*mY+(*iter).mY, (*iter).mZ); + + mPgPoints.insert(std::make_pair(name, new PathgridPoint(name, mCellNode, pos, mPhysics))); + } + + for(ESM::Pathgrid::EdgeList::const_iterator it = pathgrid.mEdges.begin(); + it != pathgrid.mEdges.end(); + ++it) + { + Ogre::SceneNode *node = mCellNode->createChildSceneNode(); + const ESM::Pathgrid::Edge &edge = *it; + const ESM::Pathgrid::Point &p0 = pathgrid.mPoints[edge.mV0]; + const ESM::Pathgrid::Point &p1 = pathgrid.mPoints[edge.mV1]; + + std::ostringstream stream; + stream << mId << "_" << edge.mV0 << " " << edge.mV1; + std::string name = stream.str(); + + Ogre::ManualObject *line = createPathgridEdge(name, + Ogre::Vector3(worldsize*mX+p0.mX, worldsize*mY+p0.mY, p0.mZ), + Ogre::Vector3(worldsize*mX+p1.mX, worldsize*mY+p1.mY, p1.mZ)); + line->setVisibilityFlags(Element_Pathgrid); + node->attachObject(line); + + mPgEdges.insert(std::make_pair(std::make_pair(edge.mV0, edge.mV1), name)); + } + } +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index d38f0c68d..c88b59353 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -17,6 +17,7 @@ namespace Ogre { class SceneManager; class SceneNode; + class ManualObject; } namespace CSMWorld @@ -31,12 +32,16 @@ namespace CSVWorld namespace CSVRender { + class PathgridPoint; + class Cell { CSMWorld::Data& mData; std::string mId; Ogre::SceneNode *mCellNode; std::map mObjects; + std::map mPgPoints; + std::map, std::string> mPgEdges; std::auto_ptr mTerrain; CSVWorld::PhysicsSystem *mPhysics; Ogre::SceneManager *mSceneMgr; @@ -82,6 +87,15 @@ namespace CSVRender bool referenceAdded (const QModelIndex& parent, int start, int end); float getTerrainHeightAt(const Ogre::Vector3 &pos) const; + + private: + + // for drawing pathgrid points & lines + void createGridMaterials(); + void destroyGridMaterials(); + void addPathgrid(); + Ogre::ManualObject *createPathgridEdge(const std::string &name, + const Ogre::Vector3 &start, const Ogre::Vector3 &end); }; } diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 45e846f74..aa8f1a785 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -206,6 +206,15 @@ namespace CSVRender mCurrentObj = result.first; } + // print some debug info + std::string referenceId = mPhysics->sceneNodeToRefId(result.first); + if(referenceId != "") + std::cout << "result: " << referenceId << std::endl; + else + std::cout << "result: " << 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; } break; } @@ -213,15 +222,22 @@ namespace CSVRender { // final placement std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); - if(planeResult.first) + if(planeResult.first && mGrabbedSceneNode != "") { - if(mGrabbedSceneNode != "") - { - std::pair planeRes = planeAxis(); - Ogre::Vector3 pos = mOrigObjPos+planeRes.first*mOffset+planeResult.second-mOrigMousePos; - // use the saved scene node name since the physics model has not moved yet - std::string referenceId = mPhysics->sceneNodeToRefId(mGrabbedSceneNode); + std::pair planeRes = planeAxis(); + Ogre::Vector3 pos = mOrigObjPos+planeRes.first*mOffset+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"))) + { + // move pathgrid point, but don't save yet (need pathgrid + // table feature & its data structure to be completed) + // FIXME: need to signal PathgridPoint object of change + placeObject(mGrabbedSceneNode, pos); + } + else + { mParent->mDocument.getUndoStack().beginMacro (QObject::tr("Move Object")); mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, mIdTableModel->getModelIndex(referenceId, mColIndexPosX), pos.x)); @@ -230,22 +246,22 @@ namespace CSVRender mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, mIdTableModel->getModelIndex(referenceId, mColIndexPosZ), pos.z)); mParent->mDocument.getUndoStack().endMacro(); - - // FIXME: highlight current object? - //mCurrentObj = mGrabbedSceneNode; // FIXME: doesn't work? - mCurrentObj = ""; // whether the object is selected - - mMouseState = Mouse_Edit; - - // reset states - mCurrentMousePos = Ogre::Vector3(); // mouse pos to use in wheel event - mOrigMousePos = Ogre::Vector3(); // starting pos of mouse in world space - mOrigObjPos = Ogre::Vector3(); // starting pos of object in world space - mGrabbedSceneNode = ""; // id of the object - mOffset = 0.0f; // used for z-axis movement - mOldPos = QPoint(0, 0); // to calculate relative movement of mouse } - } + + // FIXME: highlight current object? + //mCurrentObj = mGrabbedSceneNode; // FIXME: doesn't work? + mCurrentObj = ""; // whether the object is selected + + mMouseState = Mouse_Edit; + + // reset states + mCurrentMousePos = Ogre::Vector3(); // mouse pos to use in wheel event + mOrigMousePos = Ogre::Vector3(); // starting pos of mouse in world space + mOrigObjPos = Ogre::Vector3(); // starting pos of object in world space + mGrabbedSceneNode = ""; // id of the object + mOffset = 0.0f; // used for z-axis movement + mOldPos = QPoint(0, 0); // to calculate relative movement of mouse + } break; } case Mouse_Edit: @@ -266,9 +282,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) @@ -401,6 +417,10 @@ namespace CSVRender std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); if(result.first != "") { + std::cout << "result: " << 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; // FIXME: is there a better way to distinguish terrain from objects? QString name = QString(result.first.c_str()); if(name.contains(QRegExp("^HeightField"))) @@ -423,7 +443,7 @@ namespace CSVRender std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); if(result.first != "") { - // NOTE: anything not terrain is assumed to be an object + // 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"))) { @@ -460,4 +480,17 @@ namespace CSVRender { return mParent->getCamera()->getViewport(); } + + void MouseState::placeObject(const std::string sceneNode, const Ogre::Vector3 &pos) + { + mSceneManager->getSceneNode(sceneNode)->setPosition(pos); + + // update physics + std::string refId = mPhysics->sceneNodeToRefId(sceneNode); + + mPhysics->replaceObject(sceneNode, 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 27907bb33..36d04ef6b 100644 --- a/apps/opencs/view/render/mousestate.hpp +++ b/apps/opencs/view/render/mousestate.hpp @@ -82,6 +82,8 @@ namespace CSVRender std::pair planeAxis(); void updateSceneWidgets(); + void placeObject(const std::string sceneNode, const Ogre::Vector3 &pos); // FIXME + Ogre::Camera *getCamera(); // friend access Ogre::Viewport *getViewport(); // friend access }; diff --git a/apps/opencs/view/render/pathgridpoint.cpp b/apps/opencs/view/render/pathgridpoint.cpp new file mode 100644 index 000000000..2455ea1a8 --- /dev/null +++ b/apps/opencs/view/render/pathgridpoint.cpp @@ -0,0 +1,38 @@ +#include "pathgridpoint.hpp" + +#include // FIXME + +#include +#include + +//#include "../../model/world/pathgrid.hpp" +#include "../world/physicssystem.hpp" + +#include "elements.hpp" + +namespace CSVRender +{ + PathgridPoint::PathgridPoint(const std::string &name, + Ogre::SceneNode *cellNode, const Ogre::Vector3 &pos, CSVWorld::PhysicsSystem *physics) + : mBase(cellNode), mPhysics(physics) + { + mBase = cellNode->createChildSceneNode(); + + mPgPoint = NifOgre::Loader::createObjects(mBase, "pathgrid_pt.nif"); + mPgPoint->setVisibilityFlags(Element_Pathgrid); + mBase->setPosition(pos); + + physics->addObject("pathgrid_pt.nif", + mBase->getName(), name, 1, pos, Ogre::Quaternion::IDENTITY); + } + + PathgridPoint::~PathgridPoint() + { + mPgPoint.setNull(); + + mPhysics->removeObject(mBase->getName()); + + if (mBase) + mBase->getCreator()->destroySceneNode(mBase); + } +} diff --git a/apps/opencs/view/render/pathgridpoint.hpp b/apps/opencs/view/render/pathgridpoint.hpp new file mode 100644 index 000000000..f4fa42790 --- /dev/null +++ b/apps/opencs/view/render/pathgridpoint.hpp @@ -0,0 +1,35 @@ +#ifndef OPENCS_VIEW_PATHGRIDPOINT_H +#define OPENCS_VIEW_PATHGRIDPOINT_H + +#include + +namespace Ogre +{ + class Vector3; + class SceneNode; + class SceneManager; +} + +namespace CSVWorld +{ + class PhysicsSystem; +} + +namespace CSVRender +{ + class PathgridPoint + { + CSVWorld::PhysicsSystem *mPhysics; // local copy + NifOgre::ObjectScenePtr mPgPoint; + Ogre::SceneNode *mBase; + + public: + + PathgridPoint(const std::string &name, + Ogre::SceneNode *cellNode, const Ogre::Vector3 &pos, CSVWorld::PhysicsSystem *physics); + + ~PathgridPoint(); + }; +} + +#endif // OPENCS_VIEW_PATHGRIDPOINT_H diff --git a/files/materials/pathgrid_pt.nif b/files/materials/pathgrid_pt.nif new file mode 100644 index 0000000000000000000000000000000000000000..579b03036c05d5deefe564880dbe312ebbb671f2 GIT binary patch literal 1683 zcmb_c&2G~`5T2w?TS{o5<)=VFsl*Xg0afBs5fvdM4p>M~t z{C?Np?FC)$y&eQghexm&7u~;CWz{hD0=54Y+fzoWSk5~yRND7?35Oe)*tVL@XADTG z$msazOQxZWjz48KHiA7Fu|IzA>~=bx)-sfI<6e8A_tM49L(g%nZumu9vX(p%#5uQlEoZ8R#7-VYypD5R1EVB3_buexwNtrloXhIZ@iTF9 z{Hz^${+)}5IF;yZR(x^t`RvblZ2ox}hRvJ-a%RA%8BP(Knrxg>jG7~^xAk0x1sv9V z%5N;g-(S>Q9HU>GX1)qD24gYiESTIxGG_#)x;!zCin-NQ+-pZ_Xf6w~DA&+ju7hzy zmSsh5$}QZ@HMuQ!;I=7Xbdk!1z;9(1`L8re49DCSSsnHYnc}(&b DaQ$}< literal 0 HcmV?d00001 From 2c09b9ba212c699e53045e81d5d8ba936a67ce9a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 9 Nov 2014 12:34:26 +1100 Subject: [PATCH 02/29] Fix scene node being erased in the object reference map. --- apps/opencs/view/world/physicssystem.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 57909f4d3..13b29ba5a 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -70,9 +70,6 @@ namespace CSVWorld if(referenceId != "") { - mSceneNodeToRefId.erase(sceneNodeName); - mSceneNodeToMesh.erase(sceneNodeName); - // find which SceneManager has this object Ogre::SceneManager *sceneManager = findSceneManager(sceneNodeName); if(!sceneManager) @@ -97,7 +94,8 @@ namespace CSVWorld mRefIdToSceneNode.begin(); for(; itRef != mRefIdToSceneNode.end(); ++itRef) { - if((*itRef).second.find(sceneManager) != (*itRef).second.end()) + if((*itRef).first == referenceId && + (*itRef).second.find(sceneManager) != (*itRef).second.end()) { (*itRef).second.erase(sceneManager); break; @@ -110,6 +108,9 @@ namespace CSVWorld mEngine->removeRigidBody(referenceId); mEngine->deleteRigidBody(referenceId); } + + mSceneNodeToRefId.erase(sceneNodeName); + mSceneNodeToMesh.erase(sceneNodeName); } } @@ -252,11 +253,13 @@ namespace CSVWorld return std::make_pair("", Ogre::Vector3(0,0,0)); else { + // 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; + name = result.first; // prob terrain else - name = refIdToSceneNode(result.first, sceneMgr); + name = refIdToSceneNode(result.first, sceneMgr); // prob object return std::make_pair(name, ray.getPoint(farClipDist*result.second)); } From a5a76cadca8f5cc4002eec0f6d2cf2c0ffeb997a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 9 Nov 2014 14:36:58 +1100 Subject: [PATCH 03/29] Adding, deleting and moving pathgrid points work. However still not saving to the document. --- apps/opencs/view/render/cell.cpp | 204 +++++++++++++++++- apps/opencs/view/render/cell.hpp | 16 +- apps/opencs/view/render/mousestate.cpp | 38 +++- apps/opencs/view/render/mousestate.hpp | 3 +- .../view/render/pagedworldspacewidget.cpp | 94 ++++++++ .../view/render/pagedworldspacewidget.hpp | 13 ++ apps/opencs/view/render/pathgridpoint.cpp | 35 +++ apps/opencs/view/render/pathgridpoint.hpp | 4 + .../view/render/unpagedworldspacewidget.cpp | 18 ++ .../view/render/unpagedworldspacewidget.hpp | 6 + apps/opencs/view/render/worldspacewidget.cpp | 50 +++++ apps/opencs/view/render/worldspacewidget.hpp | 10 + 12 files changed, 474 insertions(+), 17 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 6979a4042..e703c8a9d 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -112,7 +112,8 @@ bool CSVRender::Cell::addObjects (int start, int end) CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, CSVWorld::PhysicsSystem *physics, const Ogre::Vector3& origin) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics), + mPathgridId("") { mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode->setPosition (origin); @@ -146,7 +147,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, } } - addPathgrid(); + loadPathgrid(); } CSVRender::Cell::~Cell() @@ -156,7 +157,13 @@ CSVRender::Cell::~Cell() iter != mPgEdges.end(); ++iter) { if(mSceneMgr->hasManualObject((*iter).second)) + { + Ogre::ManualObject *manual = mSceneMgr->getManualObject((*iter).second); + Ogre::SceneNode *node = manual->getParentSceneNode(); mSceneMgr->destroyManualObject((*iter).second); + if(mSceneMgr->hasSceneNode(node->getName())) + mSceneMgr->destroySceneNode(node); + } } destroyGridMaterials(); Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(DEBUGGING_GROUP); @@ -306,7 +313,14 @@ float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const return -std::numeric_limits::max(); } -void CSVRender::Cell::addPathgrid() +// FIXME: +// - updating indicies +// - collision mask +// - add pathgrid point above an object +// - adding edges +// - save to document & signals +// - repainting edges while moving +void CSVRender::Cell::loadPathgrid() { if(!Ogre::ResourceGroupManager::getSingleton().resourceGroupExists(DEBUGGING_GROUP)) Ogre::ResourceGroupManager::getSingleton().createResourceGroup(DEBUGGING_GROUP); @@ -318,19 +332,20 @@ void CSVRender::Cell::addPathgrid() int index = pathgridCollection.searchId(mId); if(index != -1) { - const CSMWorld::Pathgrid pathgrid = pathgridCollection.getRecord(index).get(); + const CSMWorld::Pathgrid &pathgrid = pathgridCollection.getRecord(index).get(); + mPathgridId = pathgrid.mId; // FIXME: temporary storage (should be document) + mPoints.resize(pathgrid.mPoints.size()); std::vector::const_iterator iter = pathgrid.mPoints.begin(); for(index = 0; iter != pathgrid.mPoints.end(); ++iter, ++index) { - std::ostringstream stream; - stream << "Pathgrid_" << mId << "_" << index; - std::string name = stream.str(); + std::string name = PathgridPoint::getName(pathgrid.mId, index); Ogre::Vector3 pos = Ogre::Vector3(worldsize*mX+(*iter).mX, worldsize*mY+(*iter).mY, (*iter).mZ); mPgPoints.insert(std::make_pair(name, new PathgridPoint(name, mCellNode, pos, mPhysics))); + mPoints[index] = *iter; // FIXME: temporary storage (should be document) } for(ESM::Pathgrid::EdgeList::const_iterator it = pathgrid.mEdges.begin(); @@ -343,7 +358,7 @@ void CSVRender::Cell::addPathgrid() const ESM::Pathgrid::Point &p1 = pathgrid.mPoints[edge.mV1]; std::ostringstream stream; - stream << mId << "_" << edge.mV0 << " " << edge.mV1; + stream << pathgrid.mId << "_" << edge.mV0 << " " << edge.mV1; std::string name = stream.str(); Ogre::ManualObject *line = createPathgridEdge(name, @@ -353,6 +368,179 @@ void CSVRender::Cell::addPathgrid() node->attachObject(line); mPgEdges.insert(std::make_pair(std::make_pair(edge.mV0, edge.mV1), name)); + mEdges.push_back(*it); // FIXME: temporary storage (should be document) } } } + +// NOTE: pos is in world coordinates +// FIXME: save to the document +void CSVRender::Cell::pathgridPointAdded(const Ogre::Vector3 &pos) +{ + std::string name = PathgridPoint::getName(mId, mPoints.size()); + + mPgPoints.insert(std::make_pair(name, new PathgridPoint(name, mCellNode, pos, mPhysics))); + + // store to document + ESM::Pathgrid::Point point((int)pos.x, (int)pos.y, (int)pos.z); + point.mConnectionNum = 0; + mPoints.push_back(point); + mPathgridId = mId; + // FIXME: update other scene managers +} + +// FIXME: save to the document +void CSVRender::Cell::pathgridPointRemoved(const std::string &name) +{ + std::pair result = PathgridPoint::getIdAndIndex(name); + if(result.first == "") + return; + + std::string pathgridId = result.first; + int index = result.second; + + // check if the point exists + if(index < 0 || mPathgridId != pathgridId || index >= mPoints.size()) + return; + + int numToDelete = mPoints[index].mConnectionNum * 2; // for sanity check later + int edgeCount = 0; + + // find edges to delete + std::vector > edges; + for(unsigned i = 0; i < mEdges.size(); ++i) + { + if(mEdges[i].mV0 == index || mEdges[i].mV1 == index) + { + for(std::map, std::string>::iterator iter = mPgEdges.begin(); + iter != mPgEdges.end(); ++iter) + { + if((*iter).first.first == index || (*iter).first.second == index) + { + edges.push_back(std::make_pair((*iter).first.first, (*iter).first.second)); + } + } + } + } + + // delete the edges + for(std::vector >::iterator iter = edges.begin(); + iter != edges.end(); ++iter) + { + std::string name = mPgEdges[*iter]; + if(mSceneMgr->hasManualObject(name)) + { + // remove manual objects + Ogre::ManualObject *manual = mSceneMgr->getManualObject(name); + Ogre::SceneNode *node = manual->getParentSceneNode(); + mSceneMgr->destroyManualObject(name); + if(mSceneMgr->hasSceneNode(node->getName())) + mSceneMgr->destroySceneNode(node); + + edgeCount++; // for sanity check later + + // update map + mPgEdges.erase(*iter); + + // update document + assert(mPoints[(*iter).first].mConnectionNum > 0); + mPoints[(*iter).first].mConnectionNum -= 1; + for(unsigned i = mEdges.size() - 1; i > 0; --i) + { + if(mEdges[i].mV0 == index || mEdges[i].mV1 == index) + mEdges.erase(mEdges.begin() + i); + } + } + } + + if(edgeCount != numToDelete) + { + // WARNING: continue anyway? Or should this be an exception? + std::cerr << "The no of edges del does not match the no of conn for: " + << mPathgridId + "_" + QString::number(index).toStdString() << std::endl; + } + + if(edgeCount || mPoints[index].mConnectionNum == 0) + { + // remove the point + delete mPgPoints[name]; + mPgPoints.erase(name); + // FIXME: update other scene managers + } + + // store to document + //mPoints.erase(mPoints.begin() + index); // WARNING: Can't erase because the index will change + // FIXME: it should be possible to refresh indicies but that means index values + // can't be stored in maps, names, etc +} + +// NOTE: newPos is in world coordinates +void CSVRender::Cell::pathgridPointMoved(const std::string &name, const Ogre::Vector3 &newPos) +{ + std::pair result = PathgridPoint::getIdAndIndex(name); + if(result.first == "") + return; + + std::string pathgridId = result.first; + int index = result.second; + + // check if the point exists + if(index < 0 || mPathgridId != pathgridId || index >= mPoints.size()) + return; + + float worldsize = ESM::Land::REAL_SIZE; + + // delete then recreate the edges + for(unsigned i = 0; i < mEdges.size(); ++i) + { + if(mEdges[i].mV0 == index || mEdges[i].mV1 == index) + { + std::ostringstream stream; + stream << pathgridId << "_" << mEdges[i].mV0 << " " << mEdges[i].mV1; + std::string name = stream.str(); + + if(mSceneMgr->hasManualObject(name)) + { + // remove manual objects + Ogre::ManualObject *manual = mSceneMgr->getManualObject(name); + Ogre::SceneNode *node = manual->getParentSceneNode(); + mSceneMgr->destroyManualObject(name); + + if(mEdges[i].mV0 == index) + { + const ESM::Pathgrid::Point &p1 = mPoints[mEdges[i].mV1]; + + Ogre::ManualObject *line = createPathgridEdge(name, + newPos, + Ogre::Vector3(worldsize*mX+p1.mX, worldsize*mY+p1.mY, p1.mZ)); + line->setVisibilityFlags(Element_Pathgrid); + node->attachObject(line); + } + else if(mEdges[i].mV1 == index) + { + const ESM::Pathgrid::Point &p0 = mPoints[mEdges[i].mV0]; + + Ogre::ManualObject *line = createPathgridEdge(name, + Ogre::Vector3(worldsize*mX+p0.mX, worldsize*mY+p0.mY, p0.mZ), + newPos); + line->setVisibilityFlags(Element_Pathgrid); + node->attachObject(line); + } + } + } + } +} + +// FIXME: save to the document +void CSVRender::Cell::addPathgridEdge() +{ + // check if the points exist + // update the edges + // store to document + // FIXME: update other scene managers +} + +// FIXME: save to the document +void CSVRender::Cell::removePathgridEdge() +{ +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index c88b59353..5d7b9088a 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -8,6 +8,7 @@ #include #include +#include // FIXME: temporaty storage until saving to document #include "object.hpp" @@ -23,6 +24,7 @@ namespace Ogre namespace CSMWorld { class Data; + class Pathgrid; } namespace CSVWorld @@ -42,6 +44,11 @@ namespace CSVRender std::map mObjects; std::map mPgPoints; std::map, std::string> mPgEdges; + + ESM::Pathgrid::PointList mPoints; // FIXME: temporary storage until saving to document + ESM::Pathgrid::EdgeList mEdges; // FIXME: temporary storage until saving to document + std::string mPathgridId; // FIXME: temporary storage until saving to document + std::auto_ptr mTerrain; CSVWorld::PhysicsSystem *mPhysics; Ogre::SceneManager *mSceneMgr; @@ -88,14 +95,21 @@ namespace CSVRender float getTerrainHeightAt(const Ogre::Vector3 &pos) const; + void pathgridPointAdded(const Ogre::Vector3 &pos); + void pathgridPointMoved(const std::string &name, const Ogre::Vector3 &newPos); + void pathgridPointRemoved(const std::string &name); + private: // for drawing pathgrid points & lines void createGridMaterials(); void destroyGridMaterials(); - void addPathgrid(); + void loadPathgrid(); Ogre::ManualObject *createPathgridEdge(const std::string &name, const Ogre::Vector3 &start, const Ogre::Vector3 &end); + + void addPathgridEdge(); + void removePathgridEdge(); }; } diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index aa8f1a785..bceae716c 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -209,9 +209,9 @@ namespace CSVRender // print some debug info std::string referenceId = mPhysics->sceneNodeToRefId(result.first); if(referenceId != "") - std::cout << "result: " << referenceId << std::endl; + std::cout << "result grab release: " << referenceId << std::endl; else - std::cout << "result: " << 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; @@ -234,7 +234,20 @@ namespace CSVRender // move pathgrid point, but don't save yet (need pathgrid // table feature & its data structure to be completed) // FIXME: need to signal PathgridPoint object of change - placeObject(mGrabbedSceneNode, pos); + std::pair result = + terrainUnderCursor(event->x(), event->y()); // FIXME: some pathgrid points are on objects + if(result.first != "") + { + // FIXME: rather than just updating at the end, should + // consider providing visual feedback of terrain height + // while dragging the pathgrid point (maybe check whether + // the object is a pathgrid point at the begging and set + // a flag?) + // FIXME: this also disallows dragging over objects, so + // may need to use ignoreObjects while raycasting + placeObject(mGrabbedSceneNode, result.second); + mParent->pathgridMoved(referenceId, result.second); + } } else { @@ -389,6 +402,21 @@ 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::mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane) { // using a really small value seems to mess up with the projections @@ -417,10 +445,6 @@ namespace CSVRender std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); if(result.first != "") { - std::cout << "result: " << 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; // FIXME: is there a better way to distinguish terrain from objects? QString name = QString(result.first.c_str()); if(name.contains(QRegExp("^HeightField"))) diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp index 36d04ef6b..b56860cac 100644 --- a/apps/opencs/view/render/mousestate.hpp +++ b/apps/opencs/view/render/mousestate.hpp @@ -71,13 +71,14 @@ 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 terrainUnderCursor(const int mouseX, const int mouseY); void cancelDrag(); private: std::pair mousePositionOnPlane(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(); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 49e7e1f09..e528733c0 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -22,6 +22,7 @@ #include "../widget/scenetooltoggle.hpp" +#include "pathgridpoint.hpp" #include "elements.hpp" bool CSVRender::PagedWorldspaceWidget::adjustCells() @@ -295,6 +296,99 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent flagAsModified(); } +//void CSVRender::PagedWorldspaceWidget::pathgridAdded (const QModelIndex& parent, +// int start, int end) +//{ +// // FIXME: +//} +// +//void CSVRender::PagedWorldspaceWidget::pathgridDataChanged (const QModelIndex& topLeft, +// const QModelIndex& bottomRight) +//{ +// // FIXME: +//} +// +//void CSVRender::PagedWorldspaceWidget::pathgridAboutToBeRemoved (const QModelIndex& parent, +// int start, int end) +//{ +// // FIXME: +//} + +CSVRender::Cell *CSVRender::PagedWorldspaceWidget::findCell(const std::string &cellId) +{ + const CSMWorld::IdCollection& cells = mDocument.getData().getCells(); + + std::map::iterator iter (mCells.begin()); + for(; iter!= mCells.end(); ++iter) + { + int index = cells.searchId(cellId); + + if (index != -1 && cellId == iter->first.getId (mWorldspace)) + { + return iter->second; + } + } + + return NULL; +} + +// FIXME: pathgrid may be inserted above an object, the parsing needs to change +void CSVRender::PagedWorldspaceWidget::pathgridInserted (const std::string &terrain, const Ogre::Vector3 &pos) +{ + // decode name + QString id = QString(terrain.c_str()); + QRegExp terrainRe("^HeightField_([\\d-]+)_([\\d-]+)$"); + + if (id.isEmpty() || !id.startsWith("HeightField_")) + return; + + if (terrainRe.indexIn(id) == -1) + return; + + int cellX = terrainRe.cap(1).toInt(); + int cellY = terrainRe.cap(2).toInt(); + + std::ostringstream stream; + stream << "#" << cellX << " " << cellY; + + Cell *cell = findCell(stream.str()); + if(cell) + { + cell->pathgridPointAdded(pos); + flagAsModified(); + + return; + } +} + +void CSVRender::PagedWorldspaceWidget::pathgridMoved (const std::string &pgName, const Ogre::Vector3 &pos) +{ + std::pair result = PathgridPoint::getIdAndIndex(pgName); + + Cell *cell = findCell(result.first); + if(cell) + { + cell->pathgridPointMoved(pgName, pos); + flagAsModified(); + + return; + } +} + +void CSVRender::PagedWorldspaceWidget::pathgridAboutToBeRemoved (const std::string &pgName) +{ + std::pair result = PathgridPoint::getIdAndIndex(pgName); + + Cell *cell = findCell(result.first); + if(cell) + { + cell->pathgridPointRemoved(pgName); + flagAsModified(); + + return; + } +} + std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() { Ogre::Vector3 position = getCamera()->getPosition(); diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index fe79e761e..b5ca91880 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -49,8 +49,16 @@ namespace CSVRender virtual void referenceAdded (const QModelIndex& index, int start, int end); + //virtual void pathgridAdded (const QModelIndex& parent, int start, int end); + + //virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + //virtual void pathgridAboutToBeRemoved (const QModelIndex& parent, int start, int end); + virtual std::string getStartupInstruction(); + Cell *findCell(const std::string &cellId); + public: PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document); @@ -87,6 +95,11 @@ 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 pathgridMoved (const std::string &pgName, const Ogre::Vector3 &pos); + virtual void pathgridAboutToBeRemoved (const std::string &pgName); + signals: void cellSelectionChanged (const CSMWorld::CellSelection& selection); diff --git a/apps/opencs/view/render/pathgridpoint.cpp b/apps/opencs/view/render/pathgridpoint.cpp index 2455ea1a8..3e365932f 100644 --- a/apps/opencs/view/render/pathgridpoint.cpp +++ b/apps/opencs/view/render/pathgridpoint.cpp @@ -2,6 +2,8 @@ #include // FIXME +#include + #include #include @@ -35,4 +37,37 @@ namespace CSVRender if (mBase) mBase->getCreator()->destroySceneNode(mBase); } + + // FIXME: Is there a way to identify the pathgrid point other than via the index? + // ESM::Pathgrid::Edge itself uses the indicies so any change (add/delete) must be + // propagated everywhere. + std::pair PathgridPoint::getIdAndIndex(const std::string &name) + { + // decode name + QString id = QString(name.c_str()); + QRegExp pathgridRe("^Pathgrid_(.+)_(\\d+)$"); + + if (id.isEmpty() || !id.startsWith("Pathgrid_")) + return std::make_pair("", -1); + + std::string pathgridId = ""; + int index = -1; + if (pathgridRe.indexIn(id) != -1) + { + pathgridId = pathgridRe.cap(1).toStdString(); + index = pathgridRe.cap(2).toInt(); + + return std::make_pair(pathgridId, index); + } + + return std::make_pair("", -1); + } + + std::string PathgridPoint::getName(const std::string &pathgridId, const int index) + { + std::ostringstream stream; + stream << "Pathgrid_" << pathgridId << "_" << index; + + return stream.str(); + } } diff --git a/apps/opencs/view/render/pathgridpoint.hpp b/apps/opencs/view/render/pathgridpoint.hpp index f4fa42790..3419082c3 100644 --- a/apps/opencs/view/render/pathgridpoint.hpp +++ b/apps/opencs/view/render/pathgridpoint.hpp @@ -29,6 +29,10 @@ namespace CSVRender Ogre::SceneNode *cellNode, const Ogre::Vector3 &pos, CSVWorld::PhysicsSystem *physics); ~PathgridPoint(); + + static std::pair getIdAndIndex(const std::string &name); + + static std::string getName(const std::string &pathgridId, int index); }; } diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 8012b1b24..a1a8a8921 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -160,6 +160,24 @@ void CSVRender::UnpagedWorldspaceWidget::referenceAdded (const QModelIndex& pare flagAsModified(); } +//void CSVRender::UnpagedWorldspaceWidget::pathgridAdded (const QModelIndex& parent, +// int start, int end) +//{ +// // FIXME: +//} +// +//void CSVRender::UnpagedWorldspaceWidget::pathgridDataChanged (const QModelIndex& topLeft, +// const QModelIndex& bottomRight) +//{ +// // FIXME: +//} +// +//void CSVRender::UnpagedWorldspaceWidget::pathgridAboutToBeRemoved (const QModelIndex& parent, +// int start, int end) +//{ +// // FIXME: +//} + std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() { Ogre::Vector3 position = getCamera()->getPosition(); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 5924abaa9..ee397d467 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -62,6 +62,12 @@ namespace CSVRender virtual void referenceAdded (const QModelIndex& index, int start, int end); + //virtual void pathgridAdded (const QModelIndex& index, int start, int end); + + //virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + //virtual void pathgridAboutToBeRemoved (const QModelIndex& parent, int start, int end); + virtual std::string getStartupInstruction(); private slots: diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 9c8676064..1fedc8aa1 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "../../model/world/universalid.hpp" #include "../../model/world/idtable.hpp" @@ -54,6 +55,16 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); + //QAbstractItemModel *pathgrids = + //document.getData().getTableModel (CSMWorld::UniversalId::Type_Pathgrid); + + //connect (pathgrids, SIGNAL (rowsInserted (const QModelIndex&, int, int)), + //this, SLOT (pathgridAdded (const QModelIndex&, int, int))); + //connect (pathgrids, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), + //this, SLOT (pathgridDataChanged (const QModelIndex&, const QModelIndex&))); + //connect (pathgrids, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), + //this, SLOT (pathgridAboutToBeRemoved (const QModelIndex&, int, int))); + // associate WorldSpaceWidgets (and their SceneManagers) with Documents // then create physics if there is a new document mPhysics = CSVWorld::PhysicsManager::instance()->addSceneWidget(document, this); @@ -389,12 +400,51 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) SceneWidget::wheelEvent(event); } +// FIXME: mouse button events are processed in MouseState but key events are +// processed here - seems inconsistent void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) { if(event->key() == Qt::Key_Escape) { mMouse->cancelDrag(); } + else if(event->key() == Qt::Key_Delete) + { + QPoint p = this->mapFromGlobal(QCursor::pos()); + std::pair result = mMouse->pgPointUnderCursor(p.x(), p.y()); + if(result.first != "") + { + pathgridAboutToBeRemoved(result.first); + } + else + SceneWidget::keyPressEvent(event); + } + else if(event->key() == Qt::Key_Insert) + { + QPoint p = this->mapFromGlobal(QCursor::pos()); + std::pair result = mMouse->terrainUnderCursor(p.x(), p.y()); + if(result.first != "") + { + pathgridInserted(result.first, result.second); + } + else + SceneWidget::keyPressEvent(event); + } else SceneWidget::keyPressEvent(event); } + +// FIXME: temporary until signals from the document are implemented +void CSVRender::WorldspaceWidget::pathgridAboutToBeRemoved (const std::string &pgName) +{ +} + +// FIXME: temporary until signals from the document are implemented +void CSVRender::WorldspaceWidget::pathgridMoved (const std::string &pgName, const Ogre::Vector3 &newPos) +{ +} + +// FIXME: temporary until signals from the document are implemented +void CSVRender::WorldspaceWidget::pathgridInserted (const std::string &name, const Ogre::Vector3 &pos) +{ +} diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 5bad3933d..75dc0c264 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -109,6 +109,11 @@ namespace CSVRender virtual void wheelEvent (QWheelEvent *event); virtual void keyPressEvent (QKeyEvent *event); + // FIXME: temporary only until the signals from the document are implemented + virtual void pathgridInserted (const std::string &terrain, const Ogre::Vector3 &pos); + virtual void pathgridMoved (const std::string &pgName, const Ogre::Vector3 &pos); + virtual void pathgridAboutToBeRemoved (const std::string &pgName); + private: void dragEnterEvent(QDragEnterEvent *event); @@ -143,6 +148,11 @@ namespace CSVRender void debugProfileAboutToBeRemoved (const QModelIndex& parent, int start, int end); + //virtual void pathgridAdded (const QModelIndex& index, int start, int end) = 0; + + //virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) = 0; + + //virtual void pathgridAboutToBeRemoved (const QModelIndex& parent, int start, int end) = 0; protected slots: From 895739d6bbc092076ac6ec6d0d9a3645bd2dc1a6 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 9 Nov 2014 17:53:54 +1100 Subject: [PATCH 04/29] Visibility mask working correctly. --- apps/opencs/view/render/cell.cpp | 1 - apps/opencs/view/render/mousestate.cpp | 8 +++++++- apps/opencs/view/world/physicssystem.cpp | 23 +++++++++++++++++++---- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index e703c8a9d..a53a2939f 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -315,7 +315,6 @@ float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const // FIXME: // - updating indicies -// - collision mask // - add pathgrid point above an object // - adding edges // - save to document & signals diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index bceae716c..ee7776890 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -285,6 +285,10 @@ namespace CSVRender if(result.first != "") { // FIXME: terrain editing goes here + std::cout << "result default/edit 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; } break; } @@ -456,6 +460,7 @@ namespace CSVRender return std::make_pair("", Ogre::Vector3()); } + // NOTE: also returns pathgrids std::pair MouseState::objectUnderCursor(const int mouseX, const int mouseY) { if(!getViewport()) @@ -473,8 +478,9 @@ namespace CSVRender { uint32_t visibilityMask = getViewport()->getVisibilityMask(); bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); + bool ignorePathgrid = !(visibilityMask & (uint32_t)CSVRender::Element_Pathgrid); - if(!ignoreObjects && mSceneManager->hasSceneNode(result.first)) + if((!ignoreObjects || !ignorePathgrid) && mSceneManager->hasSceneNode(result.first)) { return result; } diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 13b29ba5a..788e42c55 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -243,14 +243,29 @@ namespace CSVWorld 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::Vector3 norm; // not used - std::pair result = - mEngine->rayTest(_from, _to, !ignoreObjects, ignoreHeightMap, &norm); + std::pair result = std::make_pair("", -1); + short mask = OEngine::Physic::CollisionType_Raycasting; + std::vector > objects = mEngine->rayTest2(_from, _to, mask); + + for (std::vector >::iterator it = objects.begin(); + it != objects.end(); ++it) + { + if(ignorePathgrid && QString((*it).second.c_str()).contains(QRegExp("^Pathgrid"))) + continue; + else if(ignoreObjects && QString((*it).second.c_str()).contains(QRegExp("^ref#"))) + continue; + else if(ignoreHeightMap && QString((*it).second.c_str()).contains(QRegExp("^Height"))) + continue; + + result = std::make_pair((*it).second, (*it).first); + break; + } // result.first is the object's referenceId if(result.first == "") - return std::make_pair("", Ogre::Vector3(0,0,0)); + return std::make_pair("", Ogre::Vector3()); else { // FIXME: maybe below logic belongs in the caller, i.e. terrainUnderCursor or From f5ba74cd1015bd652301fb48bd7ee1f83044aeae Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 9 Nov 2014 18:10:44 +1100 Subject: [PATCH 05/29] Suppress warnings. --- apps/opencs/view/render/cell.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index a53a2939f..238f60bb5 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -399,7 +399,7 @@ void CSVRender::Cell::pathgridPointRemoved(const std::string &name) int index = result.second; // check if the point exists - if(index < 0 || mPathgridId != pathgridId || index >= mPoints.size()) + if(index < 0 || mPathgridId != pathgridId || (unsigned int)index >= mPoints.size()) return; int numToDelete = mPoints[index].mConnectionNum * 2; // for sanity check later @@ -484,7 +484,7 @@ void CSVRender::Cell::pathgridPointMoved(const std::string &name, const Ogre::Ve int index = result.second; // check if the point exists - if(index < 0 || mPathgridId != pathgridId || index >= mPoints.size()) + if(index < 0 || mPathgridId != pathgridId || (unsigned int)index >= mPoints.size()) return; float worldsize = ESM::Land::REAL_SIZE; From 9f16b86bd8fd8f01d23589f4bc201a3ee1fcee49 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 9 Nov 2014 18:21:47 +1100 Subject: [PATCH 06/29] Fix installing pathgrid_pt.nif --- files/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 9b2325744..6ee219a8a 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -17,6 +17,7 @@ set(MATERIAL_FILES objects.shader objects.shaderset openmw.configuration + pathgrid_pt.nif quad.mat quad.shader quad.shaderset From 89eb30054be61f4c7eab911f16e48aef5ca7b03a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 9 Nov 2014 18:37:04 +1100 Subject: [PATCH 07/29] Fix deleting physic objects. --- apps/opencs/view/world/physicssystem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 788e42c55..cae5563e6 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -103,7 +103,8 @@ namespace CSVWorld } // check whether the physics model should be deleted - if(mRefIdToSceneNode.find(referenceId) == mRefIdToSceneNode.end()) + itRef = mRefIdToSceneNode.find(referenceId); + if(itRef == mRefIdToSceneNode.end() || (*itRef).second.empty()) { mEngine->removeRigidBody(referenceId); mEngine->deleteRigidBody(referenceId); From 1f73fae6efd077a6f744b8e2179017ac6c8595b2 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 9 Nov 2014 20:03:29 +1100 Subject: [PATCH 08/29] Allow adding or dragging pathgrid points over objects as well as terrain. --- apps/opencs/view/render/cell.cpp | 3 +- apps/opencs/view/render/mousestate.cpp | 38 +++++++++------- apps/opencs/view/render/mousestate.hpp | 3 +- .../view/render/pagedworldspacewidget.cpp | 45 +++++++++++++------ apps/opencs/view/render/worldspacewidget.cpp | 2 +- 5 files changed, 57 insertions(+), 34 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 238f60bb5..4e3416111 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -315,8 +315,7 @@ float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const // FIXME: // - updating indicies -// - add pathgrid point above an object -// - adding edges +// - adding edges (need the ability to select a pathgrid and highlight) // - save to document & signals // - repainting edges while moving void CSVRender::Cell::loadPathgrid() diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index ee7776890..ee59770e4 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -234,8 +234,9 @@ namespace CSVRender // move pathgrid point, but don't save yet (need pathgrid // table feature & its data structure to be completed) // FIXME: need to signal PathgridPoint object of change + // FIXME: shouldn't allow pathgrid points under the cursor std::pair result = - terrainUnderCursor(event->x(), event->y()); // FIXME: some pathgrid points are on objects + anyUnderCursor(event->x(), event->y()); if(result.first != "") { // FIXME: rather than just updating at the end, should @@ -243,8 +244,6 @@ namespace CSVRender // while dragging the pathgrid point (maybe check whether // the object is a pathgrid point at the begging and set // a flag?) - // FIXME: this also disallows dragging over objects, so - // may need to use ignoreObjects while raycasting placeObject(mGrabbedSceneNode, result.second); mParent->pathgridMoved(referenceId, result.second); } @@ -440,13 +439,7 @@ namespace CSVRender std::pair MouseState::terrainUnderCursor(const int mouseX, const int mouseY) { - if(!getViewport()) - return std::make_pair("", Ogre::Vector3()); - - float x = (float) mouseX / getViewport()->getActualWidth(); - float y = (float) mouseY / getViewport()->getActualHeight(); - - std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); + std::pair result = anyUnderCursor(mouseX, mouseY); if(result.first != "") { // FIXME: is there a better way to distinguish terrain from objects? @@ -463,13 +456,7 @@ namespace CSVRender // NOTE: also returns pathgrids std::pair MouseState::objectUnderCursor(const int mouseX, const int mouseY) { - if(!getViewport()) - return std::make_pair("", Ogre::Vector3()); - - float x = (float) mouseX / getViewport()->getActualWidth(); - float y = (float) mouseY / getViewport()->getActualHeight(); - - std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); + std::pair result = anyUnderCursor(mouseX, mouseY); if(result.first != "") { // NOTE: anything not terrain is assumed to be an object, e.g pathgrid points @@ -490,6 +477,23 @@ namespace CSVRender return std::make_pair("", Ogre::Vector3()); } + std::pair MouseState::anyUnderCursor(const int mouseX, const int mouseY) + { + if(!getViewport()) + return std::make_pair("", Ogre::Vector3()); + + 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()); + } + void MouseState::updateSceneWidgets() { std::map sceneWidgets = mPhysics->sceneWidgets(); diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp index b56860cac..fd752349a 100644 --- a/apps/opencs/view/render/mousestate.hpp +++ b/apps/opencs/view/render/mousestate.hpp @@ -72,13 +72,14 @@ namespace CSVRender void mouseDoubleClickEvent (QMouseEvent *event); bool wheelEvent (QWheelEvent *event); std::pair pgPointUnderCursor(const int mouseX, const int mouseY); - std::pair terrainUnderCursor(const int mouseX, const int mouseY); + std::pair anyUnderCursor(const int mouseX, const int mouseY); void cancelDrag(); private: std::pair mousePositionOnPlane(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(); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index e528733c0..506fd54df 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -21,6 +21,7 @@ #include "../../model/world/idtable.hpp" #include "../widget/scenetooltoggle.hpp" +#include "../world/physicssystem.hpp" #include "pathgridpoint.hpp" #include "elements.hpp" @@ -332,26 +333,44 @@ CSVRender::Cell *CSVRender::PagedWorldspaceWidget::findCell(const std::string &c return NULL; } -// FIXME: pathgrid may be inserted above an object, the parsing needs to change -void CSVRender::PagedWorldspaceWidget::pathgridInserted (const std::string &terrain, const Ogre::Vector3 &pos) +// NOTE: allow placing pathgrid points above objects and terrain +void CSVRender::PagedWorldspaceWidget::pathgridInserted (const std::string &name, const Ogre::Vector3 &pos) { - // decode name - QString id = QString(terrain.c_str()); - QRegExp terrainRe("^HeightField_([\\d-]+)_([\\d-]+)$"); + QString id = QString(name.c_str()); + std::string referenceId = getPhysics()->sceneNodeToRefId(name); // FIXME: move back - if (id.isEmpty() || !id.startsWith("HeightField_")) + bool terrain = id.startsWith("HeightField_"); + bool object = QString(referenceId.c_str()).startsWith("ref#"); + // don't allow placing another one on top of a pathgrid point + if (id.isEmpty() || (!terrain && !object)) return; - if (terrainRe.indexIn(id) == -1) - return; + std::string cellId; + if(terrain) + { + QRegExp nameRe("^HeightField_([\\d-]+)_([\\d-]+)$"); + if (nameRe.indexIn(id) == -1) + return; - int cellX = terrainRe.cap(1).toInt(); - int cellY = terrainRe.cap(2).toInt(); + int cellX = nameRe.cap(1).toInt(); + int cellY = nameRe.cap(2).toInt(); - std::ostringstream stream; - stream << "#" << cellX << " " << cellY; + std::ostringstream stream; + stream << "#" << cellX << " " << cellY; + cellId = stream.str(); + } + else + { + const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); + int index = references.searchId(referenceId); + if(index == -1) + return; - Cell *cell = findCell(stream.str()); + cellId = references.getData(index, references.findColumnIndex(CSMWorld::Columns::ColumnId_Cell)) + .toString().toUtf8().constData(); + } + + Cell *cell = findCell(cellId); if(cell) { cell->pathgridPointAdded(pos); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 1fedc8aa1..4f85f3a30 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -422,7 +422,7 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) else if(event->key() == Qt::Key_Insert) { QPoint p = this->mapFromGlobal(QCursor::pos()); - std::pair result = mMouse->terrainUnderCursor(p.x(), p.y()); + std::pair result = mMouse->anyUnderCursor(p.x(), p.y()); if(result.first != "") { pathgridInserted(result.first, result.second); From d7804974e8e2921cbda8f048ae01f2ca730fe414 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 10 Nov 2014 20:37:07 +1100 Subject: [PATCH 09/29] Better mouse cursor tracking for the third axis. --- apps/opencs/view/render/mousestate.cpp | 127 ++++++++++++++++--------- apps/opencs/view/render/mousestate.hpp | 7 +- 2 files changed, 83 insertions(+), 51 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index ee59770e4..989dbdb91 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -57,9 +57,9 @@ namespace CSVRender MouseState::MouseState(WorldspaceWidget *parent) : mParent(parent), mPhysics(parent->getPhysics()), mSceneManager(parent->getSceneManager()) - , mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) + , mCurrentObj(""), mMouseState(Mouse_Default), mOldCursorPos(0,0), mMouseEventTimer(0) , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) - , mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f) + , mOldMousePos(Ogre::Vector3()), mPlane(0) , mColIndexPosX(0), mColIndexPosY(0), mColIndexPosZ(0), mIdTableModel(0) { const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); @@ -79,11 +79,11 @@ namespace CSVRender Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createPlane("mouse", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, *mPlane, - 300000,300000, // FIXME: use far clip dist? - 1,1, // segments - true, // normals - 1, // numTexCoordSets - 1,1, // uTile, vTile + 300000,300000, // FIXME: use far clip dist? + 1,1, // segments + true, // normals + 1, // numTexCoordSets + 1,1, // uTile, vTile planeRes.second // upVector ); } @@ -111,23 +111,24 @@ namespace CSVRender } case Mouse_Drag: { - if(event->pos() != mOldPos) // TODO: maybe don't update less than a quantum? + if(event->pos() != mOldCursorPos) // TODO: maybe don't update less than a quantum? { - mOldPos = event->pos(); + mOldCursorPos = event->pos(); // ray test against the plane to provide feedback to the user the - // relative movement of the object on the x-y plane - std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); + // relative movement of the object on the movement plane + std::pair planeResult = mousePosOnPlane(event->pos(), *mPlane); if(planeResult.first) { if(mGrabbedSceneNode != "") { - std::pair planeRes = planeAxis(); - Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset; - mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+planeResult.second-mOrigMousePos); - mCurrentMousePos = planeResult.second; - mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+planeResult.second-mOrigMousePos); + Ogre::Vector3 pos = mOrigObjPos + (planeResult.second-mOrigMousePos); + + mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos); + mPhysics->moveSceneNodes(mGrabbedSceneNode, pos); updateSceneWidgets(); + + mOldMousePos = planeResult.second; } } } @@ -165,12 +166,11 @@ namespace CSVRender // mouse in relation to the object position std::pair planeRes = planeAxis(); mPlane->redefine(planeRes.first, result.second); - std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); + std::pair planeResult = mousePosOnPlane(event->pos(), *mPlane); if(planeResult.first) { mOrigMousePos = planeResult.second; - mCurrentMousePos = planeResult.second; - mOffset = 0.0f; + mOldMousePos = planeResult.second; } mOrigObjPos = mSceneManager->getSceneNode(mGrabbedSceneNode)->getPosition(); @@ -206,6 +206,7 @@ namespace CSVRender mCurrentObj = result.first; } +//#if 0 // print some debug info std::string referenceId = mPhysics->sceneNodeToRefId(result.first); if(referenceId != "") @@ -215,17 +216,18 @@ namespace CSVRender std::cout << " hit pos "+ QString::number(result.second.x).toStdString() + ", " + QString::number(result.second.y).toStdString() + ", " + QString::number(result.second.z).toStdString() << std::endl; +//#endif } break; } case Mouse_Drag: { // final placement - std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); + std::pair planeResult = mousePosOnPlane(event->pos(), *mPlane); if(planeResult.first && mGrabbedSceneNode != "") { - std::pair planeRes = planeAxis(); - Ogre::Vector3 pos = mOrigObjPos+planeRes.first*mOffset+planeResult.second-mOrigMousePos; + 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); @@ -234,18 +236,19 @@ namespace CSVRender // move pathgrid point, but don't save yet (need pathgrid // table feature & its data structure to be completed) // FIXME: need to signal PathgridPoint object of change - // FIXME: shouldn't allow pathgrid points under the cursor - std::pair result = - anyUnderCursor(event->x(), event->y()); - if(result.first != "") + //std::pair result = + //anyUnderCursor(event->x(), event->y()); + //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"))) { // FIXME: rather than just updating at the end, should // consider providing visual feedback of terrain height // while dragging the pathgrid point (maybe check whether // the object is a pathgrid point at the begging and set // a flag?) - placeObject(mGrabbedSceneNode, result.second); - mParent->pathgridMoved(referenceId, result.second); + placeObject(mGrabbedSceneNode, pos); // result.second + mParent->pathgridMoved(referenceId, pos); // result.second } } else @@ -267,12 +270,11 @@ namespace CSVRender mMouseState = Mouse_Edit; // reset states - mCurrentMousePos = Ogre::Vector3(); // mouse pos to use in wheel event - mOrigMousePos = Ogre::Vector3(); // starting pos of mouse in world space - mOrigObjPos = Ogre::Vector3(); // starting pos of object in world space - mGrabbedSceneNode = ""; // id of the object - mOffset = 0.0f; // used for z-axis movement - mOldPos = QPoint(0, 0); // to calculate relative movement of mouse + mGrabbedSceneNode = ""; // id of the object + 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 + mOldCursorPos = QPoint(0, 0); // to calculate relative movement of mouse } break; } @@ -284,10 +286,12 @@ namespace CSVRender if(result.first != "") { // FIXME: terrain editing goes here +//#if 0 std::cout << "result default/edit 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; +//#endif } break; } @@ -298,9 +302,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) @@ -313,17 +317,47 @@ namespace CSVRender /* FALL_THROUGH */ case Mouse_Drag: { - // move the object along the z axis during Mouse_Drag or Mouse_Grab + // move the object along the axis normal to the plane during Mouse_Drag or Mouse_Grab if (event->delta()) { - // seems positive is up and negative is down - mOffset += (event->delta()/1); // FIXME: arbitrary number, make config option? + // The mouse point is where the mouse points the object when dragging starts. + // The object position is usually a little away from the mount point. + // Get the new world position of mouse on the plane offset from the wheel std::pair planeRes = planeAxis(); - Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset; - mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+mCurrentMousePos-mOrigMousePos); - mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+mCurrentMousePos-mOrigMousePos); + Ogre::Vector3 mousePos = mOldMousePos + planeRes.first*(event->delta()/2); + + // Move the movement plane to the new mouse position. The plane is created on + // the mouse point (i.e. not the object position) + mPlane->redefine(planeRes.first, mousePos); + + // Calculate the new screen position of the cursor + Ogre::Vector3 screenPos = + getCamera()->getProjectionMatrix() * getCamera()->getViewMatrix() * mousePos; + int screenX = (screenPos.x/2+0.5) * getViewport()->getActualWidth(); + int screenY = (1-(screenPos.y/2+0.5)) * getViewport()->getActualHeight(); + + // Move the cursor to the new screen position + QCursor::setPos(mParent->mapToGlobal(QPoint(screenX, screenY))); + + // Use the new position to check the world position of the mouse + std::pair planeResult = + mousePosOnPlane(QPoint(screenX, screenY), *mPlane); + { + if(planeResult.first) + mousePos = planeResult.second; + } + + // Find the final world position of the cursor + Ogre::Vector3 finalPos = mOrigObjPos + (mousePos-mOrigMousePos); + + mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(finalPos); + mPhysics->moveSceneNodes(mGrabbedSceneNode, finalPos); updateSceneWidgets(); + + // remember positions for next time + mOldMousePos = mousePos; + mOldCursorPos = QPoint(screenX, screenY); } break; } @@ -353,14 +387,13 @@ namespace CSVRender // reset states mMouseState = Mouse_Default; - mCurrentMousePos = Ogre::Vector3(); + mOldMousePos = Ogre::Vector3(); mOrigMousePos = Ogre::Vector3(); mOrigObjPos = Ogre::Vector3(); mGrabbedSceneNode = ""; mCurrentObj = ""; - mOldPos = QPoint(0, 0); + mOldCursorPos = QPoint(0, 0); mMouseEventTimer->invalidate(); - mOffset = 0.0f; break; } @@ -420,7 +453,7 @@ namespace CSVRender return std::make_pair("", Ogre::Vector3()); } - std::pair MouseState::mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane) + std::pair MouseState::mousePosOnPlane(const QPoint &pos, const Ogre::Plane &plane) { // using a really small value seems to mess up with the projections float nearClipDistance = getCamera()->getNearClipDistance(); // save existing diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp index fd752349a..d21735a78 100644 --- a/apps/opencs/view/render/mousestate.hpp +++ b/apps/opencs/view/render/mousestate.hpp @@ -46,15 +46,14 @@ namespace CSVRender CSVWorld::PhysicsSystem *mPhysics; // local copy Ogre::SceneManager *mSceneManager; // local copy - QPoint mOldPos; + QPoint mOldCursorPos; std::string mCurrentObj; std::string mGrabbedSceneNode; QElapsedTimer *mMouseEventTimer; Ogre::Plane *mPlane; Ogre::Vector3 mOrigObjPos; Ogre::Vector3 mOrigMousePos; - Ogre::Vector3 mCurrentMousePos; - float mOffset; + Ogre::Vector3 mOldMousePos; CSMWorld::IdTable *mIdTableModel; int mColIndexPosX; @@ -78,7 +77,7 @@ namespace CSVRender private: - std::pair mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane); + 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(); From 2412d127b0b2694f136e0f468034ffaec117560f Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 10 Nov 2014 22:29:01 +1100 Subject: [PATCH 10/29] Fix saving pathgrid positions when adding or moving. --- apps/opencs/view/render/cell.cpp | 36 +++++++++++++++++++++++++------- apps/opencs/view/render/cell.hpp | 5 +++-- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 4e3416111..043515907 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -18,7 +18,6 @@ #include "terrainstorage.hpp" #include "pathgridpoint.hpp" -// FIXME: redraw edges when pathgrid points are moved, added and deleted namespace CSVRender { // PLEASE NOTE: pathgrid edge code copied and adapted from mwrender/debugging @@ -314,7 +313,7 @@ float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const } // FIXME: -// - updating indicies +// - updating indicies, including mData // - adding edges (need the ability to select a pathgrid and highlight) // - save to document & signals // - repainting edges while moving @@ -324,7 +323,7 @@ void CSVRender::Cell::loadPathgrid() Ogre::ResourceGroupManager::getSingleton().createResourceGroup(DEBUGGING_GROUP); createGridMaterials(); - float worldsize = ESM::Land::REAL_SIZE; + int worldsize = ESM::Land::REAL_SIZE; CSMWorld::SubCellCollection& pathgridCollection = mData.getPathgrids(); int index = pathgridCollection.searchId(mId); @@ -373,14 +372,24 @@ void CSVRender::Cell::loadPathgrid() // NOTE: pos is in world coordinates // FIXME: save to the document -void CSVRender::Cell::pathgridPointAdded(const Ogre::Vector3 &pos) +void CSVRender::Cell::pathgridPointAdded(const Ogre::Vector3 &pos, bool interior) { std::string name = PathgridPoint::getName(mId, mPoints.size()); mPgPoints.insert(std::make_pair(name, new PathgridPoint(name, mCellNode, pos, mPhysics))); // store to document - ESM::Pathgrid::Point point((int)pos.x, (int)pos.y, (int)pos.z); + int worldsize = ESM::Land::REAL_SIZE; + + int x = pos.x; + int y = pos.y; + if(!interior) + { + x = x - (worldsize * mX); + y = y - (worldsize * mY); + } + + ESM::Pathgrid::Point point(x, y, (int)pos.z); point.mConnectionNum = 0; mPoints.push_back(point); mPathgridId = mId; @@ -473,7 +482,8 @@ void CSVRender::Cell::pathgridPointRemoved(const std::string &name) } // NOTE: newPos is in world coordinates -void CSVRender::Cell::pathgridPointMoved(const std::string &name, const Ogre::Vector3 &newPos) +void CSVRender::Cell::pathgridPointMoved(const std::string &name, + const Ogre::Vector3 &newPos, bool interior) { std::pair result = PathgridPoint::getIdAndIndex(name); if(result.first == "") @@ -486,7 +496,19 @@ void CSVRender::Cell::pathgridPointMoved(const std::string &name, const Ogre::Ve if(index < 0 || mPathgridId != pathgridId || (unsigned int)index >= mPoints.size()) return; - float worldsize = ESM::Land::REAL_SIZE; + int worldsize = ESM::Land::REAL_SIZE; + + int x = newPos.x; + int y = newPos.y; + if(!interior) + { + x = x - (worldsize * mX); + y = y - (worldsize * mY); + } + + mPoints[index].mX = x; + mPoints[index].mY = y; + mPoints[index].mZ = newPos.z; // delete then recreate the edges for(unsigned i = 0; i < mEdges.size(); ++i) diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 5d7b9088a..8a7f01f20 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -95,8 +95,9 @@ namespace CSVRender float getTerrainHeightAt(const Ogre::Vector3 &pos) const; - void pathgridPointAdded(const Ogre::Vector3 &pos); - void pathgridPointMoved(const std::string &name, const Ogre::Vector3 &newPos); + void pathgridPointAdded(const Ogre::Vector3 &pos, bool interior = false); + void pathgridPointMoved(const std::string &name, + const Ogre::Vector3 &newPos, bool interior = false); void pathgridPointRemoved(const std::string &name); private: From 48ecea71036d92752f7a228a21e1c4b93f2d7394 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 10 Nov 2014 22:38:29 +1100 Subject: [PATCH 11/29] Simplistic drop-to-ground functionality for pathgrid points. --- apps/opencs/view/render/mousestate.cpp | 17 +++++++---- apps/opencs/view/world/physicssystem.cpp | 37 ++++++++++++++++++++++++ apps/opencs/view/world/physicssystem.hpp | 2 ++ 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 989dbdb91..01f16c339 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -236,12 +236,17 @@ namespace CSVRender // move pathgrid point, but don't save yet (need pathgrid // table feature & its data structure to be completed) // FIXME: need to signal PathgridPoint object of change - //std::pair result = - //anyUnderCursor(event->x(), event->y()); - //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"))) + std::pair result = + anyUnderCursor(event->x(), event->y()); + 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"))) { + // drop (does not work if placed below the object/terrain) + // maybe look for closest object/terrain in both directions? + std::pair res = mPhysics->distToGround(pos, getCamera()); + if(res.first != "") + pos.z -= res.second; // FIXME: rather than just updating at the end, should // consider providing visual feedback of terrain height // while dragging the pathgrid point (maybe check whether @@ -250,6 +255,8 @@ namespace CSVRender placeObject(mGrabbedSceneNode, pos); // result.second mParent->pathgridMoved(referenceId, pos); // result.second } + else + cancelDrag(); } else { diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index cae5563e6..55da2e221 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -281,6 +281,43 @@ namespace CSVWorld } } + std::pair PhysicsSystem::distToGround(Ogre::Vector3 &position, + Ogre::Camera *camera) + { + btVector3 _from, _to; + _from = btVector3(position.x, position.y, position.z); + _to = btVector3(position.x, position.y, position.z-300000); + + 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); + + std::pair result = std::make_pair("", -1); + short mask = OEngine::Physic::CollisionType_Raycasting; + std::vector > objects = mEngine->rayTest2(_from, _to, mask); + + for (std::vector >::iterator it = objects.begin(); + it != objects.end(); ++it) + { + if(ignorePathgrid && QString((*it).second.c_str()).contains(QRegExp("^Pathgrid"))) + continue; + else if(ignoreObjects && QString((*it).second.c_str()).contains(QRegExp("^ref#"))) + continue; + else if(ignoreHeightMap && QString((*it).second.c_str()).contains(QRegExp("^Height"))) + continue; + + result = std::make_pair((*it).second, (*it).first); + break; + } + + // result.first is the object's referenceId + if(result.first == "") + return std::make_pair("", -1); + else + return std::make_pair(result.first, 300000*result.second); + } + std::string PhysicsSystem::refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr) { return mRefIdToSceneNode[referenceId][sceneMgr]; diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 0036bf769..f28272532 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -73,6 +73,8 @@ namespace CSVWorld std::pair castRay(float mouseX, float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera); + std::pair distToGround(Ogre::Vector3 &position, Ogre::Camera *camera); + std::string sceneNodeToRefId(std::string sceneNodeName); // for multi-scene manager per physics engine From 1504119da776121b79927c6188872bad06036cc6 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 11 Nov 2014 06:07:52 +1100 Subject: [PATCH 12/29] Increase the sensitivity of the wheel movement. --- apps/opencs/view/render/mousestate.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 01f16c339..ba668901f 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -233,9 +233,9 @@ namespace CSVRender if(QString(referenceId.c_str()).contains(QRegExp("^Pathgrid"))) { - // move pathgrid point, but don't save yet (need pathgrid + // FIXME: move pathgrid point, but don't save yet (need pathgrid // table feature & its data structure to be completed) - // FIXME: need to signal PathgridPoint object of change + // Also need to signal PathgridPoint object of change std::pair result = anyUnderCursor(event->x(), event->y()); std::string refId = mPhysics->sceneNodeToRefId(result.first); @@ -256,7 +256,7 @@ namespace CSVRender mParent->pathgridMoved(referenceId, pos); // result.second } else - cancelDrag(); + cancelDrag(); // FIXME: does not allow editing if terrain not visible } else { @@ -331,8 +331,9 @@ namespace CSVRender // The object position is usually a little away from the mount point. // Get the new world position of mouse on the plane offset from the wheel + // FIXME: make the sensitivity a user setting and/or allow modifiers std::pair planeRes = planeAxis(); - Ogre::Vector3 mousePos = mOldMousePos + planeRes.first*(event->delta()/2); + Ogre::Vector3 mousePos = mOldMousePos + planeRes.first*(event->delta()/1.5); // Move the movement plane to the new mouse position. The plane is created on // the mouse point (i.e. not the object position) From 407edc770c0005a9f179717fa9532d063b8ecbd8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 11 Nov 2014 07:47:35 +1100 Subject: [PATCH 13/29] Added a simplistic snap to closest object or terrain. --- apps/opencs/view/render/mousestate.cpp | 25 +++++---- apps/opencs/view/world/physicssystem.cpp | 70 +++++++++++++++++++++++- apps/opencs/view/world/physicssystem.hpp | 6 +- 3 files changed, 89 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index ba668901f..8f254f08d 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -242,18 +242,23 @@ namespace CSVRender if(result.first != "" && // don't allow pathgrid points under the cursor !QString(refId.c_str()).contains(QRegExp("^Pathgrid"))) { - // drop (does not work if placed below the object/terrain) - // maybe look for closest object/terrain in both directions? - std::pair res = mPhysics->distToGround(pos, getCamera()); + // snap (defaults to 300 or less) + // FIXME: sticks to the underside of the object if snapping up + std::pair res = + mPhysics->distToClosest(pos, getCamera(), 500); if(res.first != "") + { pos.z -= res.second; - // FIXME: rather than just updating at the end, should - // consider providing visual feedback of terrain height - // while dragging the pathgrid point (maybe check whether - // the object is a pathgrid point at the begging and set - // a flag?) - placeObject(mGrabbedSceneNode, pos); // result.second - mParent->pathgridMoved(referenceId, pos); // result.second + // FIXME: rather than just updating at the end, should + // consider providing visual feedback of terrain height + // while dragging the pathgrid point (maybe check whether + // the object is a pathgrid point at the begging and set + // a flag?) + placeObject(mGrabbedSceneNode, pos); // result.second + mParent->pathgridMoved(referenceId, pos); // result.second + } + else + cancelDrag(); } else cancelDrag(); // FIXME: does not allow editing if terrain not visible diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 55da2e221..358bb90ca 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -281,7 +281,7 @@ namespace CSVWorld } } - std::pair PhysicsSystem::distToGround(Ogre::Vector3 &position, + std::pair PhysicsSystem::distToGround(const Ogre::Vector3 &position, Ogre::Camera *camera) { btVector3 _from, _to; @@ -318,6 +318,74 @@ namespace CSVWorld return std::make_pair(result.first, 300000*result.second); } + // FIXME: remove code duplication + std::pair PhysicsSystem::distToClosest(const Ogre::Vector3 &position, + Ogre::Camera *camera, const float limit) + { + 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); + + short mask = OEngine::Physic::CollisionType_Raycasting; + + btVector3 _from, _to; + _from = btVector3(position.x, position.y, position.z); + _to = btVector3(position.x, position.y, position.z-limit); + + std::pair resDown = std::make_pair("", -1); + std::vector > objectsDown = mEngine->rayTest2(_from, _to, mask); + + for (std::vector >::iterator it = objectsDown.begin(); + it != objectsDown.end(); ++it) + { + if(ignorePathgrid && QString((*it).second.c_str()).contains(QRegExp("^Pathgrid"))) + continue; + else if(ignoreObjects && QString((*it).second.c_str()).contains(QRegExp("^ref#"))) + continue; + else if(ignoreHeightMap && QString((*it).second.c_str()).contains(QRegExp("^Height"))) + continue; + + resDown = std::make_pair((*it).second, (*it).first); + break; + } + + _to = btVector3(position.x, position.y, position.z+limit); + std::pair resUp = std::make_pair("", -1); + std::vector > objectsUp = mEngine->rayTest2(_from, _to, mask); + + for (std::vector >::iterator it = objectsDown.begin(); + it != objectsDown.end(); ++it) + { + if(ignorePathgrid && QString((*it).second.c_str()).contains(QRegExp("^Pathgrid"))) + continue; + else if(ignoreObjects && QString((*it).second.c_str()).contains(QRegExp("^ref#"))) + continue; + else if(ignoreHeightMap && QString((*it).second.c_str()).contains(QRegExp("^Height"))) + continue; + + resUp = std::make_pair((*it).second, (*it).first); + break; + } + + if(resDown.first != "") + { + if(resUp.first != "") + { + if(fabs(resUp.second) < fabs(resDown.second)) + return std::make_pair(resUp.first, -limit*resUp.second); + else + return std::make_pair(resDown.first, limit*resDown.second); + } + else + return std::make_pair(resDown.first, limit*resDown.second); + } + else if(resUp.first != "") + return std::make_pair(resUp.first, -limit*resUp.second); + else + return std::make_pair("", -1); + } + std::string PhysicsSystem::refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr) { return mRefIdToSceneNode[referenceId][sceneMgr]; diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index f28272532..6436b8743 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -73,7 +73,11 @@ namespace CSVWorld std::pair castRay(float mouseX, float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera); - std::pair distToGround(Ogre::Vector3 &position, Ogre::Camera *camera); + std::pair distToGround(const Ogre::Vector3 &position, + Ogre::Camera *camera); + + std::pair distToClosest(const Ogre::Vector3 &position, + Ogre::Camera *camera, const float limit = 300.0f); std::string sceneNodeToRefId(std::string sceneNodeName); From 3eb556ff8ac7bf756ae5c2e2b5a6c4e5d2b6622a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 11 Nov 2014 19:40:04 +1100 Subject: [PATCH 14/29] Enhanced snap functionality for pathgrid points. --- apps/opencs/view/render/mousestate.cpp | 31 ++++------ apps/opencs/view/world/physicssystem.cpp | 73 ++++-------------------- apps/opencs/view/world/physicssystem.hpp | 4 +- 3 files changed, 25 insertions(+), 83 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 8f254f08d..c9fcdbc86 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -236,29 +236,22 @@ namespace CSVRender // 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 = - anyUnderCursor(event->x(), event->y()); + 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"))) { - // snap (defaults to 300 or less) - // FIXME: sticks to the underside of the object if snapping up - std::pair res = - mPhysics->distToClosest(pos, getCamera(), 500); - if(res.first != "") - { - pos.z -= res.second; - // FIXME: rather than just updating at the end, should - // consider providing visual feedback of terrain height - // while dragging the pathgrid point (maybe check whether - // the object is a pathgrid point at the begging and set - // a flag?) - placeObject(mGrabbedSceneNode, pos); // result.second - mParent->pathgridMoved(referenceId, pos); // result.second - } - else - cancelDrag(); + pos.z -= result.second; + pos.z += 2; // arbitrary number, lift up slightly (maybe change the nif?) + // FIXME: rather than just updating at the end, should + // consider providing visual feedback of terrain height + // while dragging the pathgrid point (maybe check whether + // the object is a pathgrid point at the begging and set + // a flag?) + placeObject(mGrabbedSceneNode, pos); // result.second + mParent->pathgridMoved(referenceId, pos); // result.second } else cancelDrag(); // FIXME: does not allow editing if terrain not visible diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 358bb90ca..9ff945829 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -282,16 +282,17 @@ namespace CSVWorld } std::pair PhysicsSystem::distToGround(const Ogre::Vector3 &position, - Ogre::Camera *camera) + Ogre::Camera *camera, const float limit, bool ignorePgPoint) { btVector3 _from, _to; _from = btVector3(position.x, position.y, position.z); - _to = btVector3(position.x, position.y, position.z-300000); + _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); - bool ignorePathgrid = !(visibilityMask & (uint32_t)CSVRender::Element_Pathgrid); + bool ignorePathgrid = ignorePgPoint || + !(visibilityMask & (uint32_t)CSVRender::Element_Pathgrid); std::pair result = std::make_pair("", -1); short mask = OEngine::Physic::CollisionType_Raycasting; @@ -315,73 +316,21 @@ namespace CSVWorld if(result.first == "") return std::make_pair("", -1); else - return std::make_pair(result.first, 300000*result.second); + return std::make_pair(result.first, limit*result.second); } - // FIXME: remove code duplication + // tries to find the distance to the "top" of the closest object std::pair PhysicsSystem::distToClosest(const Ogre::Vector3 &position, Ogre::Camera *camera, const float limit) { - 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); + const float thickness = 50; // arbitrary number - short mask = OEngine::Physic::CollisionType_Raycasting; - - btVector3 _from, _to; - _from = btVector3(position.x, position.y, position.z); - _to = btVector3(position.x, position.y, position.z-limit); - - std::pair resDown = std::make_pair("", -1); - std::vector > objectsDown = mEngine->rayTest2(_from, _to, mask); - - for (std::vector >::iterator it = objectsDown.begin(); - it != objectsDown.end(); ++it) - { - if(ignorePathgrid && QString((*it).second.c_str()).contains(QRegExp("^Pathgrid"))) - continue; - else if(ignoreObjects && QString((*it).second.c_str()).contains(QRegExp("^ref#"))) - continue; - else if(ignoreHeightMap && QString((*it).second.c_str()).contains(QRegExp("^Height"))) - continue; - - resDown = std::make_pair((*it).second, (*it).first); - break; - } - - _to = btVector3(position.x, position.y, position.z+limit); - std::pair resUp = std::make_pair("", -1); - std::vector > objectsUp = mEngine->rayTest2(_from, _to, mask); - - for (std::vector >::iterator it = objectsDown.begin(); - it != objectsDown.end(); ++it) - { - if(ignorePathgrid && QString((*it).second.c_str()).contains(QRegExp("^Pathgrid"))) - continue; - else if(ignoreObjects && QString((*it).second.c_str()).contains(QRegExp("^ref#"))) - continue; - else if(ignoreHeightMap && QString((*it).second.c_str()).contains(QRegExp("^Height"))) - continue; - - resUp = std::make_pair((*it).second, (*it).first); - break; - } + std::pair resDown = + distToGround(Ogre::Vector3(position.x, position.y, position.z+thickness), + camera, limit+thickness, true); if(resDown.first != "") - { - if(resUp.first != "") - { - if(fabs(resUp.second) < fabs(resDown.second)) - return std::make_pair(resUp.first, -limit*resUp.second); - else - return std::make_pair(resDown.first, limit*resDown.second); - } - else - return std::make_pair(resDown.first, limit*resDown.second); - } - else if(resUp.first != "") - return std::make_pair(resUp.first, -limit*resUp.second); + return std::make_pair(resDown.first, resDown.second-thickness); else return std::make_pair("", -1); } diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 6436b8743..589dca9c5 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -74,10 +74,10 @@ namespace CSVWorld float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera); std::pair distToGround(const Ogre::Vector3 &position, - Ogre::Camera *camera); + Ogre::Camera *camera, const float limit = 300000, bool ignorePgPoint = false); std::pair distToClosest(const Ogre::Vector3 &position, - Ogre::Camera *camera, const float limit = 300.0f); + Ogre::Camera *camera, const float limit = 100.0f); std::string sceneNodeToRefId(std::string sceneNodeName); From d65adc4376228d842c792c690bfb2bf95dbb3220 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 12 Nov 2014 22:04:48 +1100 Subject: [PATCH 15/29] Reduce code duplication. --- apps/opencs/view/render/mousestate.cpp | 144 ++++++------------ apps/opencs/view/render/mousestate.hpp | 10 +- .../view/render/pagedworldspacewidget.cpp | 5 +- .../view/render/pagedworldspacewidget.hpp | 2 +- apps/opencs/view/render/worldspacewidget.cpp | 8 +- apps/opencs/view/world/physicssystem.cpp | 46 +++--- apps/opencs/view/world/physicssystem.hpp | 9 +- 7 files changed, 83 insertions(+), 141 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index c9fcdbc86..65596b752 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 d21735a78..d55d5f6c3 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 506fd54df..bb856dbff 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 b5ca91880..63f6caa60 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 4f85f3a30..54d0ce8e8 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 9ff945829..9012a06c2 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 589dca9c5..5543c84b9 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); }; From 8c6890c682e283b401dbd4286deada91822f94c5 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 12 Nov 2014 22:28:41 +1100 Subject: [PATCH 16/29] Move element filtering back out of castRay(). --- apps/opencs/view/render/mousestate.cpp | 18 ++++++++++++++++-- apps/opencs/view/render/mousestate.hpp | 2 +- apps/opencs/view/world/physicssystem.cpp | 24 +++++++----------------- apps/opencs/view/world/physicssystem.hpp | 7 +++---- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 65596b752..e62a4b1ff 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -237,7 +237,8 @@ namespace CSVRender // 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 + mPhysics->distToClosest(pos, + getCamera()->getViewport()->getVisibilityMask(), 600); // snap if(result.first != "" && // don't allow pathgrid points under the cursor !QString(result.first.c_str()).contains(QRegExp("^Pathgrid"))) @@ -474,7 +475,20 @@ namespace CSVRender float x = (float) mouseX / getViewport()->getActualWidth(); float y = (float) mouseY / getViewport()->getActualHeight(); - return mPhysics->castRay(x, y, mSceneManager, getCamera(), elements); + std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); + + 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"))))) + { + return result; + } + else + return std::make_pair("", Ogre::Vector3()); } void MouseState::updateSceneWidgets() diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp index d55d5f6c3..cde53f2c5 100644 --- a/apps/opencs/view/render/mousestate.hpp +++ b/apps/opencs/view/render/mousestate.hpp @@ -73,7 +73,7 @@ namespace CSVRender bool wheelEvent (QWheelEvent *event); std::pair underCursor(const int mouseX, - const int mouseY, Ogre::uint32 elements); + const int mouseY, Ogre::uint32 elements = 0xFFFFFFFF); void cancelDrag(); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 9012a06c2..6450b5cf6 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -214,8 +214,7 @@ namespace CSVWorld // 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, - Ogre::uint32 elements) + float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera) { // NOTE: there could be more than one camera for the scene manager // TODO: check whether camera belongs to sceneMgr @@ -261,28 +260,19 @@ namespace CSVWorld } // result.first is the object's referenceId - 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"))))) - { - return std::make_pair(result.first, ray.getPoint(farClipDist*result.second)); - } - else + if(result.first == "") return std::make_pair("", Ogre::Vector3()); + else + return std::make_pair(result.first, ray.getPoint(farClipDist*result.second)); } std::pair PhysicsSystem::distToGround(const Ogre::Vector3 &position, - Ogre::Camera *camera, const float limit, bool ignorePgPoint) + Ogre::uint32 visibilityMask, const float limit, bool ignorePgPoint) { btVector3 _from, _to; _from = btVector3(position.x, position.y, position.z); _to = btVector3(position.x, position.y, position.z-limit); - 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 || @@ -315,13 +305,13 @@ namespace CSVWorld // tries to find the distance to the "top" of the closest object std::pair PhysicsSystem::distToClosest(const Ogre::Vector3 &position, - Ogre::Camera *camera, const float limit) + Ogre::uint32 visibilityMask, const float limit) { const float thickness = 50; // arbitrary number std::pair resDown = distToGround(Ogre::Vector3(position.x, position.y, position.z+thickness), - camera, limit+thickness, true); + visibilityMask, limit+thickness, true); if(resDown.first != "") return std::make_pair(resDown.first, resDown.second-thickness); diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 5543c84b9..f71ab685c 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -73,14 +73,13 @@ 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, - Ogre::uint32 elements = 0xFFFFFFFF); + float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera); std::pair distToGround(const Ogre::Vector3 &position, - Ogre::Camera *camera, const float limit = 300000, bool ignorePgPoint = false); + Ogre::uint32 visibilityMask, const float limit = 300000, bool ignorePgPoint = false); std::pair distToClosest(const Ogre::Vector3 &position, - Ogre::Camera *camera, const float limit = 100.0f); + Ogre::uint32 visibilityMask, const float limit = 100.0f); std::string refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr); From 12511778d1d262365205b0c532c2d62e670a6ba2 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 12 Nov 2014 22:43:22 +1100 Subject: [PATCH 17/29] Remove duplicate parameter. --- apps/opencs/view/render/mousestate.cpp | 2 +- apps/opencs/view/world/physicssystem.cpp | 9 ++++----- apps/opencs/view/world/physicssystem.hpp | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index e62a4b1ff..41908d11c 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -244,7 +244,7 @@ namespace CSVRender !QString(result.first.c_str()).contains(QRegExp("^Pathgrid"))) { pos.z -= result.second; - pos.z += 2; // arbitrary number, lift up slightly (maybe change the nif?) + pos.z += 1; // arbitrary number, lift up slightly (maybe change the nif?) // FIXME: rather than just updating at the end, should // consider providing visual feedback of terrain height // while dragging the pathgrid point (maybe check whether diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 6450b5cf6..c5f1d0a75 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -267,7 +267,7 @@ namespace CSVWorld } std::pair PhysicsSystem::distToGround(const Ogre::Vector3 &position, - Ogre::uint32 visibilityMask, const float limit, bool ignorePgPoint) + Ogre::uint32 visibilityMask, const float limit) { btVector3 _from, _to; _from = btVector3(position.x, position.y, position.z); @@ -275,8 +275,7 @@ namespace CSVWorld bool ignoreHeightMap = !(visibilityMask & (Ogre::uint32)CSVRender::Element_Terrain); bool ignoreObjects = !(visibilityMask & (Ogre::uint32)CSVRender::Element_Reference); - bool ignorePathgrid = ignorePgPoint || - !(visibilityMask & (Ogre::uint32)CSVRender::Element_Pathgrid); + bool ignorePathgrid = !(visibilityMask & (Ogre::uint32)CSVRender::Element_Pathgrid); std::pair result = std::make_pair("", -1); short mask = OEngine::Physic::CollisionType_Raycasting; @@ -303,7 +302,7 @@ namespace CSVWorld return std::make_pair(result.first, limit*result.second); } - // tries to find the distance to the "top" of the closest object + // tries to find the distance to the "top" of the closest object (ignores pathgrid points) std::pair PhysicsSystem::distToClosest(const Ogre::Vector3 &position, Ogre::uint32 visibilityMask, const float limit) { @@ -311,7 +310,7 @@ namespace CSVWorld std::pair resDown = distToGround(Ogre::Vector3(position.x, position.y, position.z+thickness), - visibilityMask, limit+thickness, true); + visibilityMask&(~CSVRender::Element_Pathgrid), limit+thickness); if(resDown.first != "") return std::make_pair(resDown.first, resDown.second-thickness); diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index f71ab685c..839d55654 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -76,7 +76,7 @@ namespace CSVWorld float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera); std::pair distToGround(const Ogre::Vector3 &position, - Ogre::uint32 visibilityMask, const float limit = 300000, bool ignorePgPoint = false); + Ogre::uint32 visibilityMask, const float limit = 300000); std::pair distToClosest(const Ogre::Vector3 &position, Ogre::uint32 visibilityMask, const float limit = 100.0f); From e430dcfd8ad1884cfab800e38874bcc1e854cfff Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 13 Nov 2014 05:59:04 +1100 Subject: [PATCH 18/29] Check the resource group's existence before destroying it. --- apps/opencs/view/render/cell.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 043515907..40cf904f8 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -42,8 +42,13 @@ void CSVRender::Cell::createGridMaterials() void CSVRender::Cell::destroyGridMaterials() { - if(!Ogre::MaterialManager::getSingleton().getByName(PG_LINE_MATERIAL, DEBUGGING_GROUP).isNull()) - Ogre::MaterialManager::getSingleton().remove(PG_LINE_MATERIAL); + if(Ogre::ResourceGroupManager::getSingleton().resourceGroupExists(DEBUGGING_GROUP)) + { + if(!Ogre::MaterialManager::getSingleton().getByName(PG_LINE_MATERIAL, DEBUGGING_GROUP).isNull()) + Ogre::MaterialManager::getSingleton().remove(PG_LINE_MATERIAL); + + Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(DEBUGGING_GROUP); + } } Ogre::ManualObject *CSVRender::Cell::createPathgridEdge(const std::string &name, @@ -165,7 +170,6 @@ CSVRender::Cell::~Cell() } } destroyGridMaterials(); - Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(DEBUGGING_GROUP); for(std::map::iterator iter (mPgPoints.begin()); iter!=mPgPoints.end(); ++iter) From 0e0ad97a9108580b9ee8c8472342d4624c98a6ad Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 13 Nov 2014 06:36:47 +1100 Subject: [PATCH 19/29] Pathgrid edge resource management for editing multiple cells or multiple documents. --- apps/opencs/view/render/cell.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 40cf904f8..32ef101e5 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -28,6 +28,9 @@ namespace CSVRender void CSVRender::Cell::createGridMaterials() { + if(!Ogre::ResourceGroupManager::getSingleton().resourceGroupExists(DEBUGGING_GROUP)) + Ogre::ResourceGroupManager::getSingleton().createResourceGroup(DEBUGGING_GROUP); + if(Ogre::MaterialManager::getSingleton().getByName(PG_LINE_MATERIAL, DEBUGGING_GROUP).isNull()) { Ogre::MaterialPtr lineMatPtr = @@ -56,6 +59,7 @@ Ogre::ManualObject *CSVRender::Cell::createPathgridEdge(const std::string &name, { Ogre::ManualObject *result = mSceneMgr->createManualObject(name); + createGridMaterials(); result->begin(PG_LINE_MATERIAL, Ogre::RenderOperation::OT_LINE_LIST); Ogre::Vector3 direction = (end - start); @@ -323,8 +327,6 @@ float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const // - repainting edges while moving void CSVRender::Cell::loadPathgrid() { - if(!Ogre::ResourceGroupManager::getSingleton().resourceGroupExists(DEBUGGING_GROUP)) - Ogre::ResourceGroupManager::getSingleton().createResourceGroup(DEBUGGING_GROUP); createGridMaterials(); int worldsize = ESM::Land::REAL_SIZE; From ba1a42ec05161d5816a8bf67855cf21ba4afc308 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 13 Nov 2014 07:41:31 +1100 Subject: [PATCH 20/29] Don't delete physics object if it was never created. --- apps/opencs/view/render/object.cpp | 6 ++++-- apps/opencs/view/render/object.hpp | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 21219db8f..e27371766 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -93,6 +93,7 @@ void CSVRender::Object::update() Ogre::Quaternion yr (Ogre::Radian (-reference.mPos.rot[1]), Ogre::Vector3::UNIT_Y); Ogre::Quaternion zr (Ogre::Radian (-reference.mPos.rot[2]), Ogre::Vector3::UNIT_Z); + mPhysicsObject = mReferenceId; mPhysics->addObject("meshes\\" + model, mBase->getName(), mReferenceId, reference.mScale, position, xr*yr*zr); } } @@ -134,7 +135,7 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const CSVRender::Object::Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode, const std::string& id, bool referenceable, CSVWorld::PhysicsSystem *physics, bool forceBaseToZero) -: mData (data), mBase (0), mForceBaseToZero (forceBaseToZero), mPhysics(physics) +: mData (data), mBase (0), mForceBaseToZero (forceBaseToZero), mPhysics(physics), mPhysicsObject("") { mBase = cellNode->createChildSceneNode(); @@ -156,7 +157,8 @@ CSVRender::Object::~Object() { clear(); - mPhysics->removeObject(mBase->getName()); + if(mPhysicsObject != "") + mPhysics->removeObject(mBase->getName()); if (mBase) mBase->getCreator()->destroySceneNode (mBase); diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index eba2dc814..8ce204e1c 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -32,6 +32,7 @@ namespace CSVRender NifOgre::ObjectScenePtr mObject; bool mForceBaseToZero; CSVWorld::PhysicsSystem *mPhysics; + std::string mPhysicsObject; /// Not implemented Object (const Object&); From 0a66877cf150a178b7cbc977ed553b2539083bca Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 13 Nov 2014 07:47:32 +1100 Subject: [PATCH 21/29] Remove no longer needed code. --- apps/opencs/view/render/cell.cpp | 2 -- apps/opencs/view/world/physicssystem.hpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 32ef101e5..12e00ca46 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -327,8 +327,6 @@ float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const // - repainting edges while moving void CSVRender::Cell::loadPathgrid() { - createGridMaterials(); - int worldsize = ESM::Land::REAL_SIZE; CSMWorld::SubCellCollection& pathgridCollection = mData.getPathgrids(); diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 839d55654..6a634ed26 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -91,8 +91,6 @@ namespace CSVWorld void moveSceneNodeImpl(const std::string sceneNodeName, const std::string referenceId, const Ogre::Vector3 &position); - void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); - std::string sceneNodeToRefId(std::string sceneNodeName); Ogre::SceneManager *findSceneManager(std::string sceneNodeName); From 4c3c67422313ba747808eff5a6c3bc2882671c98 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 9 Dec 2014 19:37:37 +1100 Subject: [PATCH 22/29] Resolve merge issues. --- apps/opencs/view/render/pathgridpoint.cpp | 2 +- apps/opencs/view/render/pathgridpoint.hpp | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/pathgridpoint.cpp b/apps/opencs/view/render/pathgridpoint.cpp index 3e365932f..85b03beea 100644 --- a/apps/opencs/view/render/pathgridpoint.cpp +++ b/apps/opencs/view/render/pathgridpoint.cpp @@ -15,7 +15,7 @@ namespace CSVRender { PathgridPoint::PathgridPoint(const std::string &name, - Ogre::SceneNode *cellNode, const Ogre::Vector3 &pos, CSVWorld::PhysicsSystem *physics) + Ogre::SceneNode *cellNode, const Ogre::Vector3 &pos, boost::shared_ptr physics) : mBase(cellNode), mPhysics(physics) { mBase = cellNode->createChildSceneNode(); diff --git a/apps/opencs/view/render/pathgridpoint.hpp b/apps/opencs/view/render/pathgridpoint.hpp index 3419082c3..54fe70e31 100644 --- a/apps/opencs/view/render/pathgridpoint.hpp +++ b/apps/opencs/view/render/pathgridpoint.hpp @@ -1,6 +1,8 @@ #ifndef OPENCS_VIEW_PATHGRIDPOINT_H #define OPENCS_VIEW_PATHGRIDPOINT_H +#include + #include namespace Ogre @@ -19,14 +21,15 @@ namespace CSVRender { class PathgridPoint { - CSVWorld::PhysicsSystem *mPhysics; // local copy + boost::shared_ptr mPhysics; // local copy NifOgre::ObjectScenePtr mPgPoint; Ogre::SceneNode *mBase; public: PathgridPoint(const std::string &name, - Ogre::SceneNode *cellNode, const Ogre::Vector3 &pos, CSVWorld::PhysicsSystem *physics); + Ogre::SceneNode *cellNode, const Ogre::Vector3 &pos, + boost::shared_ptr physics); ~PathgridPoint(); From 68dbf929a2c024d0cbc3086ff15865a7125844af Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 18 Apr 2015 16:14:25 +1000 Subject: [PATCH 23/29] Add updated pathgrid marker nif file and fix merge issues. --- apps/opencs/view/render/cell.cpp | 3 +-- apps/opencs/view/render/cell.hpp | 3 --- files/materials/pathgrid_pt.nif | Bin 1683 -> 1484 bytes 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index d13649d3e..ef63909af 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -93,7 +93,7 @@ bool CSVRender::Cell::addObjects (int start, int end) bool modified = false; const CSMWorld::RefCollection& collection = mData.getReferences(); - + for (int i=start; i<=end; ++i) { std::string cell = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mCell); @@ -177,7 +177,6 @@ CSVRender::Cell::~Cell() if (mTerrain.get()) mPhysics->removeHeightField(mSceneMgr, mX, mY); - for (std::map::iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) delete iter->second; diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index e504fc7a4..0afd0920b 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -11,11 +11,8 @@ #ifndef Q_MOC_RUN #include -<<<<<<< .mine #include // FIXME: temporaty storage until saving to document -======= #endif ->>>>>>> .theirs #include "object.hpp" diff --git a/files/materials/pathgrid_pt.nif b/files/materials/pathgrid_pt.nif index 579b03036c05d5deefe564880dbe312ebbb671f2..cc37e0ee37ef732d4b42d2aadde343580bbd717c 100644 GIT binary patch literal 1484 zcmb7E%}&BV5FVrmA_{^(9C-jk(0K4*Bp5X@(ME&uYE~`Mq)1ci!5eQz;#ptA8;@Z0 zo9(V_q4+ao*>7gP`N^<@?Sv=2o)bJewPV-AS3l^9aId=Yl<1NZLQ53g^$PbCF-Oc^vyjVMW1kWN(b(dIEIfxuI-U3ZG45cx1L*o_58r#Ox7X7q|5D?r z9g0v?YoN z&n!&faL+Qw518|4&J^Z2)erZXh}o|tdPiEzQB}eewkS;&Ww6Cr%FzP0c##UUM9Wm9 z60KklDzr*#v`!m{_;ts>H^S1T)E(bn45}F?us&&v7+GArW7C^5|KClS^`c^S-Pi1i b@yz&tCynW4R1aw&3wjE7G*L@>^gI0m*A66H literal 1683 zcmb_c&2G~`5T2w?TS{o5<)=VFsl*Xg0afBs5fvdM4p>M~t z{C?Np?FC)$y&eQghexm&7u~;CWz{hD0=54Y+fzoWSk5~yRND7?35Oe)*tVL@XADTG z$msazOQxZWjz48KHiA7Fu|IzA>~=bx)-sfI<6e8A_tM49L(g%nZumu9vX(p%#5uQlEoZ8R#7-VYypD5R1EVB3_buexwNtrloXhIZ@iTF9 z{Hz^${+)}5IF;yZR(x^t`RvblZ2ox}hRvJ-a%RA%8BP(Knrxg>jG7~^xAk0x1sv9V z%5N;g-(S>Q9HU>GX1)qD24gYiESTIxGG_#)x;!zCin-NQ+-pZ_Xf6w~DA&+ju7hzy zmSsh5$}QZ@HMuQ!;I=7Xbdk!1z;9(1`L8re49DCSSsnHYnc}(&b DaQ$}< From 27a73a25e345307cfa92adc38b7990c69dc0c74b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 23 Apr 2015 08:50:05 +1000 Subject: [PATCH 24/29] Saving to document via UndoStack implemented. --- apps/opencs/model/world/commands.cpp | 26 ++++ apps/opencs/model/world/commands.hpp | 26 +++- apps/opencs/model/world/idtree.cpp | 4 + .../model/world/nestedcoladapterimp.cpp | 6 + .../model/world/nestedcoladapterimp.hpp | 16 --- .../opencs/model/world/pathgridpointswrap.hpp | 26 ++++ apps/opencs/view/render/cell.cpp | 129 ++++++++++++------ apps/opencs/view/render/cell.hpp | 19 ++- .../view/render/pagedworldspacewidget.cpp | 2 +- .../view/render/unpagedworldspacewidget.cpp | 4 +- 10 files changed, 186 insertions(+), 72 deletions(-) create mode 100644 apps/opencs/model/world/pathgridpointswrap.hpp diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index d12c5d228..11a675db0 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -244,3 +244,29 @@ const CSMWorld::NestedTableWrapperBase& CSMWorld::NestedTableStoring::getOld() c { return *mOld; } + +// Current interface does not allow adding a non-blank row, so we're forced to modify +// the whole record. +CSMWorld::ModifyPathgridCommand::ModifyPathgridCommand(IdTree& model, + const std::string& id, int parentColumn, NestedTableWrapperBase* newRecord, QUndoCommand* parent) + : mModel(model), mId(id), mParentColumn(parentColumn), mRecord(newRecord) + , QUndoCommand(parent), NestedTableStoring(model, id, parentColumn) +{ + setText (("Modify Pathgrid record " + mId).c_str()); // FIXME: better description +} + +void CSMWorld::ModifyPathgridCommand::redo() +{ + const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); + + mModel.setNestedTable(parentIndex, *mRecord); +} + +void CSMWorld::ModifyPathgridCommand::undo() +{ + const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); + + mModel.setNestedTable(parentIndex, getOld()); + + // FIXME: needs to tell the cell to redraw, possibly using signals +} diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index a70b36178..4e4de25c7 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -168,7 +168,8 @@ namespace CSMWorld public: - DeleteNestedCommand (IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); + DeleteNestedCommand (IdTree& model, + const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); virtual void redo(); @@ -187,7 +188,28 @@ namespace CSMWorld public: - AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); + AddNestedCommand(IdTree& model, + const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0); + + virtual void redo(); + + virtual void undo(); + }; + + class ModifyPathgridCommand : public QUndoCommand, private NestedTableStoring + { + IdTree& mModel; + std::string mId; + + int mParentColumn; + + NestedTableWrapperBase* mRecord; + + public: + + // if newEdges is NULL, only the paths are updated + ModifyPathgridCommand(IdTree& model, const std::string& id, int parentColumn, + NestedTableWrapperBase* newRecord, QUndoCommand* parent = 0); virtual void redo(); diff --git a/apps/opencs/model/world/idtree.cpp b/apps/opencs/model/world/idtree.cpp index 06db09a0f..3cdc58f4d 100644 --- a/apps/opencs/model/world/idtree.cpp +++ b/apps/opencs/model/world/idtree.cpp @@ -248,6 +248,10 @@ void CSMWorld::IdTree::setNestedTable(const QModelIndex& index, const CSMWorld:: { emit resetEnd(this->index(index.row(), 0).data().toString()); } + // FIXME: Removing pathgrid points will also remove pathgrid edges, but we have + // no way of emitting signals to indicate those changes. In addition, the + // removed edges can be any index (and there can be several edges removed + // but always by a factor of two) } CSMWorld::NestedTableWrapperBase* CSMWorld::IdTree::nestedTable(const QModelIndex& index) const diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index d29155a47..060a6bb39 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -6,6 +6,7 @@ #include "idcollection.hpp" #include "pathgrid.hpp" #include "info.hpp" +#include "pathgridpointswrap.hpp" namespace CSMWorld { @@ -147,6 +148,8 @@ namespace CSMWorld PathgridEdgeListAdapter::PathgridEdgeListAdapter () {} // ToDo: seems to be auto-sorted in the dialog table display after insertion + // + // FIXME: edges should be added in pairs void PathgridEdgeListAdapter::addRow(Record& record, int position) const { Pathgrid pathgrid = record.get(); @@ -168,6 +171,7 @@ namespace CSMWorld record.setModified (pathgrid); } + // FIXME: edges should be removed in pairs and Point.mConnectionNum updated void PathgridEdgeListAdapter::removeRow(Record& record, int rowToRemove) const { Pathgrid pathgrid = record.get(); @@ -218,6 +222,8 @@ namespace CSMWorld } // ToDo: detect duplicates in mEdges + // + // FIXME: Point.mConnectionNum needs to be updated void PathgridEdgeListAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 96dcd943d..2613d0f20 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -3,7 +3,6 @@ #include -#include #include #include // for converting magic effect id to string & back #include // for converting skill names @@ -23,21 +22,6 @@ namespace CSMWorld struct Pathgrid; struct Info; - struct PathgridPointsWrap : public NestedTableWrapperBase - { - ESM::Pathgrid mRecord; - - PathgridPointsWrap(ESM::Pathgrid pathgrid) - : mRecord(pathgrid) {} - - virtual ~PathgridPointsWrap() {} - - virtual int size() const - { - return mRecord.mPoints.size(); // used in IdTree::setNestedTable() - } - }; - class PathgridPointListAdapter : public NestedColumnAdapter { public: diff --git a/apps/opencs/model/world/pathgridpointswrap.hpp b/apps/opencs/model/world/pathgridpointswrap.hpp new file mode 100644 index 000000000..6f1f61fc6 --- /dev/null +++ b/apps/opencs/model/world/pathgridpointswrap.hpp @@ -0,0 +1,26 @@ +#ifndef CSM_WOLRD_PATHGRIDPOINTSWRAP_H +#define CSM_WOLRD_PATHGRIDPOINTSWRAP_H + +#include + +#include "nestedtablewrapper.hpp" + +namespace CSMWorld +{ + struct PathgridPointsWrap : public NestedTableWrapperBase + { + ESM::Pathgrid mRecord; + + PathgridPointsWrap(ESM::Pathgrid pathgrid) + : mRecord(pathgrid) {} + + virtual ~PathgridPointsWrap() {} + + virtual int size() const + { + return mRecord.mPoints.size(); // used in IdTree::setNestedTable() + } + }; +} + +#endif // CSM_WOLRD_PATHGRIDPOINTSWRAP_H diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index ef63909af..698912344 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -8,11 +8,16 @@ #include #include +#include "../../model/doc/document.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/world/idtree.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" #include "../../model/world/refcollection.hpp" #include "../../model/world/pathgrid.hpp" +#include "../../model/world/commands.hpp" +#include "../../model/world/pathgridpointswrap.hpp" +#include "../../model/world/nestedtableproxymodel.hpp" #include "../world/physicssystem.hpp" #include "elements.hpp" @@ -92,7 +97,7 @@ bool CSVRender::Cell::addObjects (int start, int end) { bool modified = false; - const CSMWorld::RefCollection& collection = mData.getReferences(); + const CSMWorld::RefCollection& collection = mDocument.getData().getReferences(); for (int i=start; i<=end; ++i) { @@ -104,7 +109,7 @@ bool CSVRender::Cell::addObjects (int start, int end) { std::string id = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mId); - mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics))); + mObjects.insert (std::make_pair (id, new Object (mDocument.getData(), mCellNode, id, false, mPhysics))); modified = true; } } @@ -112,29 +117,29 @@ bool CSVRender::Cell::addObjects (int start, int end) return modified; } -CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, +CSVRender::Cell::Cell (CSMDoc::Document& document, Ogre::SceneManager *sceneManager, const std::string& id, boost::shared_ptr physics, const Ogre::Vector3& origin) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics), mX(0), mY(0), - mPathgridId("") +: mDocument (document), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager) +, mPhysics(physics), mX(0), mY(0), mPgIndex(-1), mModel(0), mProxyModel(0)// ,mPathgridId("") { mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode->setPosition (origin); CSMWorld::IdTable& references = dynamic_cast ( - *mData.getTableModel (CSMWorld::UniversalId::Type_References)); + *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_References)); int rows = references.rowCount(); addObjects (0, rows-1); - const CSMWorld::IdCollection& land = mData.getLand(); + const CSMWorld::IdCollection& land = mDocument.getData().getLand(); int landIndex = land.searchId(mId); if (landIndex != -1) { const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT) { - mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true, + mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mDocument.getData()), Element_Terrain, true, Terrain::Align_XY)); mTerrain->loadCell(esmLand->mX, esmLand->mY); @@ -174,6 +179,8 @@ CSVRender::Cell::~Cell() delete iter->second; } + delete mProxyModel; + if (mTerrain.get()) mPhysics->removeHeightField(mSceneMgr, mX, mY); @@ -217,7 +224,7 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { CSMWorld::IdTable& references = dynamic_cast ( - *mData.getTableModel (CSMWorld::UniversalId::Type_References)); + *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_References)); int idColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Id); int cellColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Cell); @@ -269,7 +276,7 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, for (std::map::iterator iter (ids.begin()); iter!=ids.end(); ++iter) { mObjects.insert (std::make_pair ( - iter->first, new Object (mData, mCellNode, iter->first, false, mPhysics))); + iter->first, new Object (mDocument.getData(), mCellNode, iter->first, false, mPhysics))); modified = true; } @@ -284,7 +291,7 @@ bool CSVRender::Cell::referenceAboutToBeRemoved (const QModelIndex& parent, int return false; CSMWorld::IdTable& references = dynamic_cast ( - *mData.getTableModel (CSMWorld::UniversalId::Type_References)); + *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_References)); int idColumn = references.findColumnIndex (CSMWorld::Columns::ColumnId_Id); @@ -323,14 +330,22 @@ void CSVRender::Cell::loadPathgrid() { int worldsize = ESM::Land::REAL_SIZE; - CSMWorld::SubCellCollection& pathgridCollection = mData.getPathgrids(); - int index = pathgridCollection.searchId(mId); + const CSMWorld::SubCellCollection& pathgrids = mDocument.getData().getPathgrids(); + int index = pathgrids.searchId(mId); if(index != -1) { - const CSMWorld::Pathgrid &pathgrid = pathgridCollection.getRecord(index).get(); - mPathgridId = pathgrid.mId; // FIXME: temporary storage (should be document) + mPgIndex = index; // keep a copy to save from searching mId all the time + + int col = pathgrids.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridPoints); + + mModel = dynamic_cast( + mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Pathgrid)); + + mProxyModel = new CSMWorld::NestedTableProxyModel (mModel->index(mPgIndex, col), + CSMWorld::ColumnBase::Display_NestedHeader, mModel); + + const CSMWorld::Pathgrid &pathgrid = pathgrids.getRecord(index).get(); - mPoints.resize(pathgrid.mPoints.size()); std::vector::const_iterator iter = pathgrid.mPoints.begin(); for(index = 0; iter != pathgrid.mPoints.end(); ++iter, ++index) { @@ -340,7 +355,6 @@ void CSVRender::Cell::loadPathgrid() Ogre::Vector3(worldsize*mX+(*iter).mX, worldsize*mY+(*iter).mY, (*iter).mZ); mPgPoints.insert(std::make_pair(name, new PathgridPoint(name, mCellNode, pos, mPhysics))); - mPoints[index] = *iter; // FIXME: temporary storage (should be document) } for(ESM::Pathgrid::EdgeList::const_iterator it = pathgrid.mEdges.begin(); @@ -363,16 +377,17 @@ void CSVRender::Cell::loadPathgrid() node->attachObject(line); mPgEdges.insert(std::make_pair(std::make_pair(edge.mV0, edge.mV1), name)); - mEdges.push_back(*it); // FIXME: temporary storage (should be document) } } } // NOTE: pos is in world coordinates -// FIXME: save to the document void CSVRender::Cell::pathgridPointAdded(const Ogre::Vector3 &pos, bool interior) { - std::string name = PathgridPoint::getName(mId, mPoints.size()); + const CSMWorld::SubCellCollection& pathgrids = mDocument.getData().getPathgrids(); + CSMWorld::Pathgrid pathgrid = pathgrids.getRecord(mPgIndex).get(); + + std::string name = PathgridPoint::getName(mId, pathgrid.mPoints.size()); // generate a new name mPgPoints.insert(std::make_pair(name, new PathgridPoint(name, mCellNode, pos, mPhysics))); @@ -389,12 +404,18 @@ void CSVRender::Cell::pathgridPointAdded(const Ogre::Vector3 &pos, bool interior ESM::Pathgrid::Point point(x, y, (int)pos.z); point.mConnectionNum = 0; - mPoints.push_back(point); - mPathgridId = mId; + pathgrid.mPoints.push_back(point); // FIXME: update other scene managers + + pathgrid.mData.mS2 += 1; // increment the number of points + + // FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards + mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel, + mProxyModel->getParentId(), mProxyModel->getParentColumn(), + new CSMWorld::PathgridPointsWrap(pathgrid))); + // emit signal here? } -// FIXME: save to the document void CSVRender::Cell::pathgridPointRemoved(const std::string &name) { std::pair result = PathgridPoint::getIdAndIndex(name); @@ -404,18 +425,21 @@ void CSVRender::Cell::pathgridPointRemoved(const std::string &name) std::string pathgridId = result.first; int index = result.second; + const CSMWorld::SubCellCollection& pathgrids = mDocument.getData().getPathgrids(); + CSMWorld::Pathgrid pathgrid = pathgrids.getRecord(mPgIndex).get(); + // check if the point exists - if(index < 0 || mPathgridId != pathgridId || (unsigned int)index >= mPoints.size()) + if(index < 0 || (unsigned int)index >= pathgrid.mPoints.size()) return; - int numToDelete = mPoints[index].mConnectionNum * 2; // for sanity check later + int numToDelete = pathgrid.mPoints[index].mConnectionNum * 2; // for sanity check later int edgeCount = 0; // find edges to delete std::vector > edges; - for(unsigned i = 0; i < mEdges.size(); ++i) + for(unsigned i = 0; i < pathgrid.mEdges.size(); ++i) { - if(mEdges[i].mV0 == index || mEdges[i].mV1 == index) + if(pathgrid.mEdges[i].mV0 == index || pathgrid.mEdges[i].mV1 == index) { for(std::map, std::string>::iterator iter = mPgEdges.begin(); iter != mPgEdges.end(); ++iter) @@ -448,12 +472,12 @@ void CSVRender::Cell::pathgridPointRemoved(const std::string &name) mPgEdges.erase(*iter); // update document - assert(mPoints[(*iter).first].mConnectionNum > 0); - mPoints[(*iter).first].mConnectionNum -= 1; - for(unsigned i = mEdges.size() - 1; i > 0; --i) + assert(pathgrid.mPoints[(*iter).first].mConnectionNum > 0); + pathgrid.mPoints[(*iter).first].mConnectionNum -= 1; + for(unsigned i = pathgrid.mEdges.size() - 1; i > 0; --i) { - if(mEdges[i].mV0 == index || mEdges[i].mV1 == index) - mEdges.erase(mEdges.begin() + i); + if(pathgrid.mEdges[i].mV0 == index || pathgrid.mEdges[i].mV1 == index) + pathgrid.mEdges.erase(pathgrid.mEdges.begin() + i); } } } @@ -462,10 +486,10 @@ void CSVRender::Cell::pathgridPointRemoved(const std::string &name) { // WARNING: continue anyway? Or should this be an exception? std::cerr << "The no of edges del does not match the no of conn for: " - << mPathgridId + "_" + QString::number(index).toStdString() << std::endl; + << pathgridId + "_" + QString::number(index).toStdString() << std::endl; } - if(edgeCount || mPoints[index].mConnectionNum == 0) + if(edgeCount || pathgrid.mPoints[index].mConnectionNum == 0) { // remove the point delete mPgPoints[name]; @@ -477,6 +501,13 @@ void CSVRender::Cell::pathgridPointRemoved(const std::string &name) //mPoints.erase(mPoints.begin() + index); // WARNING: Can't erase because the index will change // FIXME: it should be possible to refresh indicies but that means index values // can't be stored in maps, names, etc + + + + + // FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards + mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel, + mProxyModel->getParentId(), mProxyModel->getParentColumn(), new CSMWorld::PathgridPointsWrap(pathgrid))); } // NOTE: newPos is in world coordinates @@ -490,8 +521,11 @@ void CSVRender::Cell::pathgridPointMoved(const std::string &name, std::string pathgridId = result.first; int index = result.second; + const CSMWorld::SubCellCollection& pathgrids = mDocument.getData().getPathgrids(); + CSMWorld::Pathgrid pathgrid = pathgrids.getRecord(mPgIndex).get(); + // check if the point exists - if(index < 0 || mPathgridId != pathgridId || (unsigned int)index >= mPoints.size()) + if(index < 0 || (unsigned int)index >= pathgrid.mPoints.size()) return; int worldsize = ESM::Land::REAL_SIZE; @@ -504,17 +538,17 @@ void CSVRender::Cell::pathgridPointMoved(const std::string &name, y = y - (worldsize * mY); } - mPoints[index].mX = x; - mPoints[index].mY = y; - mPoints[index].mZ = newPos.z; + pathgrid.mPoints[index].mX = x; + pathgrid.mPoints[index].mY = y; + pathgrid.mPoints[index].mZ = newPos.z; // delete then recreate the edges - for(unsigned i = 0; i < mEdges.size(); ++i) + for(unsigned i = 0; i < pathgrid.mEdges.size(); ++i) { - if(mEdges[i].mV0 == index || mEdges[i].mV1 == index) + if(pathgrid.mEdges[i].mV0 == index || pathgrid.mEdges[i].mV1 == index) { std::ostringstream stream; - stream << pathgridId << "_" << mEdges[i].mV0 << " " << mEdges[i].mV1; + stream << pathgridId << "_" << pathgrid.mEdges[i].mV0 << " " << pathgrid.mEdges[i].mV1; std::string name = stream.str(); if(mSceneMgr->hasManualObject(name)) @@ -524,9 +558,9 @@ void CSVRender::Cell::pathgridPointMoved(const std::string &name, Ogre::SceneNode *node = manual->getParentSceneNode(); mSceneMgr->destroyManualObject(name); - if(mEdges[i].mV0 == index) + if(pathgrid.mEdges[i].mV0 == index) { - const ESM::Pathgrid::Point &p1 = mPoints[mEdges[i].mV1]; + const ESM::Pathgrid::Point &p1 = pathgrid.mPoints[pathgrid.mEdges[i].mV1]; Ogre::ManualObject *line = createPathgridEdge(name, newPos, @@ -534,9 +568,9 @@ void CSVRender::Cell::pathgridPointMoved(const std::string &name, line->setVisibilityFlags(Element_Pathgrid); node->attachObject(line); } - else if(mEdges[i].mV1 == index) + else if(pathgrid.mEdges[i].mV1 == index) { - const ESM::Pathgrid::Point &p0 = mPoints[mEdges[i].mV0]; + const ESM::Pathgrid::Point &p0 = pathgrid.mPoints[pathgrid.mEdges[i].mV0]; Ogre::ManualObject *line = createPathgridEdge(name, Ogre::Vector3(worldsize*mX+p0.mX, worldsize*mY+p0.mY, p0.mZ), @@ -547,6 +581,11 @@ void CSVRender::Cell::pathgridPointMoved(const std::string &name, } } } + + // FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards + mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel, + mProxyModel->getParentId(), mProxyModel->getParentColumn(), + new CSMWorld::PathgridPointsWrap(pathgrid))); } // FIXME: save to the document diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 0afd0920b..2658ff1ad 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -25,10 +25,17 @@ namespace Ogre class ManualObject; } +namespace CSMDoc +{ + class Document; +} + namespace CSMWorld { - class Data; + //class Data; class Pathgrid; + class NestedTableProxyModel; + class IdTree; } namespace CSVWorld @@ -42,16 +49,16 @@ namespace CSVRender class Cell { - CSMWorld::Data& mData; + CSMDoc::Document& mDocument; std::string mId; Ogre::SceneNode *mCellNode; std::map mObjects; std::map mPgPoints; std::map, std::string> mPgEdges; - ESM::Pathgrid::PointList mPoints; // FIXME: temporary storage until saving to document - ESM::Pathgrid::EdgeList mEdges; // FIXME: temporary storage until saving to document - std::string mPathgridId; // FIXME: temporary storage until saving to document + CSMWorld::NestedTableProxyModel *mProxyModel; + CSMWorld::IdTree *mModel; + int mPgIndex; std::auto_ptr mTerrain; boost::shared_ptr mPhysics; @@ -71,7 +78,7 @@ namespace CSVRender public: - Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, + Cell (CSMDoc::Document& document, Ogre::SceneManager *sceneManager, const std::string& id, boost::shared_ptr physics, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); ~Cell(); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 9c42e471e..cc00b9159 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -113,7 +113,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() if (index > 0 && cells.getRecord (index).mState!=CSMWorld::RecordBase::State_Deleted && mCells.find (*iter)==mCells.end()) { - Cell *cell = new Cell (mDocument.getData(), getSceneManager(), + Cell *cell = new Cell (mDocument, getSceneManager(), iter->getId (mWorldspace), mDocument.getPhysics()); mCells.insert (std::make_pair (*iter, cell)); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 237bfabf5..b5e9504f3 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -49,7 +49,7 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& update(); - mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, document.getPhysics())); + mCell.reset (new Cell (document, getSceneManager(), mCellId, document.getPhysics())); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, @@ -91,7 +91,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); - mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getDocument().getPhysics())); + mCell.reset (new Cell (getDocument(), getSceneManager(), mCellId, getDocument().getPhysics())); update(); emit cellChanged(*data.begin()); From 1a31aecc2f1eb3599922e5b1595f982847edd723 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 23 Apr 2015 22:20:45 +1000 Subject: [PATCH 25/29] Undo rendering works, but not using signals yet. --- apps/opencs/model/world/commands.cpp | 9 +- apps/opencs/model/world/commands.hpp | 9 +- apps/opencs/view/render/cell.cpp | 264 +++++++++------------- apps/opencs/view/render/cell.hpp | 8 +- apps/opencs/view/render/pathgridpoint.cpp | 3 - 5 files changed, 127 insertions(+), 166 deletions(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 11a675db0..172211d7b 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -6,6 +6,7 @@ #include "idtree.hpp" #include #include "nestedtablewrapper.hpp" +#include "../../view/render/cell.hpp" CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) @@ -248,8 +249,9 @@ const CSMWorld::NestedTableWrapperBase& CSMWorld::NestedTableStoring::getOld() c // Current interface does not allow adding a non-blank row, so we're forced to modify // the whole record. CSMWorld::ModifyPathgridCommand::ModifyPathgridCommand(IdTree& model, - const std::string& id, int parentColumn, NestedTableWrapperBase* newRecord, QUndoCommand* parent) - : mModel(model), mId(id), mParentColumn(parentColumn), mRecord(newRecord) + const std::string& id, int parentColumn, CSVRender::Cell *cell, + NestedTableWrapperBase* newRecord, QUndoCommand* parent) + : mModel(model), mId(id), mParentColumn(parentColumn), mRecord(newRecord), mCell(cell) , QUndoCommand(parent), NestedTableStoring(model, id, parentColumn) { setText (("Modify Pathgrid record " + mId).c_str()); // FIXME: better description @@ -268,5 +270,6 @@ void CSMWorld::ModifyPathgridCommand::undo() mModel.setNestedTable(parentIndex, getOld()); - // FIXME: needs to tell the cell to redraw, possibly using signals + mCell->clearPathgrid(); + mCell->buildPathgrid(); } diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 4e4de25c7..8661f987a 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -17,6 +17,11 @@ class QModelIndex; class QAbstractItemModel; +namespace CSVRender +{ + class Cell; +} + namespace CSMWorld { class IdTable; @@ -204,11 +209,13 @@ namespace CSMWorld int mParentColumn; NestedTableWrapperBase* mRecord; + CSVRender::Cell *mCell; public: // if newEdges is NULL, only the paths are updated - ModifyPathgridCommand(IdTree& model, const std::string& id, int parentColumn, + ModifyPathgridCommand(IdTree& model, + const std::string& id, int parentColumn, CSVRender::Cell *cell, NestedTableWrapperBase* newRecord, QUndoCommand* parent = 0); virtual void redo(); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 698912344..87f70b48e 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -120,7 +120,7 @@ bool CSVRender::Cell::addObjects (int start, int end) CSVRender::Cell::Cell (CSMDoc::Document& document, Ogre::SceneManager *sceneManager, const std::string& id, boost::shared_ptr physics, const Ogre::Vector3& origin) : mDocument (document), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager) -, mPhysics(physics), mX(0), mY(0), mPgIndex(-1), mModel(0), mProxyModel(0)// ,mPathgridId("") +, mPhysics(physics), mX(0), mY(0), mPgIndex(-1), mModel(0), mProxyModel(0) { mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode->setPosition (origin); @@ -153,32 +153,15 @@ CSVRender::Cell::Cell (CSMDoc::Document& document, Ogre::SceneManager *sceneMana } } - loadPathgrid(); + setupPathgrid(); + buildPathgrid(); } CSVRender::Cell::~Cell() { - // destroy manual objects - for(std::map, std::string>::iterator iter = mPgEdges.begin(); - iter != mPgEdges.end(); ++iter) - { - if(mSceneMgr->hasManualObject((*iter).second)) - { - Ogre::ManualObject *manual = mSceneMgr->getManualObject((*iter).second); - Ogre::SceneNode *node = manual->getParentSceneNode(); - mSceneMgr->destroyManualObject((*iter).second); - if(mSceneMgr->hasSceneNode(node->getName())) - mSceneMgr->destroySceneNode(node); - } - } + clearPathgrid(); destroyGridMaterials(); - for(std::map::iterator iter (mPgPoints.begin()); - iter!=mPgPoints.end(); ++iter) - { - delete iter->second; - } - delete mProxyModel; if (mTerrain.get()) @@ -322,62 +305,101 @@ float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const } // FIXME: -// - updating indicies, including mData // - adding edges (need the ability to select a pathgrid and highlight) // - save to document & signals // - repainting edges while moving -void CSVRender::Cell::loadPathgrid() +void CSVRender::Cell::setupPathgrid() { - int worldsize = ESM::Land::REAL_SIZE; - const CSMWorld::SubCellCollection& pathgrids = mDocument.getData().getPathgrids(); int index = pathgrids.searchId(mId); if(index != -1) { - mPgIndex = index; // keep a copy to save from searching mId all the time - int col = pathgrids.findColumnIndex(CSMWorld::Columns::ColumnId_PathgridPoints); + mPgIndex = index; // keep a copy to save from searching mId all the time + mModel = dynamic_cast( mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Pathgrid)); mProxyModel = new CSMWorld::NestedTableProxyModel (mModel->index(mPgIndex, col), CSMWorld::ColumnBase::Display_NestedHeader, mModel); - const CSMWorld::Pathgrid &pathgrid = pathgrids.getRecord(index).get(); + } +} - std::vector::const_iterator iter = pathgrid.mPoints.begin(); - for(index = 0; iter != pathgrid.mPoints.end(); ++iter, ++index) +void CSVRender::Cell::clearPathgrid() +{ + // destroy manual objects (edges) + for(std::map, std::string>::iterator iter = mPgEdges.begin(); + iter != mPgEdges.end(); ++iter) + { + if(mSceneMgr->hasManualObject((*iter).second)) { - std::string name = PathgridPoint::getName(pathgrid.mId, index); - - Ogre::Vector3 pos = - Ogre::Vector3(worldsize*mX+(*iter).mX, worldsize*mY+(*iter).mY, (*iter).mZ); - - mPgPoints.insert(std::make_pair(name, new PathgridPoint(name, mCellNode, pos, mPhysics))); + Ogre::ManualObject *manual = mSceneMgr->getManualObject((*iter).second); + Ogre::SceneNode *node = manual->getParentSceneNode(); + mSceneMgr->destroyManualObject((*iter).second); + if(mSceneMgr->hasSceneNode(node->getName())) + mSceneMgr->destroySceneNode(node); } + } + mPgEdges.clear(); - for(ESM::Pathgrid::EdgeList::const_iterator it = pathgrid.mEdges.begin(); - it != pathgrid.mEdges.end(); - ++it) - { - Ogre::SceneNode *node = mCellNode->createChildSceneNode(); - const ESM::Pathgrid::Edge &edge = *it; - const ESM::Pathgrid::Point &p0 = pathgrid.mPoints[edge.mV0]; - const ESM::Pathgrid::Point &p1 = pathgrid.mPoints[edge.mV1]; + // destroy points + for(std::map::iterator iter (mPgPoints.begin()); + iter!=mPgPoints.end(); ++iter) + { + delete iter->second; + } + mPgPoints.clear(); +} - std::ostringstream stream; - stream << pathgrid.mId << "_" << edge.mV0 << " " << edge.mV1; - std::string name = stream.str(); +// NOTE: getName() generates a string representation of mId+index to uniquely identify a +// pathgrid point. The trouble is that the index can change when a pathgrid point is deleted. +// Need a new way of uniquely identifying a pathgrid point. +// +// A workaround is to re-generate the pathgrids and edges each time a point is deleted or +// undo() is called (probably via a signal) +void CSVRender::Cell::buildPathgrid() +{ + if (!mModel) + return; - Ogre::ManualObject *line = createPathgridEdge(name, - Ogre::Vector3(worldsize*mX+p0.mX, worldsize*mY+p0.mY, p0.mZ), - Ogre::Vector3(worldsize*mX+p1.mX, worldsize*mY+p1.mY, p1.mZ)); - line->setVisibilityFlags(Element_Pathgrid); - node->attachObject(line); + const CSMWorld::SubCellCollection& pathgrids = mDocument.getData().getPathgrids(); + const CSMWorld::Pathgrid &pathgrid = pathgrids.getRecord(mPgIndex).get(); - mPgEdges.insert(std::make_pair(std::make_pair(edge.mV0, edge.mV1), name)); - } + int worldsize = ESM::Land::REAL_SIZE; + + std::vector::const_iterator iter = pathgrid.mPoints.begin(); + for(int index = 0; iter != pathgrid.mPoints.end(); ++iter, ++index) + { + std::string name = PathgridPoint::getName(pathgrid.mId, index); + + Ogre::Vector3 pos = + Ogre::Vector3(worldsize*mX+(*iter).mX, worldsize*mY+(*iter).mY, (*iter).mZ); + + mPgPoints.insert(std::make_pair(name, new PathgridPoint(name, mCellNode, pos, mPhysics))); + } + + for(ESM::Pathgrid::EdgeList::const_iterator it = pathgrid.mEdges.begin(); + it != pathgrid.mEdges.end(); + ++it) + { + Ogre::SceneNode *node = mCellNode->createChildSceneNode(); + const ESM::Pathgrid::Edge &edge = *it; + const ESM::Pathgrid::Point &p0 = pathgrid.mPoints[edge.mV0]; + const ESM::Pathgrid::Point &p1 = pathgrid.mPoints[edge.mV1]; + + std::ostringstream stream; + stream << pathgrid.mId << "_" << edge.mV0 << " " << edge.mV1; + std::string name = stream.str(); + + Ogre::ManualObject *line = createPathgridEdge(name, + Ogre::Vector3(worldsize*mX+p0.mX, worldsize*mY+p0.mY, p0.mZ), + Ogre::Vector3(worldsize*mX+p1.mX, worldsize*mY+p1.mY, p1.mZ)); + line->setVisibilityFlags(Element_Pathgrid); + node->attachObject(line); + + mPgEdges.insert(std::make_pair(std::make_pair(edge.mV0, edge.mV1), name)); } } @@ -411,7 +433,7 @@ void CSVRender::Cell::pathgridPointAdded(const Ogre::Vector3 &pos, bool interior // FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel, - mProxyModel->getParentId(), mProxyModel->getParentColumn(), + mProxyModel->getParentId(), mProxyModel->getParentColumn(), this, new CSMWorld::PathgridPointsWrap(pathgrid))); // emit signal here? } @@ -433,81 +455,46 @@ void CSVRender::Cell::pathgridPointRemoved(const std::string &name) return; int numToDelete = pathgrid.mPoints[index].mConnectionNum * 2; // for sanity check later - int edgeCount = 0; + int deletedEdgeCount = 0; - // find edges to delete - std::vector > edges; - for(unsigned i = 0; i < pathgrid.mEdges.size(); ++i) + // update edge indicies to account for the deleted pathgrid point + std::vector::iterator iter = pathgrid.mEdges.begin(); + for (; iter != pathgrid.mEdges.end();) { - if(pathgrid.mEdges[i].mV0 == index || pathgrid.mEdges[i].mV1 == index) + if (((*iter).mV0 == index) || ((*iter).mV1 == index)) { - for(std::map, std::string>::iterator iter = mPgEdges.begin(); - iter != mPgEdges.end(); ++iter) - { - if((*iter).first.first == index || (*iter).first.second == index) - { - edges.push_back(std::make_pair((*iter).first.first, (*iter).first.second)); - } - } + iter = pathgrid.mEdges.erase(iter); + pathgrid.mPoints[index].mConnectionNum -= 1; + deletedEdgeCount++; // for sanity check later + } + else + { + if ((*iter).mV0 > index) + (*iter).mV0--; + + if ((*iter).mV1 > index) + (*iter).mV1--; + + ++iter; } } + pathgrid.mPoints.erase(pathgrid.mPoints.begin()+index); + pathgrid.mData.mS2 -= 1; // decrement the number of points - // delete the edges - for(std::vector >::iterator iter = edges.begin(); - iter != edges.end(); ++iter) - { - std::string name = mPgEdges[*iter]; - if(mSceneMgr->hasManualObject(name)) - { - // remove manual objects - Ogre::ManualObject *manual = mSceneMgr->getManualObject(name); - Ogre::SceneNode *node = manual->getParentSceneNode(); - mSceneMgr->destroyManualObject(name); - if(mSceneMgr->hasSceneNode(node->getName())) - mSceneMgr->destroySceneNode(node); - - edgeCount++; // for sanity check later - - // update map - mPgEdges.erase(*iter); - - // update document - assert(pathgrid.mPoints[(*iter).first].mConnectionNum > 0); - pathgrid.mPoints[(*iter).first].mConnectionNum -= 1; - for(unsigned i = pathgrid.mEdges.size() - 1; i > 0; --i) - { - if(pathgrid.mEdges[i].mV0 == index || pathgrid.mEdges[i].mV1 == index) - pathgrid.mEdges.erase(pathgrid.mEdges.begin() + i); - } - } - } - - if(edgeCount != numToDelete) + if(deletedEdgeCount != numToDelete) { // WARNING: continue anyway? Or should this be an exception? std::cerr << "The no of edges del does not match the no of conn for: " << pathgridId + "_" + QString::number(index).toStdString() << std::endl; } - if(edgeCount || pathgrid.mPoints[index].mConnectionNum == 0) - { - // remove the point - delete mPgPoints[name]; - mPgPoints.erase(name); - // FIXME: update other scene managers - } - - // store to document - //mPoints.erase(mPoints.begin() + index); // WARNING: Can't erase because the index will change - // FIXME: it should be possible to refresh indicies but that means index values - // can't be stored in maps, names, etc - - - - // FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel, - mProxyModel->getParentId(), mProxyModel->getParentColumn(), new CSMWorld::PathgridPointsWrap(pathgrid))); + mProxyModel->getParentId(), mProxyModel->getParentColumn(), this, + new CSMWorld::PathgridPointsWrap(pathgrid))); + + clearPathgrid(); + buildPathgrid(); } // NOTE: newPos is in world coordinates @@ -542,50 +529,13 @@ void CSVRender::Cell::pathgridPointMoved(const std::string &name, pathgrid.mPoints[index].mY = y; pathgrid.mPoints[index].mZ = newPos.z; - // delete then recreate the edges - for(unsigned i = 0; i < pathgrid.mEdges.size(); ++i) - { - if(pathgrid.mEdges[i].mV0 == index || pathgrid.mEdges[i].mV1 == index) - { - std::ostringstream stream; - stream << pathgridId << "_" << pathgrid.mEdges[i].mV0 << " " << pathgrid.mEdges[i].mV1; - std::string name = stream.str(); - - if(mSceneMgr->hasManualObject(name)) - { - // remove manual objects - Ogre::ManualObject *manual = mSceneMgr->getManualObject(name); - Ogre::SceneNode *node = manual->getParentSceneNode(); - mSceneMgr->destroyManualObject(name); - - if(pathgrid.mEdges[i].mV0 == index) - { - const ESM::Pathgrid::Point &p1 = pathgrid.mPoints[pathgrid.mEdges[i].mV1]; - - Ogre::ManualObject *line = createPathgridEdge(name, - newPos, - Ogre::Vector3(worldsize*mX+p1.mX, worldsize*mY+p1.mY, p1.mZ)); - line->setVisibilityFlags(Element_Pathgrid); - node->attachObject(line); - } - else if(pathgrid.mEdges[i].mV1 == index) - { - const ESM::Pathgrid::Point &p0 = pathgrid.mPoints[pathgrid.mEdges[i].mV0]; - - Ogre::ManualObject *line = createPathgridEdge(name, - Ogre::Vector3(worldsize*mX+p0.mX, worldsize*mY+p0.mY, p0.mZ), - newPos); - line->setVisibilityFlags(Element_Pathgrid); - node->attachObject(line); - } - } - } - } - // FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel, - mProxyModel->getParentId(), mProxyModel->getParentColumn(), + mProxyModel->getParentId(), mProxyModel->getParentColumn(), this, new CSMWorld::PathgridPointsWrap(pathgrid))); + + clearPathgrid(); + buildPathgrid(); } // FIXME: save to the document diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 2658ff1ad..fac4ded59 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -11,7 +11,6 @@ #ifndef Q_MOC_RUN #include -#include // FIXME: temporaty storage until saving to document #endif #include "object.hpp" @@ -116,12 +115,17 @@ namespace CSVRender // for drawing pathgrid points & lines void createGridMaterials(); void destroyGridMaterials(); - void loadPathgrid(); + void setupPathgrid(); Ogre::ManualObject *createPathgridEdge(const std::string &name, const Ogre::Vector3 &start, const Ogre::Vector3 &end); void addPathgridEdge(); void removePathgridEdge(); + + public: + + void clearPathgrid(); + void buildPathgrid(); }; } diff --git a/apps/opencs/view/render/pathgridpoint.cpp b/apps/opencs/view/render/pathgridpoint.cpp index 85b03beea..ea6815fbe 100644 --- a/apps/opencs/view/render/pathgridpoint.cpp +++ b/apps/opencs/view/render/pathgridpoint.cpp @@ -1,13 +1,10 @@ #include "pathgridpoint.hpp" -#include // FIXME - #include #include #include -//#include "../../model/world/pathgrid.hpp" #include "../world/physicssystem.hpp" #include "elements.hpp" From e7bd29873922d8788422e3da83cd3a668feeb0c3 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 24 Apr 2015 01:28:49 +1000 Subject: [PATCH 26/29] Undo now working via signals. --- apps/opencs/CMakeLists.txt | 3 +- apps/opencs/model/world/commands.cpp | 29 --------- apps/opencs/model/world/commands.hpp | 29 +-------- apps/opencs/model/world/pathgridcommands.cpp | 48 ++++++++++++++ apps/opencs/model/world/pathgridcommands.hpp | 65 +++++++++++++++++++ apps/opencs/view/render/cell.cpp | 42 ++++++++---- apps/opencs/view/render/cell.hpp | 4 +- .../view/render/pagedworldspacewidget.cpp | 7 ++ .../view/render/pagedworldspacewidget.hpp | 1 + .../view/render/unpagedworldspacewidget.cpp | 14 +++- .../view/render/unpagedworldspacewidget.hpp | 2 + 11 files changed, 169 insertions(+), 75 deletions(-) create mode 100644 apps/opencs/model/world/pathgridcommands.cpp create mode 100644 apps/opencs/model/world/pathgridcommands.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5822b433a..35d5e5d3c 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -18,7 +18,8 @@ opencs_hdrs_noqt (model/doc opencs_units (model/world - idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree + idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable + nestedtableproxymodel idtree pathgridcommands ) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index 172211d7b..d12c5d228 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -6,7 +6,6 @@ #include "idtree.hpp" #include #include "nestedtablewrapper.hpp" -#include "../../view/render/cell.hpp" CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index, const QVariant& new_, QUndoCommand* parent) @@ -245,31 +244,3 @@ const CSMWorld::NestedTableWrapperBase& CSMWorld::NestedTableStoring::getOld() c { return *mOld; } - -// Current interface does not allow adding a non-blank row, so we're forced to modify -// the whole record. -CSMWorld::ModifyPathgridCommand::ModifyPathgridCommand(IdTree& model, - const std::string& id, int parentColumn, CSVRender::Cell *cell, - NestedTableWrapperBase* newRecord, QUndoCommand* parent) - : mModel(model), mId(id), mParentColumn(parentColumn), mRecord(newRecord), mCell(cell) - , QUndoCommand(parent), NestedTableStoring(model, id, parentColumn) -{ - setText (("Modify Pathgrid record " + mId).c_str()); // FIXME: better description -} - -void CSMWorld::ModifyPathgridCommand::redo() -{ - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - - mModel.setNestedTable(parentIndex, *mRecord); -} - -void CSMWorld::ModifyPathgridCommand::undo() -{ - const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); - - mModel.setNestedTable(parentIndex, getOld()); - - mCell->clearPathgrid(); - mCell->buildPathgrid(); -} diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 8661f987a..0cd8a00f8 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -12,16 +12,11 @@ #include #include "universalid.hpp" -#include "nestedtablewrapper.hpp" +//#include "nestedtablewrapper.hpp" class QModelIndex; class QAbstractItemModel; -namespace CSVRender -{ - class Cell; -} - namespace CSMWorld { class IdTable; @@ -200,28 +195,6 @@ namespace CSMWorld virtual void undo(); }; - - class ModifyPathgridCommand : public QUndoCommand, private NestedTableStoring - { - IdTree& mModel; - std::string mId; - - int mParentColumn; - - NestedTableWrapperBase* mRecord; - CSVRender::Cell *mCell; - - public: - - // if newEdges is NULL, only the paths are updated - ModifyPathgridCommand(IdTree& model, - const std::string& id, int parentColumn, CSVRender::Cell *cell, - NestedTableWrapperBase* newRecord, QUndoCommand* parent = 0); - - virtual void redo(); - - virtual void undo(); - }; } #endif diff --git a/apps/opencs/model/world/pathgridcommands.cpp b/apps/opencs/model/world/pathgridcommands.cpp new file mode 100644 index 000000000..356806dcd --- /dev/null +++ b/apps/opencs/model/world/pathgridcommands.cpp @@ -0,0 +1,48 @@ +#include "pathgridcommands.hpp" + +#include "../../view/render/cell.hpp" +#include "idtree.hpp" +#include "nestedtablewrapper.hpp" + +// Current interface does not allow adding a non-blank row, so we're forced to modify +// the whole record. +CSMWorld::ModifyPathgridCommand::ModifyPathgridCommand(IdTree& model, + const std::string& id, int parentColumn, NestedTableWrapperBase* newRecord, QUndoCommand* parent) + : mModel(model), mId(id), mParentColumn(parentColumn), mRecord(newRecord) + , QUndoCommand(parent), NestedTableStoring(model, id, parentColumn) +{ + setText (("Modify Pathgrid record " + mId).c_str()); // FIXME: better description +} + +void CSMWorld::ModifyPathgridCommand::redo() +{ + const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); + + mModel.setNestedTable(parentIndex, *mRecord); +} + +void CSMWorld::ModifyPathgridCommand::undo() +{ + const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn); + + mModel.setNestedTable(parentIndex, getOld()); + + emit undoActioned(); +} + +void CSMWorld::SignalHandler::rebuildPathgrid() +{ + mParent->clearPathgrid(); + mParent->buildPathgrid(); + + emit flagAsModified(); +} + +CSMWorld::SignalHandler::SignalHandler (CSVRender::Cell *parent) : mParent(parent) +{} + +void CSMWorld::SignalHandler::connectToCommand(const CSMWorld::ModifyPathgridCommand *command) +{ + connect (command, SIGNAL(undoActioned()), + this, SLOT(rebuildPathgrid())); +} diff --git a/apps/opencs/model/world/pathgridcommands.hpp b/apps/opencs/model/world/pathgridcommands.hpp new file mode 100644 index 000000000..335e3a893 --- /dev/null +++ b/apps/opencs/model/world/pathgridcommands.hpp @@ -0,0 +1,65 @@ +#ifndef CSM_WOLRD_PATHGRIDCOMMANDS_H +#define CSM_WOLRD_PATHGRIDCOMMANDS_H + +#include + +#include "commands.hpp" + +namespace CSVRender +{ + class Cell; +} + +namespace CSMWorld +{ + class IdTree; + class NestedTableWrapperBase; + + class ModifyPathgridCommand : public QObject, public QUndoCommand, private NestedTableStoring + { + Q_OBJECT + + IdTree& mModel; + std::string mId; + + int mParentColumn; + + NestedTableWrapperBase* mRecord; + + public: + + ModifyPathgridCommand(IdTree& model, + const std::string& id, int parentColumn, NestedTableWrapperBase* newRecord, + QUndoCommand* parent = 0); + + virtual void redo(); + + virtual void undo(); + + signals: + + void undoActioned(); + }; + + class SignalHandler : public QObject + { + Q_OBJECT + + CSVRender::Cell *mParent; + + public: + + SignalHandler (CSVRender::Cell *parent); + + void connectToCommand(const ModifyPathgridCommand *command); + + private slots: + + void rebuildPathgrid(); + + signals: + + void flagAsModified(); + }; +} +#endif // CSM_WOLRD_PATHGRIDCOMMANDS_H diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 87f70b48e..7976fd55e 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -16,6 +16,7 @@ #include "../../model/world/refcollection.hpp" #include "../../model/world/pathgrid.hpp" #include "../../model/world/commands.hpp" +#include "../../model/world/pathgridcommands.hpp" #include "../../model/world/pathgridpointswrap.hpp" #include "../../model/world/nestedtableproxymodel.hpp" #include "../world/physicssystem.hpp" @@ -119,8 +120,9 @@ bool CSVRender::Cell::addObjects (int start, int end) CSVRender::Cell::Cell (CSMDoc::Document& document, Ogre::SceneManager *sceneManager, const std::string& id, boost::shared_ptr physics, const Ogre::Vector3& origin) -: mDocument (document), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager) -, mPhysics(physics), mX(0), mY(0), mPgIndex(-1), mModel(0), mProxyModel(0) + : mDocument (document), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager) + , mPhysics(physics), mX(0), mY(0), mPgIndex(-1), mModel(0), mProxyModel(0) + , mHandler(new CSMWorld::SignalHandler(this)) { mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode->setPosition (origin); @@ -163,6 +165,7 @@ CSVRender::Cell::~Cell() destroyGridMaterials(); delete mProxyModel; + delete mHandler; if (mTerrain.get()) mPhysics->removeHeightField(mSceneMgr, mX, mY); @@ -431,10 +434,12 @@ void CSVRender::Cell::pathgridPointAdded(const Ogre::Vector3 &pos, bool interior pathgrid.mData.mS2 += 1; // increment the number of points - // FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards - mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel, - mProxyModel->getParentId(), mProxyModel->getParentColumn(), this, - new CSMWorld::PathgridPointsWrap(pathgrid))); + // FIXME: possible issue if this cell is deleted and undo() is actioned afterwards + CSMWorld::ModifyPathgridCommand *cmd = new CSMWorld::ModifyPathgridCommand(*mModel, + mProxyModel->getParentId(), mProxyModel->getParentColumn(), + new CSMWorld::PathgridPointsWrap(pathgrid)); + mHandler->connectToCommand(cmd); + mDocument.getUndoStack().push(cmd); // emit signal here? } @@ -488,10 +493,12 @@ void CSVRender::Cell::pathgridPointRemoved(const std::string &name) << pathgridId + "_" + QString::number(index).toStdString() << std::endl; } - // FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards - mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel, - mProxyModel->getParentId(), mProxyModel->getParentColumn(), this, - new CSMWorld::PathgridPointsWrap(pathgrid))); + // FIXME: possible issue if this cell is deleted and undo() is actioned afterwards + CSMWorld::ModifyPathgridCommand *cmd = new CSMWorld::ModifyPathgridCommand(*mModel, + mProxyModel->getParentId(), mProxyModel->getParentColumn(), + new CSMWorld::PathgridPointsWrap(pathgrid)); + mHandler->connectToCommand(cmd); + mDocument.getUndoStack().push(cmd); clearPathgrid(); buildPathgrid(); @@ -529,10 +536,12 @@ void CSVRender::Cell::pathgridPointMoved(const std::string &name, pathgrid.mPoints[index].mY = y; pathgrid.mPoints[index].mZ = newPos.z; - // FIXME: probably will crash if this cell is deleted and undo() is actioned afterwards - mDocument.getUndoStack().push(new CSMWorld::ModifyPathgridCommand(*mModel, - mProxyModel->getParentId(), mProxyModel->getParentColumn(), this, - new CSMWorld::PathgridPointsWrap(pathgrid))); + // FIXME: possible issue if this cell is deleted and undo() is actioned afterwards + CSMWorld::ModifyPathgridCommand *cmd = new CSMWorld::ModifyPathgridCommand(*mModel, + mProxyModel->getParentId(), mProxyModel->getParentColumn(), + new CSMWorld::PathgridPointsWrap(pathgrid)); + mHandler->connectToCommand(cmd); + mDocument.getUndoStack().push(cmd); clearPathgrid(); buildPathgrid(); @@ -551,3 +560,8 @@ void CSVRender::Cell::addPathgridEdge() void CSVRender::Cell::removePathgridEdge() { } + +CSMWorld::SignalHandler *CSVRender::Cell::getSignalHandler() +{ + return mHandler; +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index fac4ded59..cc00ee1c8 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -31,10 +31,10 @@ namespace CSMDoc namespace CSMWorld { - //class Data; class Pathgrid; class NestedTableProxyModel; class IdTree; + class SignalHandler; } namespace CSVWorld @@ -58,6 +58,7 @@ namespace CSVRender CSMWorld::NestedTableProxyModel *mProxyModel; CSMWorld::IdTree *mModel; int mPgIndex; + CSMWorld::SignalHandler *mHandler; std::auto_ptr mTerrain; boost::shared_ptr mPhysics; @@ -126,6 +127,7 @@ namespace CSVRender void clearPathgrid(); void buildPathgrid(); + CSMWorld::SignalHandler *getSignalHandler(); }; } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index cc00b9159..130f5c409 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -19,6 +19,7 @@ #include "../../model/world/tablemimedata.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/world/pathgridcommands.hpp" #include "../widget/scenetooltoggle.hpp" #include "../widget/scenetoolmode.hpp" @@ -115,6 +116,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() { Cell *cell = new Cell (mDocument, getSceneManager(), iter->getId (mWorldspace), mDocument.getPhysics()); + connect (cell->getSignalHandler(), SIGNAL(flagAsModified()), this, SLOT(flagAsModSlot())); mCells.insert (std::make_pair (*iter, cell)); float height = cell->getTerrainHeightAt(Ogre::Vector3( @@ -637,3 +639,8 @@ void CSVRender::PagedWorldspaceWidget::cellAdded (const QModelIndex& index, int if (adjustCells()) flagAsModified(); } + +void CSVRender::PagedWorldspaceWidget::flagAsModSlot () +{ + flagAsModified(); +} diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 45e5dd8f7..099b4db25 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -120,6 +120,7 @@ namespace CSVRender virtual void cellAdded (const QModelIndex& index, int start, int end); + virtual void flagAsModSlot(); }; } diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index b5e9504f3..c95a87d03 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -13,6 +13,7 @@ #include "../../model/world/data.hpp" #include "../../model/world/idtable.hpp" #include "../../model/world/tablemimedata.hpp" +#include "../../model/world/pathgridcommands.hpp" #include "../widget/scenetooltoggle.hpp" #include "../widget/scenetooltoggle2.hpp" @@ -49,7 +50,9 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& update(); - mCell.reset (new Cell (document, getSceneManager(), mCellId, document.getPhysics())); + Cell *cell = new Cell (document, getSceneManager(), mCellId, document.getPhysics()); + connect (cell->getSignalHandler(), SIGNAL(flagAsModified()), this, SLOT(flagAsModSlot())); + mCell.reset (cell); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, @@ -91,7 +94,9 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); - mCell.reset (new Cell (getDocument(), getSceneManager(), mCellId, getDocument().getPhysics())); + Cell *cell = new Cell (getDocument(), getSceneManager(), mCellId, getDocument().getPhysics()); + connect (cell->getSignalHandler(), SIGNAL(flagAsModified()), this, SLOT(flagAsModSlot())); + mCell.reset (cell); update(); emit cellChanged(*data.begin()); @@ -212,3 +217,8 @@ CSVRender::WorldspaceWidget::dropRequirments CSVRender::UnpagedWorldspaceWidget: return ignored; } } + +void CSVRender::UnpagedWorldspaceWidget::flagAsModSlot () +{ + flagAsModified(); +} diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 11bfaeca3..468c48739 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -76,6 +76,8 @@ namespace CSVRender void cellRowsAboutToBeRemoved (const QModelIndex& parent, int start, int end); + virtual void flagAsModSlot(); + signals: void cellChanged(const CSMWorld::UniversalId& id); From 3102a175229982ae5db914fe327718776d3732aa Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 24 Apr 2015 04:00:49 +1000 Subject: [PATCH 27/29] Changes made to DialogueSubview pathgrid tables are now reflected on PagedWorldspaceWidget. --- apps/opencs/model/world/commands.hpp | 1 - apps/opencs/model/world/pathgridcommands.cpp | 4 +-- apps/opencs/model/world/pathgridcommands.hpp | 2 +- apps/opencs/view/render/cell.cpp | 33 ++++++++++++++++--- apps/opencs/view/render/cell.hpp | 2 ++ .../view/render/pagedworldspacewidget.cpp | 24 ++++---------- .../view/render/pagedworldspacewidget.hpp | 9 ++--- .../view/render/unpagedworldspacewidget.cpp | 22 +++---------- .../view/render/unpagedworldspacewidget.hpp | 8 ++--- apps/opencs/view/render/worldspacewidget.cpp | 15 +++------ apps/opencs/view/render/worldspacewidget.hpp | 6 +--- 11 files changed, 55 insertions(+), 71 deletions(-) diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 02d042487..2d63b66c9 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -12,7 +12,6 @@ #include #include "universalid.hpp" -//#include "nestedtablewrapper.hpp" class QModelIndex; class QAbstractItemModel; diff --git a/apps/opencs/model/world/pathgridcommands.cpp b/apps/opencs/model/world/pathgridcommands.cpp index 356806dcd..193ab4457 100644 --- a/apps/opencs/model/world/pathgridcommands.cpp +++ b/apps/opencs/model/world/pathgridcommands.cpp @@ -1,6 +1,7 @@ #include "pathgridcommands.hpp" #include "../../view/render/cell.hpp" + #include "idtree.hpp" #include "nestedtablewrapper.hpp" @@ -43,6 +44,5 @@ CSMWorld::SignalHandler::SignalHandler (CSVRender::Cell *parent) : mParent(paren void CSMWorld::SignalHandler::connectToCommand(const CSMWorld::ModifyPathgridCommand *command) { - connect (command, SIGNAL(undoActioned()), - this, SLOT(rebuildPathgrid())); + connect (command, SIGNAL(undoActioned()), this, SLOT(rebuildPathgrid())); } diff --git a/apps/opencs/model/world/pathgridcommands.hpp b/apps/opencs/model/world/pathgridcommands.hpp index 335e3a893..3acf0865b 100644 --- a/apps/opencs/model/world/pathgridcommands.hpp +++ b/apps/opencs/model/world/pathgridcommands.hpp @@ -53,7 +53,7 @@ namespace CSMWorld void connectToCommand(const ModifyPathgridCommand *command); - private slots: + public slots: void rebuildPathgrid(); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 7976fd55e..f7ec24a56 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -307,9 +307,34 @@ float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const return -std::numeric_limits::max(); } +void CSVRender::Cell::pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + CSMWorld::IdTree *pathgrids = dynamic_cast( + mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Pathgrid)); + + int idColumn = pathgrids->findColumnIndex(CSMWorld::Columns::ColumnId_Id); + int colPaths = pathgrids->findColumnIndex(CSMWorld::Columns::ColumnId_PathgridPoints); + //int colEdges = pathgrids->findColumnIndex(CSMWorld::Columns::ColumnId_PathgridEdges); + + // FIXME: how to detect adds/deletes/modifies? + + for (int i=topLeft.row(); i<=bottomRight.row(); ++i) + { + std::string cell = Misc::StringUtils::lowerCase (pathgrids->data ( + pathgrids->index (i, idColumn)).toString().toUtf8().constData()); + + if (cell==mId && colPaths >= topLeft.column() && colPaths <= bottomRight.column()) + { + if (!mModel) + setupPathgrid(); + + mHandler->rebuildPathgrid(); + } + } +} + // FIXME: // - adding edges (need the ability to select a pathgrid and highlight) -// - save to document & signals // - repainting edges while moving void CSVRender::Cell::setupPathgrid() { @@ -434,7 +459,7 @@ void CSVRender::Cell::pathgridPointAdded(const Ogre::Vector3 &pos, bool interior pathgrid.mData.mS2 += 1; // increment the number of points - // FIXME: possible issue if this cell is deleted and undo() is actioned afterwards + // TODO: check for possible issue if this cell is deleted and undo() is actioned afterwards CSMWorld::ModifyPathgridCommand *cmd = new CSMWorld::ModifyPathgridCommand(*mModel, mProxyModel->getParentId(), mProxyModel->getParentColumn(), new CSMWorld::PathgridPointsWrap(pathgrid)); @@ -493,7 +518,7 @@ void CSVRender::Cell::pathgridPointRemoved(const std::string &name) << pathgridId + "_" + QString::number(index).toStdString() << std::endl; } - // FIXME: possible issue if this cell is deleted and undo() is actioned afterwards + // TODO: check for possible issue if this cell is deleted and undo() is actioned afterwards CSMWorld::ModifyPathgridCommand *cmd = new CSMWorld::ModifyPathgridCommand(*mModel, mProxyModel->getParentId(), mProxyModel->getParentColumn(), new CSMWorld::PathgridPointsWrap(pathgrid)); @@ -536,7 +561,7 @@ void CSVRender::Cell::pathgridPointMoved(const std::string &name, pathgrid.mPoints[index].mY = y; pathgrid.mPoints[index].mZ = newPos.z; - // FIXME: possible issue if this cell is deleted and undo() is actioned afterwards + // TODO: check for possible issue if this cell is deleted and undo() is actioned afterwards CSMWorld::ModifyPathgridCommand *cmd = new CSMWorld::ModifyPathgridCommand(*mModel, mProxyModel->getParentId(), mProxyModel->getParentColumn(), new CSMWorld::PathgridPointsWrap(pathgrid)); diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index cc00ee1c8..dbf680dd4 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -111,6 +111,8 @@ namespace CSVRender const Ogre::Vector3 &newPos, bool interior = false); void pathgridPointRemoved(const std::string &name); + void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + private: // for drawing pathgrid points & lines diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 130f5c409..799dd1e7f 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -330,23 +330,13 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent flagAsModified(); } -//void CSVRender::PagedWorldspaceWidget::pathgridAdded (const QModelIndex& parent, -// int start, int end) -//{ -// // FIXME: -//} -// -//void CSVRender::PagedWorldspaceWidget::pathgridDataChanged (const QModelIndex& topLeft, -// const QModelIndex& bottomRight) -//{ -// // FIXME: -//} -// -//void CSVRender::PagedWorldspaceWidget::pathgridAboutToBeRemoved (const QModelIndex& parent, -// int start, int end) -//{ -// // FIXME: -//} +void CSVRender::PagedWorldspaceWidget::pathgridDataChanged (const QModelIndex& topLeft, + const QModelIndex& bottomRight) +{ + for (std::map::iterator iter (mCells.begin()); + iter!=mCells.end(); ++iter) + iter->second->pathgridDataChanged (topLeft, bottomRight); +} CSVRender::Cell *CSVRender::PagedWorldspaceWidget::findCell(const std::string &cellId) { diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 099b4db25..ea9449b2f 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -53,12 +53,6 @@ namespace CSVRender virtual void referenceAdded (const QModelIndex& index, int start, int end); - //virtual void pathgridAdded (const QModelIndex& parent, int start, int end); - - //virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); - - //virtual void pathgridAboutToBeRemoved (const QModelIndex& parent, int start, int end); - virtual std::string getStartupInstruction(); Cell *findCell(const std::string &cellId); @@ -103,7 +97,6 @@ namespace CSVRender virtual void mouseDoubleClickEvent (QMouseEvent *event); - // FIXME: temporary only until signals from the document is implemented 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); @@ -121,6 +114,8 @@ namespace CSVRender virtual void cellAdded (const QModelIndex& index, int start, int end); virtual void flagAsModSlot(); + + virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); }; } diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index c95a87d03..af121ec19 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -166,23 +166,11 @@ void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons ( tool->addButton (Element_Fog, "Fog"); } -//void CSVRender::UnpagedWorldspaceWidget::pathgridAdded (const QModelIndex& parent, -// int start, int end) -//{ -// // FIXME: -//} -// -//void CSVRender::UnpagedWorldspaceWidget::pathgridDataChanged (const QModelIndex& topLeft, -// const QModelIndex& bottomRight) -//{ -// // FIXME: -//} -// -//void CSVRender::UnpagedWorldspaceWidget::pathgridAboutToBeRemoved (const QModelIndex& parent, -// int start, int end) -//{ -// // FIXME: -//} +void CSVRender::UnpagedWorldspaceWidget::pathgridDataChanged (const QModelIndex& topLeft, + const QModelIndex& bottomRight) +{ + // FIXME: +} std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction() { diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 468c48739..4e19efbf0 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -58,12 +58,6 @@ namespace CSVRender virtual void referenceAdded (const QModelIndex& index, int start, int end); - //virtual void pathgridAdded (const QModelIndex& index, int start, int end); - - //virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); - - //virtual void pathgridAboutToBeRemoved (const QModelIndex& parent, int start, int end); - virtual std::string getStartupInstruction(); protected: @@ -78,6 +72,8 @@ namespace CSVRender virtual void flagAsModSlot(); + virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + signals: void cellChanged(const CSMWorld::UniversalId& id); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 8418a32a6..2d690303c 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -56,15 +56,11 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); - //QAbstractItemModel *pathgrids = - //document.getData().getTableModel (CSMWorld::UniversalId::Type_Pathgrid); + QAbstractItemModel *pathgrids = + document.getData().getTableModel (CSMWorld::UniversalId::Type_Pathgrid); - //connect (pathgrids, SIGNAL (rowsInserted (const QModelIndex&, int, int)), - //this, SLOT (pathgridAdded (const QModelIndex&, int, int))); - //connect (pathgrids, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), - //this, SLOT (pathgridDataChanged (const QModelIndex&, const QModelIndex&))); - //connect (pathgrids, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), - //this, SLOT (pathgridAboutToBeRemoved (const QModelIndex&, int, int))); + connect (pathgrids, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), + this, SLOT (pathgridDataChanged (const QModelIndex&, const QModelIndex&))); mPhysics = document.getPhysics(); // create physics if one doesn't exist mPhysics->addSceneManager(getSceneManager(), this); @@ -460,17 +456,14 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) SceneWidget::keyPressEvent(event); } -// FIXME: temporary until signals from the document are implemented void CSVRender::WorldspaceWidget::pathgridAboutToBeRemoved (const std::string &pgName) { } -// FIXME: temporary until signals from the document are implemented void CSVRender::WorldspaceWidget::pathgridMoved (const std::string &pgName, const Ogre::Vector3 &newPos) { } -// FIXME: temporary until signals from the document are implemented void CSVRender::WorldspaceWidget::pathgridInserted (const std::string &name, const Ogre::Vector3 &pos) { } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index efd2ee8c0..a250547b3 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -163,11 +163,7 @@ namespace CSVRender void debugProfileAboutToBeRemoved (const QModelIndex& parent, int start, int end); - //virtual void pathgridAdded (const QModelIndex& index, int start, int end) = 0; - - //virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) = 0; - - //virtual void pathgridAboutToBeRemoved (const QModelIndex& parent, int start, int end) = 0; + virtual void pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) = 0; protected slots: From 193873b82952baba6866051058dc7bbfe23cf341 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 31 May 2015 10:28:45 +1000 Subject: [PATCH 28/29] Feature #1278: Editor: Mouse picking in worldspace widget - With the move to OSG (see: https://forum.openmw.org/viewtopic.php?f=7&t=2755&p=31850#p31839) all the work done so far will soon be removed from the master branch. - The pathgrid editing and integration to the model, as well as other improvements made, are unlikely to be accepted to the master. - These will be maintained here until they can be ported to OSG. It is easier to port when there is a working code base, anyway. --- apps/opencs/view/render/cell.cpp | 7 ++++--- apps/opencs/view/render/mousestate.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index f7ec24a56..49af585fd 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -120,9 +120,10 @@ bool CSVRender::Cell::addObjects (int start, int end) CSVRender::Cell::Cell (CSMDoc::Document& document, Ogre::SceneManager *sceneManager, const std::string& id, boost::shared_ptr physics, const Ogre::Vector3& origin) - : mDocument (document), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager) - , mPhysics(physics), mX(0), mY(0), mPgIndex(-1), mModel(0), mProxyModel(0) - , mHandler(new CSMWorld::SignalHandler(this)) +: mDocument (document), mId (Misc::StringUtils::lowerCase (id)) +, mProxyModel(0), mModel(0), mPgIndex(-1), mHandler(new CSMWorld::SignalHandler(this)) +, mPhysics(physics), mSceneMgr(sceneManager), mX(0), mY(0) + { mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode->setPosition (origin); diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 38dc41fbc..e4921c4b7 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -56,11 +56,11 @@ namespace CSVRender // MouseState::MouseState(WorldspaceWidget *parent) - : mParent(parent), mPhysics(parent->mDocument.getPhysics()), mSceneManager(parent->getSceneManager()) - , mCurrentObj(""), mMouseState(Mouse_Default), mOldCursorPos(0,0), mMouseEventTimer(0) - , mGrabbedSceneNode(""), mGrabbedRefId(""), mOrigObjPos(Ogre::Vector3()) - , mOrigMousePos(Ogre::Vector3()), mOldMousePos(Ogre::Vector3()), mPlane(0) - , mColIndexPosX(0), mColIndexPosY(0), mColIndexPosZ(0), mIdTableModel(0) + : mMouseState(Mouse_Default), mParent(parent), mPhysics(parent->mDocument.getPhysics()) + , mSceneManager(parent->getSceneManager()), mOldCursorPos(0,0), mCurrentObj(""), mGrabbedSceneNode(""), mGrabbedRefId("") + , mMouseEventTimer(0), mPlane(0), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) + , mOldMousePos(Ogre::Vector3()), mIdTableModel(0), mColIndexPosX(0) + , mColIndexPosY(0), mColIndexPosZ(0) { const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); From 610e6591213bb1ce07ed8869f39b0c14c7765646 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 12 Jun 2015 21:38:53 +1000 Subject: [PATCH 29/29] Fix physics model not being moved since commit ec80884. --- apps/opencs/view/render/object.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 3607fb415..9e39ee37b 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -223,12 +223,10 @@ bool CSVRender::Object::referenceDataChanged (const QModelIndex& topLeft, { mReferenceableId = references.getData (index, columnIndex).toString().toUtf8().constData(); - - update(); } + update(); adjust(); - return true; }