From f2ff2f298888d32d5dcdb7ae5a18e47f2b07fe6b Mon Sep 17 00:00:00 2001 From: cc9cii <cc9c@iinet.net.au> 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 ec6f802cfa..29f93e5666 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 591667ebb7..beab0b6072 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -308,6 +308,9 @@ std::auto_ptr<sh::Factory> 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 75e11cc10a..6979a4042b 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -3,6 +3,7 @@ #include <OgreSceneManager.h> #include <OgreSceneNode.h> +#include <OgreManualObject.h> #include <components/misc/stringops.hpp> #include <components/esm/loadland.hpp> @@ -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::pair<int, int>, 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<std::string, PathgridPoint *>::iterator iter (mPgPoints.begin()); + iter!=mPgPoints.end(); ++iter) + { + delete iter->second; + } + mPhysics->removeHeightField(mSceneMgr, mX, mY); for (std::map<std::string, Object *>::iterator iter (mObjects.begin()); @@ -236,3 +305,54 @@ float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const else return -std::numeric_limits<float>::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<CSMWorld::Pathgrid>& pathgridCollection = mData.getPathgrids(); + int index = pathgridCollection.searchId(mId); + if(index != -1) + { + const CSMWorld::Pathgrid pathgrid = pathgridCollection.getRecord(index).get(); + + std::vector<ESM::Pathgrid::Point>::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 d38f0c68d1..c88b593532 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<std::string, Object *> mObjects; + std::map<std::string, PathgridPoint *> mPgPoints; + std::map<std::pair<int, int>, std::string> mPgEdges; std::auto_ptr<Terrain::TerrainGrid> 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 45e846f74a..aa8f1a785b 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<bool, Ogre::Vector3> planeResult = mousePositionOnPlane(event->pos(), *mPlane); - if(planeResult.first) + if(planeResult.first && mGrabbedSceneNode != "") { - if(mGrabbedSceneNode != "") - { - std::pair<Ogre::Vector3, Ogre::Vector3> 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<Ogre::Vector3, Ogre::Vector3> 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<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> 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 27907bb331..36d04ef6ba 100644 --- a/apps/opencs/view/render/mousestate.hpp +++ b/apps/opencs/view/render/mousestate.hpp @@ -82,6 +82,8 @@ namespace CSVRender std::pair<Ogre::Vector3, Ogre::Vector3> 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 0000000000..2455ea1a83 --- /dev/null +++ b/apps/opencs/view/render/pathgridpoint.cpp @@ -0,0 +1,38 @@ +#include "pathgridpoint.hpp" + +#include <iostream> // FIXME + +#include <OgreSceneManager.h> +#include <OgreSceneNode.h> + +//#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 0000000000..f4fa42790d --- /dev/null +++ b/apps/opencs/view/render/pathgridpoint.hpp @@ -0,0 +1,35 @@ +#ifndef OPENCS_VIEW_PATHGRIDPOINT_H +#define OPENCS_VIEW_PATHGRIDPOINT_H + +#include <components/nifogre/ogrenifloader.hpp> + +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<NE}dPwVTFLLadEBRN~+V z;02o3sJOOLU!vj-xbO;u?_00qpSUy!##-+;GvCgP*Sq7Y@NK`Z^iVb4_&vM^y6=Tg z8y{iv2VWZ7TTMLAm#QMpqKM36xV}3$P%A*eVLJ%hS{<}|o<3A#D|NWC61B3LNSR)= z#Ve3jDi};lS;BDr58B`BdVyMlmX;87kB0vKu+dD)aJV8P#S~?F-ZqETEP-<ptp>~t z{C?Np?FC)$y&eQghexm&7u~;CWz{hD0=54Y+fzoWSk5~yRND7?35Oe)*tVL@XADTG z$msazOQxZWjz48KHiA7Fu|IzA>~=bx)-sfI<6e8A_t<Q#Nc~kj$Ts*KAOgnBF~Q(X zB>M49L(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!<gVP4b-dT*zC4hJvVr%8JVK;d+R^0lI!R4-&bJ!ut@)8DiF(l% zdlxXV9ZX;9`TuaKvxh&ehUn_etRg>;I=7Xbdk!1z;9(1`L8re49DCSSsnHYnc}(&b DaQ$}< literal 0 HcmV?d00001 From 2c09b9ba212c699e53045e81d5d8ba936a67ce9a Mon Sep 17 00:00:00 2001 From: cc9cii <cc9c@iinet.net.au> 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 57909f4d38..13b29ba5a5 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 <cc9c@iinet.net.au> 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 6979a4042b..e703c8a9dc 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<float>::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<ESM::Pathgrid::Point>::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<std::string, int> 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<std::pair<int, int> > edges; + for(unsigned i = 0; i < mEdges.size(); ++i) + { + if(mEdges[i].mV0 == index || mEdges[i].mV1 == index) + { + for(std::map<std::pair<int, int>, 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<std::pair<int, int> >::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<std::string, int> 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 c88b593532..5d7b9088a5 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -8,6 +8,7 @@ #include <OgreVector3.h> #include <components/terrain/terraingrid.hpp> +#include <components/esm/loadpgrd.hpp> // 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<std::string, Object *> mObjects; std::map<std::string, PathgridPoint *> mPgPoints; std::map<std::pair<int, int>, 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<Terrain::TerrainGrid> 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 aa8f1a785b..bceae716cf 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<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> MouseState::pgPointUnderCursor(const int mouseX, const int mouseY) + { + std::pair<std::string, Ogre::Vector3> 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<bool, Ogre::Vector3> 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<std::string, Ogre::Vector3> 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 36d04ef6ba..b56860cace 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<std::string, Ogre::Vector3> pgPointUnderCursor(const int mouseX, const int mouseY); + std::pair<std::string, Ogre::Vector3> terrainUnderCursor(const int mouseX, const int mouseY); void cancelDrag(); private: std::pair<bool, Ogre::Vector3> mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane); - std::pair<std::string, Ogre::Vector3> terrainUnderCursor(const int mouseX, const int mouseY); std::pair<std::string, Ogre::Vector3> objectUnderCursor(const int mouseX, const int mouseY); std::pair<Ogre::Vector3, Ogre::Vector3> planeAxis(); void updateSceneWidgets(); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 49e7e1f097..e528733c01 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<CSMWorld::Cell>& cells = mDocument.getData().getCells(); + + std::map<CSMWorld::CellCoordinates, Cell *>::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<std::string, int> 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<std::string, int> 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 fe79e761e5..b5ca91880b 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 2455ea1a83..3e365932f9 100644 --- a/apps/opencs/view/render/pathgridpoint.cpp +++ b/apps/opencs/view/render/pathgridpoint.cpp @@ -2,6 +2,8 @@ #include <iostream> // FIXME +#include <QRegExp> + #include <OgreSceneManager.h> #include <OgreSceneNode.h> @@ -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<std::string, int> 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 f4fa42790d..3419082c3a 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<std::string, int> 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 8012b1b246..a1a8a89219 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 5924abaa9e..ee397d467a 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 9c86760640..1fedc8aa12 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -8,6 +8,7 @@ #include <OgreEntity.h> #include <QtGui/qevent.h> +#include <QPoint> #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<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> 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 5bad3933d8..75dc0c2647 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 <cc9c@iinet.net.au> 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 e703c8a9dc..a53a2939f3 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 bceae716cf..ee77768908 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<std::string, Ogre::Vector3> 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 13b29ba5a5..788e42c55e 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<std::string, float> result = - mEngine->rayTest(_from, _to, !ignoreObjects, ignoreHeightMap, &norm); + std::pair<std::string, float> result = std::make_pair("", -1); + short mask = OEngine::Physic::CollisionType_Raycasting; + std::vector<std::pair<float, std::string> > objects = mEngine->rayTest2(_from, _to, mask); + + for (std::vector<std::pair<float, std::string> >::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 <cc9c@iinet.net.au> 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 a53a2939f3..238f60bb5d 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 <cc9c@iinet.net.au> 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 9b2325744e..6ee219a8ad 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 <cc9c@iinet.net.au> 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 788e42c55e..cae5563e6f 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 <cc9c@iinet.net.au> 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 238f60bb5d..4e3416111f 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 ee77768908..ee59770e45 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<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> result = mPhysics->castRay(x, y, mSceneManager, getCamera()); + std::pair<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> result = mPhysics->castRay(x, y, mSceneManager, getCamera()); + std::pair<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> result = mPhysics->castRay(x, y, mSceneManager, getCamera()); + if(result.first != "") + { + return result; + } + + return std::make_pair("", Ogre::Vector3()); + } + void MouseState::updateSceneWidgets() { std::map<Ogre::SceneManager*, CSVRender::SceneWidget *> sceneWidgets = mPhysics->sceneWidgets(); diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp index b56860cace..fd752349a7 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<std::string, Ogre::Vector3> pgPointUnderCursor(const int mouseX, const int mouseY); - std::pair<std::string, Ogre::Vector3> terrainUnderCursor(const int mouseX, const int mouseY); + std::pair<std::string, Ogre::Vector3> anyUnderCursor(const int mouseX, const int mouseY); void cancelDrag(); private: std::pair<bool, Ogre::Vector3> mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane); + std::pair<std::string, Ogre::Vector3> terrainUnderCursor(const int mouseX, const int mouseY); std::pair<std::string, Ogre::Vector3> objectUnderCursor(const int mouseX, const int mouseY); std::pair<Ogre::Vector3, Ogre::Vector3> planeAxis(); void updateSceneWidgets(); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index e528733c01..506fd54df9 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 1fedc8aa12..4f85f3a30c 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<std::string, Ogre::Vector3> result = mMouse->terrainUnderCursor(p.x(), p.y()); + std::pair<std::string, Ogre::Vector3> 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 <cc9c@iinet.net.au> 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 ee59770e45..989dbdb912 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<bool, Ogre::Vector3> planeResult = mousePositionOnPlane(event->pos(), *mPlane); + // relative movement of the object on the movement plane + std::pair<bool, Ogre::Vector3> planeResult = mousePosOnPlane(event->pos(), *mPlane); if(planeResult.first) { if(mGrabbedSceneNode != "") { - std::pair<Ogre::Vector3, Ogre::Vector3> 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<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis(); mPlane->redefine(planeRes.first, result.second); - std::pair<bool, Ogre::Vector3> planeResult = mousePositionOnPlane(event->pos(), *mPlane); + std::pair<bool, Ogre::Vector3> 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<bool, Ogre::Vector3> planeResult = mousePositionOnPlane(event->pos(), *mPlane); + std::pair<bool, Ogre::Vector3> planeResult = mousePosOnPlane(event->pos(), *mPlane); if(planeResult.first && mGrabbedSceneNode != "") { - std::pair<Ogre::Vector3, Ogre::Vector3> 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<std::string, Ogre::Vector3> result = - anyUnderCursor(event->x(), event->y()); - if(result.first != "") + //std::pair<std::string, Ogre::Vector3> 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<Ogre::Vector3, Ogre::Vector3> 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<bool, Ogre::Vector3> 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<bool, Ogre::Vector3> MouseState::mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane) + std::pair<bool, Ogre::Vector3> 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 fd752349a7..d21735a78d 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<bool, Ogre::Vector3> mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane); + std::pair<bool, Ogre::Vector3> mousePosOnPlane(const QPoint &pos, const Ogre::Plane &plane); std::pair<std::string, Ogre::Vector3> terrainUnderCursor(const int mouseX, const int mouseY); std::pair<std::string, Ogre::Vector3> objectUnderCursor(const int mouseX, const int mouseY); std::pair<Ogre::Vector3, Ogre::Vector3> planeAxis(); From 2412d127b0b2694f136e0f468034ffaec117560f Mon Sep 17 00:00:00 2001 From: cc9cii <cc9c@iinet.net.au> 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 4e3416111f..0435159075 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<CSMWorld::Pathgrid>& 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<std::string, int> 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 5d7b9088a5..8a7f01f202 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 <cc9c@iinet.net.au> 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 989dbdb912..01f16c3397 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<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> 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<std::string, float> 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 cae5563e6f..55da2e2210 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -281,6 +281,43 @@ namespace CSVWorld } } + std::pair<std::string, float> 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<std::string, float> result = std::make_pair("", -1); + short mask = OEngine::Physic::CollisionType_Raycasting; + std::vector<std::pair<float, std::string> > objects = mEngine->rayTest2(_from, _to, mask); + + for (std::vector<std::pair<float, std::string> >::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 0036bf769d..f28272532d 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -73,6 +73,8 @@ namespace CSVWorld std::pair<std::string, Ogre::Vector3> castRay(float mouseX, float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera); + std::pair<std::string, float> 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 <cc9c@iinet.net.au> 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 01f16c3397..ba668901f2 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<std::string, Ogre::Vector3> 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<Ogre::Vector3, Ogre::Vector3> 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 <cc9c@iinet.net.au> 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 ba668901f2..8f254f08d4 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<std::string, float> res = mPhysics->distToGround(pos, getCamera()); + // snap (defaults to 300 or less) + // FIXME: sticks to the underside of the object if snapping up + std::pair<std::string, float> 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 55da2e2210..358bb90ca0 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -281,7 +281,7 @@ namespace CSVWorld } } - std::pair<std::string, float> PhysicsSystem::distToGround(Ogre::Vector3 &position, + std::pair<std::string, float> 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<std::string, float> 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<std::string, float> resDown = std::make_pair("", -1); + std::vector<std::pair<float, std::string> > objectsDown = mEngine->rayTest2(_from, _to, mask); + + for (std::vector<std::pair<float, std::string> >::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<std::string, float> resUp = std::make_pair("", -1); + std::vector<std::pair<float, std::string> > objectsUp = mEngine->rayTest2(_from, _to, mask); + + for (std::vector<std::pair<float, std::string> >::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 f28272532d..6436b87431 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -73,7 +73,11 @@ namespace CSVWorld std::pair<std::string, Ogre::Vector3> castRay(float mouseX, float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera); - std::pair<std::string, float> distToGround(Ogre::Vector3 &position, Ogre::Camera *camera); + std::pair<std::string, float> distToGround(const Ogre::Vector3 &position, + Ogre::Camera *camera); + + std::pair<std::string, float> 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 <cc9c@iinet.net.au> 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 8f254f08d4..c9fcdbc867 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<std::string, Ogre::Vector3> result = - anyUnderCursor(event->x(), event->y()); + std::pair<std::string, float> 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<std::string, float> 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 358bb90ca0..9ff945829a 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -282,16 +282,17 @@ namespace CSVWorld } std::pair<std::string, float> 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<std::string, float> 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<std::string, float> 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<std::string, float> resDown = std::make_pair("", -1); - std::vector<std::pair<float, std::string> > objectsDown = mEngine->rayTest2(_from, _to, mask); - - for (std::vector<std::pair<float, std::string> >::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<std::string, float> resUp = std::make_pair("", -1); - std::vector<std::pair<float, std::string> > objectsUp = mEngine->rayTest2(_from, _to, mask); - - for (std::vector<std::pair<float, std::string> >::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<std::string, float> 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 6436b87431..589dca9c5b 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<std::string, float> distToGround(const Ogre::Vector3 &position, - Ogre::Camera *camera); + Ogre::Camera *camera, const float limit = 300000, bool ignorePgPoint = false); std::pair<std::string, float> 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 <cc9c@iinet.net.au> 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 c9fcdbc867..65596b752d 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -58,8 +58,8 @@ namespace CSVRender MouseState::MouseState(WorldspaceWidget *parent) : mParent(parent), mPhysics(parent->getPhysics()), mSceneManager(parent->getSceneManager()) , mCurrentObj(""), mMouseState(Mouse_Default), mOldCursorPos(0,0), mMouseEventTimer(0) - , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) - , mOldMousePos(Ogre::Vector3()), mPlane(0) + , mGrabbedSceneNode(""), mGrabbedRefId(""), mOrigObjPos(Ogre::Vector3()) + , mOrigMousePos(Ogre::Vector3()), mOldMousePos(Ogre::Vector3()), mPlane(0) , mColIndexPosX(0), mColIndexPosY(0), mColIndexPosZ(0), mIdTableModel(0) { const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); @@ -120,16 +120,13 @@ namespace CSVRender std::pair<bool, Ogre::Vector3> 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<std::string, Ogre::Vector3> result = objectUnderCursor(event->x(), event->y()); + // get object or pathgrid + std::pair<std::string, Ogre::Vector3> 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<Ogre::Vector3, Ogre::Vector3> planeRes = planeAxis(); @@ -190,7 +194,9 @@ namespace CSVRender { case Mouse_Grab: { - std::pair<std::string, Ogre::Vector3> result = objectUnderCursor(event->x(), event->y()); + std::pair<std::string, Ogre::Vector3> 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<bool, Ogre::Vector3> 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<std::string, float> 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<std::string, Ogre::Vector3> result = terrainUnderCursor(event->x(), event->y()); + std::pair<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> MouseState::pgPointUnderCursor(const int mouseX, const int mouseY) - { - std::pair<std::string, Ogre::Vector3> 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<bool, Ogre::Vector3> 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<std::string, Ogre::Vector3> MouseState::terrainUnderCursor(const int mouseX, const int mouseY) - { - std::pair<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> MouseState::objectUnderCursor(const int mouseX, const int mouseY) - { - std::pair<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> MouseState::anyUnderCursor(const int mouseX, const int mouseY) + std::pair<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> result = mPhysics->castRay(x, y, mSceneManager, getCamera()); - if(result.first != "") - { - return result; - } - - return std::make_pair("", Ogre::Vector3()); + return mPhysics->castRay(x, y, mSceneManager, getCamera(), elements); } void MouseState::updateSceneWidgets() @@ -554,14 +498,12 @@ namespace CSVRender return mParent->getCamera()->getViewport(); } - void MouseState::placeObject(const std::string sceneNode, const Ogre::Vector3 &pos) + void MouseState::placeObject(const std::string sceneNodeName, const Ogre::Vector3 &pos) { - mSceneManager->getSceneNode(sceneNode)->setPosition(pos); + mSceneManager->getSceneNode(sceneNodeName)->setPosition(pos); // update physics - std::string refId = mPhysics->sceneNodeToRefId(sceneNode); - - mPhysics->replaceObject(sceneNode, 1, pos, Ogre::Quaternion::IDENTITY); + mPhysics->replaceObject(sceneNodeName, 1, pos, Ogre::Quaternion::IDENTITY); // update all SceneWidgets and their SceneManagers updateSceneWidgets(); diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp index d21735a78d..d55d5f6c30 100644 --- a/apps/opencs/view/render/mousestate.hpp +++ b/apps/opencs/view/render/mousestate.hpp @@ -49,6 +49,7 @@ namespace CSVRender QPoint mOldCursorPos; std::string mCurrentObj; std::string mGrabbedSceneNode; + std::string mGrabbedRefId; QElapsedTimer *mMouseEventTimer; Ogre::Plane *mPlane; Ogre::Vector3 mOrigObjPos; @@ -70,20 +71,19 @@ namespace CSVRender void mouseReleaseEvent (QMouseEvent *event); void mouseDoubleClickEvent (QMouseEvent *event); bool wheelEvent (QWheelEvent *event); - std::pair<std::string, Ogre::Vector3> pgPointUnderCursor(const int mouseX, const int mouseY); - std::pair<std::string, Ogre::Vector3> anyUnderCursor(const int mouseX, const int mouseY); + + std::pair<std::string, Ogre::Vector3> underCursor(const int mouseX, + const int mouseY, Ogre::uint32 elements); void cancelDrag(); private: std::pair<bool, Ogre::Vector3> mousePosOnPlane(const QPoint &pos, const Ogre::Plane &plane); - std::pair<std::string, Ogre::Vector3> terrainUnderCursor(const int mouseX, const int mouseY); - std::pair<std::string, Ogre::Vector3> objectUnderCursor(const int mouseX, const int mouseY); std::pair<Ogre::Vector3, Ogre::Vector3> planeAxis(); void updateSceneWidgets(); - void placeObject(const std::string sceneNode, const Ogre::Vector3 &pos); // FIXME + void placeObject(const std::string sceneNodeName, const Ogre::Vector3 &pos); // FIXME Ogre::Camera *getCamera(); // friend access Ogre::Viewport *getViewport(); // friend access diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 506fd54df9..bb856dbffd 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -334,10 +334,9 @@ CSVRender::Cell *CSVRender::PagedWorldspaceWidget::findCell(const std::string &c } // NOTE: allow placing pathgrid points above objects and terrain -void CSVRender::PagedWorldspaceWidget::pathgridInserted (const std::string &name, const Ogre::Vector3 &pos) +void CSVRender::PagedWorldspaceWidget::pathgridInserted (const std::string &referenceId, const Ogre::Vector3 &pos) { - QString id = QString(name.c_str()); - std::string referenceId = getPhysics()->sceneNodeToRefId(name); // FIXME: move back + QString id = QString(referenceId.c_str()); bool terrain = id.startsWith("HeightField_"); bool object = QString(referenceId.c_str()).startsWith("ref#"); diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index b5ca91880b..63f6caa60a 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -96,7 +96,7 @@ namespace CSVRender virtual void mouseDoubleClickEvent (QMouseEvent *event); // FIXME: temporary only until signals from the document is implemented - virtual void pathgridInserted (const std::string &terrain, const Ogre::Vector3 &pos); + virtual void pathgridInserted (const std::string &referenceId, const Ogre::Vector3 &pos); virtual void pathgridMoved (const std::string &pgName, const Ogre::Vector3 &pos); virtual void pathgridAboutToBeRemoved (const std::string &pgName); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 4f85f3a30c..54d0ce8e85 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -411,7 +411,9 @@ void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) else if(event->key() == Qt::Key_Delete) { QPoint p = this->mapFromGlobal(QCursor::pos()); - std::pair<std::string, Ogre::Vector3> result = mMouse->pgPointUnderCursor(p.x(), p.y()); + std::pair<std::string, Ogre::Vector3> 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<std::string, Ogre::Vector3> result = mMouse->anyUnderCursor(p.x(), p.y()); + std::pair<std::string, Ogre::Vector3> result = + mMouse->underCursor(p.x(), p.y(), CSVRender::Element_Reference|CSVRender::Element_Terrain); + if(result.first != "") { pathgridInserted(result.first, result.second); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 9ff945829a..9012a06c2c 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -211,15 +211,11 @@ namespace CSVWorld } } - // sceneMgr: to lookup the scene node name from the object's referenceId - // camera: primarily used to get the visibility mask for the viewport - // - // returns the found object's scene node name and its position in the world space - // // WARNING: far clip distance is a global setting, if it changes in future // this method will need to be updated std::pair<std::string, Ogre::Vector3> 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<std::string, float> 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<std::string, float> 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<std::string, float> result = std::make_pair("", -1); short mask = OEngine::Physic::CollisionType_Raycasting; diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 589dca9c5b..5543c84b96 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -4,6 +4,8 @@ #include <string> #include <map> +#include <OgrePlatform.h> + namespace Ogre { class Vector3; @@ -71,7 +73,8 @@ namespace CSVWorld // return the object's SceneNode name and position for the given SceneManager std::pair<std::string, Ogre::Vector3> 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<std::string, float> distToGround(const Ogre::Vector3 &position, Ogre::Camera *camera, const float limit = 300000, bool ignorePgPoint = false); @@ -79,7 +82,7 @@ namespace CSVWorld std::pair<std::string, float> 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<Ogre::SceneManager*, CSVRender::SceneWidget *> 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 <cc9c@iinet.net.au> 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 65596b752d..e62a4b1ff8 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<std::string, float> 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<std::string, Ogre::Vector3> 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 d55d5f6c30..cde53f2c58 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<std::string, Ogre::Vector3> 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 9012a06c2c..6450b5cf6c 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<std::string, Ogre::Vector3> 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<std::string, float> 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<std::string, float> 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<std::string, float> 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 5543c84b96..f71ab685c7 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<std::string, Ogre::Vector3> 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<std::string, float> 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<std::string, float> 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 <cc9c@iinet.net.au> 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 e62a4b1ff8..41908d11c3 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 6450b5cf6c..c5f1d0a75e 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -267,7 +267,7 @@ namespace CSVWorld } std::pair<std::string, float> 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<std::string, float> 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<std::string, float> PhysicsSystem::distToClosest(const Ogre::Vector3 &position, Ogre::uint32 visibilityMask, const float limit) { @@ -311,7 +310,7 @@ namespace CSVWorld std::pair<std::string, float> 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 f71ab685c7..839d556543 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<std::string, float> distToGround(const Ogre::Vector3 &position, - Ogre::uint32 visibilityMask, const float limit = 300000, bool ignorePgPoint = false); + Ogre::uint32 visibilityMask, const float limit = 300000); std::pair<std::string, float> distToClosest(const Ogre::Vector3 &position, Ogre::uint32 visibilityMask, const float limit = 100.0f); From e430dcfd8ad1884cfab800e38874bcc1e854cfff Mon Sep 17 00:00:00 2001 From: cc9cii <cc9c@iinet.net.au> 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 0435159075..40cf904f84 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<std::string, PathgridPoint *>::iterator iter (mPgPoints.begin()); iter!=mPgPoints.end(); ++iter) From 0e0ad97a9108580b9ee8c8472342d4624c98a6ad Mon Sep 17 00:00:00 2001 From: cc9cii <cc9c@iinet.net.au> 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 40cf904f84..32ef101e56 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 <cc9c@iinet.net.au> 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 21219db8f4..e273717664 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 eba2dc8148..8ce204e1c7 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 <cc9c@iinet.net.au> 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 32ef101e56..12e00ca46e 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<CSMWorld::Pathgrid>& pathgridCollection = mData.getPathgrids(); diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 839d556543..6a634ed26b 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 <cc9c@iinet.net.au> 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 3e365932f9..85b03beea9 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<CSVWorld::PhysicsSystem> 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 3419082c3a..54fe70e311 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 <boost/shared_ptr.hpp> + #include <components/nifogre/ogrenifloader.hpp> namespace Ogre @@ -19,14 +21,15 @@ namespace CSVRender { class PathgridPoint { - CSVWorld::PhysicsSystem *mPhysics; // local copy + boost::shared_ptr<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); + Ogre::SceneNode *cellNode, const Ogre::Vector3 &pos, + boost::shared_ptr<CSVWorld::PhysicsSystem> physics); ~PathgridPoint(); From 68dbf929a2c024d0cbc3086ff15865a7125844af Mon Sep 17 00:00:00 2001 From: cc9cii <cc9c@iinet.net.au> 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 d13649d3ee..ef63909afa 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<std::string, Object *>::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 e504fc7a48..0afd0920b3 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -11,11 +11,8 @@ #ifndef Q_MOC_RUN #include <components/terrain/terraingrid.hpp> -<<<<<<< .mine #include <components/esm/loadpgrd.hpp> // 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^9aI<y=liPo&?bI9iZ0F~QtQ--| z<Jhj<zjKy>d=Yl<1NZLQ53g^$PbCF-Oc^vyjVMW<v_%o9N+}$!%96*i-OIpjcZKhi zpv60=HFOUa(+!!-pQOiaX+(2<zIC<?Fjpwzw%wNJcg1<o_njbohDEyAJt|XKGTOd# z`{aoriIh^DGZ8w0D?H8N>1kWN(b(dIEIfxuI-U3ZG45cx1L*o_58r#Ox7X7q|5D?r z9g0v?<y2uF@Ok(+Iv^^%M2Bq!r6*$eq=2VmBLnhq4vtlvSRUnLu35|M!NjpVM(k8A z_++2VG4VmfH1ot_nXfogc9};{e3ZEu?!HyzD^9|&Ngs3mfQJTW5)Zi(l_wFyJ>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<NE}dPwVTFLLadEBRN~+V z;02o3sJOOLU!vj-xbO;u?_00qpSUy!##-+;GvCgP*Sq7Y@NK`Z^iVb4_&vM^y6=Tg z8y{iv2VWZ7TTMLAm#QMpqKM36xV}3$P%A*eVLJ%hS{<}|o<3A#D|NWC61B3LNSR)= z#Ve3jDi};lS;BDr58B`BdVyMlmX;87kB0vKu+dD)aJV8P#S~?F-ZqETEP-<ptp>~t z{C?Np?FC)$y&eQghexm&7u~;CWz{hD0=54Y+fzoWSk5~yRND7?35Oe)*tVL@XADTG z$msazOQxZWjz48KHiA7Fu|IzA>~=bx)-sfI<6e8A_t<Q#Nc~kj$Ts*KAOgnBF~Q(X zB>M49L(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!<gVP4b-dT*zC4hJvVr%8JVK;d+R^0lI!R4-&bJ!ut@)8DiF(l% zdlxXV9ZX;9`TuaKvxh&ehUn_etRg>;I=7Xbdk!1z;9(1`L8re49DCSSsnHYnc}(&b DaQ$}< From 27a73a25e345307cfa92adc38b7990c69dc0c74b Mon Sep 17 00:00:00 2001 From: cc9cii <cc9c@iinet.net.au> 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 d12c5d228f..11a675db0c 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 a70b361783..4e4de25c75 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 06db09a0fc..3cdc58f4d3 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 d29155a478..060a6bb39a 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<Pathgrid>& 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<Pathgrid>& 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<Pathgrid>& 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 96dcd943de..2613d0f203 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -3,7 +3,6 @@ #include <QVariant> -#include <components/esm/loadpgrd.hpp> #include <components/esm/effectlist.hpp> #include <components/esm/loadmgef.hpp> // for converting magic effect id to string & back #include <components/esm/loadskil.hpp> // 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<Pathgrid> { public: diff --git a/apps/opencs/model/world/pathgridpointswrap.hpp b/apps/opencs/model/world/pathgridpointswrap.hpp new file mode 100644 index 0000000000..6f1f61fc61 --- /dev/null +++ b/apps/opencs/model/world/pathgridpointswrap.hpp @@ -0,0 +1,26 @@ +#ifndef CSM_WOLRD_PATHGRIDPOINTSWRAP_H +#define CSM_WOLRD_PATHGRIDPOINTSWRAP_H + +#include <components/esm/loadpgrd.hpp> + +#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 ef63909afa..698912344b 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -8,11 +8,16 @@ #include <components/misc/stringops.hpp> #include <components/esm/loadland.hpp> +#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<CSVWorld::PhysicsSystem> 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<CSMWorld::IdTable&> ( - *mData.getTableModel (CSMWorld::UniversalId::Type_References)); + *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_References)); int rows = references.rowCount(); addObjects (0, rows-1); - const CSMWorld::IdCollection<CSMWorld::Land>& land = mData.getLand(); + const CSMWorld::IdCollection<CSMWorld::Land>& 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<CSMWorld::IdTable&> ( - *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<std::string, bool>::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<CSMWorld::IdTable&> ( - *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<CSMWorld::Pathgrid>& pathgridCollection = mData.getPathgrids(); - int index = pathgridCollection.searchId(mId); + const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& 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<CSMWorld::IdTree *>( + 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<ESM::Pathgrid::Point>::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<CSMWorld::Pathgrid>& 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<std::string, int> 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<CSMWorld::Pathgrid>& 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<std::pair<int, int> > 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::pair<int, int>, 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<CSMWorld::Pathgrid>& 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 0afd0920b3..2658ff1adc 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<std::string, Object *> mObjects; std::map<std::string, PathgridPoint *> mPgPoints; std::map<std::pair<int, int>, 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<Terrain::TerrainGrid> mTerrain; boost::shared_ptr<CSVWorld::PhysicsSystem> 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<CSVWorld::PhysicsSystem> 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 9c42e471ed..cc00b91594 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 237bfabf50..b5e9504f33 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::vector<CSMWorld: return false; mCellId = data.begin()->getId(); - 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 <cc9c@iinet.net.au> 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 11a675db0c..172211d7b5 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -6,6 +6,7 @@ #include "idtree.hpp" #include <components/misc/stringops.hpp> #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 4e4de25c75..8661f987ad 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 698912344b..87f70b48eb 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<CSVWorld::PhysicsSystem> 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::pair<int, int>, 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<std::string, PathgridPoint *>::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<CSMWorld::Pathgrid>& 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<CSMWorld::IdTree *>( 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<ESM::Pathgrid::Point>::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::pair<int, int>, 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<std::string, PathgridPoint *>::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<CSMWorld::Pathgrid>& 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<ESM::Pathgrid::Point>::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<std::pair<int, int> > edges; - for(unsigned i = 0; i < pathgrid.mEdges.size(); ++i) + // update edge indicies to account for the deleted pathgrid point + std::vector<ESM::Pathgrid::Edge>::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::pair<int, int>, 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<std::pair<int, int> >::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 2658ff1adc..fac4ded59e 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -11,7 +11,6 @@ #ifndef Q_MOC_RUN #include <components/terrain/terraingrid.hpp> -#include <components/esm/loadpgrd.hpp> // 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 85b03beea9..ea6815fbe8 100644 --- a/apps/opencs/view/render/pathgridpoint.cpp +++ b/apps/opencs/view/render/pathgridpoint.cpp @@ -1,13 +1,10 @@ #include "pathgridpoint.hpp" -#include <iostream> // FIXME - #include <QRegExp> #include <OgreSceneManager.h> #include <OgreSceneNode.h> -//#include "../../model/world/pathgrid.hpp" #include "../world/physicssystem.hpp" #include "elements.hpp" From e7bd29873922d8788422e3da83cd3a668feeb0c3 Mon Sep 17 00:00:00 2001 From: cc9cii <cc9c@iinet.net.au> 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 5822b433ab..35d5e5d3cb 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 172211d7b5..d12c5d228f 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -6,7 +6,6 @@ #include "idtree.hpp" #include <components/misc/stringops.hpp> #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 8661f987ad..0cd8a00f8f 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -12,16 +12,11 @@ #include <QModelIndex> #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 0000000000..356806dcdb --- /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 0000000000..335e3a8933 --- /dev/null +++ b/apps/opencs/model/world/pathgridcommands.hpp @@ -0,0 +1,65 @@ +#ifndef CSM_WOLRD_PATHGRIDCOMMANDS_H +#define CSM_WOLRD_PATHGRIDCOMMANDS_H + +#include <QObject> + +#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 87f70b48eb..7976fd55e9 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<CSVWorld::PhysicsSystem> 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 fac4ded59e..cc00ee1c8b 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<Terrain::TerrainGrid> mTerrain; boost::shared_ptr<CSVWorld::PhysicsSystem> 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 cc00b91594..130f5c4096 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 45e5dd8f7e..099b4db256 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 b5e9504f33..c95a87d038 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::vector<CSMWorld: return false; mCellId = data.begin()->getId(); - 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 11bfaeca30..468c48739b 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 <cc9c@iinet.net.au> 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 02d0424873..2d63b66c97 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -12,7 +12,6 @@ #include <QModelIndex> #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 356806dcdb..193ab44571 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 335e3a8933..3acf0865bf 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 7976fd55e9..f7ec24a56d 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<float>::max(); } +void CSVRender::Cell::pathgridDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + CSMWorld::IdTree *pathgrids = dynamic_cast<CSMWorld::IdTree *>( + 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 cc00ee1c8b..dbf680dd4f 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 130f5c4096..799dd1e7fe 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<CSMWorld::CellCoordinates, Cell *>::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 099b4db256..ea9449b2ff 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 c95a87d038..af121ec196 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 468c48739b..4e19efbf07 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 8418a32a6a..2d690303c5 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 efd2ee8c05..a250547b32 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 <cc9c@iinet.net.au> 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 f7ec24a56d..49af585fd5 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<CSVWorld::PhysicsSystem> 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 38dc41fbc4..e4921c4b70 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 <cc9c@iinet.net.au> 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 3607fb415d..9e39ee37bc 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; }