From f2ff2f298888d32d5dcdb7ae5a18e47f2b07fe6b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 8 Nov 2014 15:51:45 +1100 Subject: [PATCH] Render pathgrid points and edges. Can move the points but the edges are not updated. Visibility mask does not work properly because pathgrid points are considered as objects by the physics engine. --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/editor.cpp | 3 + apps/opencs/view/render/cell.cpp | 120 ++++++++++++++++++++++ apps/opencs/view/render/cell.hpp | 14 +++ apps/opencs/view/render/mousestate.cpp | 85 ++++++++++----- apps/opencs/view/render/mousestate.hpp | 2 + apps/opencs/view/render/pathgridpoint.cpp | 38 +++++++ apps/opencs/view/render/pathgridpoint.hpp | 35 +++++++ files/materials/pathgrid_pt.nif | Bin 0 -> 1683 bytes 9 files changed, 272 insertions(+), 26 deletions(-) create mode 100644 apps/opencs/view/render/pathgridpoint.cpp create mode 100644 apps/opencs/view/render/pathgridpoint.hpp create mode 100644 files/materials/pathgrid_pt.nif diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index ec6f802cf..29f93e566 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -83,6 +83,7 @@ opencs_units (view/render opencs_units_noqt (view/render navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight lightingbright object cell terrainstorage textoverlay overlaymask overlaysystem mousestate + pathgridpoint ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 591667ebb..beab0b607 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -308,6 +308,9 @@ std::auto_ptr CS::Editor::setupGraphics() // for font used in overlays Ogre::Root::getSingleton().addResourceLocation ((mResources / "mygui").string(), "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); + // for pathgrid point nif + Ogre::Root::getSingleton().addResourceLocation ((mResources / "materials").string(), + "FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); if (!boost::filesystem::exists (mCfgMgr.getCachePath())) boost::filesystem::create_directories (mCfgMgr.getCachePath()); diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 75e11cc10..6979a4042 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -10,10 +11,60 @@ #include "../../model/world/idtable.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" +#include "../../model/world/pathgrid.hpp" #include "../world/physicssystem.hpp" #include "elements.hpp" #include "terrainstorage.hpp" +#include "pathgridpoint.hpp" + +// FIXME: redraw edges when pathgrid points are moved, added and deleted +namespace CSVRender +{ + // PLEASE NOTE: pathgrid edge code copied and adapted from mwrender/debugging + static const std::string PG_LINE_MATERIAL = "pathgridLineMaterial"; + static const int POINT_MESH_BASE = 35; + static const std::string DEBUGGING_GROUP = "debugging"; +} + +void CSVRender::Cell::createGridMaterials() +{ + if(Ogre::MaterialManager::getSingleton().getByName(PG_LINE_MATERIAL, DEBUGGING_GROUP).isNull()) + { + Ogre::MaterialPtr lineMatPtr = + Ogre::MaterialManager::getSingleton().create(PG_LINE_MATERIAL, DEBUGGING_GROUP); + lineMatPtr->setReceiveShadows(false); + lineMatPtr->getTechnique(0)->setLightingEnabled(true); + lineMatPtr->getTechnique(0)->getPass(0)->setDiffuse(1,1,0,0); + lineMatPtr->getTechnique(0)->getPass(0)->setAmbient(1,1,0); + lineMatPtr->getTechnique(0)->getPass(0)->setSelfIllumination(1,1,0); + } +} + +void CSVRender::Cell::destroyGridMaterials() +{ + if(!Ogre::MaterialManager::getSingleton().getByName(PG_LINE_MATERIAL, DEBUGGING_GROUP).isNull()) + Ogre::MaterialManager::getSingleton().remove(PG_LINE_MATERIAL); +} + +Ogre::ManualObject *CSVRender::Cell::createPathgridEdge(const std::string &name, + const Ogre::Vector3 &start, const Ogre::Vector3 &end) +{ + Ogre::ManualObject *result = mSceneMgr->createManualObject(name); + + result->begin(PG_LINE_MATERIAL, Ogre::RenderOperation::OT_LINE_LIST); + + Ogre::Vector3 direction = (end - start); + Ogre::Vector3 lineDisplacement = direction.crossProduct(Ogre::Vector3::UNIT_Z).normalisedCopy(); + // move lines up a little, so they will be less covered by meshes/landscape + lineDisplacement = lineDisplacement * POINT_MESH_BASE + Ogre::Vector3(0, 0, 10); + result->position(start + lineDisplacement); + result->position(end + lineDisplacement); + + result->end(); + + return result; +} bool CSVRender::Cell::removeObject (const std::string& id) { @@ -94,10 +145,28 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts); } } + + addPathgrid(); } CSVRender::Cell::~Cell() { + // destroy manual objects + for(std::map, std::string>::iterator iter = mPgEdges.begin(); + iter != mPgEdges.end(); ++iter) + { + if(mSceneMgr->hasManualObject((*iter).second)) + mSceneMgr->destroyManualObject((*iter).second); + } + destroyGridMaterials(); + Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup(DEBUGGING_GROUP); + + for(std::map::iterator iter (mPgPoints.begin()); + iter!=mPgPoints.end(); ++iter) + { + delete iter->second; + } + mPhysics->removeHeightField(mSceneMgr, mX, mY); for (std::map::iterator iter (mObjects.begin()); @@ -236,3 +305,54 @@ float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const else return -std::numeric_limits::max(); } + +void CSVRender::Cell::addPathgrid() +{ + if(!Ogre::ResourceGroupManager::getSingleton().resourceGroupExists(DEBUGGING_GROUP)) + Ogre::ResourceGroupManager::getSingleton().createResourceGroup(DEBUGGING_GROUP); + createGridMaterials(); + + float worldsize = ESM::Land::REAL_SIZE; + + CSMWorld::SubCellCollection& pathgridCollection = mData.getPathgrids(); + int index = pathgridCollection.searchId(mId); + if(index != -1) + { + const CSMWorld::Pathgrid pathgrid = pathgridCollection.getRecord(index).get(); + + std::vector::const_iterator iter = pathgrid.mPoints.begin(); + for(index = 0; iter != pathgrid.mPoints.end(); ++iter, ++index) + { + std::ostringstream stream; + stream << "Pathgrid_" << mId << "_" << index; + std::string name = stream.str(); + + Ogre::Vector3 pos = + Ogre::Vector3(worldsize*mX+(*iter).mX, worldsize*mY+(*iter).mY, (*iter).mZ); + + mPgPoints.insert(std::make_pair(name, new PathgridPoint(name, mCellNode, pos, mPhysics))); + } + + for(ESM::Pathgrid::EdgeList::const_iterator it = pathgrid.mEdges.begin(); + it != pathgrid.mEdges.end(); + ++it) + { + Ogre::SceneNode *node = mCellNode->createChildSceneNode(); + const ESM::Pathgrid::Edge &edge = *it; + const ESM::Pathgrid::Point &p0 = pathgrid.mPoints[edge.mV0]; + const ESM::Pathgrid::Point &p1 = pathgrid.mPoints[edge.mV1]; + + std::ostringstream stream; + stream << mId << "_" << edge.mV0 << " " << edge.mV1; + std::string name = stream.str(); + + Ogre::ManualObject *line = createPathgridEdge(name, + Ogre::Vector3(worldsize*mX+p0.mX, worldsize*mY+p0.mY, p0.mZ), + Ogre::Vector3(worldsize*mX+p1.mX, worldsize*mY+p1.mY, p1.mZ)); + line->setVisibilityFlags(Element_Pathgrid); + node->attachObject(line); + + mPgEdges.insert(std::make_pair(std::make_pair(edge.mV0, edge.mV1), name)); + } + } +} diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index d38f0c68d..c88b59353 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -17,6 +17,7 @@ namespace Ogre { class SceneManager; class SceneNode; + class ManualObject; } namespace CSMWorld @@ -31,12 +32,16 @@ namespace CSVWorld namespace CSVRender { + class PathgridPoint; + class Cell { CSMWorld::Data& mData; std::string mId; Ogre::SceneNode *mCellNode; std::map mObjects; + std::map mPgPoints; + std::map, std::string> mPgEdges; std::auto_ptr mTerrain; CSVWorld::PhysicsSystem *mPhysics; Ogre::SceneManager *mSceneMgr; @@ -82,6 +87,15 @@ namespace CSVRender bool referenceAdded (const QModelIndex& parent, int start, int end); float getTerrainHeightAt(const Ogre::Vector3 &pos) const; + + private: + + // for drawing pathgrid points & lines + void createGridMaterials(); + void destroyGridMaterials(); + void addPathgrid(); + Ogre::ManualObject *createPathgridEdge(const std::string &name, + const Ogre::Vector3 &start, const Ogre::Vector3 &end); }; } diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 45e846f74..aa8f1a785 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -206,6 +206,15 @@ namespace CSVRender mCurrentObj = result.first; } + // print some debug info + std::string referenceId = mPhysics->sceneNodeToRefId(result.first); + if(referenceId != "") + std::cout << "result: " << referenceId << std::endl; + else + std::cout << "result: " << result.first << std::endl; + std::cout << " hit pos "+ QString::number(result.second.x).toStdString() + + ", " + QString::number(result.second.y).toStdString() + + ", " + QString::number(result.second.z).toStdString() << std::endl; } break; } @@ -213,15 +222,22 @@ namespace CSVRender { // final placement std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); - if(planeResult.first) + if(planeResult.first && mGrabbedSceneNode != "") { - if(mGrabbedSceneNode != "") - { - std::pair planeRes = planeAxis(); - Ogre::Vector3 pos = mOrigObjPos+planeRes.first*mOffset+planeResult.second-mOrigMousePos; - // use the saved scene node name since the physics model has not moved yet - std::string referenceId = mPhysics->sceneNodeToRefId(mGrabbedSceneNode); + std::pair planeRes = planeAxis(); + Ogre::Vector3 pos = mOrigObjPos+planeRes.first*mOffset+planeResult.second-mOrigMousePos; + // use the saved scene node name since the physics model has not moved yet + std::string referenceId = mPhysics->sceneNodeToRefId(mGrabbedSceneNode); + if(QString(referenceId.c_str()).contains(QRegExp("^Pathgrid"))) + { + // move pathgrid point, but don't save yet (need pathgrid + // table feature & its data structure to be completed) + // FIXME: need to signal PathgridPoint object of change + placeObject(mGrabbedSceneNode, pos); + } + else + { mParent->mDocument.getUndoStack().beginMacro (QObject::tr("Move Object")); mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, mIdTableModel->getModelIndex(referenceId, mColIndexPosX), pos.x)); @@ -230,22 +246,22 @@ namespace CSVRender mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, mIdTableModel->getModelIndex(referenceId, mColIndexPosZ), pos.z)); mParent->mDocument.getUndoStack().endMacro(); - - // FIXME: highlight current object? - //mCurrentObj = mGrabbedSceneNode; // FIXME: doesn't work? - mCurrentObj = ""; // whether the object is selected - - mMouseState = Mouse_Edit; - - // reset states - mCurrentMousePos = Ogre::Vector3(); // mouse pos to use in wheel event - mOrigMousePos = Ogre::Vector3(); // starting pos of mouse in world space - mOrigObjPos = Ogre::Vector3(); // starting pos of object in world space - mGrabbedSceneNode = ""; // id of the object - mOffset = 0.0f; // used for z-axis movement - mOldPos = QPoint(0, 0); // to calculate relative movement of mouse } - } + + // FIXME: highlight current object? + //mCurrentObj = mGrabbedSceneNode; // FIXME: doesn't work? + mCurrentObj = ""; // whether the object is selected + + mMouseState = Mouse_Edit; + + // reset states + mCurrentMousePos = Ogre::Vector3(); // mouse pos to use in wheel event + mOrigMousePos = Ogre::Vector3(); // starting pos of mouse in world space + mOrigObjPos = Ogre::Vector3(); // starting pos of object in world space + mGrabbedSceneNode = ""; // id of the object + mOffset = 0.0f; // used for z-axis movement + mOldPos = QPoint(0, 0); // to calculate relative movement of mouse + } break; } case Mouse_Edit: @@ -266,9 +282,9 @@ namespace CSVRender void MouseState::mouseDoubleClickEvent (QMouseEvent *event) { - event->ignore(); - //mPhysics->toggleDebugRendering(mSceneManager); - //mParent->flagAsModified(); + //event->ignore(); + mPhysics->toggleDebugRendering(mSceneManager); + mParent->flagAsModified(); } bool MouseState::wheelEvent (QWheelEvent *event) @@ -401,6 +417,10 @@ namespace CSVRender std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); if(result.first != "") { + std::cout << "result: " << result.first << std::endl; + std::cout << " hit pos "+ QString::number(result.second.x).toStdString() + + ", " + QString::number(result.second.y).toStdString() + + ", " + QString::number(result.second.z).toStdString() << std::endl; // FIXME: is there a better way to distinguish terrain from objects? QString name = QString(result.first.c_str()); if(name.contains(QRegExp("^HeightField"))) @@ -423,7 +443,7 @@ namespace CSVRender std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); if(result.first != "") { - // NOTE: anything not terrain is assumed to be an object + // NOTE: anything not terrain is assumed to be an object, e.g pathgrid points QString name = QString(result.first.c_str()); if(!name.contains(QRegExp("^HeightField"))) { @@ -460,4 +480,17 @@ namespace CSVRender { return mParent->getCamera()->getViewport(); } + + void MouseState::placeObject(const std::string sceneNode, const Ogre::Vector3 &pos) + { + mSceneManager->getSceneNode(sceneNode)->setPosition(pos); + + // update physics + std::string refId = mPhysics->sceneNodeToRefId(sceneNode); + + mPhysics->replaceObject(sceneNode, 1, pos, Ogre::Quaternion::IDENTITY); + + // update all SceneWidgets and their SceneManagers + updateSceneWidgets(); + } } diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp index 27907bb33..36d04ef6b 100644 --- a/apps/opencs/view/render/mousestate.hpp +++ b/apps/opencs/view/render/mousestate.hpp @@ -82,6 +82,8 @@ namespace CSVRender std::pair planeAxis(); void updateSceneWidgets(); + void placeObject(const std::string sceneNode, const Ogre::Vector3 &pos); // FIXME + Ogre::Camera *getCamera(); // friend access Ogre::Viewport *getViewport(); // friend access }; diff --git a/apps/opencs/view/render/pathgridpoint.cpp b/apps/opencs/view/render/pathgridpoint.cpp new file mode 100644 index 000000000..2455ea1a8 --- /dev/null +++ b/apps/opencs/view/render/pathgridpoint.cpp @@ -0,0 +1,38 @@ +#include "pathgridpoint.hpp" + +#include // FIXME + +#include +#include + +//#include "../../model/world/pathgrid.hpp" +#include "../world/physicssystem.hpp" + +#include "elements.hpp" + +namespace CSVRender +{ + PathgridPoint::PathgridPoint(const std::string &name, + Ogre::SceneNode *cellNode, const Ogre::Vector3 &pos, CSVWorld::PhysicsSystem *physics) + : mBase(cellNode), mPhysics(physics) + { + mBase = cellNode->createChildSceneNode(); + + mPgPoint = NifOgre::Loader::createObjects(mBase, "pathgrid_pt.nif"); + mPgPoint->setVisibilityFlags(Element_Pathgrid); + mBase->setPosition(pos); + + physics->addObject("pathgrid_pt.nif", + mBase->getName(), name, 1, pos, Ogre::Quaternion::IDENTITY); + } + + PathgridPoint::~PathgridPoint() + { + mPgPoint.setNull(); + + mPhysics->removeObject(mBase->getName()); + + if (mBase) + mBase->getCreator()->destroySceneNode(mBase); + } +} diff --git a/apps/opencs/view/render/pathgridpoint.hpp b/apps/opencs/view/render/pathgridpoint.hpp new file mode 100644 index 000000000..f4fa42790 --- /dev/null +++ b/apps/opencs/view/render/pathgridpoint.hpp @@ -0,0 +1,35 @@ +#ifndef OPENCS_VIEW_PATHGRIDPOINT_H +#define OPENCS_VIEW_PATHGRIDPOINT_H + +#include + +namespace Ogre +{ + class Vector3; + class SceneNode; + class SceneManager; +} + +namespace CSVWorld +{ + class PhysicsSystem; +} + +namespace CSVRender +{ + class PathgridPoint + { + CSVWorld::PhysicsSystem *mPhysics; // local copy + NifOgre::ObjectScenePtr mPgPoint; + Ogre::SceneNode *mBase; + + public: + + PathgridPoint(const std::string &name, + Ogre::SceneNode *cellNode, const Ogre::Vector3 &pos, CSVWorld::PhysicsSystem *physics); + + ~PathgridPoint(); + }; +} + +#endif // OPENCS_VIEW_PATHGRIDPOINT_H diff --git a/files/materials/pathgrid_pt.nif b/files/materials/pathgrid_pt.nif new file mode 100644 index 0000000000000000000000000000000000000000..579b03036c05d5deefe564880dbe312ebbb671f2 GIT binary patch literal 1683 zcmb_c&2G~`5T2w?TS{o5<)=VFsl*Xg0afBs5fvdM4p>M~t z{C?Np?FC)$y&eQghexm&7u~;CWz{hD0=54Y+fzoWSk5~yRND7?35Oe)*tVL@XADTG z$msazOQxZWjz48KHiA7Fu|IzA>~=bx)-sfI<6e8A_tM49L(g%nZumu9vX(p%#5uQlEoZ8R#7-VYypD5R1EVB3_buexwNtrloXhIZ@iTF9 z{Hz^${+)}5IF;yZR(x^t`RvblZ2ox}hRvJ-a%RA%8BP(Knrxg>jG7~^xAk0x1sv9V z%5N;g-(S>Q9HU>GX1)qD24gYiESTIxGG_#)x;!zCin-NQ+-pZ_Xf6w~DA&+ju7hzy zmSsh5$}QZ@HMuQ!;I=7Xbdk!1z;9(1`L8re49DCSSsnHYnc}(&b DaQ$}< literal 0 HcmV?d00001