From 03a30c3f1dcc75bea2a1f6eee37c17a86135f592 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 18 Oct 2014 06:16:48 +1100 Subject: [PATCH 01/56] Experimental, compiles but does not work. --- apps/opencs/CMakeLists.txt | 6 +- apps/opencs/view/render/cell.cpp | 11 +++- apps/opencs/view/render/cell.hpp | 9 ++- apps/opencs/view/render/object.cpp | 15 ++++- apps/opencs/view/render/object.hpp | 11 +++- .../view/render/pagedworldspacewidget.cpp | 5 +- apps/opencs/view/render/previewwidget.cpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 10 +++ apps/opencs/view/render/scenewidget.hpp | 8 +++ .../view/render/unpagedworldspacewidget.cpp | 4 +- apps/opencs/view/world/physicssystem.cpp | 64 +++++++++++++++++++ apps/opencs/view/world/physicssystem.hpp | 48 ++++++++++++++ 12 files changed, 178 insertions(+), 15 deletions(-) create mode 100644 apps/opencs/view/world/physicssystem.cpp create mode 100644 apps/opencs/view/world/physicssystem.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e2e5aa2e5a..8285844522 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -68,7 +68,7 @@ opencs_units (view/world opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate - scripthighlighter idvalidator dialoguecreator + scripthighlighter idvalidator dialoguecreator physicssystem ) opencs_units (view/widget @@ -165,7 +165,7 @@ qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI}) qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT}) qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${BULLET_INCLUDE_DIRS}) if(APPLE) set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/opencs.icns) @@ -175,6 +175,7 @@ endif(APPLE) add_executable(opencs MACOSX_BUNDLE + ${OENGINE_BULLET} ${OPENCS_SRC} ${OPENCS_UI_HDR} ${OPENCS_MOC_SRC} @@ -203,6 +204,7 @@ target_link_libraries(opencs ${OGRE_STATIC_PLUGINS} ${SHINY_LIBRARIES} ${Boost_LIBRARIES} + ${BULLET_LIBRARIES} ${QT_LIBRARIES} components ) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 9ff24780c3..0b24da1ba0 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -10,6 +10,8 @@ #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" +#include "../world/physicssystem.hpp" + #include "elements.hpp" #include "terrainstorage.hpp" @@ -49,7 +51,7 @@ bool CSVRender::Cell::addObjects (int start, int end) std::string id = Misc::StringUtils::lowerCase (references.data ( references.index (i, idColumn)).toString().toUtf8().constData()); - mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false))); + mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics))); modified = true; } } @@ -58,8 +60,8 @@ bool CSVRender::Cell::addObjects (int start, int end) } CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, - const std::string& id, const Ogre::Vector3& origin) -: mData (data), mId (Misc::StringUtils::lowerCase (id)) + const std::string& id, CSVWorld::PhysicsSystem *physics, const Ogre::Vector3& origin) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mPhysics(physics) { mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode->setPosition (origin); @@ -82,6 +84,9 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, mTerrain->loadCell(esmLand->mX, esmLand->mY); } + std::cout << "cell pos" + std::to_string(mCellNode->getPosition().x) + + ", " + std::to_string(mCellNode->getPosition().y) + + ", " + std::to_string(mCellNode->getPosition().z) << std::endl; } CSVRender::Cell::~Cell() diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 98056c3549..5872cc7521 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -23,6 +23,11 @@ namespace CSMWorld class Data; } +namespace CSVWorld +{ + class PhysicsSystem; +} + namespace CSVRender { class Cell @@ -32,6 +37,7 @@ namespace CSVRender Ogre::SceneNode *mCellNode; std::map mObjects; std::auto_ptr mTerrain; + CSVWorld::PhysicsSystem *mPhysics; /// Ignored if cell does not have an object with the given ID. /// @@ -46,7 +52,8 @@ namespace CSVRender public: Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, - const std::string& id, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); + const std::string& id, CSVWorld::PhysicsSystem *physics, + const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); ~Cell(); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 359392d810..ede73da16d 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -9,6 +9,8 @@ #include "../../model/world/ref.hpp" #include "../../model/world/refidcollection.hpp" +#include "../world/physicssystem.hpp" + #include "elements.hpp" void CSVRender::Object::clearSceneNode (Ogre::SceneNode *node) @@ -73,6 +75,12 @@ void CSVRender::Object::update() { mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model); mObject->setVisibilityFlags (Element_Reference); + + bool placeable = true; // FIXME + mPhysics->addObject("meshes\\" + model, mBase->getName(), /*scale*/1, + mBase->getPosition(), mBase->getOrientation(), 0, 0, false, placeable); + mPhysics->addObject("meshes\\" + model, mBase->getName(), /*scale*/1, + mBase->getPosition(), mBase->getOrientation(), 0, 0, true, placeable); // FIXME: why again with raycasting? } } @@ -110,8 +118,9 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const } CSVRender::Object::Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode, - const std::string& id, bool referenceable, bool forceBaseToZero) -: mData (data), mBase (0), mForceBaseToZero (forceBaseToZero) + const std::string& id, bool referenceable, CSVWorld::PhysicsSystem* physics, + bool forceBaseToZero) +: mData (data), mBase (0), mForceBaseToZero (forceBaseToZero), mPhysics(physics) { mBase = cellNode->createChildSceneNode(); @@ -214,4 +223,4 @@ std::string CSVRender::Object::getReferenceId() const std::string CSVRender::Object::getReferenceableId() const { return mReferenceableId; -} \ No newline at end of file +} diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index df39d7393d..eba2dc8148 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -16,6 +16,11 @@ namespace CSMWorld class CellRef; } +namespace CSVWorld +{ + class PhysicsSystem; +} + namespace CSVRender { class Object @@ -26,6 +31,7 @@ namespace CSVRender Ogre::SceneNode *mBase; NifOgre::ObjectScenePtr mObject; bool mForceBaseToZero; + CSVWorld::PhysicsSystem *mPhysics; /// Not implemented Object (const Object&); @@ -51,7 +57,8 @@ namespace CSVRender public: Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode, - const std::string& id, bool referenceable, bool forceBaseToZero = false); + const std::string& id, bool referenceable, + CSVWorld::PhysicsSystem *physics = NULL, bool forceBaseToZero = false); /// \param forceBaseToZero If this is a reference ignore the coordinates and place /// it at 0, 0, 0 instead. @@ -77,4 +84,4 @@ namespace CSVRender }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 8b143e93ff..28c8192a40 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 "elements.hpp" @@ -108,7 +109,8 @@ 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(), iter->getId (mWorldspace)); + Cell *cell = new Cell (mDocument.getData(), getSceneManager(), + iter->getId (mWorldspace), getPhysics()); mCells.insert (std::make_pair (*iter, cell)); float height = cell->getTerrainHeightAt(Ogre::Vector3( @@ -191,6 +193,7 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event if(event->button() == Qt::RightButton) { std::cout << "double clicked" << std::endl; + getPhysics()->toggleDebugRendering(); } } diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index 75b4e93967..eed07f5b6c 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -10,7 +10,7 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) : SceneWidget (parent), mData (data), - mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, true) + mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, getPhysics(), true) { setNavigation (&mOrbit); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 3171e04969..9ab061ca4f 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -13,6 +13,8 @@ #include #include +#include "../world/physicssystem.hpp" + #include "../widget/scenetoolmode.hpp" #include "../../model/settings/usersettings.hpp" @@ -64,6 +66,8 @@ namespace CSVRender mOverlaySystem = OverlaySystem::instance().get(); mSceneMgr->addRenderQueueListener(mOverlaySystem); + mPhysics = new CSVWorld::PhysicsSystem(mSceneMgr); + QTimer *timer = new QTimer (this); connect (timer, SIGNAL (timeout()), this, SLOT (update())); @@ -171,6 +175,7 @@ namespace CSVRender if (mSceneMgr) Ogre::Root::getSingleton().destroySceneManager (mSceneMgr); + delete mPhysics; } void SceneWidget::setVisibilityMask (unsigned int mask) @@ -206,6 +211,11 @@ namespace CSVRender return mViewport; } + CSVWorld::PhysicsSystem *SceneWidget::getPhysics() + { + return mPhysics; + } + Ogre::SceneManager *SceneWidget::getSceneManager() { return mSceneMgr; diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 1adbf3f173..a3dd9cc805 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -25,6 +25,11 @@ namespace CSVWidget class SceneToolbar; } +namespace CSVWorld +{ + class PhysicsSystem; +} + namespace CSVRender { class Navigation; @@ -58,6 +63,8 @@ namespace CSVRender Ogre::Viewport *getViewport(); + CSVWorld::PhysicsSystem *getPhysics(); + Ogre::SceneManager *getSceneManager(); Ogre::Camera *getCamera(); @@ -98,6 +105,7 @@ namespace CSVRender Ogre::RenderWindow* mWindow; Ogre::Viewport *mViewport; Ogre::OverlaySystem *mOverlaySystem; + CSVWorld::PhysicsSystem *mPhysics; Navigation *mNavigation; Lighting *mLighting; diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index aab3791fce..8012b1b246 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -56,7 +56,7 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& update(); - mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId)); + mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, getPhysics())); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, @@ -98,7 +98,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); - mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId)); + mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getPhysics())); update(); emit cellChanged(*data.begin()); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp new file mode 100644 index 0000000000..c9f7888998 --- /dev/null +++ b/apps/opencs/view/world/physicssystem.cpp @@ -0,0 +1,64 @@ +#include "physicssystem.hpp" + +#include +//#include +//#include + +#include + +namespace CSVWorld +{ + PhysicsSystem::PhysicsSystem(Ogre::SceneManager *sceneMgr) + { + // Create physics. shapeLoader is deleted by the physic engine + NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); + mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); + + mEngine->setSceneManager(sceneMgr); // needed for toggleDebugRendering() + } + + PhysicsSystem::~PhysicsSystem() + { + delete mEngine; + } + + // OpenMW | OpenCS + // Ptr | ? + // ptr.getClass().getModel(ptr) | ? // see Object::update() + // ptr.getRefData().getBaseNode() | ? + // ptr.getCellRef().getScale() | ? + // + // getModel() returns the mesh; each class has its own implementation + // + //void PhysicsSystem::addObject (const Ptr& ptr, bool placeable) + void PhysicsSystem::addObject(const std::string &mesh, + const std::string &name, + float scale, + const Ogre::Vector3 &position, + const Ogre::Quaternion &rotation, + Ogre::Vector3* scaledBoxTranslation, + Ogre::Quaternion* boxRotation, + bool raycasting, + bool placeable) + { +#if 0 + std::string mesh = ptr.getClass().getModel(ptr); + Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); + handleToMesh[node->getName()] = mesh; + mEngine->createAndAdjustRigidBody( + mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, false, placeable); + mEngine->createAndAdjustRigidBody( + mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, true, placeable); +#endif + mEngine->createAndAdjustRigidBody(mesh, name, scale, position, rotation, + 0, 0, false, placeable); + mEngine->createAndAdjustRigidBody(mesh, name, scale, position, rotation, + 0, 0, true, placeable); + } + + void PhysicsSystem::toggleDebugRendering() + { + //mEngine->toggleDebugRendering(); + mEngine->setDebugRenderingMode(1); + } +} diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp new file mode 100644 index 0000000000..f96724e1da --- /dev/null +++ b/apps/opencs/view/world/physicssystem.hpp @@ -0,0 +1,48 @@ +#ifndef CSV_WORLD_PHYSICSSYSTEM_H +#define CSV_WORLD_PHYSICSSYSTEM_H + +#include + +namespace Ogre +{ + class Vector3; + class Quaternion; + class SceneManager; +} + +namespace OEngine +{ + namespace Physic + { + class PhysicEngine; + } +} + +namespace CSVWorld +{ + class PhysicsSystem + { + std::map handleToMesh; + OEngine::Physic::PhysicEngine* mEngine; + //Ogre::SceneManager *mSceneMgr; + + public: + + PhysicsSystem(Ogre::SceneManager *sceneMgr); + ~PhysicsSystem(); + + void addObject(const std::string &mesh, + const std::string &name, + float scale, + const Ogre::Vector3 &position, + const Ogre::Quaternion &rotation, + Ogre::Vector3* scaledBoxTranslation = 0, + Ogre::Quaternion* boxRotation = 0, + bool raycasting=false, + bool placeable=false); + + void toggleDebugRendering(); + }; +} + +#endif // CSV_WORLD_PHYSICSSYSTEM_H From 8bcd415cca2a85e85e0eee7a4b66d81b8859b176 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 19 Oct 2014 07:25:54 +1100 Subject: [PATCH 02/56] Fix duplicate calls to OEngine. Use correct position, rotation and scale. Debug draw not working. --- apps/opencs/view/render/cell.cpp | 5 +- apps/opencs/view/render/object.cpp | 51 +++++++++++++++++-- .../view/render/pagedworldspacewidget.cpp | 8 ++- apps/opencs/view/render/scenewidget.cpp | 1 + apps/opencs/view/world/physicssystem.cpp | 27 ++-------- 5 files changed, 59 insertions(+), 33 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 0b24da1ba0..827e266530 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -84,9 +84,6 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, mTerrain->loadCell(esmLand->mX, esmLand->mY); } - std::cout << "cell pos" + std::to_string(mCellNode->getPosition().x) - + ", " + std::to_string(mCellNode->getPosition().y) - + ", " + std::to_string(mCellNode->getPosition().z) << std::endl; } CSVRender::Cell::~Cell() @@ -183,7 +180,7 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, for (std::map::iterator iter (ids.begin()); iter!=ids.end(); ++iter) { mObjects.insert (std::make_pair ( - iter->first, new Object (mData, mCellNode, iter->first, false))); + iter->first, new Object (mData, mCellNode, iter->first, false, mPhysics))); modified = true; } diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index ede73da16d..fcdfc05e15 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -76,11 +76,48 @@ void CSVRender::Object::update() mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model); mObject->setVisibilityFlags (Element_Reference); - bool placeable = true; // FIXME - mPhysics->addObject("meshes\\" + model, mBase->getName(), /*scale*/1, - mBase->getPosition(), mBase->getOrientation(), 0, 0, false, placeable); - mPhysics->addObject("meshes\\" + model, mBase->getName(), /*scale*/1, - mBase->getPosition(), mBase->getOrientation(), 0, 0, true, placeable); // FIXME: why again with raycasting? + // mwrender/objects.cpp: insertBegin() + // + // creates a ChildSceneNode from root if one doesn't exist for that cell (CellStore*) + // creates a ChildSceneNode for that cell scene node + // set the position & scale of the new node (for the object) + // set the orientation of the new node + // set the new node as the basenode (for the object) + // + // render/cell.cpp: Cell() + // + // creates a ChildSceneNode from root + // set the position to origin <---- each object adjusts its position later + // pass the node when creating an Object + // + // render/object.cpp: Object() + // creates a ChildSceneNode from the cell scene node + // + if (!mReferenceId.empty()) + { + const CSMWorld::CellRef& reference = getReference(); + Ogre::Quaternion xr (Ogre::Radian (-reference.mPos.rot[0]), Ogre::Vector3::UNIT_X); + 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); + + bool placeable = false; // FIXME + mPhysics->addObject("meshes\\" + model, + mBase->getName(), + reference.mScale, + Ogre::Vector3(reference.mPos.pos[0], + reference.mPos.pos[1], + reference.mPos.pos[2]), + xr*yr*zr, + 0, 0, false, placeable); + mPhysics->addObject("meshes\\" + model, + mBase->getName(), + reference.mScale, + Ogre::Vector3(reference.mPos.pos[0], + reference.mPos.pos[1], + reference.mPos.pos[2]), + xr*yr*zr, + 0, 0, true, placeable); // FIXME: why again with raycasting? + } } } @@ -136,6 +173,10 @@ CSVRender::Object::Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode update(); adjust(); + std::cout << "obj pos" + std::to_string(mBase->getPosition().x) + + ", " + std::to_string(mBase->getPosition().y) + + ", " + std::to_string(mBase->getPosition().z) << std::endl; + } CSVRender::Object::~Object() diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 28c8192a40..c7d8663606 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -147,7 +147,11 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, height+200)); getSceneManager()->getRootSceneNode()->createChildSceneNode()->attachObject(manual); - manual->setVisible(false); + manual->setVisible(true); + + std::cout << "cell pos" + std::to_string(ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2) + + ", " + std::to_string(ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2) + + ", " + std::to_string(height) << std::endl; CSVRender::TextOverlay *textDisp = new CSVRender::TextOverlay(manual, getCamera(), iter->getId(mWorldspace)); @@ -193,6 +197,8 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event if(event->button() == Qt::RightButton) { std::cout << "double clicked" << std::endl; + //getSceneManager()->setVisibilityMask (4294967295); + getPhysics()->toggleDebugRendering(); } } diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 9ab061ca4f..bb7102f34d 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -66,6 +66,7 @@ namespace CSVRender mOverlaySystem = OverlaySystem::instance().get(); mSceneMgr->addRenderQueueListener(mOverlaySystem); + // FIXME: singleton probably needed mPhysics = new CSVWorld::PhysicsSystem(mSceneMgr); QTimer *timer = new QTimer (this); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index c9f7888998..620b92980f 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -22,15 +22,6 @@ namespace CSVWorld delete mEngine; } - // OpenMW | OpenCS - // Ptr | ? - // ptr.getClass().getModel(ptr) | ? // see Object::update() - // ptr.getRefData().getBaseNode() | ? - // ptr.getCellRef().getScale() | ? - // - // getModel() returns the mesh; each class has its own implementation - // - //void PhysicsSystem::addObject (const Ptr& ptr, bool placeable) void PhysicsSystem::addObject(const std::string &mesh, const std::string &name, float scale, @@ -41,24 +32,14 @@ namespace CSVWorld bool raycasting, bool placeable) { -#if 0 - std::string mesh = ptr.getClass().getModel(ptr); - Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - handleToMesh[node->getName()] = mesh; - mEngine->createAndAdjustRigidBody( - mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, false, placeable); - mEngine->createAndAdjustRigidBody( - mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, true, placeable); -#endif + //handleToMesh[node->getName()] = mesh; mEngine->createAndAdjustRigidBody(mesh, name, scale, position, rotation, - 0, 0, false, placeable); - mEngine->createAndAdjustRigidBody(mesh, name, scale, position, rotation, - 0, 0, true, placeable); + scaledBoxTranslation, boxRotation, raycasting, placeable); } void PhysicsSystem::toggleDebugRendering() { - //mEngine->toggleDebugRendering(); - mEngine->setDebugRenderingMode(1); + mEngine->toggleDebugRendering(); + //mEngine->setDebugRenderingMode(1); } } From 4b53b8658bdb9396217201c3cc300b0d80d288d8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 22 Oct 2014 07:11:04 +1100 Subject: [PATCH 03/56] Debug rendering toggled by double clicking the right mouse button. Raycasting works, but inaccurate. --- apps/opencs/view/render/object.cpp | 48 +++------------ .../view/render/pagedworldspacewidget.cpp | 61 +++++++++++++++++-- apps/opencs/view/world/physicssystem.cpp | 51 ++++++++++++++-- apps/opencs/view/world/physicssystem.hpp | 10 ++- 4 files changed, 118 insertions(+), 52 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index fcdfc05e15..c33131423b 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -36,6 +36,8 @@ void CSVRender::Object::clear() mObject.setNull(); clearSceneNode (mBase); + + // FIXME: also clear bullet objects } void CSVRender::Object::update() @@ -76,47 +78,21 @@ void CSVRender::Object::update() mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model); mObject->setVisibilityFlags (Element_Reference); - // mwrender/objects.cpp: insertBegin() - // - // creates a ChildSceneNode from root if one doesn't exist for that cell (CellStore*) - // creates a ChildSceneNode for that cell scene node - // set the position & scale of the new node (for the object) - // set the orientation of the new node - // set the new node as the basenode (for the object) - // - // render/cell.cpp: Cell() - // - // creates a ChildSceneNode from root - // set the position to origin <---- each object adjusts its position later - // pass the node when creating an Object - // - // render/object.cpp: Object() - // creates a ChildSceneNode from the cell scene node - // if (!mReferenceId.empty()) { const CSMWorld::CellRef& reference = getReference(); + + // position + Ogre::Vector3 position; + if (!mForceBaseToZero) + position = Ogre::Vector3(reference.mPos.pos[0], reference.mPos.pos[1], reference.mPos.pos[2]); + + // orientation Ogre::Quaternion xr (Ogre::Radian (-reference.mPos.rot[0]), Ogre::Vector3::UNIT_X); 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); - bool placeable = false; // FIXME - mPhysics->addObject("meshes\\" + model, - mBase->getName(), - reference.mScale, - Ogre::Vector3(reference.mPos.pos[0], - reference.mPos.pos[1], - reference.mPos.pos[2]), - xr*yr*zr, - 0, 0, false, placeable); - mPhysics->addObject("meshes\\" + model, - mBase->getName(), - reference.mScale, - Ogre::Vector3(reference.mPos.pos[0], - reference.mPos.pos[1], - reference.mPos.pos[2]), - xr*yr*zr, - 0, 0, true, placeable); // FIXME: why again with raycasting? + mPhysics->addObject("meshes\\" + model, mBase->getName(), reference.mScale, position, xr*yr*zr); } } } @@ -173,10 +149,6 @@ CSVRender::Object::Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode update(); adjust(); - std::cout << "obj pos" + std::to_string(mBase->getPosition().x) - + ", " + std::to_string(mBase->getPosition().y) - + ", " + std::to_string(mBase->getPosition().z) << std::endl; - } CSVRender::Object::~Object() diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index c7d8663606..c9991b58e4 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -147,11 +147,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2, height+200)); getSceneManager()->getRootSceneNode()->createChildSceneNode()->attachObject(manual); - manual->setVisible(true); - - std::cout << "cell pos" + std::to_string(ESM::Land::REAL_SIZE * iter->getX() + ESM::Land::REAL_SIZE/2) - + ", " + std::to_string(ESM::Land::REAL_SIZE * iter->getY() + ESM::Land::REAL_SIZE/2) - + ", " + std::to_string(height) << std::endl; + manual->setVisible(false); CSVRender::TextOverlay *textDisp = new CSVRender::TextOverlay(manual, getCamera(), iter->getId(mWorldspace)); @@ -190,6 +186,60 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) } } } + + // mouse picking + // FIXME: need to virtualise mouse buttons + int viewportWidth = getCamera()->getViewport()->getActualWidth(); + int viewportHeight = getCamera()->getViewport()->getActualHeight(); + + float mouseX = (float) event->x()/viewportWidth; + float mouseY = (float) event->y()/viewportHeight; + + getPhysics()->castRay(mouseX, mouseY, NULL, NULL, getCamera()); + //Ogre::Ray mouseRay = getCamera()->getCameraToViewportRay(mouseX, mouseY); + + // Issue: Say 800 pixels (a typical viewport size) representing 8000 units (in one cell) + // So best case resolution is 10 units per pixel. + +#if 0 + Ogre::RaySceneQuery *rayScnQuery = getSceneManager()->createRayQuery(Ogre::Ray()); + rayScnQuery->setRay(mouseRay); + rayScnQuery->setSortByDistance(true); + // kinda works, but bounding box tests aren't accurate + Ogre::RaySceneQueryResult result = rayScnQuery->execute(); + + std::cout << "geometry: " + std::to_string(width()) + ", " + std::to_string(height()) << std::endl; + std::cout << "event: " + std::to_string(event->x()) + ", " + std::to_string(event->y()) << std::endl; + std::cout << "viewport: " + std::to_string(viewportWidth) + ", " + std::to_string(viewportHeight) << std::endl; + std::cout << "mouse: " + std::to_string(mouseX) + ", " + std::to_string(mouseY) << std::endl; + + std::cout << "camera: " + std::to_string(getCamera()->getPosition().x) + + ", " + std::to_string(getCamera()->getPosition().y) + + ", " + std::to_string(getCamera()->getPosition().z) + << std::endl; + std::cout << "ray origin: " + std::to_string(mouseRay.getOrigin().x) + + ", " + std::to_string(mouseRay.getOrigin().y) + + ", " + std::to_string(mouseRay.getOrigin().z) + << std::endl; + std::cout << "ray direction: " + std::to_string(mouseRay.getDirection().x) + + ", " + std::to_string(mouseRay.getDirection().y) + + ", " + std::to_string(mouseRay.getDirection().z) + << std::endl; + //std::cout << "fov" + std::to_string(getCamera()->getFOVy().valueDegrees()) << std::endl; + + Ogre::Vector3 res; + Ogre::Vector3 direction = mouseRay.getDirection(); + OgreRay ray(getSceneManager()); + //if(!clicked && ray.RaycastFromPoint(getCamera()->getPosition(), direction, res)) + if(!clicked && ray.RaycastFromPoint(mouseRay.getOrigin(), direction, res)) + { + //std::cout << "found: " << std::endl; + } + + Ogre::Root::getSingleton().renderOneFrame(); // FIXME: for testing (to show the bounding box) + + getSceneManager()->destroyQuery(rayScnQuery); +#endif } void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) @@ -197,7 +247,6 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event if(event->button() == Qt::RightButton) { std::cout << "double clicked" << std::endl; - //getSceneManager()->setVisibilityMask (4294967295); getPhysics()->toggleDebugRendering(); } diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 620b92980f..5db37f0683 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -1,5 +1,9 @@ #include "physicssystem.hpp" +#include +#include +#include // FIXME: renderOneFrame + #include //#include //#include @@ -27,19 +31,56 @@ namespace CSVWorld float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation, - Ogre::Quaternion* boxRotation, - bool raycasting, + //Ogre::Vector3* scaledBoxTranslation, + //Ogre::Quaternion* boxRotation, + //bool raycasting, bool placeable) { //handleToMesh[node->getName()] = mesh; + mEngine->createAndAdjustRigidBody(mesh, name, scale, position, rotation, - scaledBoxTranslation, boxRotation, raycasting, placeable); + 0, 0, true, placeable); } void PhysicsSystem::toggleDebugRendering() { mEngine->toggleDebugRendering(); - //mEngine->setDebugRenderingMode(1); + mEngine->stepSimulation(0.0167); // FIXME: DebugDrawer::step() not accessible + Ogre::Root::getSingleton().renderOneFrame(); // FIXME: temporary workaround for immediate visual feedback + } + + /*std::pair*/ void PhysicsSystem::castRay(float mouseX, float mouseY, + Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) + { + Ogre::Ray ray = camera->getCameraToViewportRay( + mouseX, + mouseY); + Ogre::Vector3 from = ray.getOrigin(); + Ogre::Vector3 to = ray.getPoint(200000); + //Ogre::Vector3 to = ray.getDirection(); + + btVector3 _from, _to; + _from = btVector3(from.x, from.y, from.z); + _to = btVector3(to.x, to.y, to.z); + + bool raycastingObjectOnly = true; + bool ignoreHeightMap = false; + Ogre::Vector3 norm; + std::pair result = mEngine->rayTest(_from, _to, raycastingObjectOnly, ignoreHeightMap, &norm); + + if (result.first == "") + //return std::make_pair(false, Ogre::Vector3()); + std::cout << "no hit" << std::endl; + else + { + std::cout << "hit " << result.first + + " result " + std::to_string(result.second) << std::endl; + std::cout << "normal " + std::to_string(norm.x) + + ", " + std::to_string(norm.y) + + ", " + std::to_string(norm.z) << std::endl; + std::cout << "hit pos" + std::to_string(ray.getPoint(200000*result.second).x) + + ", " + std::to_string(ray.getPoint(200000*result.second).y) + + ", " + std::to_string(ray.getPoint(200000*result.second).z) << std::endl; + } } } diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index f96724e1da..0aeffc9b22 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -8,6 +8,7 @@ namespace Ogre class Vector3; class Quaternion; class SceneManager; + class Camera; } namespace OEngine @@ -36,12 +37,15 @@ namespace CSVWorld float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation = 0, - Ogre::Quaternion* boxRotation = 0, - bool raycasting=false, + //Ogre::Vector3* scaledBoxTranslation = 0, + //Ogre::Quaternion* boxRotation = 0, + //bool raycasting=false, bool placeable=false); void toggleDebugRendering(); + + /*std::pair*/ void castRay(float mouseX, float mouseY, + Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera); }; } From fdee3fd919fbc1e23e26a07787051a9992e7c2bd Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 23 Oct 2014 06:59:14 +1100 Subject: [PATCH 04/56] Added debug lines to show ray hit position. Added highlighting the Entity hit by the ray. Incorporated user setting far clip distance. --- .../view/render/pagedworldspacewidget.cpp | 70 ++----- apps/opencs/view/render/scenewidget.cpp | 1 + apps/opencs/view/world/physicssystem.cpp | 171 ++++++++++++++++-- apps/opencs/view/world/physicssystem.hpp | 4 +- 4 files changed, 181 insertions(+), 65 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index c9991b58e4..0c53fd41d3 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -186,60 +186,30 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) } } } - - // mouse picking - // FIXME: need to virtualise mouse buttons - int viewportWidth = getCamera()->getViewport()->getActualWidth(); - int viewportHeight = getCamera()->getViewport()->getActualHeight(); - - float mouseX = (float) event->x()/viewportWidth; - float mouseY = (float) event->y()/viewportHeight; - - getPhysics()->castRay(mouseX, mouseY, NULL, NULL, getCamera()); - //Ogre::Ray mouseRay = getCamera()->getCameraToViewportRay(mouseX, mouseY); - - // Issue: Say 800 pixels (a typical viewport size) representing 8000 units (in one cell) - // So best case resolution is 10 units per pixel. - -#if 0 - Ogre::RaySceneQuery *rayScnQuery = getSceneManager()->createRayQuery(Ogre::Ray()); - rayScnQuery->setRay(mouseRay); - rayScnQuery->setSortByDistance(true); - // kinda works, but bounding box tests aren't accurate - Ogre::RaySceneQueryResult result = rayScnQuery->execute(); - - std::cout << "geometry: " + std::to_string(width()) + ", " + std::to_string(height()) << std::endl; - std::cout << "event: " + std::to_string(event->x()) + ", " + std::to_string(event->y()) << std::endl; - std::cout << "viewport: " + std::to_string(viewportWidth) + ", " + std::to_string(viewportHeight) << std::endl; - std::cout << "mouse: " + std::to_string(mouseX) + ", " + std::to_string(mouseY) << std::endl; - - std::cout << "camera: " + std::to_string(getCamera()->getPosition().x) - + ", " + std::to_string(getCamera()->getPosition().y) - + ", " + std::to_string(getCamera()->getPosition().z) - << std::endl; - std::cout << "ray origin: " + std::to_string(mouseRay.getOrigin().x) - + ", " + std::to_string(mouseRay.getOrigin().y) - + ", " + std::to_string(mouseRay.getOrigin().z) - << std::endl; - std::cout << "ray direction: " + std::to_string(mouseRay.getDirection().x) - + ", " + std::to_string(mouseRay.getDirection().y) - + ", " + std::to_string(mouseRay.getDirection().z) - << std::endl; - //std::cout << "fov" + std::to_string(getCamera()->getFOVy().valueDegrees()) << std::endl; - - Ogre::Vector3 res; - Ogre::Vector3 direction = mouseRay.getDirection(); - OgreRay ray(getSceneManager()); - //if(!clicked && ray.RaycastFromPoint(getCamera()->getPosition(), direction, res)) - if(!clicked && ray.RaycastFromPoint(mouseRay.getOrigin(), direction, res)) + else { - //std::cout << "found: " << std::endl; - } + // mouse picking + // FIXME: need to virtualise mouse buttons + // Issue: Say 800 pixels (a typical viewport size) representing 8000 units (in one cell) + // So best case resolution is 10 units per pixel. + int viewportWidth = getCamera()->getViewport()->getActualWidth(); + int viewportHeight = getCamera()->getViewport()->getActualHeight(); - Ogre::Root::getSingleton().renderOneFrame(); // FIXME: for testing (to show the bounding box) + float mouseX = (float) event->x()/viewportWidth; + float mouseY = (float) event->y()/viewportHeight; - getSceneManager()->destroyQuery(rayScnQuery); + getPhysics()->castRay(mouseX, mouseY, NULL, NULL, getCamera()); +#if 0 + std::cout << "geometry: " + std::to_string(width()) + ", " + std::to_string(height()) << std::endl; + std::cout << "event: " + std::to_string(event->x()) + ", " + std::to_string(event->y()) << std::endl; + std::cout << "viewport: " + std::to_string(viewportWidth) + ", " + std::to_string(viewportHeight) << std::endl; + std::cout << "mouse: " + std::to_string(mouseX) + ", " + std::to_string(mouseY) << std::endl; + std::cout << "camera: " + std::to_string(getCamera()->getPosition().x) + + ", " + std::to_string(getCamera()->getPosition().y) + + ", " + std::to_string(getCamera()->getPosition().z) + << std::endl; #endif + } } void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index bb7102f34d..ca58d6fd4d 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -51,6 +51,7 @@ namespace CSVRender mCamera->setPosition (300, 0, 0); mCamera->lookAt (0, 0, 0); mCamera->setNearClipDistance (0.1); + //mCamera->setProjectionType(Ogre::PT_ORTHOGRAPHIC); // FIXME: debugging only CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 5db37f0683..39b402e625 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -1,24 +1,82 @@ #include "physicssystem.hpp" +#include // FIXME: debug only + #include #include +#include // FIXME: debug cursor position +#include // FIXME: visual highlight, clone +#include // FIXME: visual highlight, material +#include // FIXME: visual highlight, texture #include // FIXME: renderOneFrame #include -//#include -//#include - #include +#include "../../model/settings/usersettings.hpp" namespace CSVWorld { - PhysicsSystem::PhysicsSystem(Ogre::SceneManager *sceneMgr) + PhysicsSystem::PhysicsSystem(Ogre::SceneManager *sceneMgr) : mSceneMgr(sceneMgr) { // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); mEngine->setSceneManager(sceneMgr); // needed for toggleDebugRendering() + + // material for visual cue + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTrans"); + if(texture.isNull()) + { + texture = Ogre::TextureManager::getSingleton().createManual( + "DynamicTrans", // name + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, // type + 8, 8, // width & height + 0, // number of mipmaps + Ogre::PF_BYTE_BGRA, // pixel format + Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for + // textures updated very often (e.g. each frame) + + Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); + pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); + const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); + + uint8_t* pDest = static_cast(pixelBox.data); + + // Fill in some pixel data. This will give a semi-transparent colour, + // but this is of course dependent on the chosen pixel format. + for (size_t j = 0; j < 8; j++) + { + for(size_t i = 0; i < 8; i++) + { + *pDest++ = 255; // B + *pDest++ = 255; // G + *pDest++ = 127; // R + *pDest++ = 63; // A + } + + pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format); + } + pixelBuffer->unlock(); + } + Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName( + "TransMaterial"); + if(material.isNull()) + { + Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create( + "TransMaterial", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); + Ogre::Pass *pass = material->getTechnique( 0 )->getPass( 0 ); + pass->setLightingEnabled( false ); + pass->setDepthWriteEnabled( false ); + pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); + + Ogre::TextureUnitState *tex = pass->createTextureUnitState("CustomState", 0); + tex->setTextureName("DynamicTrans"); + tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC ); + material->load(); + } } PhysicsSystem::~PhysicsSystem() @@ -46,17 +104,17 @@ namespace CSVWorld { mEngine->toggleDebugRendering(); mEngine->stepSimulation(0.0167); // FIXME: DebugDrawer::step() not accessible - Ogre::Root::getSingleton().renderOneFrame(); // FIXME: temporary workaround for immediate visual feedback + Ogre::Root::getSingleton().renderOneFrame(); // FIXME: temporary workaround for immediate visual feedback } /*std::pair*/ void PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) { - Ogre::Ray ray = camera->getCameraToViewportRay( - mouseX, - mouseY); + Ogre::Ray ray = camera->getCameraToViewportRay(mouseX, mouseY); Ogre::Vector3 from = ray.getOrigin(); - Ogre::Vector3 to = ray.getPoint(200000); + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + float farClipDist = userSettings.setting("Scene/far clip distance", QString("300000")).toFloat(); + Ogre::Vector3 to = ray.getPoint(farClipDist); //Ogre::Vector3 to = ray.getDirection(); btVector3 _from, _to; @@ -66,7 +124,8 @@ namespace CSVWorld bool raycastingObjectOnly = true; bool ignoreHeightMap = false; Ogre::Vector3 norm; - std::pair result = mEngine->rayTest(_from, _to, raycastingObjectOnly, ignoreHeightMap, &norm); + std::pair result = + mEngine->rayTest(_from, _to, raycastingObjectOnly, ignoreHeightMap, &norm); if (result.first == "") //return std::make_pair(false, Ogre::Vector3()); @@ -74,13 +133,97 @@ namespace CSVWorld else { std::cout << "hit " << result.first - + " result " + std::to_string(result.second) << std::endl; + + " result " + std::to_string(result.second*farClipDist) << std::endl; std::cout << "normal " + std::to_string(norm.x) + ", " + std::to_string(norm.y) + ", " + std::to_string(norm.z) << std::endl; - std::cout << "hit pos" + std::to_string(ray.getPoint(200000*result.second).x) - + ", " + std::to_string(ray.getPoint(200000*result.second).y) - + ", " + std::to_string(ray.getPoint(200000*result.second).z) << std::endl; + std::cout << "hit pos "+ std::to_string(ray.getPoint(farClipDist*result.second).x) + + ", " + std::to_string(ray.getPoint(farClipDist*result.second).y) + + ", " + std::to_string(ray.getPoint(farClipDist*result.second).z) << std::endl; + if(mSceneMgr->hasSceneNode(result.first)) + { + // FIXME: for debugging cursor position + // If using orthographic projection the cursor position is very accurate, + // but with the default perspective view the cursor position is not properly + // calculated when using getCameraToViewportRay. + // See http://www.ogre3d.org/forums/viewtopic.php?p=241933 + mSceneMgr->destroyManualObject("manual" + result.first); + Ogre::ManualObject* manual = mSceneMgr->createManualObject("manual" + result.first); + manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); + manual-> position(ray.getPoint(farClipDist*result.second).x, + ray.getPoint(farClipDist*result.second).y, + ray.getPoint(farClipDist*result.second).z); + manual-> position(ray.getPoint(farClipDist*result.second).x, + ray.getPoint(farClipDist*result.second).y, + ray.getPoint(farClipDist*result.second).z+2000); + manual-> position(ray.getPoint(farClipDist*result.second).x, + ray.getPoint(farClipDist*result.second).y, + ray.getPoint(farClipDist*result.second).z); + manual-> position(ray.getPoint(farClipDist*result.second).x, + ray.getPoint(farClipDist*result.second).y+2000, + ray.getPoint(farClipDist*result.second).z); + manual-> position(ray.getPoint(farClipDist*result.second).x, + ray.getPoint(farClipDist*result.second).y, + ray.getPoint(farClipDist*result.second).z); + manual-> position(ray.getPoint(farClipDist*result.second).x+2000, + ray.getPoint(farClipDist*result.second).y, + ray.getPoint(farClipDist*result.second).z); + manual->end(); + mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); + // end debugging cursor position + + Ogre::SceneNode *scene = mSceneMgr->getSceneNode(result.first); + std::map>::iterator iter = + mSelectedEntities.find(result.first); + if(iter != mSelectedEntities.end()) // currently selected + { + //scene->showBoundingBox(false); + std::vector deletedEntities = mSelectedEntities[result.first]; + while(!deletedEntities.empty()) + { + scene->detachObject(deletedEntities.back()); + mSceneMgr->destroyEntity(deletedEntities.back()); + deletedEntities.pop_back(); + } + mSelectedEntities.erase(iter); + mSceneMgr->destroyManualObject("manual" + result.first); + } + else + { + //scene->showBoundingBox(true); + std::vector clonedEntities; + Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); + iter.begin(); + while(iter.hasMoreElements()) + { + Ogre::MovableObject * element = iter.getNext(); + if(element->getMovableType() != "Entity") + continue; + + Ogre::Entity * e = dynamic_cast(element); + if(mSceneMgr->hasEntity(e->getName()+"cover")) + { + // FIXME: this shouldn't really happen... + scene->detachObject(e->getName()+"cover"); + mSceneMgr->destroyEntity(e->getName()+"cover"); + } + Ogre::Entity * clone = e->clone(e->getName()+"cover"); + + Ogre::MaterialPtr mat = + Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); + if(!mat.isNull()) + { + clone->setMaterial(mat); + scene->attachObject(clone); + clonedEntities.push_back(e->getName()+"cover"); + } + + } + mSelectedEntities[result.first] = clonedEntities; + } + // FIXME: temporary workaround for immediate visual feedback + Ogre::Root::getSingleton().renderOneFrame(); + } } } } diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 0aeffc9b22..109a208934 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -2,6 +2,7 @@ #define CSV_WORLD_PHYSICSSYSTEM_H #include +#include namespace Ogre { @@ -25,7 +26,8 @@ namespace CSVWorld { std::map handleToMesh; OEngine::Physic::PhysicEngine* mEngine; - //Ogre::SceneManager *mSceneMgr; + Ogre::SceneManager *mSceneMgr; + std::map> mSelectedEntities; public: From cca6d0a024fadb911583f8d1a2a0c253a9d4907a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 23 Oct 2014 12:43:06 +1100 Subject: [PATCH 05/56] Fixed issue with mouse picking accuracy. --- apps/opencs/view/render/scenewidget.cpp | 1 - apps/opencs/view/world/physicssystem.cpp | 16 ++++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index ca58d6fd4d..bb7102f34d 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -51,7 +51,6 @@ namespace CSVRender mCamera->setPosition (300, 0, 0); mCamera->lookAt (0, 0, 0); mCamera->setNearClipDistance (0.1); - //mCamera->setProjectionType(Ogre::PT_ORTHOGRAPHIC); // FIXME: debugging only CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 39b402e625..b47d868ab7 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -110,12 +110,16 @@ namespace CSVWorld /*std::pair*/ void PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) { + // using a really small value seems to mess up with the projections + float nearClipDistance = camera->getNearClipDistance(); + camera->setNearClipDistance(10.0f); // arbitrary number Ogre::Ray ray = camera->getCameraToViewportRay(mouseX, mouseY); + camera->setNearClipDistance(nearClipDistance); + Ogre::Vector3 from = ray.getOrigin(); CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); float farClipDist = userSettings.setting("Scene/far clip distance", QString("300000")).toFloat(); Ogre::Vector3 to = ray.getPoint(farClipDist); - //Ogre::Vector3 to = ray.getDirection(); btVector3 _from, _to; _from = btVector3(from.x, from.y, from.z); @@ -143,10 +147,6 @@ namespace CSVWorld if(mSceneMgr->hasSceneNode(result.first)) { // FIXME: for debugging cursor position - // If using orthographic projection the cursor position is very accurate, - // but with the default perspective view the cursor position is not properly - // calculated when using getCameraToViewportRay. - // See http://www.ogre3d.org/forums/viewtopic.php?p=241933 mSceneMgr->destroyManualObject("manual" + result.first); Ogre::ManualObject* manual = mSceneMgr->createManualObject("manual" + result.first); manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); @@ -155,17 +155,17 @@ namespace CSVWorld ray.getPoint(farClipDist*result.second).z); manual-> position(ray.getPoint(farClipDist*result.second).x, ray.getPoint(farClipDist*result.second).y, - ray.getPoint(farClipDist*result.second).z+2000); + ray.getPoint(farClipDist*result.second).z+1000); manual-> position(ray.getPoint(farClipDist*result.second).x, ray.getPoint(farClipDist*result.second).y, ray.getPoint(farClipDist*result.second).z); manual-> position(ray.getPoint(farClipDist*result.second).x, - ray.getPoint(farClipDist*result.second).y+2000, + ray.getPoint(farClipDist*result.second).y+1000, ray.getPoint(farClipDist*result.second).z); manual-> position(ray.getPoint(farClipDist*result.second).x, ray.getPoint(farClipDist*result.second).y, ray.getPoint(farClipDist*result.second).z); - manual-> position(ray.getPoint(farClipDist*result.second).x+2000, + manual-> position(ray.getPoint(farClipDist*result.second).x+1000, ray.getPoint(farClipDist*result.second).y, ray.getPoint(farClipDist*result.second).z); manual->end(); From 4d86371ca35a9f82f768d2e46744d987d96e9640 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 23 Oct 2014 15:35:01 +1100 Subject: [PATCH 06/56] Minor refactoring and cleanup. --- apps/opencs/view/world/physicssystem.cpp | 188 ++++++++++++----------- apps/opencs/view/world/physicssystem.hpp | 6 +- 2 files changed, 101 insertions(+), 93 deletions(-) diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index b47d868ab7..77466d7465 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -14,6 +14,29 @@ #include #include "../../model/settings/usersettings.hpp" +namespace +{ + void showHitPoint(Ogre::SceneManager *sceneMgr, std::string name, Ogre::Vector3 point) + { + sceneMgr->destroyManualObject("manual" + name); + Ogre::ManualObject* manual = sceneMgr->createManualObject("manual" + name); + manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); + manual-> position(point.x, point.y, point.z-100); + manual-> position(point.x, point.y, point.z+100); + manual-> position(point.x, point.y-100, point.z); + manual-> position(point.x, point.y+100, point.z); + manual-> position(point.x-100, point.y, point.z); + manual-> position(point.x+100, point.y, point.z); + manual->end(); + sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); + } + + void removeHitPoint(Ogre::SceneManager *sceneMgr, std::string name) + { + sceneMgr->destroyManualObject("manual" + name); + } +} + namespace CSVWorld { PhysicsSystem::PhysicsSystem(Ogre::SceneManager *sceneMgr) : mSceneMgr(sceneMgr) @@ -24,7 +47,7 @@ namespace CSVWorld mEngine->setSceneManager(sceneMgr); // needed for toggleDebugRendering() - // material for visual cue + // material for visual cue on selected objects Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTrans"); if(texture.isNull()) { @@ -89,15 +112,21 @@ namespace CSVWorld float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - //Ogre::Vector3* scaledBoxTranslation, - //Ogre::Quaternion* boxRotation, - //bool raycasting, bool placeable) { - //handleToMesh[node->getName()] = mesh; + //mHandleToMesh[name] = mesh; mEngine->createAndAdjustRigidBody(mesh, name, scale, position, rotation, - 0, 0, true, placeable); + 0, // scaledBoxTranslation + 0, // boxRotation + true, // raycasting + placeable); + } + + void PhysicsSystem::removeObject(const std::string& name) + { + mEngine->removeRigidBody(name); + mEngine->deleteRigidBody(name); } void PhysicsSystem::toggleDebugRendering() @@ -107,7 +136,7 @@ namespace CSVWorld Ogre::Root::getSingleton().renderOneFrame(); // FIXME: temporary workaround for immediate visual feedback } - /*std::pair*/ void PhysicsSystem::castRay(float mouseX, float mouseY, + std::pair PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) { // using a really small value seems to mess up with the projections @@ -129,13 +158,68 @@ namespace CSVWorld bool ignoreHeightMap = false; Ogre::Vector3 norm; std::pair result = - mEngine->rayTest(_from, _to, raycastingObjectOnly, ignoreHeightMap, &norm); + mEngine->rayTest(_from, _to, raycastingObjectOnly, ignoreHeightMap, &norm); - if (result.first == "") - //return std::make_pair(false, Ogre::Vector3()); - std::cout << "no hit" << std::endl; + if ((result.first == "") || !mSceneMgr->hasSceneNode(result.first)) + return std::make_pair(false, Ogre::Vector3()); + //std::cout << "no hit" << std::endl; else { + //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character + Ogre::SceneNode *scene = mSceneMgr->getSceneNode(result.first); + std::map>::iterator iter = + mSelectedEntities.find(result.first); + if(iter != mSelectedEntities.end()) // currently selected + { + std::vector deletedEntities = mSelectedEntities[result.first]; + while(!deletedEntities.empty()) + { + scene->detachObject(deletedEntities.back()); + mSceneMgr->destroyEntity(deletedEntities.back()); + deletedEntities.pop_back(); + } + mSelectedEntities.erase(iter); + + removeHitPoint(mSceneMgr, result.first); // FIXME: for debugging + } + else + { + std::vector clonedEntities; + Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); + iter.begin(); + while(iter.hasMoreElements()) + { + Ogre::MovableObject * element = iter.getNext(); + if(element->getMovableType() != "Entity") + continue; + + Ogre::Entity * entity = dynamic_cast(element); + if(mSceneMgr->hasEntity(entity->getName()+"cover")) + { + // FIXME: this shouldn't really happen... but does :( + scene->detachObject(entity->getName()+"cover"); + mSceneMgr->destroyEntity(entity->getName()+"cover"); + } + Ogre::Entity * clone = entity->clone(entity->getName()+"cover"); + + Ogre::MaterialPtr mat = + Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); + if(!mat.isNull()) + { + clone->setMaterial(mat); + scene->attachObject(clone); + clonedEntities.push_back(entity->getName()+"cover"); + } + + } + mSelectedEntities[result.first] = clonedEntities; + + // FIXME: show cursor position for debugging + showHitPoint(mSceneMgr, result.first, ray.getPoint(farClipDist*result.second)); + } + // FIXME: temporary workaround for immediate visual feedback + Ogre::Root::getSingleton().renderOneFrame(); +#if 0 std::cout << "hit " << result.first + " result " + std::to_string(result.second*farClipDist) << std::endl; std::cout << "normal " + std::to_string(norm.x) @@ -144,86 +228,8 @@ namespace CSVWorld std::cout << "hit pos "+ std::to_string(ray.getPoint(farClipDist*result.second).x) + ", " + std::to_string(ray.getPoint(farClipDist*result.second).y) + ", " + std::to_string(ray.getPoint(farClipDist*result.second).z) << std::endl; - if(mSceneMgr->hasSceneNode(result.first)) - { - // FIXME: for debugging cursor position - mSceneMgr->destroyManualObject("manual" + result.first); - Ogre::ManualObject* manual = mSceneMgr->createManualObject("manual" + result.first); - manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); - manual-> position(ray.getPoint(farClipDist*result.second).x, - ray.getPoint(farClipDist*result.second).y, - ray.getPoint(farClipDist*result.second).z); - manual-> position(ray.getPoint(farClipDist*result.second).x, - ray.getPoint(farClipDist*result.second).y, - ray.getPoint(farClipDist*result.second).z+1000); - manual-> position(ray.getPoint(farClipDist*result.second).x, - ray.getPoint(farClipDist*result.second).y, - ray.getPoint(farClipDist*result.second).z); - manual-> position(ray.getPoint(farClipDist*result.second).x, - ray.getPoint(farClipDist*result.second).y+1000, - ray.getPoint(farClipDist*result.second).z); - manual-> position(ray.getPoint(farClipDist*result.second).x, - ray.getPoint(farClipDist*result.second).y, - ray.getPoint(farClipDist*result.second).z); - manual-> position(ray.getPoint(farClipDist*result.second).x+1000, - ray.getPoint(farClipDist*result.second).y, - ray.getPoint(farClipDist*result.second).z); - manual->end(); - mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); - // end debugging cursor position - - Ogre::SceneNode *scene = mSceneMgr->getSceneNode(result.first); - std::map>::iterator iter = - mSelectedEntities.find(result.first); - if(iter != mSelectedEntities.end()) // currently selected - { - //scene->showBoundingBox(false); - std::vector deletedEntities = mSelectedEntities[result.first]; - while(!deletedEntities.empty()) - { - scene->detachObject(deletedEntities.back()); - mSceneMgr->destroyEntity(deletedEntities.back()); - deletedEntities.pop_back(); - } - mSelectedEntities.erase(iter); - mSceneMgr->destroyManualObject("manual" + result.first); - } - else - { - //scene->showBoundingBox(true); - std::vector clonedEntities; - Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); - iter.begin(); - while(iter.hasMoreElements()) - { - Ogre::MovableObject * element = iter.getNext(); - if(element->getMovableType() != "Entity") - continue; - - Ogre::Entity * e = dynamic_cast(element); - if(mSceneMgr->hasEntity(e->getName()+"cover")) - { - // FIXME: this shouldn't really happen... - scene->detachObject(e->getName()+"cover"); - mSceneMgr->destroyEntity(e->getName()+"cover"); - } - Ogre::Entity * clone = e->clone(e->getName()+"cover"); - - Ogre::MaterialPtr mat = - Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); - if(!mat.isNull()) - { - clone->setMaterial(mat); - scene->attachObject(clone); - clonedEntities.push_back(e->getName()+"cover"); - } - - } - mSelectedEntities[result.first] = clonedEntities; - } - // FIXME: temporary workaround for immediate visual feedback - Ogre::Root::getSingleton().renderOneFrame(); - } +#endif + return std::make_pair(true, ray.getPoint(farClipDist*result.second)); } } } diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 109a208934..5b49e3872b 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -24,7 +24,7 @@ namespace CSVWorld { class PhysicsSystem { - std::map handleToMesh; + //std::map mHandleToMesh; OEngine::Physic::PhysicEngine* mEngine; Ogre::SceneManager *mSceneMgr; std::map> mSelectedEntities; @@ -44,9 +44,11 @@ namespace CSVWorld //bool raycasting=false, bool placeable=false); + void removeObject(const std::string &name); + void toggleDebugRendering(); - /*std::pair*/ void castRay(float mouseX, float mouseY, + std::pair castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera); }; } From 39cd89a9af922f9792ffcc94353f5a33f2556680 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 23 Oct 2014 18:51:31 +1100 Subject: [PATCH 07/56] Make gcc happy. --- apps/opencs/view/render/pagedworldspacewidget.cpp | 1 + apps/opencs/view/world/physicssystem.cpp | 7 ++----- apps/opencs/view/world/physicssystem.hpp | 3 ++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 0c53fd41d3..d2cc74587f 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -199,6 +199,7 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) float mouseY = (float) event->y()/viewportHeight; getPhysics()->castRay(mouseX, mouseY, NULL, NULL, getCamera()); + flagAsModified(); #if 0 std::cout << "geometry: " + std::to_string(width()) + ", " + std::to_string(height()) << std::endl; std::cout << "event: " + std::to_string(event->x()) + ", " + std::to_string(event->y()) << std::endl; diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 77466d7465..eeedfbb00a 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -4,11 +4,11 @@ #include #include +#include #include // FIXME: debug cursor position #include // FIXME: visual highlight, clone #include // FIXME: visual highlight, material #include // FIXME: visual highlight, texture -#include // FIXME: renderOneFrame #include #include @@ -133,7 +133,6 @@ namespace CSVWorld { mEngine->toggleDebugRendering(); mEngine->stepSimulation(0.0167); // FIXME: DebugDrawer::step() not accessible - Ogre::Root::getSingleton().renderOneFrame(); // FIXME: temporary workaround for immediate visual feedback } std::pair PhysicsSystem::castRay(float mouseX, float mouseY, @@ -167,7 +166,7 @@ namespace CSVWorld { //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character Ogre::SceneNode *scene = mSceneMgr->getSceneNode(result.first); - std::map>::iterator iter = + std::map >::iterator iter = mSelectedEntities.find(result.first); if(iter != mSelectedEntities.end()) // currently selected { @@ -217,8 +216,6 @@ namespace CSVWorld // FIXME: show cursor position for debugging showHitPoint(mSceneMgr, result.first, ray.getPoint(farClipDist*result.second)); } - // FIXME: temporary workaround for immediate visual feedback - Ogre::Root::getSingleton().renderOneFrame(); #if 0 std::cout << "hit " << result.first + " result " + std::to_string(result.second*farClipDist) << std::endl; diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 5b49e3872b..ec0657ee24 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -1,6 +1,7 @@ #ifndef CSV_WORLD_PHYSICSSYSTEM_H #define CSV_WORLD_PHYSICSSYSTEM_H +#include #include #include @@ -27,7 +28,7 @@ namespace CSVWorld //std::map mHandleToMesh; OEngine::Physic::PhysicEngine* mEngine; Ogre::SceneManager *mSceneMgr; - std::map> mSelectedEntities; + std::map > mSelectedEntities; public: From 2f26fc11881bc4853817d06af6d22c81907bf64a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 23 Oct 2014 20:14:01 +1100 Subject: [PATCH 08/56] Avoid Ogre exceptions and null pointers. --- apps/opencs/view/world/physicssystem.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index eeedfbb00a..331625c842 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -170,12 +170,15 @@ namespace CSVWorld mSelectedEntities.find(result.first); if(iter != mSelectedEntities.end()) // currently selected { - std::vector deletedEntities = mSelectedEntities[result.first]; - while(!deletedEntities.empty()) + std::vector clonedEntities = mSelectedEntities[result.first]; + while(!clonedEntities.empty()) { - scene->detachObject(deletedEntities.back()); - mSceneMgr->destroyEntity(deletedEntities.back()); - deletedEntities.pop_back(); + if(mSceneMgr->hasEntity(clonedEntities.back())) + { + scene->detachObject(clonedEntities.back()); + mSceneMgr->destroyEntity(clonedEntities.back()); + } + clonedEntities.pop_back(); } mSelectedEntities.erase(iter); @@ -189,6 +192,9 @@ namespace CSVWorld while(iter.hasMoreElements()) { Ogre::MovableObject * element = iter.getNext(); + if(!element) + break; + if(element->getMovableType() != "Entity") continue; From 98ff3e7307e0173f26b336aa6e8d8c75a90f5097 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 24 Oct 2014 07:57:29 +1100 Subject: [PATCH 09/56] No physics or mouse picking for object preview. --- apps/opencs/view/render/object.cpp | 2 +- apps/opencs/view/render/previewwidget.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index c33131423b..c973bdeae7 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -78,7 +78,7 @@ void CSVRender::Object::update() mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model); mObject->setVisibilityFlags (Element_Reference); - if (!mReferenceId.empty()) + if (mPhysics && !mReferenceId.empty()) { const CSMWorld::CellRef& reference = getReference(); diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index eed07f5b6c..f972c6361b 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -10,7 +10,7 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) : SceneWidget (parent), mData (data), - mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, getPhysics(), true) + mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, NULL, true) { setNavigation (&mOrbit); From cb53e714f7c79eaf1eebf29f8c0d60cc79ebd7d4 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 24 Oct 2014 19:14:02 +1000 Subject: [PATCH 10/56] Convert PhysicsSystem to a singleton. --- apps/opencs/editor.cpp | 3 +- apps/opencs/editor.hpp | 2 + apps/opencs/view/render/cell.cpp | 10 ++- apps/opencs/view/render/cell.hpp | 9 +-- apps/opencs/view/render/object.cpp | 10 +-- apps/opencs/view/render/object.hpp | 9 +-- .../view/render/pagedworldspacewidget.cpp | 10 ++- apps/opencs/view/render/previewwidget.cpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 9 +-- apps/opencs/view/render/scenewidget.hpp | 8 --- .../view/render/unpagedworldspacewidget.cpp | 4 +- apps/opencs/view/world/physicssystem.cpp | 64 +++++++++++++------ apps/opencs/view/world/physicssystem.hpp | 7 +- 13 files changed, 75 insertions(+), 72 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 982fc20d5b..beb50fceae 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -21,7 +21,7 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) : mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr), - mViewManager (mDocumentManager), + mViewManager (mDocumentManager), mPhysicsSystem (0), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) { std::pair > config = readConfig(); @@ -34,6 +34,7 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string()); mOverlaySystem.reset (new CSVRender::OverlaySystem); + mPhysicsSystem.reset (new CSVWorld::PhysicsSystem); Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, mFsStrict); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index cd39d53a48..4d2fdc2eb1 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -28,6 +28,7 @@ #include "view/settings/dialog.hpp" #include "view/render/overlaysystem.hpp" +#include "view/world/physicssystem.hpp" namespace OgreInit { @@ -44,6 +45,7 @@ namespace CS Files::ConfigurationManager mCfgMgr; CSMSettings::UserSettings mUserSettings; std::auto_ptr mOverlaySystem; + std::auto_ptr mPhysicsSystem; CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 827e266530..9ff24780c3 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -10,8 +10,6 @@ #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" -#include "../world/physicssystem.hpp" - #include "elements.hpp" #include "terrainstorage.hpp" @@ -51,7 +49,7 @@ bool CSVRender::Cell::addObjects (int start, int end) std::string id = Misc::StringUtils::lowerCase (references.data ( references.index (i, idColumn)).toString().toUtf8().constData()); - mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics))); + mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false))); modified = true; } } @@ -60,8 +58,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)), mPhysics(physics) + const std::string& id, const Ogre::Vector3& origin) +: mData (data), mId (Misc::StringUtils::lowerCase (id)) { mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode->setPosition (origin); @@ -180,7 +178,7 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, for (std::map::iterator iter (ids.begin()); iter!=ids.end(); ++iter) { mObjects.insert (std::make_pair ( - iter->first, new Object (mData, mCellNode, iter->first, false, mPhysics))); + iter->first, new Object (mData, mCellNode, iter->first, false))); modified = true; } diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 5872cc7521..98056c3549 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -23,11 +23,6 @@ namespace CSMWorld class Data; } -namespace CSVWorld -{ - class PhysicsSystem; -} - namespace CSVRender { class Cell @@ -37,7 +32,6 @@ namespace CSVRender Ogre::SceneNode *mCellNode; std::map mObjects; std::auto_ptr mTerrain; - CSVWorld::PhysicsSystem *mPhysics; /// Ignored if cell does not have an object with the given ID. /// @@ -52,8 +46,7 @@ namespace CSVRender public: Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, - const std::string& id, CSVWorld::PhysicsSystem *physics, - const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); + const std::string& id, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); ~Cell(); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index c973bdeae7..13266473e9 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -78,7 +78,7 @@ void CSVRender::Object::update() mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model); mObject->setVisibilityFlags (Element_Reference); - if (mPhysics && !mReferenceId.empty()) + if (!mReferenceId.empty()) { const CSMWorld::CellRef& reference = getReference(); @@ -92,7 +92,8 @@ 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); - mPhysics->addObject("meshes\\" + model, mBase->getName(), reference.mScale, position, xr*yr*zr); + CSVWorld::PhysicsSystem::instance()->addObject("meshes\\" + model, + mBase->getName(), reference.mScale, position, xr*yr*zr); } } } @@ -131,9 +132,8 @@ 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) + const std::string& id, bool referenceable, bool forceBaseToZero) +: mData (data), mBase (0), mForceBaseToZero (forceBaseToZero) { mBase = cellNode->createChildSceneNode(); diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index eba2dc8148..6a8a933e51 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -16,11 +16,6 @@ namespace CSMWorld class CellRef; } -namespace CSVWorld -{ - class PhysicsSystem; -} - namespace CSVRender { class Object @@ -31,7 +26,6 @@ namespace CSVRender Ogre::SceneNode *mBase; NifOgre::ObjectScenePtr mObject; bool mForceBaseToZero; - CSVWorld::PhysicsSystem *mPhysics; /// Not implemented Object (const Object&); @@ -57,8 +51,7 @@ namespace CSVRender public: Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode, - const std::string& id, bool referenceable, - CSVWorld::PhysicsSystem *physics = NULL, bool forceBaseToZero = false); + const std::string& id, bool referenceable, bool forceBaseToZero = false); /// \param forceBaseToZero If this is a reference ignore the coordinates and place /// it at 0, 0, 0 instead. diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index d2cc74587f..b7d53b9e3e 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -110,7 +110,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() mCells.find (*iter)==mCells.end()) { Cell *cell = new Cell (mDocument.getData(), getSceneManager(), - iter->getId (mWorldspace), getPhysics()); + iter->getId (mWorldspace)); mCells.insert (std::make_pair (*iter, cell)); float height = cell->getTerrainHeightAt(Ogre::Vector3( @@ -198,7 +198,9 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) float mouseX = (float) event->x()/viewportWidth; float mouseY = (float) event->y()/viewportHeight; - getPhysics()->castRay(mouseX, mouseY, NULL, NULL, getCamera()); + // Need to set each time in case there are multiple subviews + CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); + CSVWorld::PhysicsSystem::instance()->castRay(mouseX, mouseY, NULL, NULL, getCamera()); flagAsModified(); #if 0 std::cout << "geometry: " + std::to_string(width()) + ", " + std::to_string(height()) << std::endl; @@ -219,7 +221,9 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event { std::cout << "double clicked" << std::endl; - getPhysics()->toggleDebugRendering(); + // Need to set each time in case there are multiple subviews + CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); + CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(); } } diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index f972c6361b..75b4e93967 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -10,7 +10,7 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) : SceneWidget (parent), mData (data), - mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, NULL, true) + mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, true) { setNavigation (&mOrbit); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index bb7102f34d..cf46e52522 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -66,8 +66,7 @@ namespace CSVRender mOverlaySystem = OverlaySystem::instance().get(); mSceneMgr->addRenderQueueListener(mOverlaySystem); - // FIXME: singleton probably needed - mPhysics = new CSVWorld::PhysicsSystem(mSceneMgr); + CSVWorld::PhysicsSystem::instance()->setSceneManager(mSceneMgr); QTimer *timer = new QTimer (this); @@ -176,7 +175,6 @@ namespace CSVRender if (mSceneMgr) Ogre::Root::getSingleton().destroySceneManager (mSceneMgr); - delete mPhysics; } void SceneWidget::setVisibilityMask (unsigned int mask) @@ -212,11 +210,6 @@ namespace CSVRender return mViewport; } - CSVWorld::PhysicsSystem *SceneWidget::getPhysics() - { - return mPhysics; - } - Ogre::SceneManager *SceneWidget::getSceneManager() { return mSceneMgr; diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index a3dd9cc805..1adbf3f173 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -25,11 +25,6 @@ namespace CSVWidget class SceneToolbar; } -namespace CSVWorld -{ - class PhysicsSystem; -} - namespace CSVRender { class Navigation; @@ -63,8 +58,6 @@ namespace CSVRender Ogre::Viewport *getViewport(); - CSVWorld::PhysicsSystem *getPhysics(); - Ogre::SceneManager *getSceneManager(); Ogre::Camera *getCamera(); @@ -105,7 +98,6 @@ namespace CSVRender Ogre::RenderWindow* mWindow; Ogre::Viewport *mViewport; Ogre::OverlaySystem *mOverlaySystem; - CSVWorld::PhysicsSystem *mPhysics; Navigation *mNavigation; Lighting *mLighting; diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 8012b1b246..aab3791fce 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -56,7 +56,7 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& update(); - mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, getPhysics())); + mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId)); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, @@ -98,7 +98,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); - mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getPhysics())); + mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId)); update(); emit cellChanged(*data.begin()); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 331625c842..70531a5595 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -39,11 +39,48 @@ namespace namespace CSVWorld { + PhysicsSystem *PhysicsSystem::mPhysicsSystemInstance = 0; + PhysicsSystem::PhysicsSystem(Ogre::SceneManager *sceneMgr) : mSceneMgr(sceneMgr) { + assert(!mPhysicsSystemInstance); + mPhysicsSystemInstance = this; + // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); + } + + PhysicsSystem::~PhysicsSystem() + { + delete mEngine; + } + + PhysicsSystem *PhysicsSystem::instance() + { + assert(mPhysicsSystemInstance); + return mPhysicsSystemInstance; + } + + void PhysicsSystem::addObject(const std::string &mesh, + const std::string &name, + float scale, + const Ogre::Vector3 &position, + const Ogre::Quaternion &rotation, + bool placeable) + { + //mHandleToMesh[name] = mesh; + + mEngine->createAndAdjustRigidBody(mesh, name, scale, position, rotation, + 0, // scaledBoxTranslation + 0, // boxRotation + true, // raycasting + placeable); + } + + void PhysicsSystem::setSceneManager(Ogre::SceneManager *sceneMgr) + { + mSceneMgr = sceneMgr; mEngine->setSceneManager(sceneMgr); // needed for toggleDebugRendering() @@ -102,27 +139,6 @@ namespace CSVWorld } } - PhysicsSystem::~PhysicsSystem() - { - delete mEngine; - } - - void PhysicsSystem::addObject(const std::string &mesh, - const std::string &name, - float scale, - const Ogre::Vector3 &position, - const Ogre::Quaternion &rotation, - bool placeable) - { - //mHandleToMesh[name] = mesh; - - mEngine->createAndAdjustRigidBody(mesh, name, scale, position, rotation, - 0, // scaledBoxTranslation - 0, // boxRotation - true, // raycasting - placeable); - } - void PhysicsSystem::removeObject(const std::string& name) { mEngine->removeRigidBody(name); @@ -131,6 +147,9 @@ namespace CSVWorld void PhysicsSystem::toggleDebugRendering() { + if(!mSceneMgr) + return; // FIXME: add a warning message + mEngine->toggleDebugRendering(); mEngine->stepSimulation(0.0167); // FIXME: DebugDrawer::step() not accessible } @@ -138,6 +157,9 @@ namespace CSVWorld std::pair PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) { + if(!mSceneMgr) + return std::make_pair(false, Ogre::Vector3()); // FIXME: add a warning message + // using a really small value seems to mess up with the projections float nearClipDistance = camera->getNearClipDistance(); camera->setNearClipDistance(10.0f); // arbitrary number diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index ec0657ee24..ec4ae63e19 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -25,6 +25,7 @@ namespace CSVWorld { class PhysicsSystem { + static PhysicsSystem *mPhysicsSystemInstance; //std::map mHandleToMesh; OEngine::Physic::PhysicEngine* mEngine; Ogre::SceneManager *mSceneMgr; @@ -32,9 +33,13 @@ namespace CSVWorld public: - PhysicsSystem(Ogre::SceneManager *sceneMgr); + PhysicsSystem(Ogre::SceneManager *sceneMgr = NULL); ~PhysicsSystem(); + static PhysicsSystem *instance(); + + void setSceneManager(Ogre::SceneManager *sceneMgr); + void addObject(const std::string &mesh, const std::string &name, float scale, From e5dd8d06a0b91106c6f505b79a9236152598f5c0 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 24 Oct 2014 21:18:29 +1100 Subject: [PATCH 11/56] Store object reference id to RigidBody instead of scene node handles. --- apps/opencs/view/render/object.cpp | 2 +- .../view/render/pagedworldspacewidget.cpp | 45 +++++++++++++------ apps/opencs/view/world/physicssystem.cpp | 31 +++++++------ apps/opencs/view/world/physicssystem.hpp | 10 ++--- 4 files changed, 53 insertions(+), 35 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 13266473e9..01164366a8 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -93,7 +93,7 @@ void CSVRender::Object::update() Ogre::Quaternion zr (Ogre::Radian (-reference.mPos.rot[2]), Ogre::Vector3::UNIT_Z); CSVWorld::PhysicsSystem::instance()->addObject("meshes\\" + model, - mBase->getName(), reference.mScale, position, xr*yr*zr); + mBase->getName(), mReferenceId, reference.mScale, position, xr*yr*zr); } } } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index b7d53b9e3e..aa7409fb4e 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -190,8 +190,6 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { // mouse picking // FIXME: need to virtualise mouse buttons - // Issue: Say 800 pixels (a typical viewport size) representing 8000 units (in one cell) - // So best case resolution is 10 units per pixel. int viewportWidth = getCamera()->getViewport()->getActualWidth(); int viewportHeight = getCamera()->getViewport()->getActualHeight(); @@ -200,18 +198,37 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) // Need to set each time in case there are multiple subviews CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); - CSVWorld::PhysicsSystem::instance()->castRay(mouseX, mouseY, NULL, NULL, getCamera()); - flagAsModified(); -#if 0 - std::cout << "geometry: " + std::to_string(width()) + ", " + std::to_string(height()) << std::endl; - std::cout << "event: " + std::to_string(event->x()) + ", " + std::to_string(event->y()) << std::endl; - std::cout << "viewport: " + std::to_string(viewportWidth) + ", " + std::to_string(viewportHeight) << std::endl; - std::cout << "mouse: " + std::to_string(mouseX) + ", " + std::to_string(mouseY) << std::endl; - std::cout << "camera: " + std::to_string(getCamera()->getPosition().x) - + ", " + std::to_string(getCamera()->getPosition().y) - + ", " + std::to_string(getCamera()->getPosition().z) - << std::endl; -#endif + std::pair result = CSVWorld::PhysicsSystem::instance()->castRay(mouseX, mouseY, NULL, NULL, getCamera()); + if(result.first) + { + flagAsModified(); + std::cout << "ReferenceId: " << result.second << std::endl; + const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (result.second).get(); + //std::cout << "CellRef mId: " << cellref.mId << std::endl; // Same as ReferenceId + std::cout << "CellRef mCell: " << cellref.mCell << std::endl; + + const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); + int index = references.searchId(result.second); + if (index != -1) + { + int columnIndex = + references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); + + std::cout << "index: " + std::to_string(index) + +", column index: " + std::to_string(columnIndex) << std::endl; + } + + std::map::iterator iter (mCells.begin()); + while (iter!=mCells.end()) + { + if(iter->first.getId("dummy") == cellref.mCell) + { + std::cout << "Cell changed" << std::endl; + break; + } + ++iter; + } + } } } diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 70531a5595..31413ac717 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -64,14 +64,15 @@ namespace CSVWorld void PhysicsSystem::addObject(const std::string &mesh, const std::string &name, + const std::string &referenceId, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) { - //mHandleToMesh[name] = mesh; + mRefToSceneNode[referenceId] = name; - mEngine->createAndAdjustRigidBody(mesh, name, scale, position, rotation, + mEngine->createAndAdjustRigidBody(mesh, referenceId, scale, position, rotation, 0, // scaledBoxTranslation 0, // boxRotation true, // raycasting @@ -154,11 +155,11 @@ namespace CSVWorld mEngine->stepSimulation(0.0167); // FIXME: DebugDrawer::step() not accessible } - std::pair PhysicsSystem::castRay(float mouseX, float mouseY, + std::pair PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) { if(!mSceneMgr) - return std::make_pair(false, Ogre::Vector3()); // FIXME: add a warning message + return std::make_pair(false, ""); // FIXME: add a warning message // using a really small value seems to mess up with the projections float nearClipDistance = camera->getNearClipDistance(); @@ -181,18 +182,20 @@ namespace CSVWorld std::pair result = mEngine->rayTest(_from, _to, raycastingObjectOnly, ignoreHeightMap, &norm); - if ((result.first == "") || !mSceneMgr->hasSceneNode(result.first)) - return std::make_pair(false, Ogre::Vector3()); - //std::cout << "no hit" << std::endl; + std::string sceneNode; + if(result.first != "") + sceneNode = mRefToSceneNode[result.first]; + if ((result.first == "") || !mSceneMgr->hasSceneNode(sceneNode)) + return std::make_pair(false, ""); else { //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character - Ogre::SceneNode *scene = mSceneMgr->getSceneNode(result.first); + Ogre::SceneNode *scene = mSceneMgr->getSceneNode(sceneNode); std::map >::iterator iter = - mSelectedEntities.find(result.first); + mSelectedEntities.find(sceneNode); if(iter != mSelectedEntities.end()) // currently selected { - std::vector clonedEntities = mSelectedEntities[result.first]; + std::vector clonedEntities = mSelectedEntities[sceneNode]; while(!clonedEntities.empty()) { if(mSceneMgr->hasEntity(clonedEntities.back())) @@ -204,7 +207,7 @@ namespace CSVWorld } mSelectedEntities.erase(iter); - removeHitPoint(mSceneMgr, result.first); // FIXME: for debugging + removeHitPoint(mSceneMgr, sceneNode); // FIXME: for debugging } else { @@ -239,10 +242,10 @@ namespace CSVWorld } } - mSelectedEntities[result.first] = clonedEntities; + mSelectedEntities[sceneNode] = clonedEntities; // FIXME: show cursor position for debugging - showHitPoint(mSceneMgr, result.first, ray.getPoint(farClipDist*result.second)); + showHitPoint(mSceneMgr, sceneNode, ray.getPoint(farClipDist*result.second)); } #if 0 std::cout << "hit " << result.first @@ -254,7 +257,7 @@ namespace CSVWorld + ", " + std::to_string(ray.getPoint(farClipDist*result.second).y) + ", " + std::to_string(ray.getPoint(farClipDist*result.second).z) << std::endl; #endif - return std::make_pair(true, ray.getPoint(farClipDist*result.second)); + return std::make_pair(true, result.first); } } } diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index ec4ae63e19..045b7e1d57 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -26,7 +26,7 @@ namespace CSVWorld class PhysicsSystem { static PhysicsSystem *mPhysicsSystemInstance; - //std::map mHandleToMesh; + std::map mRefToSceneNode; OEngine::Physic::PhysicEngine* mEngine; Ogre::SceneManager *mSceneMgr; std::map > mSelectedEntities; @@ -42,20 +42,18 @@ namespace CSVWorld void addObject(const std::string &mesh, const std::string &name, + const std::string &referenceId, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - //Ogre::Vector3* scaledBoxTranslation = 0, - //Ogre::Quaternion* boxRotation = 0, - //bool raycasting=false, bool placeable=false); void removeObject(const std::string &name); void toggleDebugRendering(); - std::pair castRay(float mouseX, float mouseY, - Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera); + std::pair castRay(float mouseX, float mouseY, + Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera); }; } From 54a6897df8ea3b98ca62b5e46a444734ae536738 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 24 Oct 2014 20:43:29 +1000 Subject: [PATCH 12/56] Use QString rather than std::to_string --- apps/opencs/view/render/pagedworldspacewidget.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index aa7409fb4e..8f8b2de658 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -214,8 +214,8 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) int columnIndex = references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); - std::cout << "index: " + std::to_string(index) - +", column index: " + std::to_string(columnIndex) << std::endl; + std::cout << "index: " + QString::number(index).toStdString() + +", column index: " + QString::number(columnIndex).toStdString() << std::endl; } std::map::iterator iter (mCells.begin()); @@ -223,7 +223,7 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { if(iter->first.getId("dummy") == cellref.mCell) { - std::cout << "Cell changed" << std::endl; + std::cout << "Cell found" << std::endl; break; } ++iter; From cc0acec64c9f2a72640766b90024a6833ae0aa2b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Oct 2014 21:02:40 +1100 Subject: [PATCH 13/56] Add settings to enable/disable debug rendering of mouse picking. --- apps/opencs/model/settings/usersettings.cpp | 7 +++++ .../view/render/pagedworldspacewidget.cpp | 27 +++++++++++----- apps/opencs/view/world/physicssystem.cpp | 31 +++++++++---------- 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 1813a97ff7..9fe947b688 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -150,6 +150,13 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() ritd->setDeclaredValues (values); } + declareSection ("debug", "Debug Options"); + { + Setting *mousePicking = createSetting (Type_CheckBox, "mouse-picking", "Debug Render Mouse-Picking"); + mousePicking->setDefaultValue ("false"); + mousePicking->setToolTip ("Enable redering debug information for mouse picking. " + "This option may be removed in future once the mouse picking feature is completed."); + } { /****************************************************************** diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 8f8b2de658..2bb95912bf 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/settings/usersettings.hpp" #include "../widget/scenetooltoggle.hpp" #include "../world/physicssystem.hpp" @@ -185,9 +186,12 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) break; } } - } - else - { + + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; + if(!debug) + return; + // mouse picking // FIXME: need to virtualise mouse buttons int viewportWidth = getCamera()->getViewport()->getActualWidth(); @@ -196,12 +200,12 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) float mouseX = (float) event->x()/viewportWidth; float mouseY = (float) event->y()/viewportHeight; - // Need to set each time in case there are multiple subviews + // Need to set scene manager each time in case there are multiple subviews CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); - std::pair result = CSVWorld::PhysicsSystem::instance()->castRay(mouseX, mouseY, NULL, NULL, getCamera()); + std::pair result = + CSVWorld::PhysicsSystem::instance()->castRay(mouseX, mouseY, NULL, NULL, getCamera()); if(result.first) { - flagAsModified(); std::cout << "ReferenceId: " << result.second << std::endl; const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (result.second).get(); //std::cout << "CellRef mId: " << cellref.mId << std::endl; // Same as ReferenceId @@ -223,11 +227,12 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { if(iter->first.getId("dummy") == cellref.mCell) { - std::cout << "Cell found" << std::endl; + //std::cout << "Cell found" << std::endl; break; } ++iter; } + flagAsModified(); } } } @@ -238,9 +243,15 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event { std::cout << "double clicked" << std::endl; - // Need to set each time in case there are multiple subviews + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; + if(!debug) + return; + + // Need to set scene manager each time in case there are multiple subviews CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(); + flagAsModified(); } } diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 31413ac717..6db38dd87c 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -148,7 +148,9 @@ namespace CSVWorld void PhysicsSystem::toggleDebugRendering() { - if(!mSceneMgr) + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; + if(!mSceneMgr || !debug) return; // FIXME: add a warning message mEngine->toggleDebugRendering(); @@ -158,6 +160,8 @@ namespace CSVWorld std::pair PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) { + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; if(!mSceneMgr) return std::make_pair(false, ""); // FIXME: add a warning message @@ -168,7 +172,6 @@ namespace CSVWorld camera->setNearClipDistance(nearClipDistance); Ogre::Vector3 from = ray.getOrigin(); - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); float farClipDist = userSettings.setting("Scene/far clip distance", QString("300000")).toFloat(); Ogre::Vector3 to = ray.getPoint(farClipDist); @@ -193,7 +196,7 @@ namespace CSVWorld Ogre::SceneNode *scene = mSceneMgr->getSceneNode(sceneNode); std::map >::iterator iter = mSelectedEntities.find(sceneNode); - if(iter != mSelectedEntities.end()) // currently selected + if(debug && iter != mSelectedEntities.end()) // currently selected { std::vector clonedEntities = mSelectedEntities[sceneNode]; while(!clonedEntities.empty()) @@ -207,9 +210,12 @@ namespace CSVWorld } mSelectedEntities.erase(iter); - removeHitPoint(mSceneMgr, sceneNode); // FIXME: for debugging + bool debugCursor = userSettings.setting ( + "debug/mouse-position", QString("false")) == "true" ? true : false; + if(debugCursor) // FIXME: show cursor position for debugging + removeHitPoint(mSceneMgr, sceneNode); } - else + else if(debug) { std::vector clonedEntities; Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); @@ -244,19 +250,12 @@ namespace CSVWorld } mSelectedEntities[sceneNode] = clonedEntities; - // FIXME: show cursor position for debugging + bool debugCursor = userSettings.setting ( + "debug/mouse-position", QString("false")) == "true" ? true : false; + if(debugCursor) // FIXME: show cursor position for debugging showHitPoint(mSceneMgr, sceneNode, ray.getPoint(farClipDist*result.second)); } -#if 0 - std::cout << "hit " << result.first - + " result " + std::to_string(result.second*farClipDist) << std::endl; - std::cout << "normal " + std::to_string(norm.x) - + ", " + std::to_string(norm.y) - + ", " + std::to_string(norm.z) << std::endl; - std::cout << "hit pos "+ std::to_string(ray.getPoint(farClipDist*result.second).x) - + ", " + std::to_string(ray.getPoint(farClipDist*result.second).y) - + ", " + std::to_string(ray.getPoint(farClipDist*result.second).z) << std::endl; -#endif + return std::make_pair(true, result.first); } } From 9337d6533aa57dbc0130a3c163bce26479cd1251 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 25 Oct 2014 22:09:19 +1100 Subject: [PATCH 14/56] Add terrain collision. Support visibility mask for objects and terrain. --- apps/opencs/view/render/cell.cpp | 10 ++++++ .../view/render/pagedworldspacewidget.cpp | 32 ++++++++++++------- apps/opencs/view/world/physicssystem.cpp | 11 +++++-- apps/opencs/view/world/physicssystem.hpp | 6 +++- 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 9ff24780c3..d414498dbd 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -5,10 +5,12 @@ #include #include +#include #include "../../model/world/idtable.hpp" #include "../../model/world/columns.hpp" #include "../../model/world/data.hpp" +#include "../world/physicssystem.hpp" #include "elements.hpp" #include "terrainstorage.hpp" @@ -81,6 +83,14 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); mTerrain->loadCell(esmLand->mX, esmLand->mY); + + if(esmLand) + { + float verts = ESM::Land::LAND_SIZE; + float worldsize = ESM::Land::REAL_SIZE; + CSVWorld::PhysicsSystem::instance()->addHeightField( + esmLand->mLandData->mHeights, esmLand->mX, esmLand->mY, 0, worldsize / (verts-1), verts); + } } } diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 2bb95912bf..c48358ce12 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -187,29 +187,36 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) } } - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; - if(!debug) - return; - // mouse picking // FIXME: need to virtualise mouse buttons + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; + if(!debug || !getCamera()->getViewport()) + return; + + if(!((uint32_t)getCamera()->getViewport()->getVisibilityMask() & (uint32_t)CSVRender::Element_Reference)) + return; + int viewportWidth = getCamera()->getViewport()->getActualWidth(); int viewportHeight = getCamera()->getViewport()->getActualHeight(); float mouseX = (float) event->x()/viewportWidth; float mouseY = (float) event->y()/viewportHeight; + bool ignoreHeightMap = true; + if(((uint32_t)getCamera()->getViewport()->getVisibilityMask() & (uint32_t)CSVRender::Element_Terrain)) + ignoreHeightMap = false; + // Need to set scene manager each time in case there are multiple subviews CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); - std::pair result = - CSVWorld::PhysicsSystem::instance()->castRay(mouseX, mouseY, NULL, NULL, getCamera()); + std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( + mouseX, mouseY, NULL, NULL, getCamera(), ignoreHeightMap); if(result.first) { std::cout << "ReferenceId: " << result.second << std::endl; const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (result.second).get(); - //std::cout << "CellRef mId: " << cellref.mId << std::endl; // Same as ReferenceId - std::cout << "CellRef mCell: " << cellref.mCell << std::endl; + //std::cout << "CellRef.mId: " << cellref.mId << std::endl; // Same as ReferenceId + std::cout << "CellRef.mCell: " << cellref.mCell << std::endl; const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); int index = references.searchId(result.second); @@ -248,8 +255,11 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event if(!debug) return; - // Need to set scene manager each time in case there are multiple subviews - CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); + // FIXME: OEngine::PhysicEngine creates only one child scene node for the + // debug drawer. Hence only the first subview that creates the debug drawer + // can view the debug lines. Will need to keep a map in OEngine if multiple + // subviews are to be supported. + //CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(); flagAsModified(); } diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 6db38dd87c..f5f82c0334 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -146,6 +146,12 @@ namespace CSVWorld mEngine->deleteRigidBody(name); } + void PhysicsSystem::addHeightField(float* heights, int x, int y, float yoffset, + float triSize, float sqrtVerts) + { + mEngine->addHeightField(heights, x, y, yoffset, triSize, sqrtVerts); + } + void PhysicsSystem::toggleDebugRendering() { CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); @@ -158,7 +164,7 @@ namespace CSVWorld } std::pair PhysicsSystem::castRay(float mouseX, float mouseY, - Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) + Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera, bool ignoreHeightMap) { CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; @@ -179,8 +185,7 @@ namespace CSVWorld _from = btVector3(from.x, from.y, from.z); _to = btVector3(to.x, to.y, to.z); - bool raycastingObjectOnly = true; - bool ignoreHeightMap = false; + bool raycastingObjectOnly = true; // FIXME Ogre::Vector3 norm; std::pair result = mEngine->rayTest(_from, _to, raycastingObjectOnly, ignoreHeightMap, &norm); diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 045b7e1d57..2ae17b5e3e 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -50,10 +50,14 @@ namespace CSVWorld void removeObject(const std::string &name); + void addHeightField(float* heights, int x, int y, float yoffset, + float triSize, float sqrtVerts); + void toggleDebugRendering(); std::pair castRay(float mouseX, float mouseY, - Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera); + Ogre::Vector3* normal, std::string* hit, + Ogre::Camera *camera, bool ignoreHeightMap); }; } From b46df4034d253ef9146be09aeda2a1a829730146 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 26 Oct 2014 07:56:51 +1100 Subject: [PATCH 15/56] Cleanup bullet objects in the destructors. --- apps/opencs/view/render/cell.cpp | 13 +++++++++++++ apps/opencs/view/render/object.cpp | 5 +++-- apps/opencs/view/world/physicssystem.cpp | 14 ++++++++++++++ apps/opencs/view/world/physicssystem.hpp | 6 ++++-- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index d414498dbd..f21d6b40b4 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -96,6 +96,19 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, CSVRender::Cell::~Cell() { + // TODO: maybe store the cell coordinates rather than searching for them in the destructor? + if(mTerrain.get()) + { + const CSMWorld::IdCollection& land = mData.getLand(); + int landIndex = land.searchId(mId); + if (landIndex != -1) + { + const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); + if(esmLand) + CSVWorld::PhysicsSystem::instance()->removeHeightField(esmLand->mX, esmLand->mY); + } + } + for (std::map::iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) delete iter->second; diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 01164366a8..474c79b353 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -33,11 +33,12 @@ void CSVRender::Object::clearSceneNode (Ogre::SceneNode *node) void CSVRender::Object::clear() { + if(!mObject.isNull()) + CSVWorld::PhysicsSystem::instance()->removeObject(mBase->getName()); + mObject.setNull(); clearSceneNode (mBase); - - // FIXME: also clear bullet objects } void CSVRender::Object::update() diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index f5f82c0334..fa43a57a45 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -53,6 +53,15 @@ namespace CSVWorld PhysicsSystem::~PhysicsSystem() { + std::map >::iterator iter = mSelectedEntities.begin(); + for(;iter != mSelectedEntities.end(); ++iter) + { + removeHitPoint(mSceneMgr, iter->first); + Ogre::SceneNode *scene = mSceneMgr->getSceneNode(iter->first); + scene->removeAndDestroyAllChildren(); + mSceneMgr->destroySceneNode(iter->first); + } + delete mEngine; } @@ -152,6 +161,11 @@ namespace CSVWorld mEngine->addHeightField(heights, x, y, yoffset, triSize, sqrtVerts); } + void PhysicsSystem::removeHeightField(int x, int y) + { + mEngine->removeHeightField(x, y); + } + void PhysicsSystem::toggleDebugRendering() { CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 2ae17b5e3e..c2115bc0fc 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -53,11 +53,13 @@ namespace CSVWorld void addHeightField(float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts); + void removeHeightField(int x, int y); + void toggleDebugRendering(); std::pair castRay(float mouseX, float mouseY, - Ogre::Vector3* normal, std::string* hit, - Ogre::Camera *camera, bool ignoreHeightMap); + Ogre::Vector3* normal, std::string* hit, + Ogre::Camera *camera, bool ignoreHeightMap); }; } From 8b0dc88db852ff282469a5f71b48f5e91557f878 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 26 Oct 2014 08:15:18 +1100 Subject: [PATCH 16/56] Use the correct name for deleting objects. --- apps/opencs/view/render/object.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 474c79b353..7dba068f81 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -33,8 +33,8 @@ void CSVRender::Object::clearSceneNode (Ogre::SceneNode *node) void CSVRender::Object::clear() { - if(!mObject.isNull()) - CSVWorld::PhysicsSystem::instance()->removeObject(mBase->getName()); + if(!mObject.isNull() && !mReferenceId.empty()) + CSVWorld::PhysicsSystem::instance()->removeObject(mReferenceId); mObject.setNull(); From fb0f85c8dbe2f987ea81b4ef1984aacae4215fa9 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 26 Oct 2014 21:15:47 +1100 Subject: [PATCH 17/56] Report terrain position on cursor position. --- .../view/render/pagedworldspacewidget.cpp | 68 +++++++++++-------- apps/opencs/view/world/physicssystem.cpp | 37 ++++++---- apps/opencs/view/world/physicssystem.hpp | 5 +- 3 files changed, 63 insertions(+), 47 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index c48358ce12..631b9be8a9 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -194,52 +194,60 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) if(!debug || !getCamera()->getViewport()) return; - if(!((uint32_t)getCamera()->getViewport()->getVisibilityMask() & (uint32_t)CSVRender::Element_Reference)) - return; - int viewportWidth = getCamera()->getViewport()->getActualWidth(); int viewportHeight = getCamera()->getViewport()->getActualHeight(); float mouseX = (float) event->x()/viewportWidth; float mouseY = (float) event->y()/viewportHeight; - bool ignoreHeightMap = true; - if(((uint32_t)getCamera()->getViewport()->getVisibilityMask() & (uint32_t)CSVRender::Element_Terrain)) - ignoreHeightMap = false; - // Need to set scene manager each time in case there are multiple subviews CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); - std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( - mouseX, mouseY, NULL, NULL, getCamera(), ignoreHeightMap); - if(result.first) + std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( + mouseX, mouseY, NULL, NULL, getCamera()); + if(result.first != "") { - std::cout << "ReferenceId: " << result.second << std::endl; - const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (result.second).get(); - //std::cout << "CellRef.mId: " << cellref.mId << std::endl; // Same as ReferenceId - std::cout << "CellRef.mCell: " << cellref.mCell << std::endl; - - const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); - int index = references.searchId(result.second); - if (index != -1) + // FIXME: is there a better way to distinguish terrain from objects? + QString name = QString(result.first.c_str()); + if(name.contains(QRegExp("^HeightField"))) { - int columnIndex = - references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); + // terrain + std::cout << "terrain: " << 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; - std::cout << "index: " + QString::number(index).toStdString() - +", column index: " + QString::number(columnIndex).toStdString() << std::endl; } - - std::map::iterator iter (mCells.begin()); - while (iter!=mCells.end()) + else { - if(iter->first.getId("dummy") == cellref.mCell) + std::cout << "ReferenceId: " << result.first << std::endl; + const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (result.first).get(); + //std::cout << "CellRef.mId: " << cellref.mId << std::endl; // Same as ReferenceId + std::cout << " CellRef.mCell: " << cellref.mCell << std::endl; + + const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); + int index = references.searchId(result.first); + if (index != -1) { - //std::cout << "Cell found" << std::endl; - break; + int columnIndex = + references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); + + std::cout << " index: " + QString::number(index).toStdString() + +", column index: " + QString::number(columnIndex).toStdString() << std::endl; } - ++iter; + + std::map::iterator iter (mCells.begin()); + while (iter!=mCells.end()) + { + if(iter->first.getId("dummy") == cellref.mCell) + { + //std::cout << "Cell found" << std::endl; + break; + } + ++iter; + } + flagAsModified(); } - flagAsModified(); } } } diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index fa43a57a45..bdd7e77fad 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -13,6 +13,7 @@ #include #include #include "../../model/settings/usersettings.hpp" +#include "../render/elements.hpp" namespace { @@ -174,16 +175,17 @@ namespace CSVWorld return; // FIXME: add a warning message mEngine->toggleDebugRendering(); - mEngine->stepSimulation(0.0167); // FIXME: DebugDrawer::step() not accessible + mEngine->stepSimulation(0.0167); // DebugDrawer::step() not directly accessible } - std::pair PhysicsSystem::castRay(float mouseX, float mouseY, - Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera, bool ignoreHeightMap) + // FIXME: this method needs a cleanup/refactoring + std::pair PhysicsSystem::castRay(float mouseX, float mouseY, + Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) { CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; - if(!mSceneMgr) - return std::make_pair(false, ""); // FIXME: add a warning message + if(!mSceneMgr || !camera || !camera->getViewport()) + return std::make_pair("", Ogre::Vector3(0,0,0)); // FIXME: add a warning message // using a really small value seems to mess up with the projections float nearClipDistance = camera->getNearClipDistance(); @@ -199,17 +201,19 @@ namespace CSVWorld _from = btVector3(from.x, from.y, from.z); _to = btVector3(to.x, to.y, to.z); - bool raycastingObjectOnly = true; // FIXME + uint32_t visibilityMask = camera->getViewport()->getVisibilityMask(); + bool ignoreHeightMap = !(visibilityMask & (uint32_t)CSVRender::Element_Terrain); + bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); + Ogre::Vector3 norm; std::pair result = - mEngine->rayTest(_from, _to, raycastingObjectOnly, ignoreHeightMap, &norm); + mEngine->rayTest(_from, _to, !ignoreObjects, ignoreHeightMap, &norm); - std::string sceneNode; - if(result.first != "") - sceneNode = mRefToSceneNode[result.first]; - if ((result.first == "") || !mSceneMgr->hasSceneNode(sceneNode)) - return std::make_pair(false, ""); - else + if(result.first == "") + return std::make_pair("", Ogre::Vector3(0,0,0)); + + std::string sceneNode = mRefToSceneNode[result.first]; + if(!ignoreObjects && mSceneMgr->hasSceneNode(sceneNode)) { //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character Ogre::SceneNode *scene = mSceneMgr->getSceneNode(sceneNode); @@ -275,7 +279,12 @@ namespace CSVWorld showHitPoint(mSceneMgr, sceneNode, ray.getPoint(farClipDist*result.second)); } - return std::make_pair(true, result.first); + return std::make_pair(result.first, ray.getPoint(farClipDist*result.second)); + } + else + { + // terrain + return std::make_pair(result.first, ray.getPoint(farClipDist*result.second)); } } } diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index c2115bc0fc..351d9535be 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -57,9 +57,8 @@ namespace CSVWorld void toggleDebugRendering(); - std::pair castRay(float mouseX, float mouseY, - Ogre::Vector3* normal, std::string* hit, - Ogre::Camera *camera, bool ignoreHeightMap); + std::pair castRay(float mouseX, float mouseY, + Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera); }; } From dd2c067e176bfb596a3ad81087821c1a0b645fc0 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 27 Oct 2014 06:50:51 +1100 Subject: [PATCH 18/56] Cleanup for better legibility. --- apps/opencs/view/world/physicssystem.cpp | 270 ++++++++++++----------- apps/opencs/view/world/physicssystem.hpp | 19 +- 2 files changed, 149 insertions(+), 140 deletions(-) diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index bdd7e77fad..a65842bc2c 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -1,11 +1,11 @@ #include "physicssystem.hpp" -#include // FIXME: debug only +#include #include #include #include -#include // FIXME: debug cursor position +#include // FIXME: debug cursor position #include // FIXME: visual highlight, clone #include // FIXME: visual highlight, material #include // FIXME: visual highlight, texture @@ -17,6 +17,7 @@ namespace { + // FIXME: this section should be removed once the debugging is completed void showHitPoint(Ogre::SceneManager *sceneMgr, std::string name, Ogre::Vector3 point) { sceneMgr->destroyManualObject("manual" + name); @@ -73,12 +74,8 @@ namespace CSVWorld } void PhysicsSystem::addObject(const std::string &mesh, - const std::string &name, - const std::string &referenceId, - float scale, - const Ogre::Vector3 &position, - const Ogre::Quaternion &rotation, - bool placeable) + const std::string &name, const std::string &referenceId, float scale, + const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) { mRefToSceneNode[referenceId] = name; @@ -89,12 +86,93 @@ namespace CSVWorld placeable); } + void PhysicsSystem::removeObject(const std::string& name) + { + mEngine->removeRigidBody(name); + mEngine->deleteRigidBody(name); + } + + void PhysicsSystem::addHeightField(float* heights, int x, int y, float yoffset, + float triSize, float sqrtVerts) + { + mEngine->addHeightField(heights, x, y, yoffset, triSize, sqrtVerts); + } + + void PhysicsSystem::removeHeightField(int x, int y) + { + mEngine->removeHeightField(x, y); + } + + std::pair PhysicsSystem::castRay(float mouseX, float mouseY, + Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) + { + if(!mSceneMgr || !camera || !camera->getViewport()) + return std::make_pair("", Ogre::Vector3(0,0,0)); // FIXME: this should be an exception + + + // using a really small value seems to mess up with the projections + float nearClipDistance = camera->getNearClipDistance(); // save existing + camera->setNearClipDistance(10.0f); // arbitrary number + Ogre::Ray ray = camera->getCameraToViewportRay(mouseX, mouseY); + camera->setNearClipDistance(nearClipDistance); // restore + + Ogre::Vector3 from = ray.getOrigin(); + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + float farClipDist = userSettings.setting("Scene/far clip distance", QString("300000")).toFloat(); + Ogre::Vector3 to = ray.getPoint(farClipDist); + + btVector3 _from, _to; + _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); + + Ogre::Vector3 norm; + std::pair result = + mEngine->rayTest(_from, _to, !ignoreObjects, ignoreHeightMap, &norm); + + if(result.first == "") + return std::make_pair("", Ogre::Vector3(0,0,0)); // rayTest found nothing + + Ogre::Vector3 position = ray.getPoint(farClipDist*result.second); + std::string sceneNode = mRefToSceneNode[result.first]; + if(!ignoreObjects && mSceneMgr->hasSceneNode(sceneNode)) + { + if(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false) + updateSelectionHighlight(sceneNode, position); + } + // else terrain + return std::make_pair(result.first, position); + } + void PhysicsSystem::setSceneManager(Ogre::SceneManager *sceneMgr) { mSceneMgr = sceneMgr; - mEngine->setSceneManager(sceneMgr); // needed for toggleDebugRendering() + initDebug(); + } + + void PhysicsSystem::toggleDebugRendering() + { + if(!mSceneMgr) + return; // FIXME: maybe this should be an exception + + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + if(!(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false)) + { + std::cerr << "Turn on mouse-picking debug option to see collision shapes." << std::endl; + return; + } + + mEngine->toggleDebugRendering(); + mEngine->stepSimulation(0.0167); // DebugDrawer::step() not directly accessible + } + + void PhysicsSystem::initDebug() + { // material for visual cue on selected objects Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTrans"); if(texture.isNull()) @@ -150,141 +228,69 @@ namespace CSVWorld } } - void PhysicsSystem::removeObject(const std::string& name) - { - mEngine->removeRigidBody(name); - mEngine->deleteRigidBody(name); - } - - void PhysicsSystem::addHeightField(float* heights, int x, int y, float yoffset, - float triSize, float sqrtVerts) - { - mEngine->addHeightField(heights, x, y, yoffset, triSize, sqrtVerts); - } - - void PhysicsSystem::removeHeightField(int x, int y) - { - mEngine->removeHeightField(x, y); - } - - void PhysicsSystem::toggleDebugRendering() + void PhysicsSystem::updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position) { CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; - if(!mSceneMgr || !debug) - return; // FIXME: add a warning message + bool debugCursor = userSettings.setting( + "debug/mouse-position", QString("false")) == "true" ? true : false; - mEngine->toggleDebugRendering(); - mEngine->stepSimulation(0.0167); // DebugDrawer::step() not directly accessible - } - - // FIXME: this method needs a cleanup/refactoring - std::pair PhysicsSystem::castRay(float mouseX, float mouseY, - Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) - { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; - if(!mSceneMgr || !camera || !camera->getViewport()) - return std::make_pair("", Ogre::Vector3(0,0,0)); // FIXME: add a warning message - - // using a really small value seems to mess up with the projections - float nearClipDistance = camera->getNearClipDistance(); - camera->setNearClipDistance(10.0f); // arbitrary number - Ogre::Ray ray = camera->getCameraToViewportRay(mouseX, mouseY); - camera->setNearClipDistance(nearClipDistance); - - Ogre::Vector3 from = ray.getOrigin(); - float farClipDist = userSettings.setting("Scene/far clip distance", QString("300000")).toFloat(); - Ogre::Vector3 to = ray.getPoint(farClipDist); - - btVector3 _from, _to; - _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); - - Ogre::Vector3 norm; - std::pair result = - mEngine->rayTest(_from, _to, !ignoreObjects, ignoreHeightMap, &norm); - - if(result.first == "") - return std::make_pair("", Ogre::Vector3(0,0,0)); - - std::string sceneNode = mRefToSceneNode[result.first]; - if(!ignoreObjects && mSceneMgr->hasSceneNode(sceneNode)) + //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character + Ogre::SceneNode *scene = mSceneMgr->getSceneNode(sceneNode); + std::map >::iterator iter = + mSelectedEntities.find(sceneNode); + if(iter != mSelectedEntities.end()) // currently selected { - //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character - Ogre::SceneNode *scene = mSceneMgr->getSceneNode(sceneNode); - std::map >::iterator iter = - mSelectedEntities.find(sceneNode); - if(debug && iter != mSelectedEntities.end()) // currently selected + std::vector clonedEntities = mSelectedEntities[sceneNode]; + while(!clonedEntities.empty()) { - std::vector clonedEntities = mSelectedEntities[sceneNode]; - while(!clonedEntities.empty()) + if(mSceneMgr->hasEntity(clonedEntities.back())) { - if(mSceneMgr->hasEntity(clonedEntities.back())) - { - scene->detachObject(clonedEntities.back()); - mSceneMgr->destroyEntity(clonedEntities.back()); - } - clonedEntities.pop_back(); + scene->detachObject(clonedEntities.back()); + mSceneMgr->destroyEntity(clonedEntities.back()); } - mSelectedEntities.erase(iter); - - bool debugCursor = userSettings.setting ( - "debug/mouse-position", QString("false")) == "true" ? true : false; - if(debugCursor) // FIXME: show cursor position for debugging - removeHitPoint(mSceneMgr, sceneNode); + clonedEntities.pop_back(); } - else if(debug) - { - std::vector clonedEntities; - Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); - iter.begin(); - while(iter.hasMoreElements()) - { - Ogre::MovableObject * element = iter.getNext(); - if(!element) - break; + mSelectedEntities.erase(iter); - if(element->getMovableType() != "Entity") - continue; - - Ogre::Entity * entity = dynamic_cast(element); - if(mSceneMgr->hasEntity(entity->getName()+"cover")) - { - // FIXME: this shouldn't really happen... but does :( - scene->detachObject(entity->getName()+"cover"); - mSceneMgr->destroyEntity(entity->getName()+"cover"); - } - Ogre::Entity * clone = entity->clone(entity->getName()+"cover"); - - Ogre::MaterialPtr mat = - Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); - if(!mat.isNull()) - { - clone->setMaterial(mat); - scene->attachObject(clone); - clonedEntities.push_back(entity->getName()+"cover"); - } - - } - mSelectedEntities[sceneNode] = clonedEntities; - - bool debugCursor = userSettings.setting ( - "debug/mouse-position", QString("false")) == "true" ? true : false; - if(debugCursor) // FIXME: show cursor position for debugging - showHitPoint(mSceneMgr, sceneNode, ray.getPoint(farClipDist*result.second)); - } - - return std::make_pair(result.first, ray.getPoint(farClipDist*result.second)); + if(debugCursor) + removeHitPoint(mSceneMgr, sceneNode); } else { - // terrain - return std::make_pair(result.first, ray.getPoint(farClipDist*result.second)); + std::vector clonedEntities; + Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); + iter.begin(); + while(iter.hasMoreElements()) + { + Ogre::MovableObject * element = iter.getNext(); + if(!element) + break; + + if(element->getMovableType() != "Entity") + continue; + + Ogre::Entity * entity = dynamic_cast(element); + if(mSceneMgr->hasEntity(entity->getName()+"cover")) + { + // FIXME: this shouldn't really happen... but does :( + scene->detachObject(entity->getName()+"cover"); + mSceneMgr->destroyEntity(entity->getName()+"cover"); + } + Ogre::Entity * clone = entity->clone(entity->getName()+"cover"); + + Ogre::MaterialPtr mat = + Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); + if(!mat.isNull()) + { + clone->setMaterial(mat); + scene->attachObject(clone); + clonedEntities.push_back(entity->getName()+"cover"); + } + } + mSelectedEntities[sceneNode] = clonedEntities; + + if(debugCursor) + showHitPoint(mSceneMgr, sceneNode, position); } } } diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 351d9535be..7a84a7b18d 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -28,6 +28,7 @@ namespace CSVWorld static PhysicsSystem *mPhysicsSystemInstance; std::map mRefToSceneNode; OEngine::Physic::PhysicEngine* mEngine; + Ogre::SceneManager *mSceneMgr; std::map > mSelectedEntities; @@ -40,18 +41,15 @@ namespace CSVWorld void setSceneManager(Ogre::SceneManager *sceneMgr); - void addObject(const std::string &mesh, - const std::string &name, - const std::string &referenceId, - float scale, - const Ogre::Vector3 &position, - const Ogre::Quaternion &rotation, - bool placeable=false); + void addObject(const std::string &mesh, const std::string &name, + const std::string &referenceId, float scale, + const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, + bool placeable=false); void removeObject(const std::string &name); void addHeightField(float* heights, int x, int y, float yoffset, - float triSize, float sqrtVerts); + float triSize, float sqrtVerts); void removeHeightField(int x, int y); @@ -59,6 +57,11 @@ namespace CSVWorld std::pair castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera); + + private: + + void initDebug(); + void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); }; } From 0b63ba572770c2431f360a0484839f65629bd4b4 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 27 Oct 2014 08:08:33 +1100 Subject: [PATCH 19/56] Move debug rendering code out of PhysicsSystem. --- .../view/render/pagedworldspacewidget.cpp | 319 ++++++++++++++---- .../view/render/pagedworldspacewidget.hpp | 4 + apps/opencs/view/world/physicssystem.cpp | 179 +--------- apps/opencs/view/world/physicssystem.hpp | 3 +- 4 files changed, 263 insertions(+), 242 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 631b9be8a9..241ac2b494 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -13,6 +13,10 @@ #include #include +#include // FIXME: visual highlight, clone +#include // FIXME: visual highlight, material +#include // FIXME: visual highlight, texture + #include #include "textoverlay.hpp" #include "overlaymask.hpp" @@ -26,6 +30,89 @@ #include "elements.hpp" +namespace +{ + // FIXME: this section should be removed once the debugging is completed + void showHitPoint(Ogre::SceneManager *sceneMgr, std::string name, Ogre::Vector3 point) + { + if(sceneMgr->hasManualObject("manual" + name)) + sceneMgr->destroyManualObject("manual" + name); + Ogre::ManualObject* manual = sceneMgr->createManualObject("manual" + name); + manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); + manual-> position(point.x, point.y, point.z-100); + manual-> position(point.x, point.y, point.z+100); + manual-> position(point.x, point.y-100, point.z); + manual-> position(point.x, point.y+100, point.z); + manual-> position(point.x-100, point.y, point.z); + manual-> position(point.x+100, point.y, point.z); + manual->end(); + sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); + } + + void removeHitPoint(Ogre::SceneManager *sceneMgr, std::string name) + { + if(sceneMgr->hasManualObject("manual" + name)) + sceneMgr->destroyManualObject("manual" + name); + } + + void initDebug() + { + // material for visual cue on selected objects + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTrans"); + if(texture.isNull()) + { + texture = Ogre::TextureManager::getSingleton().createManual( + "DynamicTrans", // name + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, // type + 8, 8, // width & height + 0, // number of mipmaps + Ogre::PF_BYTE_BGRA, // pixel format + Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for + // textures updated very often (e.g. each frame) + + Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); + pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); + const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); + + uint8_t* pDest = static_cast(pixelBox.data); + + // Fill in some pixel data. This will give a semi-transparent colour, + // but this is of course dependent on the chosen pixel format. + for (size_t j = 0; j < 8; j++) + { + for(size_t i = 0; i < 8; i++) + { + *pDest++ = 255; // B + *pDest++ = 255; // G + *pDest++ = 127; // R + *pDest++ = 63; // A + } + + pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format); + } + pixelBuffer->unlock(); + } + Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName( + "TransMaterial"); + if(material.isNull()) + { + Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create( + "TransMaterial", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); + Ogre::Pass *pass = material->getTechnique( 0 )->getPass( 0 ); + pass->setLightingEnabled( false ); + pass->setDepthWriteEnabled( false ); + pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); + + Ogre::TextureUnitState *tex = pass->createTextureUnitState("CustomState", 0); + tex->setTextureName("DynamicTrans"); + tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC ); + material->load(); + } + } +} + bool CSVRender::PagedWorldspaceWidget::adjustCells() { bool modified = false; @@ -189,66 +276,11 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) // mouse picking // FIXME: need to virtualise mouse buttons - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; - if(!debug || !getCamera()->getViewport()) + if(!getCamera()->getViewport()) return; - int viewportWidth = getCamera()->getViewport()->getActualWidth(); - int viewportHeight = getCamera()->getViewport()->getActualHeight(); - - float mouseX = (float) event->x()/viewportWidth; - float mouseY = (float) event->y()/viewportHeight; - - // Need to set scene manager each time in case there are multiple subviews - CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); - std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( - mouseX, mouseY, NULL, NULL, getCamera()); - 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"))) - { - // terrain - std::cout << "terrain: " << 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; - - } - else - { - std::cout << "ReferenceId: " << result.first << std::endl; - const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (result.first).get(); - //std::cout << "CellRef.mId: " << cellref.mId << std::endl; // Same as ReferenceId - std::cout << " CellRef.mCell: " << cellref.mCell << std::endl; - - const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); - int index = references.searchId(result.first); - if (index != -1) - { - int columnIndex = - references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); - - std::cout << " index: " + QString::number(index).toStdString() - +", column index: " + QString::number(columnIndex).toStdString() << std::endl; - } - - std::map::iterator iter (mCells.begin()); - while (iter!=mCells.end()) - { - if(iter->first.getId("dummy") == cellref.mCell) - { - //std::cout << "Cell found" << std::endl; - break; - } - ++iter; - } - flagAsModified(); - } - } + debugMousePicking((float) event->x() / getCamera()->getViewport()->getActualWidth(), + (float) event->y() / getCamera()->getViewport()->getActualHeight()); } } @@ -259,17 +291,16 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event std::cout << "double clicked" << std::endl; CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; - if(!debug) - return; - - // FIXME: OEngine::PhysicEngine creates only one child scene node for the - // debug drawer. Hence only the first subview that creates the debug drawer - // can view the debug lines. Will need to keep a map in OEngine if multiple - // subviews are to be supported. - //CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); - CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(); - flagAsModified(); + if(userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false) + { + // FIXME: OEngine::PhysicEngine creates only one child scene node for the + // debug drawer. Hence only the first subview that creates the debug drawer + // can view the debug lines. Will need to keep a map in OEngine if multiple + // subviews are to be supported. + //CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); + CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(); + flagAsModified(); + } } } @@ -385,6 +416,8 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc this, SLOT (cellRemoved (const QModelIndex&, int, int))); connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (cellAdded (const QModelIndex&, int, int))); + + initDebug(); } CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() @@ -405,6 +438,19 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() removeRenderTargetListener(mOverlayMask); delete mOverlayMask; + + // For debugging only + std::map >::iterator iter = mSelectedEntities.begin(); + for(;iter != mSelectedEntities.end(); ++iter) + { + removeHitPoint(getSceneManager(), iter->first); + Ogre::SceneNode *scene = getSceneManager()->getSceneNode(iter->first); + if(scene) + { + scene->removeAndDestroyAllChildren(); + getSceneManager()->destroySceneNode(iter->first); + } + } } void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) @@ -555,3 +601,138 @@ void CSVRender::PagedWorldspaceWidget::cellAdded (const QModelIndex& index, int if (adjustCells()) flagAsModified(); } + + +void CSVRender::PagedWorldspaceWidget::debugMousePicking(float mouseX, float mouseY) +{ + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; + + // Need to set scene manager each time in case there are multiple subviews + CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); + std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( + mouseX, mouseY, NULL, NULL, getCamera()); + if(debug && 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"))) + { + // terrain + std::cout << "terrain: " << 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; + } + else + { + std::string sceneNode = + CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); + + uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); + bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); + + if(!ignoreObjects && getSceneManager()->hasSceneNode(sceneNode)) + { + if(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false) + updateSelectionHighlight(sceneNode, result.second); + } + + std::cout << "ReferenceId: " << result.first << std::endl; + const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (result.first).get(); + //std::cout << "CellRef.mId: " << cellref.mId << std::endl; // Same as ReferenceId + std::cout << " CellRef.mCell: " << cellref.mCell << std::endl; + + const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); + int index = references.searchId(result.first); + if (index != -1) + { + int columnIndex = + references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); + + std::cout << " index: " + QString::number(index).toStdString() + +", column index: " + QString::number(columnIndex).toStdString() << std::endl; + } + + std::map::iterator iter (mCells.begin()); + while (iter!=mCells.end()) + { + if(iter->first.getId("dummy") == cellref.mCell) + { + //std::cout << "Cell found" << std::endl; + break; + } + ++iter; + } + flagAsModified(); + } + } +} + +// FIXME: for debugging only +void CSVRender::PagedWorldspaceWidget::updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position) +{ + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + bool debugCursor = userSettings.setting( + "debug/mouse-position", QString("false")) == "true" ? true : false; + + //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character + Ogre::SceneNode *scene = getSceneManager()->getSceneNode(sceneNode); + std::map >::iterator iter = + mSelectedEntities.find(sceneNode); + if(iter != mSelectedEntities.end()) // currently selected + { + std::vector clonedEntities = mSelectedEntities[sceneNode]; + while(!clonedEntities.empty()) + { + if(getSceneManager()->hasEntity(clonedEntities.back())) + { + scene->detachObject(clonedEntities.back()); + getSceneManager()->destroyEntity(clonedEntities.back()); + } + clonedEntities.pop_back(); + } + mSelectedEntities.erase(iter); + + if(debugCursor) + removeHitPoint(getSceneManager(), sceneNode); + } + else + { + std::vector clonedEntities; + Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); + iter.begin(); + while(iter.hasMoreElements()) + { + Ogre::MovableObject * element = iter.getNext(); + if(!element) + break; + + if(element->getMovableType() != "Entity") + continue; + + Ogre::Entity * entity = dynamic_cast(element); + if(getSceneManager()->hasEntity(entity->getName()+"cover")) + { + // FIXME: this shouldn't really happen... but does :( + scene->detachObject(entity->getName()+"cover"); + getSceneManager()->destroyEntity(entity->getName()+"cover"); + } + Ogre::Entity * clone = entity->clone(entity->getName()+"cover"); + + Ogre::MaterialPtr mat = + Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); + if(!mat.isNull()) + { + clone->setMaterial(mat); + scene->attachObject(clone); + clonedEntities.push_back(entity->getName()+"cover"); + } + } + mSelectedEntities[sceneNode] = clonedEntities; + + if(debugCursor) + showHitPoint(getSceneManager(), sceneNode, position); + } +} diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 17b6d10c53..2c46729a82 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -26,6 +26,7 @@ namespace CSVRender bool mDisplayCellCoord; std::map mTextOverlays; OverlayMask *mOverlayMask; + std::map > mSelectedEntities; private: @@ -51,6 +52,9 @@ namespace CSVRender virtual std::string getStartupInstruction(); + void debugMousePicking(float mouseX, float mouseY); + void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); + public: PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index a65842bc2c..154cc62737 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -5,40 +5,12 @@ #include #include #include -#include // FIXME: debug cursor position -#include // FIXME: visual highlight, clone -#include // FIXME: visual highlight, material -#include // FIXME: visual highlight, texture #include #include #include "../../model/settings/usersettings.hpp" #include "../render/elements.hpp" -namespace -{ - // FIXME: this section should be removed once the debugging is completed - void showHitPoint(Ogre::SceneManager *sceneMgr, std::string name, Ogre::Vector3 point) - { - sceneMgr->destroyManualObject("manual" + name); - Ogre::ManualObject* manual = sceneMgr->createManualObject("manual" + name); - manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); - manual-> position(point.x, point.y, point.z-100); - manual-> position(point.x, point.y, point.z+100); - manual-> position(point.x, point.y-100, point.z); - manual-> position(point.x, point.y+100, point.z); - manual-> position(point.x-100, point.y, point.z); - manual-> position(point.x+100, point.y, point.z); - manual->end(); - sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); - } - - void removeHitPoint(Ogre::SceneManager *sceneMgr, std::string name) - { - sceneMgr->destroyManualObject("manual" + name); - } -} - namespace CSVWorld { PhysicsSystem *PhysicsSystem::mPhysicsSystemInstance = 0; @@ -55,15 +27,6 @@ namespace CSVWorld PhysicsSystem::~PhysicsSystem() { - std::map >::iterator iter = mSelectedEntities.begin(); - for(;iter != mSelectedEntities.end(); ++iter) - { - removeHitPoint(mSceneMgr, iter->first); - Ogre::SceneNode *scene = mSceneMgr->getSceneNode(iter->first); - scene->removeAndDestroyAllChildren(); - mSceneMgr->destroySceneNode(iter->first); - } - delete mEngine; } @@ -134,25 +97,20 @@ namespace CSVWorld mEngine->rayTest(_from, _to, !ignoreObjects, ignoreHeightMap, &norm); if(result.first == "") - return std::make_pair("", Ogre::Vector3(0,0,0)); // rayTest found nothing + return std::make_pair("", Ogre::Vector3(0,0,0)); + else + return std::make_pair(result.first, ray.getPoint(farClipDist*result.second)); + } - Ogre::Vector3 position = ray.getPoint(farClipDist*result.second); - std::string sceneNode = mRefToSceneNode[result.first]; - if(!ignoreObjects && mSceneMgr->hasSceneNode(sceneNode)) - { - if(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false) - updateSelectionHighlight(sceneNode, position); - } - // else terrain - return std::make_pair(result.first, position); + std::string PhysicsSystem::referenceToSceneNode(std::string reference) + { + return mRefToSceneNode[reference]; } void PhysicsSystem::setSceneManager(Ogre::SceneManager *sceneMgr) { mSceneMgr = sceneMgr; mEngine->setSceneManager(sceneMgr); // needed for toggleDebugRendering() - - initDebug(); } void PhysicsSystem::toggleDebugRendering() @@ -170,127 +128,4 @@ namespace CSVWorld mEngine->toggleDebugRendering(); mEngine->stepSimulation(0.0167); // DebugDrawer::step() not directly accessible } - - void PhysicsSystem::initDebug() - { - // material for visual cue on selected objects - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTrans"); - if(texture.isNull()) - { - texture = Ogre::TextureManager::getSingleton().createManual( - "DynamicTrans", // name - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, // type - 8, 8, // width & height - 0, // number of mipmaps - Ogre::PF_BYTE_BGRA, // pixel format - Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for - // textures updated very often (e.g. each frame) - - Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); - pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); - const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); - - uint8_t* pDest = static_cast(pixelBox.data); - - // Fill in some pixel data. This will give a semi-transparent colour, - // but this is of course dependent on the chosen pixel format. - for (size_t j = 0; j < 8; j++) - { - for(size_t i = 0; i < 8; i++) - { - *pDest++ = 255; // B - *pDest++ = 255; // G - *pDest++ = 127; // R - *pDest++ = 63; // A - } - - pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format); - } - pixelBuffer->unlock(); - } - Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName( - "TransMaterial"); - if(material.isNull()) - { - Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create( - "TransMaterial", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); - Ogre::Pass *pass = material->getTechnique( 0 )->getPass( 0 ); - pass->setLightingEnabled( false ); - pass->setDepthWriteEnabled( false ); - pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); - - Ogre::TextureUnitState *tex = pass->createTextureUnitState("CustomState", 0); - tex->setTextureName("DynamicTrans"); - tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC ); - material->load(); - } - } - - void PhysicsSystem::updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position) - { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debugCursor = userSettings.setting( - "debug/mouse-position", QString("false")) == "true" ? true : false; - - //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character - Ogre::SceneNode *scene = mSceneMgr->getSceneNode(sceneNode); - std::map >::iterator iter = - mSelectedEntities.find(sceneNode); - if(iter != mSelectedEntities.end()) // currently selected - { - std::vector clonedEntities = mSelectedEntities[sceneNode]; - while(!clonedEntities.empty()) - { - if(mSceneMgr->hasEntity(clonedEntities.back())) - { - scene->detachObject(clonedEntities.back()); - mSceneMgr->destroyEntity(clonedEntities.back()); - } - clonedEntities.pop_back(); - } - mSelectedEntities.erase(iter); - - if(debugCursor) - removeHitPoint(mSceneMgr, sceneNode); - } - else - { - std::vector clonedEntities; - Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); - iter.begin(); - while(iter.hasMoreElements()) - { - Ogre::MovableObject * element = iter.getNext(); - if(!element) - break; - - if(element->getMovableType() != "Entity") - continue; - - Ogre::Entity * entity = dynamic_cast(element); - if(mSceneMgr->hasEntity(entity->getName()+"cover")) - { - // FIXME: this shouldn't really happen... but does :( - scene->detachObject(entity->getName()+"cover"); - mSceneMgr->destroyEntity(entity->getName()+"cover"); - } - Ogre::Entity * clone = entity->clone(entity->getName()+"cover"); - - Ogre::MaterialPtr mat = - Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); - if(!mat.isNull()) - { - clone->setMaterial(mat); - scene->attachObject(clone); - clonedEntities.push_back(entity->getName()+"cover"); - } - } - mSelectedEntities[sceneNode] = clonedEntities; - - if(debugCursor) - showHitPoint(mSceneMgr, sceneNode, position); - } - } } diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 7a84a7b18d..eb00282537 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -30,7 +30,6 @@ namespace CSVWorld OEngine::Physic::PhysicEngine* mEngine; Ogre::SceneManager *mSceneMgr; - std::map > mSelectedEntities; public: @@ -58,6 +57,8 @@ namespace CSVWorld std::pair castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera); + std::string referenceToSceneNode(std::string reference); + private: void initDebug(); From c2c33eac0f007c85ad29b56d16bfa44144d5b228 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 27 Oct 2014 08:26:01 +1100 Subject: [PATCH 20/56] Minor cleanup. --- apps/opencs/view/render/pagedworldspacewidget.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 241ac2b494..a84164dc8a 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -608,8 +608,6 @@ void CSVRender::PagedWorldspaceWidget::debugMousePicking(float mouseX, float mou CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; - // Need to set scene manager each time in case there are multiple subviews - CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( mouseX, mouseY, NULL, NULL, getCamera()); if(debug && result.first != "") From 6c8320a638b4b46b7cb11b61c4ec4f1def06ecd7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 27 Oct 2014 12:09:20 +1100 Subject: [PATCH 21/56] More cleanup. --- apps/opencs/view/render/pagedworldspacewidget.cpp | 15 ++++++++++----- apps/opencs/view/world/physicssystem.hpp | 1 - 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index a84164dc8a..b33c83342b 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -297,7 +297,7 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event // debug drawer. Hence only the first subview that creates the debug drawer // can view the debug lines. Will need to keep a map in OEngine if multiple // subviews are to be supported. - //CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); + CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(); flagAsModified(); } @@ -444,11 +444,16 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() for(;iter != mSelectedEntities.end(); ++iter) { removeHitPoint(getSceneManager(), iter->first); - Ogre::SceneNode *scene = getSceneManager()->getSceneNode(iter->first); - if(scene) + + if(getSceneManager()->hasSceneNode(iter->first)) { - scene->removeAndDestroyAllChildren(); - getSceneManager()->destroySceneNode(iter->first); + Ogre::SceneNode *scene = getSceneManager()->getSceneNode(iter->first); + + if(scene) + { + scene->removeAndDestroyAllChildren(); + getSceneManager()->destroySceneNode(iter->first); + } } } } diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index eb00282537..c19486d17b 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -61,7 +61,6 @@ namespace CSVWorld private: - void initDebug(); void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); }; } From a01a921644162fbd67087e78db65fbcad49b7497 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 28 Oct 2014 06:01:19 +1100 Subject: [PATCH 22/56] Experimental mouse event state machine for 3d editing, starting with drag & drop objects. --- .../view/render/pagedworldspacewidget.cpp | 226 +++++++++++++++++- .../view/render/pagedworldspacewidget.hpp | 15 +- apps/opencs/view/render/scenewidget.hpp | 8 +- 3 files changed, 239 insertions(+), 10 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index b33c83342b..4f653f6fd8 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -259,6 +259,114 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() return modified; } +// mouse picking +// FIXME: need to virtualise mouse buttons +// +// State machine: +// +// [default] mousePressEvent->check if the mouse is pointing at an object +// if yes, go to [grab] else stay at [default] +// +// [grab] mouseReleaseEvent->if same button and new obj, go to [edit] +// mouseMoveEvent->if same button, create collision planes then go to [drag] +// other mouse events or buttons, go back to [default] (i.e. like 'cancel') +// +// [drag] mouseReleaseEvent->if same button, place the object at the new +// location, update the document then go to [edit] +// mouseMoveEvent->update position to the user based on ray to the collision +// planes and render the object at the new location, but do not update +// the document yet +// +// [edit] TODO, probably fine positional adjustments or rotations; clone/delete? +// +// +// press press (obj) +// [default] --------> [grab] <-------------------- [edit] +// ^ (obj) | | ------> [drag] -----> ^ +// | | | move ^ | release | +// | | | | | | +// | | | +-+ | +// | | | move | +// +----------------+ +--------------------------+ +// release release +// (same obj) (new obj) +// +// +void CSVRender::PagedWorldspaceWidget::mouseMoveEvent (QMouseEvent *event) +{ + if(event->buttons() & Qt::RightButton) + { + switch(mMouseState) + { + case Mouse_Grab: + { + // FIXME: check if min elapsed time, mTimer.elapsed(); + // then stop/disable the timer + mMouseState = Mouse_Drag; + //std::cout << "grab->drag" << std::endl; + + /* FALL_THROUGH */ + } + case Mouse_Drag: + { + // FIXME: don't update less than a quantum + //QPoint diff = mOldPos-event->pos(); + mOldPos = event->pos(); + + //std::cout << QString::number(event->pos().x()).toStdString() << ", " + //<< QString::number(event->pos().y()).toStdString() << std::endl; + // FIXME: ray test against the plane to provide feedback to the user + // the relative movement of the object on the x-z plane + break; + } + case Mouse_Edit: + case Mouse_Default: + { + break; + } + /* NO_DEFAULT_CASE */ + } + } + SceneWidget::mouseMoveEvent(event); +} + +void CSVRender::PagedWorldspaceWidget::mousePressEvent (QMouseEvent *event) +{ + if(event->buttons() & Qt::RightButton) + { + switch(mMouseState) + { + case Mouse_Grab: + case Mouse_Drag: + { + break; // error event, ignore + } + case Mouse_Edit: + case Mouse_Default: + { + if(!getCamera()->getViewport()) + break; + + std::pair result = isObjectUnderCursor( + (float) event->x() / getCamera()->getViewport()->getActualWidth(), + (float) event->y() / getCamera()->getViewport()->getActualHeight()); + if(result.first != "") + { + // FIXME: setup a x-z plane at the y position of the object + // FIXME: ray test agaist the plane to get a starting position + // of the mouse in relation to the object position + mMouseState = Mouse_Grab; + //std::cout << "default/edit->grab" << std::endl; + // FIXME: start QElapsedTimer mTimer.start(); + } + break; + } + /* NO_DEFAULT_CASE */ + } + } + //SceneWidget::mousePressEvent(event); +} + void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { if(event->button() == Qt::RightButton) @@ -274,14 +382,89 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) } } - // mouse picking - // FIXME: need to virtualise mouse buttons if(!getCamera()->getViewport()) + { + SceneWidget::mouseReleaseEvent(event); return; + } - debugMousePicking((float) event->x() / getCamera()->getViewport()->getActualWidth(), - (float) event->y() / getCamera()->getViewport()->getActualHeight()); + // FIXME: skip this if overlay clicked above + // FIXME: stop/disable the timer + switch(mMouseState) + { + case Mouse_Grab: + { + std::pair result = isObjectUnderCursor( + (float) event->x() / getCamera()->getViewport()->getActualWidth(), + (float) event->y() / getCamera()->getViewport()->getActualHeight()); + if(result.first != "") + { + if(result.first == mCurrentObj) + { + mMouseState = Mouse_Default; + //std::cout << "grab->default" << std::endl; + mCurrentObj = ""; + } + else + { + mMouseState = Mouse_Edit; + //std::cout << "grab->edit" << std::endl; + mCurrentObj = result.first; + + + // print some debug info + std::cout << "ReferenceId: " << result.first << std::endl; + const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); + int index = references.searchId(result.first); + if (index != -1) + { + int columnIndex = + references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); + std::cout << " index: " + QString::number(index).toStdString() + +", column index: " + QString::number(columnIndex).toStdString() + << std::endl; + } + } + // highlight current object + std::string sceneNode = + CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); + + uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); + bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); + + if(!ignoreObjects && getSceneManager()->hasSceneNode(sceneNode)) + { + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + if(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false) + updateSelectionHighlight(sceneNode, result.second); + } + flagAsModified(); + } + break; + } + case Mouse_Drag: + { + // ray test against the plane, then destroy the plane + // FIXME: update document + std::cout << "final position" << std::endl; + // FIXME: highlight current object + mMouseState = Mouse_Edit; + //std::cout << "drag->edit" << std::endl; + break; + } + case Mouse_Edit: + case Mouse_Default: + { + // probably terrain + debugMousePicking( + (float) event->x() / getCamera()->getViewport()->getActualWidth(), + (float) event->y() / getCamera()->getViewport()->getActualHeight()); + break; + } + /* NO_DEFAULT_CASE */ + } } + SceneWidget::mouseReleaseEvent(event); } void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) @@ -302,6 +485,14 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event flagAsModified(); } } + //SceneWidget::mouseDoubleClickEvent(event); +} + +void CSVRender::PagedWorldspaceWidget::wheelEvent (QWheelEvent *event) +{ + // FIXME: add wheel event to move the object along the y axis during Mouse_Drag or + // Mouse_Grab + SceneWidget::wheelEvent(event); } void CSVRender::PagedWorldspaceWidget::updateOverlay() @@ -405,7 +596,8 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) : WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"), - mControlElements(NULL), mDisplayCellCoord(true), mOverlayMask(NULL) + mControlElements(NULL), mDisplayCellCoord(true), mOverlayMask(NULL), + mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0) { QAbstractItemModel *cells = document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells); @@ -607,6 +799,30 @@ void CSVRender::PagedWorldspaceWidget::cellAdded (const QModelIndex& index, int flagAsModified(); } +std::pair CSVRender::PagedWorldspaceWidget::isObjectUnderCursor(float mouseX, float mouseY) +{ + std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( + mouseX, mouseY, NULL, NULL, getCamera()); + if(result.first != "") + { + QString name = QString(result.first.c_str()); + if(!name.contains(QRegExp("^HeightField"))) + { + std::string sceneNode = + CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); + + uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); + bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); + + if(!ignoreObjects && getSceneManager()->hasSceneNode(sceneNode)) + { + return result; + } + } + } + + return std::make_pair("", Ogre::Vector3(0,0,0)); +} void CSVRender::PagedWorldspaceWidget::debugMousePicking(float mouseX, float mouseY) { diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 2c46729a82..1467395b01 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -28,6 +28,16 @@ namespace CSVRender OverlayMask *mOverlayMask; std::map > mSelectedEntities; + enum MouseState { + Mouse_Grab, + Mouse_Drag, + Mouse_Edit, + Mouse_Default + }; + MouseState mMouseState; + QPoint mOldPos; + std::string mCurrentObj; + private: std::pair getCoordinatesFromId(const std::string& record) const; @@ -52,6 +62,7 @@ namespace CSVRender virtual std::string getStartupInstruction(); + std::pair isObjectUnderCursor(float mouseX, float mouseY); void debugMousePicking(float mouseX, float mouseY); void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); @@ -85,9 +96,11 @@ namespace CSVRender virtual void updateOverlay(); + virtual void mouseMoveEvent (QMouseEvent *event); + virtual void mousePressEvent (QMouseEvent *event); virtual void mouseReleaseEvent (QMouseEvent *event); - virtual void mouseDoubleClickEvent (QMouseEvent *event); + virtual void wheelEvent (QWheelEvent *event); signals: diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 1adbf3f173..5f023a7ad5 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -71,6 +71,10 @@ namespace CSVRender virtual void mouseReleaseEvent (QMouseEvent *event); + virtual void mouseMoveEvent (QMouseEvent *event); + + void wheelEvent (QWheelEvent *event); + private: void paintEvent(QPaintEvent* e); void resizeEvent(QResizeEvent* e); @@ -82,12 +86,8 @@ namespace CSVRender void focusOutEvent (QFocusEvent *event); - void wheelEvent (QWheelEvent *event); - void leaveEvent (QEvent *event); - void mouseMoveEvent (QMouseEvent *event); - void updateOgreWindow(); void setLighting (Lighting *lighting); From 5afaa0083fc94cee672ffd3fb7e790962b9f038b Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 28 Oct 2014 06:42:33 +1100 Subject: [PATCH 23/56] Minimise false detection of grab & drag operation. --- .../view/render/pagedworldspacewidget.cpp | 28 +++++++++++++------ .../view/render/pagedworldspacewidget.hpp | 3 ++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 4f653f6fd8..9d8dd56bd4 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -300,10 +301,16 @@ void CSVRender::PagedWorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { case Mouse_Grab: { - // FIXME: check if min elapsed time, mTimer.elapsed(); - // then stop/disable the timer - mMouseState = Mouse_Drag; - //std::cout << "grab->drag" << std::endl; + // check if min elapsed time to stop false detection of drag + if(!mMouseEventTimer->isValid() || !mMouseEventTimer->hasExpired(200)) // ms + break; + else + { + mMouseEventTimer->invalidate(); + + mMouseState = Mouse_Drag; + std::cout << "grab->drag" << std::endl; + } /* FALL_THROUGH */ } @@ -322,7 +329,7 @@ void CSVRender::PagedWorldspaceWidget::mouseMoveEvent (QMouseEvent *event) case Mouse_Edit: case Mouse_Default: { - break; + break; // error event, ignore } /* NO_DEFAULT_CASE */ } @@ -355,9 +362,10 @@ void CSVRender::PagedWorldspaceWidget::mousePressEvent (QMouseEvent *event) // FIXME: setup a x-z plane at the y position of the object // FIXME: ray test agaist the plane to get a starting position // of the mouse in relation to the object position + mMouseEventTimer->start(); + mMouseState = Mouse_Grab; //std::cout << "default/edit->grab" << std::endl; - // FIXME: start QElapsedTimer mTimer.start(); } break; } @@ -597,7 +605,7 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) : WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"), mControlElements(NULL), mDisplayCellCoord(true), mOverlayMask(NULL), - mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0) + mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0) { QAbstractItemModel *cells = document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells); @@ -609,7 +617,9 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (cellAdded (const QModelIndex&, int, int))); - initDebug(); + initDebug(); + mMouseEventTimer = new QElapsedTimer(); + mMouseEventTimer->invalidate(); } CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() @@ -631,6 +641,8 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() removeRenderTargetListener(mOverlayMask); delete mOverlayMask; + delete mMouseEventTimer; + // For debugging only std::map >::iterator iter = mSelectedEntities.begin(); for(;iter != mSelectedEntities.end(); ++iter) diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 1467395b01..db666ebac3 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -8,6 +8,8 @@ #include "worldspacewidget.hpp" #include "cell.hpp" +class QElapsedTimer; + namespace CSVRender { @@ -37,6 +39,7 @@ namespace CSVRender MouseState mMouseState; QPoint mOldPos; std::string mCurrentObj; + QElapsedTimer *mMouseEventTimer; private: From 68b7532383159c1d50351579c41b7800304da2a1 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 29 Oct 2014 00:50:48 +1100 Subject: [PATCH 24/56] Move code to WorldspaceWidget so that UnpagedWorldspaceWidget can be supported. --- .../view/render/pagedworldspacewidget.cpp | 264 +---------------- .../view/render/pagedworldspacewidget.hpp | 4 - apps/opencs/view/render/worldspacewidget.cpp | 269 ++++++++++++++++++ apps/opencs/view/render/worldspacewidget.hpp | 10 + 4 files changed, 281 insertions(+), 266 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index b33c83342b..b9ccc00f9c 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -13,106 +13,17 @@ #include #include -#include // FIXME: visual highlight, clone -#include // FIXME: visual highlight, material -#include // FIXME: visual highlight, texture - #include #include "textoverlay.hpp" #include "overlaymask.hpp" #include "../../model/world/tablemimedata.hpp" #include "../../model/world/idtable.hpp" -#include "../../model/settings/usersettings.hpp" #include "../widget/scenetooltoggle.hpp" -#include "../world/physicssystem.hpp" #include "elements.hpp" -namespace -{ - // FIXME: this section should be removed once the debugging is completed - void showHitPoint(Ogre::SceneManager *sceneMgr, std::string name, Ogre::Vector3 point) - { - if(sceneMgr->hasManualObject("manual" + name)) - sceneMgr->destroyManualObject("manual" + name); - Ogre::ManualObject* manual = sceneMgr->createManualObject("manual" + name); - manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); - manual-> position(point.x, point.y, point.z-100); - manual-> position(point.x, point.y, point.z+100); - manual-> position(point.x, point.y-100, point.z); - manual-> position(point.x, point.y+100, point.z); - manual-> position(point.x-100, point.y, point.z); - manual-> position(point.x+100, point.y, point.z); - manual->end(); - sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); - } - - void removeHitPoint(Ogre::SceneManager *sceneMgr, std::string name) - { - if(sceneMgr->hasManualObject("manual" + name)) - sceneMgr->destroyManualObject("manual" + name); - } - - void initDebug() - { - // material for visual cue on selected objects - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTrans"); - if(texture.isNull()) - { - texture = Ogre::TextureManager::getSingleton().createManual( - "DynamicTrans", // name - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, // type - 8, 8, // width & height - 0, // number of mipmaps - Ogre::PF_BYTE_BGRA, // pixel format - Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for - // textures updated very often (e.g. each frame) - - Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); - pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); - const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); - - uint8_t* pDest = static_cast(pixelBox.data); - - // Fill in some pixel data. This will give a semi-transparent colour, - // but this is of course dependent on the chosen pixel format. - for (size_t j = 0; j < 8; j++) - { - for(size_t i = 0; i < 8; i++) - { - *pDest++ = 255; // B - *pDest++ = 255; // G - *pDest++ = 127; // R - *pDest++ = 63; // A - } - - pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format); - } - pixelBuffer->unlock(); - } - Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName( - "TransMaterial"); - if(material.isNull()) - { - Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create( - "TransMaterial", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); - Ogre::Pass *pass = material->getTechnique( 0 )->getPass( 0 ); - pass->setLightingEnabled( false ); - pass->setDepthWriteEnabled( false ); - pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); - - Ogre::TextureUnitState *tex = pass->createTextureUnitState("CustomState", 0); - tex->setTextureName("DynamicTrans"); - tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC ); - material->load(); - } - } -} - bool CSVRender::PagedWorldspaceWidget::adjustCells() { bool modified = false; @@ -273,15 +184,8 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) break; } } - - // mouse picking - // FIXME: need to virtualise mouse buttons - if(!getCamera()->getViewport()) - return; - - debugMousePicking((float) event->x() / getCamera()->getViewport()->getActualWidth(), - (float) event->y() / getCamera()->getViewport()->getActualHeight()); } + WorldspaceWidget::mouseReleaseEvent(event); } void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) @@ -289,19 +193,8 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event if(event->button() == Qt::RightButton) { std::cout << "double clicked" << std::endl; - - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - if(userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false) - { - // FIXME: OEngine::PhysicEngine creates only one child scene node for the - // debug drawer. Hence only the first subview that creates the debug drawer - // can view the debug lines. Will need to keep a map in OEngine if multiple - // subviews are to be supported. - CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); - CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(); - flagAsModified(); - } } + WorldspaceWidget::mouseDoubleClickEvent(event); } void CSVRender::PagedWorldspaceWidget::updateOverlay() @@ -416,8 +309,6 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc this, SLOT (cellRemoved (const QModelIndex&, int, int))); connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (cellAdded (const QModelIndex&, int, int))); - - initDebug(); } CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() @@ -438,24 +329,6 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() removeRenderTargetListener(mOverlayMask); delete mOverlayMask; - - // For debugging only - std::map >::iterator iter = mSelectedEntities.begin(); - for(;iter != mSelectedEntities.end(); ++iter) - { - removeHitPoint(getSceneManager(), iter->first); - - if(getSceneManager()->hasSceneNode(iter->first)) - { - Ogre::SceneNode *scene = getSceneManager()->getSceneNode(iter->first); - - if(scene) - { - scene->removeAndDestroyAllChildren(); - getSceneManager()->destroySceneNode(iter->first); - } - } - } } void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) @@ -606,136 +479,3 @@ void CSVRender::PagedWorldspaceWidget::cellAdded (const QModelIndex& index, int if (adjustCells()) flagAsModified(); } - - -void CSVRender::PagedWorldspaceWidget::debugMousePicking(float mouseX, float mouseY) -{ - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; - - std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( - mouseX, mouseY, NULL, NULL, getCamera()); - if(debug && 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"))) - { - // terrain - std::cout << "terrain: " << 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; - } - else - { - std::string sceneNode = - CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); - - uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - - if(!ignoreObjects && getSceneManager()->hasSceneNode(sceneNode)) - { - if(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false) - updateSelectionHighlight(sceneNode, result.second); - } - - std::cout << "ReferenceId: " << result.first << std::endl; - const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (result.first).get(); - //std::cout << "CellRef.mId: " << cellref.mId << std::endl; // Same as ReferenceId - std::cout << " CellRef.mCell: " << cellref.mCell << std::endl; - - const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); - int index = references.searchId(result.first); - if (index != -1) - { - int columnIndex = - references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); - - std::cout << " index: " + QString::number(index).toStdString() - +", column index: " + QString::number(columnIndex).toStdString() << std::endl; - } - - std::map::iterator iter (mCells.begin()); - while (iter!=mCells.end()) - { - if(iter->first.getId("dummy") == cellref.mCell) - { - //std::cout << "Cell found" << std::endl; - break; - } - ++iter; - } - flagAsModified(); - } - } -} - -// FIXME: for debugging only -void CSVRender::PagedWorldspaceWidget::updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position) -{ - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debugCursor = userSettings.setting( - "debug/mouse-position", QString("false")) == "true" ? true : false; - - //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character - Ogre::SceneNode *scene = getSceneManager()->getSceneNode(sceneNode); - std::map >::iterator iter = - mSelectedEntities.find(sceneNode); - if(iter != mSelectedEntities.end()) // currently selected - { - std::vector clonedEntities = mSelectedEntities[sceneNode]; - while(!clonedEntities.empty()) - { - if(getSceneManager()->hasEntity(clonedEntities.back())) - { - scene->detachObject(clonedEntities.back()); - getSceneManager()->destroyEntity(clonedEntities.back()); - } - clonedEntities.pop_back(); - } - mSelectedEntities.erase(iter); - - if(debugCursor) - removeHitPoint(getSceneManager(), sceneNode); - } - else - { - std::vector clonedEntities; - Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); - iter.begin(); - while(iter.hasMoreElements()) - { - Ogre::MovableObject * element = iter.getNext(); - if(!element) - break; - - if(element->getMovableType() != "Entity") - continue; - - Ogre::Entity * entity = dynamic_cast(element); - if(getSceneManager()->hasEntity(entity->getName()+"cover")) - { - // FIXME: this shouldn't really happen... but does :( - scene->detachObject(entity->getName()+"cover"); - getSceneManager()->destroyEntity(entity->getName()+"cover"); - } - Ogre::Entity * clone = entity->clone(entity->getName()+"cover"); - - Ogre::MaterialPtr mat = - Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); - if(!mat.isNull()) - { - clone->setMaterial(mat); - scene->attachObject(clone); - clonedEntities.push_back(entity->getName()+"cover"); - } - } - mSelectedEntities[sceneNode] = clonedEntities; - - if(debugCursor) - showHitPoint(getSceneManager(), sceneNode, position); - } -} diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 2c46729a82..17b6d10c53 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -26,7 +26,6 @@ namespace CSVRender bool mDisplayCellCoord; std::map mTextOverlays; OverlayMask *mOverlayMask; - std::map > mSelectedEntities; private: @@ -52,9 +51,6 @@ namespace CSVRender virtual std::string getStartupInstruction(); - void debugMousePicking(float mouseX, float mouseY); - void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); - public: PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index ebb15ea2ce..7bbe7a63d8 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -7,17 +7,108 @@ #include #include +#include // FIXME: for debugging +#include // FIXME: for debugging +#include // FIXME: for debugging + +#include #include #include "../../model/world/universalid.hpp" #include "../../model/world/idtable.hpp" +#include "../../model/settings/usersettings.hpp" #include "../widget/scenetoolmode.hpp" #include "../widget/scenetooltoggle.hpp" #include "../widget/scenetoolrun.hpp" +#include "../world/physicssystem.hpp" + #include "elements.hpp" +namespace +{ + // FIXME: this section should be removed once the debugging is completed + void showHitPoint(Ogre::SceneManager *sceneMgr, std::string name, Ogre::Vector3 point) + { + if(sceneMgr->hasManualObject("manual" + name)) + sceneMgr->destroyManualObject("manual" + name); + Ogre::ManualObject* manual = sceneMgr->createManualObject("manual" + name); + manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); + manual-> position(point.x, point.y, point.z-100); + manual-> position(point.x, point.y, point.z+100); + manual-> position(point.x, point.y-100, point.z); + manual-> position(point.x, point.y+100, point.z); + manual-> position(point.x-100, point.y, point.z); + manual-> position(point.x+100, point.y, point.z); + manual->end(); + sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); + } + + void removeHitPoint(Ogre::SceneManager *sceneMgr, std::string name) + { + if(sceneMgr->hasManualObject("manual" + name)) + sceneMgr->destroyManualObject("manual" + name); + } + + void initDebug() + { + // material for visual cue on selected objects + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTrans"); + if(texture.isNull()) + { + texture = Ogre::TextureManager::getSingleton().createManual( + "DynamicTrans", // name + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, // type + 8, 8, // width & height + 0, // number of mipmaps + Ogre::PF_BYTE_BGRA, // pixel format + Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for + // textures updated very often (e.g. each frame) + + Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); + pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); + const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); + + uint8_t* pDest = static_cast(pixelBox.data); + + // Fill in some pixel data. This will give a semi-transparent colour, + // but this is of course dependent on the chosen pixel format. + for (size_t j = 0; j < 8; j++) + { + for(size_t i = 0; i < 8; i++) + { + *pDest++ = 255; // B + *pDest++ = 255; // G + *pDest++ = 127; // R + *pDest++ = 63; // A + } + + pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format); + } + pixelBuffer->unlock(); + } + Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName( + "TransMaterial"); + if(material.isNull()) + { + Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create( + "TransMaterial", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); + Ogre::Pass *pass = material->getTechnique( 0 )->getPass( 0 ); + pass->setLightingEnabled( false ); + pass->setDepthWriteEnabled( false ); + pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); + + Ogre::TextureUnitState *tex = pass->createTextureUnitState("CustomState", 0); + tex->setTextureName("DynamicTrans"); + tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC ); + material->load(); + } + } +} + CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) : SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0) { @@ -50,6 +141,29 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg this, SLOT (debugProfileDataChanged (const QModelIndex&, const QModelIndex&))); connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); + + initDebug(); +} + +CSVRender::WorldspaceWidget::~WorldspaceWidget () +{ + // For debugging only + std::map >::iterator iter = mSelectedEntities.begin(); + for(;iter != mSelectedEntities.end(); ++iter) + { + removeHitPoint(getSceneManager(), iter->first); + + if(getSceneManager()->hasSceneNode(iter->first)) + { + Ogre::SceneNode *scene = getSceneManager()->getSceneNode(iter->first); + + if(scene) + { + scene->removeAndDestroyAllChildren(); + getSceneManager()->destroySceneNode(iter->first); + } + } + } } void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) @@ -319,3 +433,158 @@ void CSVRender::WorldspaceWidget::elementSelectionChanged() void CSVRender::WorldspaceWidget::updateOverlay() { } + +void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) +{ + if(event->button() == Qt::RightButton) + { + // mouse picking + // FIXME: need to virtualise mouse buttons + if(!getCamera()->getViewport()) + return; + + debugMousePicking((float) event->x() / getCamera()->getViewport()->getActualWidth(), + (float) event->y() / getCamera()->getViewport()->getActualHeight()); + } + SceneWidget::mouseReleaseEvent(event); +} + +void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) +{ + if(event->button() == Qt::RightButton) + { + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + if(userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false) + { + // FIXME: OEngine::PhysicEngine creates only one child scene node for the + // debug drawer. Hence only the first subview that creates the debug drawer + // can view the debug lines. Will need to keep a map in OEngine if multiple + // subviews are to be supported. + CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); + CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(); + flagAsModified(); + } + } + //SceneWidget::mouseDoubleClickEvent(event); +} + +void CSVRender::WorldspaceWidget::debugMousePicking(float mouseX, float mouseY) +{ + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; + + std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( + mouseX, mouseY, NULL, NULL, getCamera()); + if(debug && 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"))) + { + // terrain + std::cout << "terrain: " << 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; + } + else + { + std::string sceneNode = + CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); + + uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); + bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); + + if(!ignoreObjects && getSceneManager()->hasSceneNode(sceneNode)) + { + if(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false) + updateSelectionHighlight(sceneNode, result.second); + } + + std::cout << "ReferenceId: " << result.first << std::endl; + const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (result.first).get(); + //std::cout << "CellRef.mId: " << cellref.mId << std::endl; // Same as ReferenceId + std::cout << " CellRef.mCell: " << cellref.mCell << std::endl; + + const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); + int index = references.searchId(result.first); + if (index != -1) + { + int columnIndex = + references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); + + std::cout << " index: " + QString::number(index).toStdString() + +", column index: " + QString::number(columnIndex).toStdString() << std::endl; + } + flagAsModified(); + } + } +} + +// FIXME: for debugging only +void CSVRender::WorldspaceWidget::updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position) +{ + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + bool debugCursor = userSettings.setting( + "debug/mouse-position", QString("false")) == "true" ? true : false; + + //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character + Ogre::SceneNode *scene = getSceneManager()->getSceneNode(sceneNode); + std::map >::iterator iter = + mSelectedEntities.find(sceneNode); + if(iter != mSelectedEntities.end()) // currently selected + { + std::vector clonedEntities = mSelectedEntities[sceneNode]; + while(!clonedEntities.empty()) + { + if(getSceneManager()->hasEntity(clonedEntities.back())) + { + scene->detachObject(clonedEntities.back()); + getSceneManager()->destroyEntity(clonedEntities.back()); + } + clonedEntities.pop_back(); + } + mSelectedEntities.erase(iter); + + if(debugCursor) + removeHitPoint(getSceneManager(), sceneNode); + } + else + { + std::vector clonedEntities; + Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); + iter.begin(); + while(iter.hasMoreElements()) + { + Ogre::MovableObject * element = iter.getNext(); + if(!element) + break; + + if(element->getMovableType() != "Entity") + continue; + + Ogre::Entity * entity = dynamic_cast(element); + if(getSceneManager()->hasEntity(entity->getName()+"cover")) + { + // FIXME: this shouldn't really happen... but does :( + scene->detachObject(entity->getName()+"cover"); + getSceneManager()->destroyEntity(entity->getName()+"cover"); + } + Ogre::Entity * clone = entity->clone(entity->getName()+"cover"); + + Ogre::MaterialPtr mat = + Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); + if(!mat.isNull()) + { + clone->setMaterial(mat); + scene->attachObject(clone); + clonedEntities.push_back(entity->getName()+"cover"); + } + } + mSelectedEntities[sceneNode] = clonedEntities; + + if(debugCursor) + showHitPoint(getSceneManager(), sceneNode, position); + } +} diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 4830d772b9..c3d37d6cf9 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -34,6 +34,8 @@ namespace CSVRender CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; + std::map > mSelectedEntities; + public: enum DropType @@ -53,6 +55,7 @@ namespace CSVRender }; WorldspaceWidget (CSMDoc::Document& document, QWidget *parent = 0); + ~WorldspaceWidget (); CSVWidget::SceneToolMode *makeNavigationSelector (CSVWidget::SceneToolbar *parent); ///< \attention The created tool is not added to the toolbar (via addTool). Doing that @@ -90,6 +93,10 @@ namespace CSVRender virtual void updateOverlay(); + virtual void mouseReleaseEvent (QMouseEvent *event); + + virtual void mouseDoubleClickEvent (QMouseEvent *event); + private: void dragEnterEvent(QDragEnterEvent *event); @@ -100,6 +107,9 @@ namespace CSVRender virtual std::string getStartupInstruction() = 0; + void debugMousePicking(float mouseX, float mouseY); + void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); + private slots: void selectNavigationMode (const std::string& mode); From 8e2a0ea90a6a678914f28fe698ff7eb40b846f75 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 29 Oct 2014 08:13:13 +1100 Subject: [PATCH 25/56] Implemented moving objects around x-y plane. --- .../view/render/pagedworldspacewidget.cpp | 119 +++++++++++++++--- .../view/render/pagedworldspacewidget.hpp | 5 + apps/opencs/view/world/physicssystem.cpp | 46 ++++--- apps/opencs/view/world/physicssystem.hpp | 25 ++-- 4 files changed, 154 insertions(+), 41 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 9d8dd56bd4..bc297a690a 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -18,6 +18,8 @@ #include // FIXME: visual highlight, material #include // FIXME: visual highlight, texture +#include + #include #include "textoverlay.hpp" #include "overlaymask.hpp" @@ -302,14 +304,14 @@ void CSVRender::PagedWorldspaceWidget::mouseMoveEvent (QMouseEvent *event) case Mouse_Grab: { // check if min elapsed time to stop false detection of drag - if(!mMouseEventTimer->isValid() || !mMouseEventTimer->hasExpired(200)) // ms + if(!mMouseEventTimer->isValid() || !mMouseEventTimer->hasExpired(100)) // ms break; else { mMouseEventTimer->invalidate(); mMouseState = Mouse_Drag; - std::cout << "grab->drag" << std::endl; + //std::cout << "grab->drag" << std::endl; } /* FALL_THROUGH */ @@ -318,12 +320,24 @@ void CSVRender::PagedWorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { // FIXME: don't update less than a quantum //QPoint diff = mOldPos-event->pos(); - mOldPos = event->pos(); + if(event->pos() != mOldPos) + { + mOldPos = event->pos(); + //std::cout << QString::number(event->pos().x()).toStdString() << ", " + //<< QString::number(event->pos().y()).toStdString() << std::endl; - //std::cout << QString::number(event->pos().x()).toStdString() << ", " - //<< QString::number(event->pos().y()).toStdString() << std::endl; - // FIXME: ray test against the plane to provide feedback to the user - // the relative movement of the object on the x-z plane + // ray test against the plane to provide feedback to the user the + // relative movement of the object on the x-y plane + std::pair planeResult = mousePositionOnPlane(event, *mPlane); + if(planeResult.first) + { + if(mObjSceneNode) + { + mObjSceneNode->setPosition(mOrigObjPos+planeResult.second-mOrigMousePos); + flagAsModified(); + } + } + } break; } case Mouse_Edit: @@ -359,9 +373,20 @@ void CSVRender::PagedWorldspaceWidget::mousePressEvent (QMouseEvent *event) (float) event->y() / getCamera()->getViewport()->getActualHeight()); if(result.first != "") { - // FIXME: setup a x-z plane at the y position of the object - // FIXME: ray test agaist the plane to get a starting position - // of the mouse in relation to the object position + mCurrentObj = result.first; // FIXME + // ray test agaist the plane to get a starting position of the + // mouse in relation to the object position + mPlane->redefine(Ogre::Vector3::UNIT_Z, result.second); + std::pair planeResult = mousePositionOnPlane(event, *mPlane); + if(planeResult.first) + mOrigMousePos = planeResult.second; + + std::string sceneNodeName = + CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); + mObjSceneNode = getSceneManager()->getSceneNode(sceneNodeName); + mOrigObjPos = mObjSceneNode->getPosition(); + + mMouseEventTimer->start(); mMouseState = Mouse_Grab; @@ -372,6 +397,8 @@ void CSVRender::PagedWorldspaceWidget::mousePressEvent (QMouseEvent *event) /* NO_DEFAULT_CASE */ } } + // FIXME: other button press - cancel grab and/or drag and place the object back in the original + // position //SceneWidget::mousePressEvent(event); } @@ -433,7 +460,7 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) << std::endl; } } - // highlight current object + // update highlighting the current object std::string sceneNode = CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); @@ -452,10 +479,39 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) } case Mouse_Drag: { - // ray test against the plane, then destroy the plane + // final placement + std::pair planeResult = mousePositionOnPlane(event, *mPlane); + if(planeResult.first) + { + if(mObjSceneNode) + { + mObjSceneNode->setPosition(mOrigObjPos+planeResult.second-mOrigMousePos); + flagAsModified(); + + // update physics + const CSMWorld::CellRef& cellref = + mDocument.getData().getReferences().getRecord (mCurrentObj).get(); + Ogre::Quaternion xr (Ogre::Radian (-cellref.mPos.rot[0]), Ogre::Vector3::UNIT_X); + Ogre::Quaternion yr (Ogre::Radian (-cellref.mPos.rot[1]), Ogre::Vector3::UNIT_Y); + Ogre::Quaternion zr (Ogre::Radian (-cellref.mPos.rot[2]), Ogre::Vector3::UNIT_Z); + + // FIXME: adjustRigidBody() seems to lose objects, delete and recreate for now + //CSVWorld::PhysicsSystem::instance()->moveObject(mCurrentObj, + //mOrigObjPos+planeResult.second-mOrigMousePos, xr*yr*zr); + std::string sceneNodeName = + CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(mCurrentObj); + std::string mesh = + CSVWorld::PhysicsSystem::instance()->sceneNodeToMesh(sceneNodeName); + CSVWorld::PhysicsSystem::instance()->removeObject(mCurrentObj); + CSVWorld::PhysicsSystem::instance()->addObject(mesh, + sceneNodeName, mCurrentObj, cellref.mScale, + mOrigObjPos+planeResult.second-mOrigMousePos, xr*yr*zr); + } + } // FIXME: update document - std::cout << "final position" << std::endl; - // FIXME: highlight current object + // FIXME: highlight current object? + //std::cout << "final position" << std::endl; + mMouseState = Mouse_Edit; //std::cout << "drag->edit" << std::endl; break; @@ -605,7 +661,7 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) : WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"), mControlElements(NULL), mDisplayCellCoord(true), mOverlayMask(NULL), - mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0) + mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) { QAbstractItemModel *cells = document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells); @@ -620,6 +676,18 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc initDebug(); mMouseEventTimer = new QElapsedTimer(); mMouseEventTimer->invalidate(); + + mPlane = new Ogre::Plane(Ogre::Vector3::UNIT_Z, 0); + Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createPlane("ground", + 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 + Ogre::Vector3::UNIT_Y // upVector + ); } CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() @@ -660,6 +728,8 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() } } } + + delete mPlane; } void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) @@ -832,10 +902,29 @@ std::pair CSVRender::PagedWorldspaceWidget::isObject } } } + else + std::cout << "error castRay returned empty " << result.first << std::endl; return std::make_pair("", Ogre::Vector3(0,0,0)); } +std::pair CSVRender::PagedWorldspaceWidget::mousePositionOnPlane(QMouseEvent *event, Ogre::Plane &plane) +{ + // using a really small value seems to mess up with the projections + float nearClipDistance = getCamera()->getNearClipDistance(); // save existing + getCamera()->setNearClipDistance(10.0f); // arbitrary number + Ogre::Ray mouseRay = getCamera()->getCameraToViewportRay( + (float) event->x() / getCamera()->getViewport()->getActualWidth(), + (float) event->y() / getCamera()->getViewport()->getActualHeight()); + getCamera()->setNearClipDistance(nearClipDistance); // restore + std::pair planeResult = mouseRay.intersects(plane); + + if(planeResult.first) + return std::make_pair(true, mouseRay.getPoint(planeResult.second)); + else + return std::make_pair(false, Ogre::Vector3()); // should only happen if the plane is too small +} + void CSVRender::PagedWorldspaceWidget::debugMousePicking(float mouseX, float mouseY) { CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index db666ebac3..defd7638ab 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -40,6 +40,10 @@ namespace CSVRender QPoint mOldPos; std::string mCurrentObj; QElapsedTimer *mMouseEventTimer; + Ogre::Plane *mPlane; + Ogre::SceneNode *mObjSceneNode; + Ogre::Vector3 mOrigObjPos; + Ogre::Vector3 mOrigMousePos; private: @@ -66,6 +70,7 @@ namespace CSVRender virtual std::string getStartupInstruction(); std::pair isObjectUnderCursor(float mouseX, float mouseY); + std::pair mousePositionOnPlane(QMouseEvent *event, Ogre::Plane &plane); void debugMousePicking(float mouseX, float mouseY); void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 154cc62737..a422147a93 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -37,26 +37,35 @@ namespace CSVWorld } void PhysicsSystem::addObject(const std::string &mesh, - const std::string &name, const std::string &referenceId, float scale, + const std::string &sceneNodeName, const std::string &referenceId, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) { - mRefToSceneNode[referenceId] = name; + mRefToSceneNode[referenceId] = sceneNodeName; + mSceneNodeToMesh[sceneNodeName] = mesh; - mEngine->createAndAdjustRigidBody(mesh, referenceId, scale, position, rotation, - 0, // scaledBoxTranslation - 0, // boxRotation - true, // raycasting - placeable); + mEngine->createAndAdjustRigidBody(mesh, + referenceId, scale, position, rotation, + 0, // scaledBoxTranslation + 0, // boxRotation + true, // raycasting + placeable); } - void PhysicsSystem::removeObject(const std::string& name) + void PhysicsSystem::removeObject(const std::string &referenceId) { - mEngine->removeRigidBody(name); - mEngine->deleteRigidBody(name); + mEngine->removeRigidBody(referenceId); + mEngine->deleteRigidBody(referenceId); } - void PhysicsSystem::addHeightField(float* heights, int x, int y, float yoffset, - float triSize, float sqrtVerts) + void PhysicsSystem::moveObject(const std::string &referenceId, + const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) + { + mEngine->adjustRigidBody(mEngine->getRigidBody(referenceId, true /*raycasting*/), + position, rotation); + } + + void PhysicsSystem::addHeightField(float* heights, + int x, int y, float yoffset, float triSize, float sqrtVerts) { mEngine->addHeightField(heights, x, y, yoffset, triSize, sqrtVerts); } @@ -66,8 +75,8 @@ namespace CSVWorld mEngine->removeHeightField(x, y); } - std::pair PhysicsSystem::castRay(float mouseX, float mouseY, - Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) + std::pair PhysicsSystem::castRay(float mouseX, + float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) { if(!mSceneMgr || !camera || !camera->getViewport()) return std::make_pair("", Ogre::Vector3(0,0,0)); // FIXME: this should be an exception @@ -102,9 +111,14 @@ namespace CSVWorld return std::make_pair(result.first, ray.getPoint(farClipDist*result.second)); } - std::string PhysicsSystem::referenceToSceneNode(std::string reference) + std::string PhysicsSystem::referenceToSceneNode(std::string referenceId) { - return mRefToSceneNode[reference]; + return mRefToSceneNode[referenceId]; + } + + std::string PhysicsSystem::sceneNodeToMesh(std::string sceneNodeName) + { + return mSceneNodeToMesh[sceneNodeName]; } void PhysicsSystem::setSceneManager(Ogre::SceneManager *sceneMgr) diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index c19486d17b..983f1a2a76 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -27,6 +27,7 @@ namespace CSVWorld { static PhysicsSystem *mPhysicsSystemInstance; std::map mRefToSceneNode; + std::map mSceneNodeToMesh; OEngine::Physic::PhysicEngine* mEngine; Ogre::SceneManager *mSceneMgr; @@ -40,24 +41,28 @@ namespace CSVWorld void setSceneManager(Ogre::SceneManager *sceneMgr); - void addObject(const std::string &mesh, const std::string &name, - const std::string &referenceId, float scale, - const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - bool placeable=false); + void addObject(const std::string &mesh, + const std::string &sceneNodeName, const std::string &referenceId, float scale, + const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, + bool placeable=false); - void removeObject(const std::string &name); + void removeObject(const std::string &referenceId); - void addHeightField(float* heights, int x, int y, float yoffset, - float triSize, float sqrtVerts); + void moveObject(const std::string &referenceId, + const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); + + void addHeightField(float* heights, + int x, int y, float yoffset, float triSize, float sqrtVerts); void removeHeightField(int x, int y); void toggleDebugRendering(); - std::pair castRay(float mouseX, float mouseY, - Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera); + std::pair castRay(float mouseX, + float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera); - std::string referenceToSceneNode(std::string reference); + std::string referenceToSceneNode(std::string referenceId); + std::string sceneNodeToMesh(std::string sceneNodeName); private: From 792fbd119f45e5bac066a4c8885d77f4261405f8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 29 Oct 2014 10:43:55 +1100 Subject: [PATCH 26/56] Resolve incorrect merge issues. --- .../view/render/pagedworldspacewidget.cpp | 483 +----------------- .../view/render/pagedworldspacewidget.hpp | 26 +- apps/opencs/view/render/worldspacewidget.cpp | 323 +++++++++++- apps/opencs/view/render/worldspacewidget.hpp | 22 +- 4 files changed, 343 insertions(+), 511 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 70d807ea77..e102801a2c 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -14,8 +13,6 @@ #include #include -#include - #include #include "textoverlay.hpp" #include "overlaymask.hpp" @@ -173,146 +170,6 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() return modified; } -// mouse picking -// FIXME: need to virtualise mouse buttons -// -// State machine: -// -// [default] mousePressEvent->check if the mouse is pointing at an object -// if yes, go to [grab] else stay at [default] -// -// [grab] mouseReleaseEvent->if same button and new obj, go to [edit] -// mouseMoveEvent->if same button, create collision planes then go to [drag] -// other mouse events or buttons, go back to [default] (i.e. like 'cancel') -// -// [drag] mouseReleaseEvent->if same button, place the object at the new -// location, update the document then go to [edit] -// mouseMoveEvent->update position to the user based on ray to the collision -// planes and render the object at the new location, but do not update -// the document yet -// -// [edit] TODO, probably fine positional adjustments or rotations; clone/delete? -// -// -// press press (obj) -// [default] --------> [grab] <-------------------- [edit] -// ^ (obj) | | ------> [drag] -----> ^ -// | | | move ^ | release | -// | | | | | | -// | | | +-+ | -// | | | move | -// +----------------+ +--------------------------+ -// release release -// (same obj) (new obj) -// -// -void CSVRender::PagedWorldspaceWidget::mouseMoveEvent (QMouseEvent *event) -{ - if(event->buttons() & Qt::RightButton) - { - switch(mMouseState) - { - case Mouse_Grab: - { - // check if min elapsed time to stop false detection of drag - if(!mMouseEventTimer->isValid() || !mMouseEventTimer->hasExpired(100)) // ms - break; - else - { - mMouseEventTimer->invalidate(); - - mMouseState = Mouse_Drag; - //std::cout << "grab->drag" << std::endl; - } - - /* FALL_THROUGH */ - } - case Mouse_Drag: - { - // FIXME: don't update less than a quantum - //QPoint diff = mOldPos-event->pos(); - if(event->pos() != mOldPos) - { - mOldPos = event->pos(); - //std::cout << QString::number(event->pos().x()).toStdString() << ", " - //<< QString::number(event->pos().y()).toStdString() << std::endl; - - // ray test against the plane to provide feedback to the user the - // relative movement of the object on the x-y plane - std::pair planeResult = mousePositionOnPlane(event, *mPlane); - if(planeResult.first) - { - if(mObjSceneNode) - { - mObjSceneNode->setPosition(mOrigObjPos+planeResult.second-mOrigMousePos); - flagAsModified(); - } - } - } - break; - } - case Mouse_Edit: - case Mouse_Default: - { - break; // error event, ignore - } - /* NO_DEFAULT_CASE */ - } - } - SceneWidget::mouseMoveEvent(event); -} - -void CSVRender::PagedWorldspaceWidget::mousePressEvent (QMouseEvent *event) -{ - if(event->buttons() & Qt::RightButton) - { - switch(mMouseState) - { - case Mouse_Grab: - case Mouse_Drag: - { - break; // error event, ignore - } - case Mouse_Edit: - case Mouse_Default: - { - if(!getCamera()->getViewport()) - break; - - std::pair result = isObjectUnderCursor( - (float) event->x() / getCamera()->getViewport()->getActualWidth(), - (float) event->y() / getCamera()->getViewport()->getActualHeight()); - if(result.first != "") - { - mCurrentObj = result.first; // FIXME - // ray test agaist the plane to get a starting position of the - // mouse in relation to the object position - mPlane->redefine(Ogre::Vector3::UNIT_Z, result.second); - std::pair planeResult = mousePositionOnPlane(event, *mPlane); - if(planeResult.first) - mOrigMousePos = planeResult.second; - - std::string sceneNodeName = - CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); - mObjSceneNode = getSceneManager()->getSceneNode(sceneNodeName); - mOrigObjPos = mObjSceneNode->getPosition(); - - - mMouseEventTimer->start(); - - mMouseState = Mouse_Grab; - //std::cout << "default/edit->grab" << std::endl; - } - break; - } - /* NO_DEFAULT_CASE */ - } - } - // FIXME: other button press - cancel grab and/or drag and place the object back in the original - // position - //SceneWidget::mousePressEvent(event); -} - void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { if(event->button() == Qt::RightButton) @@ -327,119 +184,8 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) break; } } - - if(!getCamera()->getViewport()) - { - SceneWidget::mouseReleaseEvent(event); - return; - } - - // FIXME: skip this if overlay clicked above - // FIXME: stop/disable the timer - switch(mMouseState) - { - case Mouse_Grab: - { - std::pair result = isObjectUnderCursor( - (float) event->x() / getCamera()->getViewport()->getActualWidth(), - (float) event->y() / getCamera()->getViewport()->getActualHeight()); - if(result.first != "") - { - if(result.first == mCurrentObj) - { - mMouseState = Mouse_Default; - //std::cout << "grab->default" << std::endl; - mCurrentObj = ""; - } - else - { - mMouseState = Mouse_Edit; - //std::cout << "grab->edit" << std::endl; - mCurrentObj = result.first; - - - // print some debug info - std::cout << "ReferenceId: " << result.first << std::endl; - const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); - int index = references.searchId(result.first); - if (index != -1) - { - int columnIndex = - references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); - std::cout << " index: " + QString::number(index).toStdString() - +", column index: " + QString::number(columnIndex).toStdString() - << std::endl; - } - } - // update highlighting the current object - std::string sceneNode = - CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); - - uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - - if(!ignoreObjects && getSceneManager()->hasSceneNode(sceneNode)) - { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - if(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false) - updateSelectionHighlight(sceneNode, result.second); - } - flagAsModified(); - } - break; - } - case Mouse_Drag: - { - // final placement - std::pair planeResult = mousePositionOnPlane(event, *mPlane); - if(planeResult.first) - { - if(mObjSceneNode) - { - mObjSceneNode->setPosition(mOrigObjPos+planeResult.second-mOrigMousePos); - flagAsModified(); - - // update physics - const CSMWorld::CellRef& cellref = - mDocument.getData().getReferences().getRecord (mCurrentObj).get(); - Ogre::Quaternion xr (Ogre::Radian (-cellref.mPos.rot[0]), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yr (Ogre::Radian (-cellref.mPos.rot[1]), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zr (Ogre::Radian (-cellref.mPos.rot[2]), Ogre::Vector3::UNIT_Z); - - // FIXME: adjustRigidBody() seems to lose objects, delete and recreate for now - //CSVWorld::PhysicsSystem::instance()->moveObject(mCurrentObj, - //mOrigObjPos+planeResult.second-mOrigMousePos, xr*yr*zr); - std::string sceneNodeName = - CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(mCurrentObj); - std::string mesh = - CSVWorld::PhysicsSystem::instance()->sceneNodeToMesh(sceneNodeName); - CSVWorld::PhysicsSystem::instance()->removeObject(mCurrentObj); - CSVWorld::PhysicsSystem::instance()->addObject(mesh, - sceneNodeName, mCurrentObj, cellref.mScale, - mOrigObjPos+planeResult.second-mOrigMousePos, xr*yr*zr); - } - } - // FIXME: update document - // FIXME: highlight current object? - //std::cout << "final position" << std::endl; - - mMouseState = Mouse_Edit; - //std::cout << "drag->edit" << std::endl; - break; - } - case Mouse_Edit: - case Mouse_Default: - { - // probably terrain - debugMousePicking( - (float) event->x() / getCamera()->getViewport()->getActualWidth(), - (float) event->y() / getCamera()->getViewport()->getActualHeight()); - break; - } - /* NO_DEFAULT_CASE */ - } } - SceneWidget::mouseReleaseEvent(event); + WorldspaceWidget::mouseReleaseEvent(event); } void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) @@ -448,14 +194,7 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event { std::cout << "double clicked" << std::endl; } - //SceneWidget::mouseDoubleClickEvent(event); -} - -void CSVRender::PagedWorldspaceWidget::wheelEvent (QWheelEvent *event) -{ - // FIXME: add wheel event to move the object along the y axis during Mouse_Drag or - // Mouse_Grab - SceneWidget::wheelEvent(event); + //WorldspaceWidget::mouseDoubleClickEvent(event); } void CSVRender::PagedWorldspaceWidget::updateOverlay() @@ -559,8 +298,7 @@ std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction() CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) : WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"), - mControlElements(NULL), mDisplayCellCoord(true), mOverlayMask(NULL), - mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) + mControlElements(NULL), mDisplayCellCoord(true), mOverlayMask(NULL) { QAbstractItemModel *cells = document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells); @@ -571,22 +309,6 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc this, SLOT (cellRemoved (const QModelIndex&, int, int))); connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (cellAdded (const QModelIndex&, int, int))); - - initDebug(); - mMouseEventTimer = new QElapsedTimer(); - mMouseEventTimer->invalidate(); - - mPlane = new Ogre::Plane(Ogre::Vector3::UNIT_Z, 0); - Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createPlane("ground", - 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 - Ogre::Vector3::UNIT_Y // upVector - ); } CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() @@ -607,28 +329,6 @@ CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget() removeRenderTargetListener(mOverlayMask); delete mOverlayMask; - - delete mMouseEventTimer; - - // For debugging only - std::map >::iterator iter = mSelectedEntities.begin(); - for(;iter != mSelectedEntities.end(); ++iter) - { - removeHitPoint(getSceneManager(), iter->first); - - if(getSceneManager()->hasSceneNode(iter->first)) - { - Ogre::SceneNode *scene = getSceneManager()->getSceneNode(iter->first); - - if(scene) - { - scene->removeAndDestroyAllChildren(); - getSceneManager()->destroySceneNode(iter->first); - } - } - } - - delete mPlane; } void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) @@ -732,7 +432,6 @@ CSVRender::WorldspaceWidget::dropRequirments CSVRender::PagedWorldspaceWidget::g } } - unsigned int CSVRender::PagedWorldspaceWidget::getElementMask() const { return WorldspaceWidget::getElementMask() | mControlElements->getSelection(); @@ -779,179 +478,3 @@ void CSVRender::PagedWorldspaceWidget::cellAdded (const QModelIndex& index, int if (adjustCells()) flagAsModified(); } - -std::pair CSVRender::PagedWorldspaceWidget::isObjectUnderCursor(float mouseX, float mouseY) -{ - std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( - mouseX, mouseY, NULL, NULL, getCamera()); - if(result.first != "") - { - QString name = QString(result.first.c_str()); - if(!name.contains(QRegExp("^HeightField"))) - { - std::string sceneNode = - CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); - - uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - - if(!ignoreObjects && getSceneManager()->hasSceneNode(sceneNode)) - { - return result; - } - } - } - else - std::cout << "error castRay returned empty " << result.first << std::endl; - - return std::make_pair("", Ogre::Vector3(0,0,0)); -} - -std::pair CSVRender::PagedWorldspaceWidget::mousePositionOnPlane(QMouseEvent *event, Ogre::Plane &plane) -{ - // using a really small value seems to mess up with the projections - float nearClipDistance = getCamera()->getNearClipDistance(); // save existing - getCamera()->setNearClipDistance(10.0f); // arbitrary number - Ogre::Ray mouseRay = getCamera()->getCameraToViewportRay( - (float) event->x() / getCamera()->getViewport()->getActualWidth(), - (float) event->y() / getCamera()->getViewport()->getActualHeight()); - getCamera()->setNearClipDistance(nearClipDistance); // restore - std::pair planeResult = mouseRay.intersects(plane); - - if(planeResult.first) - return std::make_pair(true, mouseRay.getPoint(planeResult.second)); - else - return std::make_pair(false, Ogre::Vector3()); // should only happen if the plane is too small -} - -void CSVRender::PagedWorldspaceWidget::debugMousePicking(float mouseX, float mouseY) -{ - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; - - std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( - mouseX, mouseY, NULL, NULL, getCamera()); - if(debug && 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"))) - { - // terrain - std::cout << "terrain: " << 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; - } - else - { - std::string sceneNode = - CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); - - uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - - if(!ignoreObjects && getSceneManager()->hasSceneNode(sceneNode)) - { - if(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false) - updateSelectionHighlight(sceneNode, result.second); - } - - std::cout << "ReferenceId: " << result.first << std::endl; - const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (result.first).get(); - //std::cout << "CellRef.mId: " << cellref.mId << std::endl; // Same as ReferenceId - std::cout << " CellRef.mCell: " << cellref.mCell << std::endl; - - const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); - int index = references.searchId(result.first); - if (index != -1) - { - int columnIndex = - references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); - - std::cout << " index: " + QString::number(index).toStdString() - +", column index: " + QString::number(columnIndex).toStdString() << std::endl; - } - - std::map::iterator iter (mCells.begin()); - while (iter!=mCells.end()) - { - if(iter->first.getId("dummy") == cellref.mCell) - { - //std::cout << "Cell found" << std::endl; - break; - } - ++iter; - } - flagAsModified(); - } - } -} - -// FIXME: for debugging only -void CSVRender::PagedWorldspaceWidget::updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position) -{ - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debugCursor = userSettings.setting( - "debug/mouse-position", QString("false")) == "true" ? true : false; - - //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character - Ogre::SceneNode *scene = getSceneManager()->getSceneNode(sceneNode); - std::map >::iterator iter = - mSelectedEntities.find(sceneNode); - if(iter != mSelectedEntities.end()) // currently selected - { - std::vector clonedEntities = mSelectedEntities[sceneNode]; - while(!clonedEntities.empty()) - { - if(getSceneManager()->hasEntity(clonedEntities.back())) - { - scene->detachObject(clonedEntities.back()); - getSceneManager()->destroyEntity(clonedEntities.back()); - } - clonedEntities.pop_back(); - } - mSelectedEntities.erase(iter); - - if(debugCursor) - removeHitPoint(getSceneManager(), sceneNode); - } - else - { - std::vector clonedEntities; - Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); - iter.begin(); - while(iter.hasMoreElements()) - { - Ogre::MovableObject * element = iter.getNext(); - if(!element) - break; - - if(element->getMovableType() != "Entity") - continue; - - Ogre::Entity * entity = dynamic_cast(element); - if(getSceneManager()->hasEntity(entity->getName()+"cover")) - { - // FIXME: this shouldn't really happen... but does :( - scene->detachObject(entity->getName()+"cover"); - getSceneManager()->destroyEntity(entity->getName()+"cover"); - } - Ogre::Entity * clone = entity->clone(entity->getName()+"cover"); - - Ogre::MaterialPtr mat = - Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); - if(!mat.isNull()) - { - clone->setMaterial(mat); - scene->attachObject(clone); - clonedEntities.push_back(entity->getName()+"cover"); - } - } - mSelectedEntities[sceneNode] = clonedEntities; - - if(debugCursor) - showHitPoint(getSceneManager(), sceneNode, position); - } -} diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index dc71e19dbc..17b6d10c53 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -8,8 +8,6 @@ #include "worldspacewidget.hpp" #include "cell.hpp" -class QElapsedTimer; - namespace CSVRender { @@ -29,21 +27,6 @@ namespace CSVRender std::map mTextOverlays; OverlayMask *mOverlayMask; - enum MouseState { - Mouse_Grab, - Mouse_Drag, - Mouse_Edit, - Mouse_Default - }; - MouseState mMouseState; - QPoint mOldPos; - std::string mCurrentObj; - QElapsedTimer *mMouseEventTimer; - Ogre::Plane *mPlane; - Ogre::SceneNode *mObjSceneNode; - Ogre::Vector3 mOrigObjPos; - Ogre::Vector3 mOrigMousePos; - private: std::pair getCoordinatesFromId(const std::string& record) const; @@ -68,11 +51,6 @@ namespace CSVRender virtual std::string getStartupInstruction(); - std::pair isObjectUnderCursor(float mouseX, float mouseY); - std::pair mousePositionOnPlane(QMouseEvent *event, Ogre::Plane &plane); - void debugMousePicking(float mouseX, float mouseY); - void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); - public: PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document); @@ -103,11 +81,9 @@ namespace CSVRender virtual void updateOverlay(); - virtual void mouseMoveEvent (QMouseEvent *event); - virtual void mousePressEvent (QMouseEvent *event); virtual void mouseReleaseEvent (QMouseEvent *event); + virtual void mouseDoubleClickEvent (QMouseEvent *event); - virtual void wheelEvent (QWheelEvent *event); signals: diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 7bbe7a63d8..65abe09c35 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -7,11 +7,13 @@ #include #include +#include #include // FIXME: for debugging #include // FIXME: for debugging #include // FIXME: for debugging #include +#include #include #include "../../model/world/universalid.hpp" @@ -110,7 +112,8 @@ namespace } CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0) +: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), + mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) { setAcceptDrops(true); @@ -143,10 +146,26 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); initDebug(); + mMouseEventTimer = new QElapsedTimer(); + mMouseEventTimer->invalidate(); + + mPlane = new Ogre::Plane(Ogre::Vector3::UNIT_Z, 0); + Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createPlane("ground", + 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 + Ogre::Vector3::UNIT_Y // upVector + ); } CSVRender::WorldspaceWidget::~WorldspaceWidget () { + delete mMouseEventTimer; + // For debugging only std::map >::iterator iter = mSelectedEntities.begin(); for(;iter != mSelectedEntities.end(); ++iter) @@ -164,6 +183,8 @@ CSVRender::WorldspaceWidget::~WorldspaceWidget () } } } + + delete mPlane; } void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) @@ -434,17 +455,260 @@ void CSVRender::WorldspaceWidget::updateOverlay() { } +// mouse picking +// FIXME: need to virtualise mouse buttons +// +// State machine: +// +// [default] mousePressEvent->check if the mouse is pointing at an object +// if yes, go to [grab] else stay at [default] +// +// [grab] mouseReleaseEvent->if same button and new obj, go to [edit] +// mouseMoveEvent->if same button, create collision planes then go to [drag] +// other mouse events or buttons, go back to [default] (i.e. like 'cancel') +// +// [drag] mouseReleaseEvent->if same button, place the object at the new +// location, update the document then go to [edit] +// mouseMoveEvent->update position to the user based on ray to the collision +// planes and render the object at the new location, but do not update +// the document yet +// +// [edit] TODO, probably fine positional adjustments or rotations; clone/delete? +// +// +// press press (obj) +// [default] --------> [grab] <-------------------- [edit] +// ^ (obj) | | ------> [drag] -----> ^ +// | | | move ^ | release | +// | | | | | | +// | | | +-+ | +// | | | move | +// +----------------+ +--------------------------+ +// release release +// (same obj) (new obj) +// +// +void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) +{ + if(event->buttons() & Qt::RightButton) + { + switch(mMouseState) + { + case Mouse_Grab: + { + // check if min elapsed time to stop false detection of drag + if(!mMouseEventTimer->isValid() || !mMouseEventTimer->hasExpired(100)) // ms + break; + else + { + mMouseEventTimer->invalidate(); + + mMouseState = Mouse_Drag; + //std::cout << "grab->drag" << std::endl; + } + + /* FALL_THROUGH */ + } + case Mouse_Drag: + { + // FIXME: don't update less than a quantum + //QPoint diff = mOldPos-event->pos(); + if(event->pos() != mOldPos) + { + mOldPos = event->pos(); + //std::cout << QString::number(event->pos().x()).toStdString() << ", " + //<< QString::number(event->pos().y()).toStdString() << std::endl; + + // ray test against the plane to provide feedback to the user the + // relative movement of the object on the x-y plane + std::pair planeResult = mousePositionOnPlane(event, *mPlane); + if(planeResult.first) + { + if(mObjSceneNode) + { + mObjSceneNode->setPosition(mOrigObjPos+planeResult.second-mOrigMousePos); + flagAsModified(); + } + } + } + break; + } + case Mouse_Edit: + case Mouse_Default: + { + break; // error event, ignore + } + /* NO_DEFAULT_CASE */ + } + } + SceneWidget::mouseMoveEvent(event); +} + +void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) +{ + if(event->buttons() & Qt::RightButton) + { + switch(mMouseState) + { + case Mouse_Grab: + case Mouse_Drag: + { + break; // error event, ignore + } + case Mouse_Edit: + case Mouse_Default: + { + if(!getCamera()->getViewport()) + break; + + std::pair result = isObjectUnderCursor( + (float) event->x() / getCamera()->getViewport()->getActualWidth(), + (float) event->y() / getCamera()->getViewport()->getActualHeight()); + if(result.first != "") + { + mCurrentObj = result.first; // FIXME + // ray test agaist the plane to get a starting position of the + // mouse in relation to the object position + mPlane->redefine(Ogre::Vector3::UNIT_Z, result.second); + std::pair planeResult = mousePositionOnPlane(event, *mPlane); + if(planeResult.first) + mOrigMousePos = planeResult.second; + + std::string sceneNodeName = + CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); + mObjSceneNode = getSceneManager()->getSceneNode(sceneNodeName); + mOrigObjPos = mObjSceneNode->getPosition(); + + + mMouseEventTimer->start(); + + mMouseState = Mouse_Grab; + //std::cout << "default/edit->grab" << std::endl; + } + break; + } + /* NO_DEFAULT_CASE */ + } + } + // FIXME: other button press - cancel grab and/or drag and place the object back in the original + // position + //SceneWidget::mousePressEvent(event); +} + void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { if(event->button() == Qt::RightButton) { - // mouse picking - // FIXME: need to virtualise mouse buttons if(!getCamera()->getViewport()) + { + SceneWidget::mouseReleaseEvent(event); return; + } - debugMousePicking((float) event->x() / getCamera()->getViewport()->getActualWidth(), - (float) event->y() / getCamera()->getViewport()->getActualHeight()); + // FIXME: skip this if overlay clicked above + // FIXME: stop/disable the timer + switch(mMouseState) + { + case Mouse_Grab: + { + std::pair result = isObjectUnderCursor( + (float) event->x() / getCamera()->getViewport()->getActualWidth(), + (float) event->y() / getCamera()->getViewport()->getActualHeight()); + if(result.first != "") + { + if(result.first == mCurrentObj) + { + mMouseState = Mouse_Default; + //std::cout << "grab->default" << std::endl; + mCurrentObj = ""; + } + else + { + mMouseState = Mouse_Edit; + //std::cout << "grab->edit" << std::endl; + mCurrentObj = result.first; + + + // print some debug info + std::cout << "ReferenceId: " << result.first << std::endl; + const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); + int index = references.searchId(result.first); + if (index != -1) + { + int columnIndex = + references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); + std::cout << " index: " + QString::number(index).toStdString() + +", column index: " + QString::number(columnIndex).toStdString() + << std::endl; + } + } + // update highlighting the current object + std::string sceneNode = + CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); + + uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); + bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); + + if(!ignoreObjects && getSceneManager()->hasSceneNode(sceneNode)) + { + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + if(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false) + updateSelectionHighlight(sceneNode, result.second); + } + flagAsModified(); + } + break; + } + case Mouse_Drag: + { + // final placement + std::pair planeResult = mousePositionOnPlane(event, *mPlane); + if(planeResult.first) + { + if(mObjSceneNode) + { + mObjSceneNode->setPosition(mOrigObjPos+planeResult.second-mOrigMousePos); + flagAsModified(); + + // update physics + const CSMWorld::CellRef& cellref = + mDocument.getData().getReferences().getRecord (mCurrentObj).get(); + Ogre::Quaternion xr (Ogre::Radian (-cellref.mPos.rot[0]), Ogre::Vector3::UNIT_X); + Ogre::Quaternion yr (Ogre::Radian (-cellref.mPos.rot[1]), Ogre::Vector3::UNIT_Y); + Ogre::Quaternion zr (Ogre::Radian (-cellref.mPos.rot[2]), Ogre::Vector3::UNIT_Z); + + // FIXME: adjustRigidBody() seems to lose objects, delete and recreate for now + //CSVWorld::PhysicsSystem::instance()->moveObject(mCurrentObj, + //mOrigObjPos+planeResult.second-mOrigMousePos, xr*yr*zr); + std::string sceneNodeName = + CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(mCurrentObj); + std::string mesh = + CSVWorld::PhysicsSystem::instance()->sceneNodeToMesh(sceneNodeName); + CSVWorld::PhysicsSystem::instance()->removeObject(mCurrentObj); + CSVWorld::PhysicsSystem::instance()->addObject(mesh, + sceneNodeName, mCurrentObj, cellref.mScale, + mOrigObjPos+planeResult.second-mOrigMousePos, xr*yr*zr); + } + } + // FIXME: update document + // FIXME: highlight current object? + //std::cout << "final position" << std::endl; + + mMouseState = Mouse_Edit; + //std::cout << "drag->edit" << std::endl; + break; + } + case Mouse_Edit: + case Mouse_Default: + { + // probably terrain + debugMousePicking( + (float) event->x() / getCamera()->getViewport()->getActualWidth(), + (float) event->y() / getCamera()->getViewport()->getActualHeight()); + break; + } + /* NO_DEFAULT_CASE */ + } } SceneWidget::mouseReleaseEvent(event); } @@ -468,6 +732,13 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) //SceneWidget::mouseDoubleClickEvent(event); } +void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) +{ + // FIXME: add wheel event to move the object along the y axis during Mouse_Drag or + // Mouse_Grab + SceneWidget::wheelEvent(event); +} + void CSVRender::WorldspaceWidget::debugMousePicking(float mouseX, float mouseY) { CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); @@ -588,3 +859,45 @@ void CSVRender::WorldspaceWidget::updateSelectionHighlight(std::string sceneNode showHitPoint(getSceneManager(), sceneNode, position); } } + +std::pair CSVRender::WorldspaceWidget::isObjectUnderCursor(float mouseX, float mouseY) +{ + std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( + mouseX, mouseY, NULL, NULL, getCamera()); + if(result.first != "") + { + QString name = QString(result.first.c_str()); + if(!name.contains(QRegExp("^HeightField"))) + { + std::string sceneNode = + CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); + + uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); + bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); + + if(!ignoreObjects && getSceneManager()->hasSceneNode(sceneNode)) + { + return result; + } + } + } + + return std::make_pair("", Ogre::Vector3(0,0,0)); +} + +std::pair CSVRender::WorldspaceWidget::mousePositionOnPlane(QMouseEvent *event, Ogre::Plane &plane) +{ + // using a really small value seems to mess up with the projections + float nearClipDistance = getCamera()->getNearClipDistance(); // save existing + getCamera()->setNearClipDistance(10.0f); // arbitrary number + Ogre::Ray mouseRay = getCamera()->getCameraToViewportRay( + (float) event->x() / getCamera()->getViewport()->getActualWidth(), + (float) event->y() / getCamera()->getViewport()->getActualHeight()); + getCamera()->setNearClipDistance(nearClipDistance); // restore + std::pair planeResult = mouseRay.intersects(plane); + + if(planeResult.first) + return std::make_pair(true, mouseRay.getPoint(planeResult.second)); + else + return std::make_pair(false, Ogre::Vector3()); // should only happen if the plane is too small +} diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index c3d37d6cf9..756debfe59 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -21,6 +21,8 @@ namespace CSVWidget class SceneToolRun; } +class QElapsedTimer; + namespace CSVRender { class WorldspaceWidget : public SceneWidget @@ -34,6 +36,20 @@ namespace CSVRender CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; + enum MouseState { + Mouse_Grab, + Mouse_Drag, + Mouse_Edit, + Mouse_Default + }; + MouseState mMouseState; + QPoint mOldPos; + std::string mCurrentObj; + QElapsedTimer *mMouseEventTimer; + Ogre::Plane *mPlane; + Ogre::SceneNode *mObjSceneNode; + Ogre::Vector3 mOrigObjPos; + Ogre::Vector3 mOrigMousePos; std::map > mSelectedEntities; public: @@ -93,9 +109,11 @@ namespace CSVRender virtual void updateOverlay(); + virtual void mouseMoveEvent (QMouseEvent *event); + virtual void mousePressEvent (QMouseEvent *event); virtual void mouseReleaseEvent (QMouseEvent *event); - virtual void mouseDoubleClickEvent (QMouseEvent *event); + virtual void wheelEvent (QWheelEvent *event); private: @@ -107,6 +125,8 @@ namespace CSVRender virtual std::string getStartupInstruction() = 0; + std::pair isObjectUnderCursor(float mouseX, float mouseY); + std::pair mousePositionOnPlane(QMouseEvent *event, Ogre::Plane &plane); void debugMousePicking(float mouseX, float mouseY); void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); From 1741043f20a0916b27c9adc5eef3f6f39a6b3923 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 29 Oct 2014 23:02:38 +1100 Subject: [PATCH 27/56] Revert to storing Scene Node names as the key in RigidBody. Allow moving objects up/down using scroll wheel or touchpad while dragging. Cleanup code a little. --- apps/opencs/view/render/object.cpp | 4 +- .../view/render/pagedworldspacewidget.cpp | 21 +- .../view/render/pagedworldspacewidget.hpp | 2 + apps/opencs/view/render/worldspacewidget.cpp | 381 ++++++++++-------- apps/opencs/view/render/worldspacewidget.hpp | 18 +- apps/opencs/view/world/physicssystem.cpp | 19 +- apps/opencs/view/world/physicssystem.hpp | 8 +- 7 files changed, 252 insertions(+), 201 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 7dba068f81..474c79b353 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -33,8 +33,8 @@ void CSVRender::Object::clearSceneNode (Ogre::SceneNode *node) void CSVRender::Object::clear() { - if(!mObject.isNull() && !mReferenceId.empty()) - CSVWorld::PhysicsSystem::instance()->removeObject(mReferenceId); + if(!mObject.isNull()) + CSVWorld::PhysicsSystem::instance()->removeObject(mBase->getName()); mObject.setNull(); diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index e102801a2c..26f460446c 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -170,6 +170,23 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() return modified; } +void CSVRender::PagedWorldspaceWidget::mousePressEvent (QMouseEvent *event) +{ + if(event->button() == Qt::RightButton) + { + std::map::iterator iter = mTextOverlays.begin(); + for(; iter != mTextOverlays.end(); ++iter) + { + if(mDisplayCellCoord && + iter->second->isEnabled() && iter->second->container().contains(event->x(), event->y())) + { + return; + } + } + } + WorldspaceWidget::mouseReleaseEvent(event); +} + void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { if(event->button() == Qt::RightButton) @@ -181,7 +198,7 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) iter->second->isEnabled() && iter->second->container().contains(event->x(), event->y())) { std::cout << "clicked: " << iter->second->getCaption() << std::endl; - break; + return; } } } @@ -194,7 +211,7 @@ void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event { std::cout << "double clicked" << std::endl; } - //WorldspaceWidget::mouseDoubleClickEvent(event); + WorldspaceWidget::mouseDoubleClickEvent(event); } void CSVRender::PagedWorldspaceWidget::updateOverlay() diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index 17b6d10c53..fe79e761e5 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -81,6 +81,8 @@ namespace CSVRender virtual void updateOverlay(); + virtual void mousePressEvent (QMouseEvent *event); + virtual void mouseReleaseEvent (QMouseEvent *event); virtual void mouseDoubleClickEvent (QMouseEvent *event); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 65abe09c35..d11a9bb605 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -113,7 +113,9 @@ namespace CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) : SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), - mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) + mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0), + mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()), + mCurrentMousePos(Ogre::Vector3()), mZOffset(0.0f) { setAcceptDrops(true); @@ -461,10 +463,11 @@ void CSVRender::WorldspaceWidget::updateOverlay() // State machine: // // [default] mousePressEvent->check if the mouse is pointing at an object -// if yes, go to [grab] else stay at [default] +// if yes, create collision planes then go to [grab] +// else check for terrain // -// [grab] mouseReleaseEvent->if same button and new obj, go to [edit] -// mouseMoveEvent->if same button, create collision planes then go to [drag] +// [grab] mouseReleaseEvent->if same button and new obj, go to [edit] +// mouseMoveEvent->if same button, go to [drag] // other mouse events or buttons, go back to [default] (i.e. like 'cancel') // // [drag] mouseReleaseEvent->if same button, place the object at the new @@ -499,34 +502,29 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) // check if min elapsed time to stop false detection of drag if(!mMouseEventTimer->isValid() || !mMouseEventTimer->hasExpired(100)) // ms break; - else - { - mMouseEventTimer->invalidate(); - mMouseState = Mouse_Drag; - //std::cout << "grab->drag" << std::endl; - } + mMouseEventTimer->invalidate(); + mMouseState = Mouse_Drag; /* FALL_THROUGH */ } case Mouse_Drag: { - // FIXME: don't update less than a quantum - //QPoint diff = mOldPos-event->pos(); - if(event->pos() != mOldPos) + if(event->pos() != mOldPos) // TODO: maybe don't update less than a quantum? { mOldPos = event->pos(); - //std::cout << QString::number(event->pos().x()).toStdString() << ", " - //<< QString::number(event->pos().y()).toStdString() << std::endl; // ray test against the plane to provide feedback to the user the // relative movement of the object on the x-y plane - std::pair planeResult = mousePositionOnPlane(event, *mPlane); + std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); if(planeResult.first) { - if(mObjSceneNode) + if(mGrabbedSceneNode != "") { - mObjSceneNode->setPosition(mOrigObjPos+planeResult.second-mOrigMousePos); + Ogre::Vector3 pos = mOrigObjPos; + pos.z += mZOffset; + getSceneManager()->getSceneNode(mGrabbedSceneNode)->setPosition(pos+planeResult.second-mOrigMousePos); + mCurrentMousePos = planeResult.second; flagAsModified(); } } @@ -546,52 +544,59 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { - if(event->buttons() & Qt::RightButton) + switch(mMouseState) { - switch(mMouseState) + case Mouse_Grab: + case Mouse_Drag: { - case Mouse_Grab: - case Mouse_Drag: + if(event->buttons() & ~Qt::RightButton) { - break; // error event, ignore + // cancel operation & return the object to the original position + placeObject(mGrabbedSceneNode, mOrigObjPos); + mMouseState = Mouse_Default; + + // reset states + mCurrentMousePos = Ogre::Vector3(); + mOrigMousePos = Ogre::Vector3(); + mOrigObjPos = Ogre::Vector3(); + mGrabbedSceneNode = ""; + mCurrentObj = ""; + mOldPos = QPoint(0, 0); + mMouseEventTimer->invalidate(); + mZOffset = 0.0f; } - case Mouse_Edit: - case Mouse_Default: + break; + } + case Mouse_Edit: + case Mouse_Default: + { + if(event->buttons() & Qt::RightButton) { - if(!getCamera()->getViewport()) + std::pair result = objectUnderCursor(event->x(), event->y()); + if(result.first == "") break; - std::pair result = isObjectUnderCursor( - (float) event->x() / getCamera()->getViewport()->getActualWidth(), - (float) event->y() / getCamera()->getViewport()->getActualHeight()); - if(result.first != "") + mGrabbedSceneNode = result.first; + // ray test agaist the plane to get a starting position of the + // mouse in relation to the object position + mPlane->redefine(Ogre::Vector3::UNIT_Z, result.second); + std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); + if(planeResult.first) { - mCurrentObj = result.first; // FIXME - // ray test agaist the plane to get a starting position of the - // mouse in relation to the object position - mPlane->redefine(Ogre::Vector3::UNIT_Z, result.second); - std::pair planeResult = mousePositionOnPlane(event, *mPlane); - if(planeResult.first) - mOrigMousePos = planeResult.second; - - std::string sceneNodeName = - CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); - mObjSceneNode = getSceneManager()->getSceneNode(sceneNodeName); - mOrigObjPos = mObjSceneNode->getPosition(); - - - mMouseEventTimer->start(); - - mMouseState = Mouse_Grab; - //std::cout << "default/edit->grab" << std::endl; + mOrigMousePos = planeResult.second; + mCurrentMousePos = planeResult.second; + mZOffset = 0.0f; } - break; + + mOrigObjPos = getSceneManager()->getSceneNode(mGrabbedSceneNode)->getPosition(); + mMouseEventTimer->start(); + + mMouseState = Mouse_Grab; } - /* NO_DEFAULT_CASE */ + break; } + /* NO_DEFAULT_CASE */ } - // FIXME: other button press - cancel grab and/or drag and place the object back in the original - // position //SceneWidget::mousePressEvent(event); } @@ -605,110 +610,98 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) return; } - // FIXME: skip this if overlay clicked above - // FIXME: stop/disable the timer switch(mMouseState) { case Mouse_Grab: { - std::pair result = isObjectUnderCursor( - (float) event->x() / getCamera()->getViewport()->getActualWidth(), - (float) event->y() / getCamera()->getViewport()->getActualHeight()); + std::pair result = objectUnderCursor(event->x(), event->y()); if(result.first != "") { if(result.first == mCurrentObj) { + // unselect object mMouseState = Mouse_Default; - //std::cout << "grab->default" << std::endl; mCurrentObj = ""; } else { + // select object mMouseState = Mouse_Edit; - //std::cout << "grab->edit" << std::endl; mCurrentObj = result.first; - // print some debug info - std::cout << "ReferenceId: " << result.first << std::endl; - const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); - int index = references.searchId(result.first); - if (index != -1) + if(isDebug()) { - int columnIndex = - references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); - std::cout << " index: " + QString::number(index).toStdString() - +", column index: " + QString::number(columnIndex).toStdString() - << std::endl; + std::string referenceId = + CSVWorld::PhysicsSystem::instance()->sceneNodeToRefId(result.first); + std::cout << "ReferenceId: " << referenceId << std::endl; + const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); + int index = references.searchId(referenceId); + if (index != -1) + { + int columnIndex = + references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); + std::cout << " index: " + QString::number(index).toStdString() + +", column index: " + QString::number(columnIndex).toStdString() + << std::endl; + } } } // update highlighting the current object - std::string sceneNode = - CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); - - uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - - if(!ignoreObjects && getSceneManager()->hasSceneNode(sceneNode)) - { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - if(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false) - updateSelectionHighlight(sceneNode, result.second); - } - flagAsModified(); + if(isDebug()) + updateSelectionHighlight(result.first, result.second); } break; } case Mouse_Drag: { // final placement - std::pair planeResult = mousePositionOnPlane(event, *mPlane); + std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); if(planeResult.first) { - if(mObjSceneNode) + if(mGrabbedSceneNode != "") { - mObjSceneNode->setPosition(mOrigObjPos+planeResult.second-mOrigMousePos); - flagAsModified(); + mOrigObjPos.z += mZOffset; + Ogre::Vector3 pos = mOrigObjPos+planeResult.second-mOrigMousePos; + placeObject(mGrabbedSceneNode, pos); + //mCurrentObj = mGrabbedSceneNode; // FIXME + mCurrentObj = ""; - // update physics - const CSMWorld::CellRef& cellref = - mDocument.getData().getReferences().getRecord (mCurrentObj).get(); - Ogre::Quaternion xr (Ogre::Radian (-cellref.mPos.rot[0]), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yr (Ogre::Radian (-cellref.mPos.rot[1]), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zr (Ogre::Radian (-cellref.mPos.rot[2]), Ogre::Vector3::UNIT_Z); + // reset states + mCurrentMousePos = Ogre::Vector3(); + mOrigMousePos = Ogre::Vector3(); + mOrigObjPos = Ogre::Vector3(); + mGrabbedSceneNode = ""; + mOldPos = QPoint(0, 0); + mZOffset = 0.0f; - // FIXME: adjustRigidBody() seems to lose objects, delete and recreate for now - //CSVWorld::PhysicsSystem::instance()->moveObject(mCurrentObj, - //mOrigObjPos+planeResult.second-mOrigMousePos, xr*yr*zr); - std::string sceneNodeName = - CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(mCurrentObj); - std::string mesh = - CSVWorld::PhysicsSystem::instance()->sceneNodeToMesh(sceneNodeName); - CSVWorld::PhysicsSystem::instance()->removeObject(mCurrentObj); - CSVWorld::PhysicsSystem::instance()->addObject(mesh, - sceneNodeName, mCurrentObj, cellref.mScale, - mOrigObjPos+planeResult.second-mOrigMousePos, xr*yr*zr); + // FIXME: update document + // FIXME: highlight current object? + mMouseState = Mouse_Edit; } } - // FIXME: update document - // FIXME: highlight current object? - //std::cout << "final position" << std::endl; - - mMouseState = Mouse_Edit; - //std::cout << "drag->edit" << std::endl; break; } case Mouse_Edit: case Mouse_Default: { - // probably terrain - debugMousePicking( - (float) event->x() / getCamera()->getViewport()->getActualWidth(), - (float) event->y() / getCamera()->getViewport()->getActualHeight()); + // probably terrain, check + std::pair result = terrainUnderCursor(event->x(), event->y()); + if(result.first != "") + { + if(isDebug()) + { + std::cout << "terrain: " << 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; } /* NO_DEFAULT_CASE */ } + mMouseEventTimer->invalidate(); } SceneWidget::mouseReleaseEvent(event); } @@ -717,8 +710,7 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) { if(event->button() == Qt::RightButton) { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - if(userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false) + if(isDebug()) { // FIXME: OEngine::PhysicEngine creates only one child scene node for the // debug drawer. Hence only the first subview that creates the debug drawer @@ -734,68 +726,46 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) { - // FIXME: add wheel event to move the object along the y axis during Mouse_Drag or - // Mouse_Grab - SceneWidget::wheelEvent(event); -} - -void CSVRender::WorldspaceWidget::debugMousePicking(float mouseX, float mouseY) -{ - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debug = userSettings.setting ("debug/mouse-picking", QString("false")) == "true" ? true : false; - - std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( - mouseX, mouseY, NULL, NULL, getCamera()); - if(debug && result.first != "") + switch(mMouseState) { - // FIXME: is there a better way to distinguish terrain from objects? - QString name = QString(result.first.c_str()); - if(name.contains(QRegExp("^HeightField"))) + case Mouse_Grab: + mMouseState = Mouse_Drag; + + /* FALL_THROUGH */ + case Mouse_Drag: { - // terrain - std::cout << "terrain: " << 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; + // move the object along the z axis during Mouse_Drag or Mouse_Grab + if (event->delta()) + { + // seems positive is up and negative is down + mZOffset += (event->delta()/5); // FIXME: arbitrary number, make config option? + + Ogre::Vector3 pos = mOrigObjPos; + pos.z += mZOffset; + getSceneManager()->getSceneNode(mGrabbedSceneNode)->setPosition(pos+mCurrentMousePos-mOrigMousePos); + flagAsModified(); + } + break; } - else + case Mouse_Edit: + case Mouse_Default: { - std::string sceneNode = - CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); - - uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - - if(!ignoreObjects && getSceneManager()->hasSceneNode(sceneNode)) - { - if(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false) - updateSelectionHighlight(sceneNode, result.second); - } - - std::cout << "ReferenceId: " << result.first << std::endl; - const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (result.first).get(); - //std::cout << "CellRef.mId: " << cellref.mId << std::endl; // Same as ReferenceId - std::cout << " CellRef.mCell: " << cellref.mCell << std::endl; - - const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); - int index = references.searchId(result.first); - if (index != -1) - { - int columnIndex = - references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); - - std::cout << " index: " + QString::number(index).toStdString() - +", column index: " + QString::number(columnIndex).toStdString() << std::endl; - } - flagAsModified(); + SceneWidget::wheelEvent(event); + break; } + /* NO_DEFAULT_CASE */ } } // FIXME: for debugging only -void CSVRender::WorldspaceWidget::updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position) +void CSVRender::WorldspaceWidget::updateSelectionHighlight(const std::string sceneNode, const Ogre::Vector3 &position) { + uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); + bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); + + if(ignoreObjects || !getSceneManager()->hasSceneNode(sceneNode) || !isDebug()) + return; + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); bool debugCursor = userSettings.setting( "debug/mouse-position", QString("false")) == "true" ? true : false; @@ -858,41 +828,69 @@ void CSVRender::WorldspaceWidget::updateSelectionHighlight(std::string sceneNode if(debugCursor) showHitPoint(getSceneManager(), sceneNode, position); } + flagAsModified(); } -std::pair CSVRender::WorldspaceWidget::isObjectUnderCursor(float mouseX, float mouseY) +std::pair CSVRender::WorldspaceWidget::terrainUnderCursor(const int mouseX, const int mouseY) { - std::pair result = CSVWorld::PhysicsSystem::instance()->castRay( - mouseX, mouseY, NULL, NULL, getCamera()); + if(!getCamera()->getViewport()) + return std::make_pair("", Ogre::Vector3()); + + float x = (float) mouseX / getCamera()->getViewport()->getActualWidth(); + float y = (float) mouseY / getCamera()->getViewport()->getActualHeight(); + + std::pair result = + CSVWorld::PhysicsSystem::instance()->castRay(x, y, NULL, NULL, getCamera()); 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()); +} + +std::pair CSVRender::WorldspaceWidget::objectUnderCursor(const int mouseX, const int mouseY) +{ + if(!getCamera()->getViewport()) + return std::make_pair("", Ogre::Vector3()); + + float x = (float) mouseX / getCamera()->getViewport()->getActualWidth(); + float y = (float) mouseY / getCamera()->getViewport()->getActualHeight(); + + std::pair result = + CSVWorld::PhysicsSystem::instance()->castRay(x, y, NULL, NULL, getCamera()); + if(result.first != "") + { + // NOTE: anything not terrain is assumed to be an object QString name = QString(result.first.c_str()); if(!name.contains(QRegExp("^HeightField"))) { - std::string sceneNode = - CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); - uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - if(!ignoreObjects && getSceneManager()->hasSceneNode(sceneNode)) + if(!ignoreObjects && getSceneManager()->hasSceneNode(result.first)) { return result; } } } - return std::make_pair("", Ogre::Vector3(0,0,0)); + return std::make_pair("", Ogre::Vector3()); } -std::pair CSVRender::WorldspaceWidget::mousePositionOnPlane(QMouseEvent *event, Ogre::Plane &plane) +std::pair CSVRender::WorldspaceWidget::mousePositionOnPlane(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 getCamera()->setNearClipDistance(10.0f); // arbitrary number Ogre::Ray mouseRay = getCamera()->getCameraToViewportRay( - (float) event->x() / getCamera()->getViewport()->getActualWidth(), - (float) event->y() / getCamera()->getViewport()->getActualHeight()); + (float) pos.x() / getCamera()->getViewport()->getActualWidth(), + (float) pos.y() / getCamera()->getViewport()->getActualHeight()); getCamera()->setNearClipDistance(nearClipDistance); // restore std::pair planeResult = mouseRay.intersects(plane); @@ -901,3 +899,30 @@ std::pair CSVRender::WorldspaceWidget::mousePositionOnPlane else return std::make_pair(false, Ogre::Vector3()); // should only happen if the plane is too small } + +void CSVRender::WorldspaceWidget::placeObject(const std::string sceneNode, const Ogre::Vector3 &pos) +{ + getSceneManager()->getSceneNode(sceneNode)->setPosition(pos); + flagAsModified(); + + // update physics + std::string refId = CSVWorld::PhysicsSystem::instance()->sceneNodeToRefId(sceneNode); + const CSMWorld::CellRef& cellref = + mDocument.getData().getReferences().getRecord (refId).get(); + Ogre::Quaternion xr (Ogre::Radian (-cellref.mPos.rot[0]), Ogre::Vector3::UNIT_X); + Ogre::Quaternion yr (Ogre::Radian (-cellref.mPos.rot[1]), Ogre::Vector3::UNIT_Y); + Ogre::Quaternion zr (Ogre::Radian (-cellref.mPos.rot[2]), Ogre::Vector3::UNIT_Z); + + // FIXME: adjustRigidBody() seems to lose objects, work around by deleting and recreating objects + //CSVWorld::PhysicsSystem::instance()->moveObject(sceneNode, pos, xr*yr*zr); + std::string mesh = CSVWorld::PhysicsSystem::instance()->sceneNodeToMesh(sceneNode); + CSVWorld::PhysicsSystem::instance()->removeObject(sceneNode); + CSVWorld::PhysicsSystem::instance()->addObject(mesh, sceneNode, refId, cellref.mScale, pos, xr*yr*zr); +} + +bool CSVRender::WorldspaceWidget::isDebug() +{ + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + + return userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false; +} diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 756debfe59..48f5e98d43 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -36,20 +36,24 @@ namespace CSVRender CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; - enum MouseState { + enum MouseState + { Mouse_Grab, Mouse_Drag, Mouse_Edit, Mouse_Default }; MouseState mMouseState; + QPoint mOldPos; std::string mCurrentObj; + std::string mGrabbedSceneNode; QElapsedTimer *mMouseEventTimer; Ogre::Plane *mPlane; - Ogre::SceneNode *mObjSceneNode; Ogre::Vector3 mOrigObjPos; Ogre::Vector3 mOrigMousePos; + Ogre::Vector3 mCurrentMousePos; + float mZOffset; std::map > mSelectedEntities; public: @@ -125,10 +129,12 @@ namespace CSVRender virtual std::string getStartupInstruction() = 0; - std::pair isObjectUnderCursor(float mouseX, float mouseY); - std::pair mousePositionOnPlane(QMouseEvent *event, Ogre::Plane &plane); - void debugMousePicking(float mouseX, float mouseY); - void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); + void placeObject(const std::string sceneNode, const Ogre::Vector3 &pos); + bool isDebug(); + std::pair terrainUnderCursor(const int mouseX, const int mouseY); + std::pair objectUnderCursor(const int mouseX, const int mouseY); + std::pair mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane); + void updateSelectionHighlight(const std::string sceneNode, const Ogre::Vector3 &position); private slots: diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index a422147a93..0e3790d931 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -40,27 +40,28 @@ namespace CSVWorld const std::string &sceneNodeName, const std::string &referenceId, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) { - mRefToSceneNode[referenceId] = sceneNodeName; + // NOTE: referenceId may not be unique when editing multiple documents concurrently + mSceneNodeToRefId[sceneNodeName] = referenceId; mSceneNodeToMesh[sceneNodeName] = mesh; mEngine->createAndAdjustRigidBody(mesh, - referenceId, scale, position, rotation, + sceneNodeName, scale, position, rotation, 0, // scaledBoxTranslation 0, // boxRotation true, // raycasting placeable); } - void PhysicsSystem::removeObject(const std::string &referenceId) + void PhysicsSystem::removeObject(const std::string &sceneNodeName) { - mEngine->removeRigidBody(referenceId); - mEngine->deleteRigidBody(referenceId); + mEngine->removeRigidBody(sceneNodeName); + mEngine->deleteRigidBody(sceneNodeName); } - void PhysicsSystem::moveObject(const std::string &referenceId, + void PhysicsSystem::moveObject(const std::string &sceneNodeName, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) { - mEngine->adjustRigidBody(mEngine->getRigidBody(referenceId, true /*raycasting*/), + mEngine->adjustRigidBody(mEngine->getRigidBody(sceneNodeName, true /*raycasting*/), position, rotation); } @@ -111,9 +112,9 @@ namespace CSVWorld return std::make_pair(result.first, ray.getPoint(farClipDist*result.second)); } - std::string PhysicsSystem::referenceToSceneNode(std::string referenceId) + std::string PhysicsSystem::sceneNodeToRefId(std::string sceneNodeName) { - return mRefToSceneNode[referenceId]; + return mSceneNodeToRefId[sceneNodeName]; } std::string PhysicsSystem::sceneNodeToMesh(std::string sceneNodeName) diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 983f1a2a76..5cf568784c 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -26,7 +26,7 @@ namespace CSVWorld class PhysicsSystem { static PhysicsSystem *mPhysicsSystemInstance; - std::map mRefToSceneNode; + std::map mSceneNodeToRefId; std::map mSceneNodeToMesh; OEngine::Physic::PhysicEngine* mEngine; @@ -46,9 +46,9 @@ namespace CSVWorld const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable=false); - void removeObject(const std::string &referenceId); + void removeObject(const std::string &sceneNodeName); - void moveObject(const std::string &referenceId, + void moveObject(const std::string &sceneNodeName, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); void addHeightField(float* heights, @@ -61,7 +61,7 @@ namespace CSVWorld std::pair castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera); - std::string referenceToSceneNode(std::string referenceId); + std::string sceneNodeToRefId(std::string sceneNodeName); std::string sceneNodeToMesh(std::string sceneNodeName); private: From 0515159b742a36df0d6496c26acbd8602a7b9d06 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 29 Oct 2014 23:38:19 +1100 Subject: [PATCH 28/56] Fix typo. --- apps/opencs/view/render/pagedworldspacewidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 26f460446c..cce627ded9 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -184,7 +184,7 @@ void CSVRender::PagedWorldspaceWidget::mousePressEvent (QMouseEvent *event) } } } - WorldspaceWidget::mouseReleaseEvent(event); + WorldspaceWidget::mousePressEvent(event); } void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) From a2ac4c765040191d7815fc9a59fbb70cf58dcf8a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 31 Oct 2014 08:18:15 +1100 Subject: [PATCH 29/56] Allow multiple scene managers per physics engine. Compiles but does not work properly. --- apps/opencs/view/render/scenewidget.cpp | 2 +- apps/opencs/view/render/worldspacewidget.cpp | 8 +-- apps/opencs/view/world/physicssystem.cpp | 71 ++++++++++++++------ apps/opencs/view/world/physicssystem.hpp | 14 ++-- 4 files changed, 66 insertions(+), 29 deletions(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index c5712c7e88..ee6630eac6 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -66,7 +66,7 @@ namespace CSVRender mOverlaySystem = OverlaySystem::instance().get(); mSceneMgr->addRenderQueueListener(mOverlaySystem); - CSVWorld::PhysicsSystem::instance()->setSceneManager(mSceneMgr); + CSVWorld::PhysicsSystem::instance()->addSceneManager(mSceneMgr); QTimer *timer = new QTimer (this); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index d11a9bb605..655a2e0268 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -716,8 +716,8 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) // debug drawer. Hence only the first subview that creates the debug drawer // can view the debug lines. Will need to keep a map in OEngine if multiple // subviews are to be supported. - CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); - CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(); + //CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); + CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(getSceneManager()); flagAsModified(); } } @@ -840,7 +840,7 @@ std::pair CSVRender::WorldspaceWidget::terrainUnderC float y = (float) mouseY / getCamera()->getViewport()->getActualHeight(); std::pair result = - CSVWorld::PhysicsSystem::instance()->castRay(x, y, NULL, NULL, getCamera()); + CSVWorld::PhysicsSystem::instance()->castRay(x, y, getSceneManager(), getCamera()); if(result.first != "") { // FIXME: is there a better way to distinguish terrain from objects? @@ -863,7 +863,7 @@ std::pair CSVRender::WorldspaceWidget::objectUnderCu float y = (float) mouseY / getCamera()->getViewport()->getActualHeight(); std::pair result = - CSVWorld::PhysicsSystem::instance()->castRay(x, y, NULL, NULL, getCamera()); + CSVWorld::PhysicsSystem::instance()->castRay(x, y, getSceneManager(), getCamera()); if(result.first != "") { // NOTE: anything not terrain is assumed to be an object diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 0e3790d931..02775801c8 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -15,7 +15,7 @@ namespace CSVWorld { PhysicsSystem *PhysicsSystem::mPhysicsSystemInstance = 0; - PhysicsSystem::PhysicsSystem(Ogre::SceneManager *sceneMgr) : mSceneMgr(sceneMgr) + PhysicsSystem::PhysicsSystem() : mSceneMgr(0) { assert(!mPhysicsSystemInstance); mPhysicsSystemInstance = this; @@ -36,20 +36,37 @@ namespace CSVWorld return mPhysicsSystemInstance; } + // FIXME: looks up the scene manager based on the scene node name (highly inefficient) + // NOTE: referenceId is assumed to be unique per document + // NOTE: searching is done here rather than after rayTest, so slower to load but + // faster to find (not verified w/ perf test) void PhysicsSystem::addObject(const std::string &mesh, const std::string &sceneNodeName, const std::string &referenceId, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) { - // NOTE: referenceId may not be unique when editing multiple documents concurrently - mSceneNodeToRefId[sceneNodeName] = referenceId; - mSceneNodeToMesh[sceneNodeName] = mesh; + bool foundSceneManager = false; + std::list::const_iterator iter = mSceneManagers.begin(); + for(; iter != mSceneManagers.end(); ++iter) + { + if((*iter)->hasSceneNode(sceneNodeName)) + { + mSceneNodeToRefId[sceneNodeName] = referenceId; + mRefIdToSceneNode[referenceId][*iter] = sceneNodeName; + mSceneNodeToMesh[sceneNodeName] = mesh; + foundSceneManager = true; + break; + } + } - mEngine->createAndAdjustRigidBody(mesh, - sceneNodeName, scale, position, rotation, - 0, // scaledBoxTranslation - 0, // boxRotation - true, // raycasting - placeable); + if(foundSceneManager) + { + mEngine->createAndAdjustRigidBody(mesh, + referenceId, scale, position, rotation, + 0, // scaledBoxTranslation + 0, // boxRotation + true, // raycasting + placeable); + } } void PhysicsSystem::removeObject(const std::string &sceneNodeName) @@ -76,13 +93,21 @@ namespace CSVWorld mEngine->removeHeightField(x, y); } + // sceneMgr: to lookup the scene node name from the object's referenceId + // camera: primarily used to get the visibility mask for the viewport + // + // returns the found object's scene node name and its position in the world space + // + // WARNING: far clip distance is a global setting, if it changes in future + // this method will need to be updated std::pair PhysicsSystem::castRay(float mouseX, - float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) + float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera) { - if(!mSceneMgr || !camera || !camera->getViewport()) + // NOTE: there could be more than one camera for the scene manager + // TODO: check whether camera belongs to sceneMgr + if(!sceneMgr || !camera || !camera->getViewport()) return std::make_pair("", Ogre::Vector3(0,0,0)); // FIXME: this should be an exception - // using a really small value seems to mess up with the projections float nearClipDistance = camera->getNearClipDistance(); // save existing camera->setNearClipDistance(10.0f); // arbitrary number @@ -102,14 +127,20 @@ namespace CSVWorld bool ignoreHeightMap = !(visibilityMask & (uint32_t)CSVRender::Element_Terrain); bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - Ogre::Vector3 norm; + Ogre::Vector3 norm; // not used std::pair result = mEngine->rayTest(_from, _to, !ignoreObjects, ignoreHeightMap, &norm); + // result.first is the object's referenceId if(result.first == "") return std::make_pair("", Ogre::Vector3(0,0,0)); else - return std::make_pair(result.first, ray.getPoint(farClipDist*result.second)); + return std::make_pair(refIdToSceneNode(result.first, sceneMgr), ray.getPoint(farClipDist*result.second)); + } + + std::string PhysicsSystem::refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr) + { + return mRefIdToSceneNode[referenceId][sceneMgr]; } std::string PhysicsSystem::sceneNodeToRefId(std::string sceneNodeName) @@ -122,17 +153,19 @@ namespace CSVWorld return mSceneNodeToMesh[sceneNodeName]; } - void PhysicsSystem::setSceneManager(Ogre::SceneManager *sceneMgr) + void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr) { - mSceneMgr = sceneMgr; - mEngine->setSceneManager(sceneMgr); // needed for toggleDebugRendering() + mSceneManagers.push_back(sceneMgr); } - void PhysicsSystem::toggleDebugRendering() + void PhysicsSystem::toggleDebugRendering(Ogre::SceneManager *sceneMgr) { + // FIXME: should check if sceneMgr is in the list if(!mSceneMgr) return; // FIXME: maybe this should be an exception + mEngine->setSceneManager(sceneMgr); + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); if(!(userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false)) { diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 5cf568784c..616bd13e6b 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -3,7 +3,7 @@ #include #include -#include +#include namespace Ogre { @@ -27,19 +27,21 @@ namespace CSVWorld { static PhysicsSystem *mPhysicsSystemInstance; std::map mSceneNodeToRefId; + std::map > mRefIdToSceneNode; std::map mSceneNodeToMesh; + std::list mSceneManagers; // FIXME: change to list per OEngine OEngine::Physic::PhysicEngine* mEngine; Ogre::SceneManager *mSceneMgr; public: - PhysicsSystem(Ogre::SceneManager *sceneMgr = NULL); + PhysicsSystem(); ~PhysicsSystem(); static PhysicsSystem *instance(); - void setSceneManager(Ogre::SceneManager *sceneMgr); + void addSceneManager(Ogre::SceneManager *sceneMgr); void addObject(const std::string &mesh, const std::string &sceneNodeName, const std::string &referenceId, float scale, @@ -56,10 +58,11 @@ namespace CSVWorld void removeHeightField(int x, int y); - void toggleDebugRendering(); + void toggleDebugRendering(Ogre::SceneManager *sceneMgr); + // return the object's SceneNode name and position for the given SceneManager std::pair castRay(float mouseX, - float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera); + float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera); std::string sceneNodeToRefId(std::string sceneNodeName); std::string sceneNodeToMesh(std::string sceneNodeName); @@ -67,6 +70,7 @@ namespace CSVWorld private: void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); + std::string refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr); }; } From fbadaf55eee36f0be5efb5728defde27065aeaaa Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 31 Oct 2014 21:50:57 +1100 Subject: [PATCH 30/56] Multiple SceneManagers per physics engine now working. --- apps/opencs/view/doc/subview.cpp | 5 +- apps/opencs/view/doc/subview.hpp | 4 ++ apps/opencs/view/doc/view.cpp | 12 ++++ apps/opencs/view/doc/view.hpp | 2 + apps/opencs/view/render/scenewidget.cpp | 8 ++- apps/opencs/view/render/scenewidget.hpp | 2 + apps/opencs/view/render/worldspacewidget.cpp | 19 ++--- apps/opencs/view/render/worldspacewidget.hpp | 3 + apps/opencs/view/world/physicssystem.cpp | 76 +++++++++++++++++--- apps/opencs/view/world/physicssystem.hpp | 13 +++- apps/opencs/view/world/scenesubview.cpp | 16 +++-- apps/opencs/view/world/scenesubview.hpp | 2 + 12 files changed, 136 insertions(+), 26 deletions(-) diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index a9dce25bec..bce14a642d 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -42,4 +42,7 @@ std::string CSVDoc::SubView::getTitle() const void CSVDoc::SubView::closeRequest() { emit closeRequest (this); -} \ No newline at end of file +} + +void CSVDoc::SubView::updateScene() +{} diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index a8aa3cda1e..9acb7a5ae7 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -52,6 +52,8 @@ namespace CSVDoc virtual void updateUserSetting (const QString& name, const QStringList& value); + virtual void updateScene(); + private: void closeEvent (QCloseEvent *event); @@ -66,6 +68,8 @@ namespace CSVDoc void updateSubViewIndicies (SubView *view = 0); + void refreshSubViews(); + protected slots: void closeRequest(); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 8a6665cf26..932dab3aa3 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -16,6 +16,7 @@ #include "../../model/world/idtable.hpp" #include "../world/subviews.hpp" +#include "../doc/subview.hpp" #include "../tools/subviews.hpp" @@ -300,6 +301,15 @@ void CSVDoc::View::setupUi() setupDebugMenu(); } +void CSVDoc::View::refreshSubViews() +{ + QList::iterator iter = mSubViews.begin(); + for(; iter != mSubViews.end(); ++iter) + { + (*iter)->updateScene(); + } +} + void CSVDoc::View::updateTitle() { std::ostringstream stream; @@ -527,6 +537,8 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin connect (view, SIGNAL (updateSubViewIndicies (SubView *)), this, SLOT (updateSubViewIndicies (SubView *))); + connect (view, SIGNAL (refreshSubViews()), this, SLOT (refreshSubViews())); + view->show(); } diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 55ea5ee515..c6bb206d6f 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -139,6 +139,8 @@ namespace CSVDoc // called when subviews are added or removed void updateSubViewIndicies (SubView *view = 0); + void refreshSubViews(); + private slots: void newView(); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index ee6630eac6..40bca30b15 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -66,7 +66,7 @@ namespace CSVRender mOverlaySystem = OverlaySystem::instance().get(); mSceneMgr->addRenderQueueListener(mOverlaySystem); - CSVWorld::PhysicsSystem::instance()->addSceneManager(mSceneMgr); + CSVWorld::PhysicsSystem::instance()->addSceneManager(mSceneMgr, this); QTimer *timer = new QTimer (this); @@ -414,6 +414,12 @@ namespace CSVRender } } + void SceneWidget::updateScene() + { + flagAsModified(); + update(); + } + void SceneWidget::updateOverlay() { } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 5f023a7ad5..a3b8cd4b05 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -47,6 +47,8 @@ namespace CSVRender virtual void setVisibilityMask (unsigned int mask); + virtual void updateScene(); + protected: void setNavigation (Navigation *navigation); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 655a2e0268..a94ad9dfd0 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -665,15 +665,16 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) Ogre::Vector3 pos = mOrigObjPos+planeResult.second-mOrigMousePos; placeObject(mGrabbedSceneNode, pos); //mCurrentObj = mGrabbedSceneNode; // FIXME - mCurrentObj = ""; + mCurrentObj = ""; // whether the object is selected // reset states - mCurrentMousePos = Ogre::Vector3(); - mOrigMousePos = Ogre::Vector3(); - mOrigObjPos = Ogre::Vector3(); - mGrabbedSceneNode = ""; - mOldPos = QPoint(0, 0); - mZOffset = 0.0f; + 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 + mZOffset = 0.0f; // used for z-axis movement + mOldPos = QPoint(0, 0); // to calculate relative movement of mouse + // on screen // FIXME: update document // FIXME: highlight current object? @@ -903,7 +904,6 @@ std::pair CSVRender::WorldspaceWidget::mousePositionOnPlane void CSVRender::WorldspaceWidget::placeObject(const std::string sceneNode, const Ogre::Vector3 &pos) { getSceneManager()->getSceneNode(sceneNode)->setPosition(pos); - flagAsModified(); // update physics std::string refId = CSVWorld::PhysicsSystem::instance()->sceneNodeToRefId(sceneNode); @@ -918,6 +918,9 @@ void CSVRender::WorldspaceWidget::placeObject(const std::string sceneNode, const std::string mesh = CSVWorld::PhysicsSystem::instance()->sceneNodeToMesh(sceneNode); CSVWorld::PhysicsSystem::instance()->removeObject(sceneNode); CSVWorld::PhysicsSystem::instance()->addObject(mesh, sceneNode, refId, cellref.mScale, pos, xr*yr*zr); + + // update all SceneWidgets and their SceneManagers + emit signalAsModified(); } bool CSVRender::WorldspaceWidget::isDebug() diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 48f5e98d43..e69fbe08eb 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -168,7 +168,10 @@ namespace CSVRender signals: void closeRequest(); + void dataDropped(const std::vector& data); + + void signalAsModified(); }; } diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 02775801c8..bcf9aeff29 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -15,7 +15,7 @@ namespace CSVWorld { PhysicsSystem *PhysicsSystem::mPhysicsSystemInstance = 0; - PhysicsSystem::PhysicsSystem() : mSceneMgr(0) + PhysicsSystem::PhysicsSystem() { assert(!mPhysicsSystemInstance); mPhysicsSystemInstance = this; @@ -28,6 +28,7 @@ namespace CSVWorld PhysicsSystem::~PhysicsSystem() { delete mEngine; + // FIXME: update maps when SceneManagers are destroyed } PhysicsSystem *PhysicsSystem::instance() @@ -39,7 +40,7 @@ namespace CSVWorld // FIXME: looks up the scene manager based on the scene node name (highly inefficient) // NOTE: referenceId is assumed to be unique per document // NOTE: searching is done here rather than after rayTest, so slower to load but - // faster to find (not verified w/ perf test) + // faster to find (not verified w/ perf test) void PhysicsSystem::addObject(const std::string &mesh, const std::string &sceneNodeName, const std::string &referenceId, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) @@ -58,21 +59,67 @@ namespace CSVWorld } } - if(foundSceneManager) + if(!foundSceneManager) + return; // FIXME: this should be an exception + + // update physics, only one physics model per referenceId + if(mEngine->getRigidBody(referenceId, true) == NULL) { + mEngine->createAndAdjustRigidBody(mesh, referenceId, scale, position, rotation, 0, // scaledBoxTranslation 0, // boxRotation true, // raycasting placeable); + + // update other scene managers if they have the referenceId (may have moved) + iter = mSceneManagers.begin(); + for(; iter != mSceneManagers.end(); ++iter) + { + std::string name = refIdToSceneNode(referenceId, *iter); + if(name != sceneNodeName && (*iter)->hasSceneNode(name)) + { + // FIXME: rotation or scale not updated + (*iter)->getSceneNode(name)->setPosition(position); + } + } } } void PhysicsSystem::removeObject(const std::string &sceneNodeName) { - mEngine->removeRigidBody(sceneNodeName); - mEngine->deleteRigidBody(sceneNodeName); + std::string referenceId = sceneNodeToRefId(sceneNodeName); + if(referenceId != "") + { + mEngine->removeRigidBody(referenceId); + mEngine->deleteRigidBody(referenceId); + + Ogre::SceneManager *sceneManager = NULL; + std::list::const_iterator iter = mSceneManagers.begin(); + for(; iter != mSceneManagers.end(); ++iter) + { + if((*iter)->hasSceneNode(sceneNodeName)) + { + sceneManager = *iter; + break; + } + } + + if(!sceneManager) + return; // FIXME: maybe this should be an exception + + std::map >::iterator itRef = + mRefIdToSceneNode.begin(); + for(; itRef != mRefIdToSceneNode.end(); ++itRef) + { + if((*itRef).second.find(sceneManager) != (*itRef).second.end()) + { + (*itRef).second.erase(sceneManager); + return; + } + } + } } void PhysicsSystem::moveObject(const std::string &sceneNodeName, @@ -135,7 +182,15 @@ namespace CSVWorld if(result.first == "") return std::make_pair("", Ogre::Vector3(0,0,0)); else - return std::make_pair(refIdToSceneNode(result.first, sceneMgr), ray.getPoint(farClipDist*result.second)); + { + std::string name = refIdToSceneNode(result.first, sceneMgr); + if(name == "") + name = result.first; + else + name = refIdToSceneNode(result.first, sceneMgr); + + return std::make_pair(name, ray.getPoint(farClipDist*result.second)); + } } std::string PhysicsSystem::refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr) @@ -153,15 +208,20 @@ namespace CSVWorld return mSceneNodeToMesh[sceneNodeName]; } - void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr) + void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget * scene) { mSceneManagers.push_back(sceneMgr); } + std::list PhysicsSystem::sceneWidgets() + { + return mSceneWidgets; + } + void PhysicsSystem::toggleDebugRendering(Ogre::SceneManager *sceneMgr) { // FIXME: should check if sceneMgr is in the list - if(!mSceneMgr) + if(!sceneMgr) return; // FIXME: maybe this should be an exception mEngine->setSceneManager(sceneMgr); diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 616bd13e6b..d62c5089b6 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -21,6 +21,11 @@ namespace OEngine } } +namespace CSVRender +{ + class SceneWidget; +} + namespace CSVWorld { class PhysicsSystem @@ -30,10 +35,9 @@ namespace CSVWorld std::map > mRefIdToSceneNode; std::map mSceneNodeToMesh; std::list mSceneManagers; // FIXME: change to list per OEngine + std::list mSceneWidgets; // FIXME: change to list per OEngine OEngine::Physic::PhysicEngine* mEngine; - Ogre::SceneManager *mSceneMgr; - public: PhysicsSystem(); @@ -41,7 +45,7 @@ namespace CSVWorld static PhysicsSystem *instance(); - void addSceneManager(Ogre::SceneManager *sceneMgr); + void addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget * scene); void addObject(const std::string &mesh, const std::string &sceneNodeName, const std::string &referenceId, float scale, @@ -65,8 +69,11 @@ namespace CSVWorld float mouseY, Ogre::SceneManager *sceneMgr, Ogre::Camera *camera); std::string sceneNodeToRefId(std::string sceneNodeName); + std::string sceneNodeToMesh(std::string sceneNodeName); + std::list sceneWidgets(); + private: void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index ce68da3623..b02c14f12c 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -38,7 +38,7 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D mLayout->setContentsMargins (QMargins (0, 0, 0, 0)); - CSVRender::WorldspaceWidget* wordspaceWidget = NULL; + CSVRender::WorldspaceWidget* worldspaceWidget = NULL; widgetType whatWidget; if (id.getId()=="sys::default") @@ -47,7 +47,7 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D CSVRender::PagedWorldspaceWidget *newWidget = new CSVRender::PagedWorldspaceWidget (this, document); - wordspaceWidget = newWidget; + worldspaceWidget = newWidget; makeConnections(newWidget); } @@ -57,12 +57,14 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D CSVRender::UnpagedWorldspaceWidget *newWidget = new CSVRender::UnpagedWorldspaceWidget (id.getId(), document, this); - wordspaceWidget = newWidget; + worldspaceWidget = newWidget; makeConnections(newWidget); } - replaceToolbarAndWorldspace(wordspaceWidget, makeToolbar(wordspaceWidget, whatWidget)); + connect (worldspaceWidget, SIGNAL (signalAsModified()), this, SIGNAL (refreshSubViews())); + + replaceToolbarAndWorldspace(worldspaceWidget, makeToolbar(worldspaceWidget, whatWidget)); layout->insertLayout (0, mLayout, 1); @@ -137,7 +139,6 @@ void CSVWorld::SceneSubView::setEditLock (bool locked) void CSVWorld::SceneSubView::updateEditorSetting(const QString &settingName, const QString &settingValue) { - } void CSVWorld::SceneSubView::setStatusBar (bool show) @@ -150,6 +151,11 @@ void CSVWorld::SceneSubView::useHint (const std::string& hint) mScene->useViewHint (hint); } +void CSVWorld::SceneSubView::updateScene() +{ + if(mScene) mScene->updateScene(); +} + std::string CSVWorld::SceneSubView::getTitle() const { return mTitle; diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index fc45347d0b..0bf19ee693 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -60,6 +60,8 @@ namespace CSVWorld virtual std::string getTitle() const; + virtual void updateScene(); + private: void makeConnections(CSVRender::PagedWorldspaceWidget* widget); From aa7b693a13469e13a905bb2e51b45cd4514da4c7 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 31 Oct 2014 22:04:10 +1100 Subject: [PATCH 31/56] Remove debug settings and minor cleanup. --- apps/opencs/model/settings/usersettings.cpp | 8 -------- apps/opencs/view/render/scenewidget.cpp | 1 - apps/opencs/view/render/worldspacewidget.cpp | 4 +--- apps/opencs/view/world/physicssystem.cpp | 5 ----- apps/opencs/view/world/physicssystem.hpp | 2 -- 5 files changed, 1 insertion(+), 19 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index f38f0cde0a..7dac660c35 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -161,14 +161,6 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() ritd->setDeclaredValues (values); } - declareSection ("debug", "Debug Options"); - { - Setting *mousePicking = createSetting (Type_CheckBox, "mouse-picking", "Debug Render Mouse-Picking"); - mousePicking->setDefaultValue ("false"); - mousePicking->setToolTip ("Enable redering debug information for mouse picking. " - "This option may be removed in future once the mouse picking feature is completed."); - } - declareSection ("table-input", "Table Input"); { QString inPlaceEdit ("Edit in Place"); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 40bca30b15..1a11ddad35 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -417,7 +417,6 @@ namespace CSVRender void SceneWidget::updateScene() { flagAsModified(); - update(); } void SceneWidget::updateOverlay() diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index a94ad9dfd0..62e924a94b 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -925,7 +925,5 @@ void CSVRender::WorldspaceWidget::placeObject(const std::string sceneNode, const bool CSVRender::WorldspaceWidget::isDebug() { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - - return userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false; + return false; } diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index bcf9aeff29..e1acdbbfe7 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -213,11 +213,6 @@ namespace CSVWorld mSceneManagers.push_back(sceneMgr); } - std::list PhysicsSystem::sceneWidgets() - { - return mSceneWidgets; - } - void PhysicsSystem::toggleDebugRendering(Ogre::SceneManager *sceneMgr) { // FIXME: should check if sceneMgr is in the list diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index d62c5089b6..f746ef531a 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -72,8 +72,6 @@ namespace CSVWorld std::string sceneNodeToMesh(std::string sceneNodeName); - std::list sceneWidgets(); - private: void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); From ac7acb2c22558edd39c7a7b1e4616b05593032d1 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 31 Oct 2014 22:21:24 +1100 Subject: [PATCH 32/56] Disable more debug code. --- apps/opencs/view/render/pagedworldspacewidget.cpp | 4 ---- apps/opencs/view/render/worldspacewidget.cpp | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index cce627ded9..b39f3733f7 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -207,10 +207,6 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) { - if(event->button() == Qt::RightButton) - { - std::cout << "double clicked" << std::endl; - } WorldspaceWidget::mouseDoubleClickEvent(event); } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 62e924a94b..a53681404c 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -549,7 +549,7 @@ void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) case Mouse_Grab: case Mouse_Drag: { - if(event->buttons() & ~Qt::RightButton) + if(0 /*event->buttons() & ~Qt::RightButton*/) { // cancel operation & return the object to the original position placeObject(mGrabbedSceneNode, mOrigObjPos); From ade7f092032a7e85202b966c103066590b6719ff Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 1 Nov 2014 00:03:09 +1100 Subject: [PATCH 33/56] Keep track of terrain in physics engine. Should resolve crash exiting after opening multiple subviews of the same cell. --- apps/opencs/view/render/cell.cpp | 6 ++--- apps/opencs/view/render/cell.hpp | 1 + apps/opencs/view/world/physicssystem.cpp | 30 ++++++++++++++++++++---- apps/opencs/view/world/physicssystem.hpp | 7 +++--- 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index f21d6b40b4..52e2335981 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -61,7 +61,7 @@ bool CSVRender::Cell::addObjects (int start, int end) CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, const Ogre::Vector3& origin) -: mData (data), mId (Misc::StringUtils::lowerCase (id)) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager) { mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode->setPosition (origin); @@ -88,7 +88,7 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, { float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; - CSVWorld::PhysicsSystem::instance()->addHeightField( + CSVWorld::PhysicsSystem::instance()->addHeightField(sceneManager, esmLand->mLandData->mHeights, esmLand->mX, esmLand->mY, 0, worldsize / (verts-1), verts); } } @@ -105,7 +105,7 @@ CSVRender::Cell::~Cell() { const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); if(esmLand) - CSVWorld::PhysicsSystem::instance()->removeHeightField(esmLand->mX, esmLand->mY); + CSVWorld::PhysicsSystem::instance()->removeHeightField(mSceneMgr, esmLand->mX, esmLand->mY); } } diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 98056c3549..2badc84d2f 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -32,6 +32,7 @@ namespace CSVRender Ogre::SceneNode *mCellNode; std::map mObjects; std::auto_ptr mTerrain; + Ogre::SceneManager *mSceneMgr; /// Ignored if cell does not have an object with the given ID. /// diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index e1acdbbfe7..a8cf5c37b6 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -129,15 +129,35 @@ namespace CSVWorld position, rotation); } - void PhysicsSystem::addHeightField(float* heights, - int x, int y, float yoffset, float triSize, float sqrtVerts) + void PhysicsSystem::addHeightField(Ogre::SceneManager *sceneManager, + float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts) { - mEngine->addHeightField(heights, x, y, yoffset, triSize, sqrtVerts); + std::string name = "HeightField_" + + QString::number(x).toStdString() + "_" + QString::number(y).toStdString(); + + if(mTerrain.find(name) == mTerrain.end()) + mEngine->addHeightField(heights, x, y, yoffset, triSize, sqrtVerts); + + mTerrain.insert(std::pair(name, sceneManager)); } - void PhysicsSystem::removeHeightField(int x, int y) + void PhysicsSystem::removeHeightField(Ogre::SceneManager *sceneManager, int x, int y) { - mEngine->removeHeightField(x, y); + std::string name = "HeightField_" + + QString::number(x).toStdString() + "_" + QString::number(y).toStdString(); + + if(mTerrain.count(name) == 1) + mEngine->removeHeightField(x, y); + + std::multimap::iterator iter = mTerrain.begin(); + for(; iter != mTerrain.end(); ++iter) + { + if((*iter).second == sceneManager) + { + mTerrain.erase(iter); + break; + } + } } // sceneMgr: to lookup the scene node name from the object's referenceId diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index f746ef531a..c2cb567be5 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -37,6 +37,7 @@ namespace CSVWorld std::list mSceneManagers; // FIXME: change to list per OEngine std::list mSceneWidgets; // FIXME: change to list per OEngine OEngine::Physic::PhysicEngine* mEngine; + std::multimap mTerrain; public: @@ -57,10 +58,10 @@ namespace CSVWorld void moveObject(const std::string &sceneNodeName, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); - void addHeightField(float* heights, - int x, int y, float yoffset, float triSize, float sqrtVerts); + void addHeightField(Ogre::SceneManager *sceneManager, + float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts); - void removeHeightField(int x, int y); + void removeHeightField(Ogre::SceneManager *sceneManager, int x, int y); void toggleDebugRendering(Ogre::SceneManager *sceneMgr); From d6e67b248f15a279f00941df2fb2cd16af080647 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 1 Nov 2014 07:29:16 +1100 Subject: [PATCH 34/56] Fix deleting objects and scenewidgets. --- apps/opencs/view/render/scenewidget.cpp | 4 +- apps/opencs/view/render/worldspacewidget.cpp | 3 +- apps/opencs/view/world/physicssystem.cpp | 59 +++++++++++++++++--- apps/opencs/view/world/physicssystem.hpp | 11 +++- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 1a11ddad35..aa00de0226 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -66,7 +66,7 @@ namespace CSVRender mOverlaySystem = OverlaySystem::instance().get(); mSceneMgr->addRenderQueueListener(mOverlaySystem); - CSVWorld::PhysicsSystem::instance()->addSceneManager(mSceneMgr, this); + CSVWorld::PhysicsSystem::instance()->addSceneManager(mSceneMgr); QTimer *timer = new QTimer (this); @@ -166,6 +166,8 @@ namespace CSVRender SceneWidget::~SceneWidget() { + CSVWorld::PhysicsSystem::instance()->removeSceneManager(mSceneMgr); + if (mWindow) Ogre::Root::getSingleton().destroyRenderTarget (mWindow); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index a53681404c..4d64c77751 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -916,8 +916,7 @@ void CSVRender::WorldspaceWidget::placeObject(const std::string sceneNode, const // FIXME: adjustRigidBody() seems to lose objects, work around by deleting and recreating objects //CSVWorld::PhysicsSystem::instance()->moveObject(sceneNode, pos, xr*yr*zr); std::string mesh = CSVWorld::PhysicsSystem::instance()->sceneNodeToMesh(sceneNode); - CSVWorld::PhysicsSystem::instance()->removeObject(sceneNode); - CSVWorld::PhysicsSystem::instance()->addObject(mesh, sceneNode, refId, cellref.mScale, pos, xr*yr*zr); + CSVWorld::PhysicsSystem::instance()->replaceObject(mesh, sceneNode, refId, cellref.mScale, pos, xr*yr*zr); // update all SceneWidgets and their SceneManagers emit signalAsModified(); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index a8cf5c37b6..7272552b62 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -65,7 +65,6 @@ namespace CSVWorld // update physics, only one physics model per referenceId if(mEngine->getRigidBody(referenceId, true) == NULL) { - mEngine->createAndAdjustRigidBody(mesh, referenceId, scale, position, rotation, 0, // scaledBoxTranslation @@ -74,27 +73,32 @@ namespace CSVWorld placeable); // update other scene managers if they have the referenceId (may have moved) + // FIXME: this bit not needed if object has not moved iter = mSceneManagers.begin(); for(; iter != mSceneManagers.end(); ++iter) { std::string name = refIdToSceneNode(referenceId, *iter); if(name != sceneNodeName && (*iter)->hasSceneNode(name)) { - // FIXME: rotation or scale not updated + // FIXME: rotation or scale not updated (*iter)->getSceneNode(name)->setPosition(position); } } } } - void PhysicsSystem::removeObject(const std::string &sceneNodeName) + // normal delete (e.g closing a scene subview) + // TODO: should think about using some kind of reference counting within RigidBody + void PhysicsSystem::removeObject(const std::string &sceneNodeName, bool force) { - std::string referenceId = sceneNodeToRefId(sceneNodeName); + std::string referenceId = mSceneNodeToRefId[sceneNodeName]; + if(referenceId != "") { - mEngine->removeRigidBody(referenceId); - mEngine->deleteRigidBody(referenceId); + mSceneNodeToRefId.erase(sceneNodeName); + mSceneNodeToMesh.erase(sceneNodeName); + // find which SceneManager has this object Ogre::SceneManager *sceneManager = NULL; std::list::const_iterator iter = mSceneManagers.begin(); for(; iter != mSceneManagers.end(); ++iter) @@ -109,6 +113,17 @@ namespace CSVWorld if(!sceneManager) return; // FIXME: maybe this should be an exception + // illustration: erase the object "K" from the object map + // + // RidigBody SubView Ogre + // --------------- -------------- ------------- + // ReferenceId "A" (SceneManager X SceneNode "J") + // (SceneManager Y SceneNode "K") <--- erase + // (SceneManager Z SceneNode "L") + // + // ReferenceId "B" (SceneManager X SceneNode "M") + // (SceneManager Y SceneNode "N") <--- notice not deleted + // (SceneManager Z SceneNode "O") std::map >::iterator itRef = mRefIdToSceneNode.begin(); for(; itRef != mRefIdToSceneNode.end(); ++itRef) @@ -116,12 +131,27 @@ namespace CSVWorld if((*itRef).second.find(sceneManager) != (*itRef).second.end()) { (*itRef).second.erase(sceneManager); - return; + break; } } + + // should the physics model be deleted? + if(force || mRefIdToSceneNode.find(referenceId) == mRefIdToSceneNode.end()) + { + mEngine->removeRigidBody(referenceId); + mEngine->deleteRigidBody(referenceId); + } } } + void PhysicsSystem::replaceObject(const std::string &mesh, + const std::string &sceneNodeName, const std::string &referenceId, float scale, + const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) + { + removeObject(sceneNodeName, true); // force delete + addObject(mesh, sceneNodeName, referenceId, scale, position, rotation, placeable); + } + void PhysicsSystem::moveObject(const std::string &sceneNodeName, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) { @@ -228,11 +258,24 @@ namespace CSVWorld return mSceneNodeToMesh[sceneNodeName]; } - void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget * scene) + void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr) { mSceneManagers.push_back(sceneMgr); } + void PhysicsSystem::removeSceneManager(Ogre::SceneManager *sceneMgr) + { + std::list::iterator iter = mSceneManagers.begin(); + for(; iter != mSceneManagers.end(); ++iter) + { + if(*iter == sceneMgr) + { + mSceneManagers.erase(iter); + break; + } + } + } + void PhysicsSystem::toggleDebugRendering(Ogre::SceneManager *sceneMgr) { // FIXME: should check if sceneMgr is in the list diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index c2cb567be5..b5b7658838 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -35,7 +35,6 @@ namespace CSVWorld std::map > mRefIdToSceneNode; std::map mSceneNodeToMesh; std::list mSceneManagers; // FIXME: change to list per OEngine - std::list mSceneWidgets; // FIXME: change to list per OEngine OEngine::Physic::PhysicEngine* mEngine; std::multimap mTerrain; @@ -46,14 +45,20 @@ namespace CSVWorld static PhysicsSystem *instance(); - void addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget * scene); + void addSceneManager(Ogre::SceneManager *sceneMgr); + void removeSceneManager(Ogre::SceneManager *sceneMgr); void addObject(const std::string &mesh, const std::string &sceneNodeName, const std::string &referenceId, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable=false); - void removeObject(const std::string &sceneNodeName); + void removeObject(const std::string &sceneNodeName, bool force = false); + + void replaceObject(const std::string &mesh, + const std::string &sceneNodeName, const std::string &referenceId, float scale, + const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, + bool placeable=false); void moveObject(const std::string &sceneNodeName, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); From e51d532795040dc59177fef93f8fab1c7a65d55a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 1 Nov 2014 07:39:58 +1100 Subject: [PATCH 35/56] Show drag movements of objects in multiple scene managers. --- apps/opencs/view/render/worldspacewidget.cpp | 8 ++++++-- apps/opencs/view/world/physicssystem.cpp | 18 ++++++++++++++++++ apps/opencs/view/world/physicssystem.hpp | 5 +++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 4d64c77751..f25a24158d 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -525,7 +525,9 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) pos.z += mZOffset; getSceneManager()->getSceneNode(mGrabbedSceneNode)->setPosition(pos+planeResult.second-mOrigMousePos); mCurrentMousePos = planeResult.second; - flagAsModified(); + CSVWorld::PhysicsSystem::instance()->moveSceneNodes(mGrabbedSceneNode, + pos+planeResult.second-mOrigMousePos); + emit signalAsModified(); } } } @@ -744,7 +746,9 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) Ogre::Vector3 pos = mOrigObjPos; pos.z += mZOffset; getSceneManager()->getSceneNode(mGrabbedSceneNode)->setPosition(pos+mCurrentMousePos-mOrigMousePos); - flagAsModified(); + CSVWorld::PhysicsSystem::instance()->moveSceneNodes(mGrabbedSceneNode, + pos+mCurrentMousePos-mOrigMousePos); + emit signalAsModified(); } break; } diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 7272552b62..58d8e7662e 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -159,6 +159,24 @@ namespace CSVWorld position, rotation); } + void PhysicsSystem::moveSceneNodeImpl(const std::string sceneNodeName, + const std::string referenceId, const Ogre::Vector3 &position) + { + std::list::const_iterator iter = mSceneManagers.begin(); + for(; iter != mSceneManagers.end(); ++iter) + { + std::string name = refIdToSceneNode(referenceId, *iter); + if(name != sceneNodeName && (*iter)->hasSceneNode(name)) + { + (*iter)->getSceneNode(name)->setPosition(position); + } + } + } + + void PhysicsSystem::moveSceneNodes(const std::string sceneNodeName, const Ogre::Vector3 &position) + { + moveSceneNodeImpl(sceneNodeName, sceneNodeToRefId(sceneNodeName), position); + } void PhysicsSystem::addHeightField(Ogre::SceneManager *sceneManager, float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts) { diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index b5b7658838..0742bbf475 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -63,6 +63,8 @@ namespace CSVWorld void moveObject(const std::string &sceneNodeName, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); + void moveSceneNodes(const std::string sceneNodeName, const Ogre::Vector3 &position); + void addHeightField(Ogre::SceneManager *sceneManager, float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts); @@ -80,6 +82,9 @@ namespace CSVWorld private: + 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 refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr); }; From 057982b1f8f2f8750b1ee4b4f966dae135b23782 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 1 Nov 2014 08:29:08 +1100 Subject: [PATCH 36/56] Fix Subview interface clutter by keeping a map of Scenewidgets. --- apps/opencs/view/doc/subview.cpp | 3 --- apps/opencs/view/doc/subview.hpp | 4 ---- apps/opencs/view/doc/view.cpp | 12 ------------ apps/opencs/view/doc/view.hpp | 2 -- apps/opencs/view/render/scenewidget.cpp | 2 +- apps/opencs/view/render/worldspacewidget.cpp | 18 +++++++++++++++--- apps/opencs/view/render/worldspacewidget.hpp | 6 +++--- apps/opencs/view/world/physicssystem.cpp | 9 ++++++++- apps/opencs/view/world/physicssystem.hpp | 6 +++++- apps/opencs/view/world/scenesubview.cpp | 8 -------- apps/opencs/view/world/scenesubview.hpp | 2 -- 11 files changed, 32 insertions(+), 40 deletions(-) diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index bce14a642d..a399b5b5bf 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -43,6 +43,3 @@ void CSVDoc::SubView::closeRequest() { emit closeRequest (this); } - -void CSVDoc::SubView::updateScene() -{} diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index 9acb7a5ae7..a8aa3cda1e 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -52,8 +52,6 @@ namespace CSVDoc virtual void updateUserSetting (const QString& name, const QStringList& value); - virtual void updateScene(); - private: void closeEvent (QCloseEvent *event); @@ -68,8 +66,6 @@ namespace CSVDoc void updateSubViewIndicies (SubView *view = 0); - void refreshSubViews(); - protected slots: void closeRequest(); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 932dab3aa3..8a6665cf26 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -16,7 +16,6 @@ #include "../../model/world/idtable.hpp" #include "../world/subviews.hpp" -#include "../doc/subview.hpp" #include "../tools/subviews.hpp" @@ -301,15 +300,6 @@ void CSVDoc::View::setupUi() setupDebugMenu(); } -void CSVDoc::View::refreshSubViews() -{ - QList::iterator iter = mSubViews.begin(); - for(; iter != mSubViews.end(); ++iter) - { - (*iter)->updateScene(); - } -} - void CSVDoc::View::updateTitle() { std::ostringstream stream; @@ -537,8 +527,6 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin connect (view, SIGNAL (updateSubViewIndicies (SubView *)), this, SLOT (updateSubViewIndicies (SubView *))); - connect (view, SIGNAL (refreshSubViews()), this, SLOT (refreshSubViews())); - view->show(); } diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index c6bb206d6f..55ea5ee515 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -139,8 +139,6 @@ namespace CSVDoc // called when subviews are added or removed void updateSubViewIndicies (SubView *view = 0); - void refreshSubViews(); - private slots: void newView(); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index aa00de0226..5611c22431 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -66,7 +66,7 @@ namespace CSVRender mOverlaySystem = OverlaySystem::instance().get(); mSceneMgr->addRenderQueueListener(mOverlaySystem); - CSVWorld::PhysicsSystem::instance()->addSceneManager(mSceneMgr); + CSVWorld::PhysicsSystem::instance()->addSceneManager(mSceneMgr, this); QTimer *timer = new QTimer (this); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index f25a24158d..5656b2dd62 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -527,7 +527,7 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) mCurrentMousePos = planeResult.second; CSVWorld::PhysicsSystem::instance()->moveSceneNodes(mGrabbedSceneNode, pos+planeResult.second-mOrigMousePos); - emit signalAsModified(); + updateSceneWidgets(); } } } @@ -748,7 +748,7 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) getSceneManager()->getSceneNode(mGrabbedSceneNode)->setPosition(pos+mCurrentMousePos-mOrigMousePos); CSVWorld::PhysicsSystem::instance()->moveSceneNodes(mGrabbedSceneNode, pos+mCurrentMousePos-mOrigMousePos); - emit signalAsModified(); + updateSceneWidgets(); } break; } @@ -923,7 +923,19 @@ void CSVRender::WorldspaceWidget::placeObject(const std::string sceneNode, const CSVWorld::PhysicsSystem::instance()->replaceObject(mesh, sceneNode, refId, cellref.mScale, pos, xr*yr*zr); // update all SceneWidgets and their SceneManagers - emit signalAsModified(); + updateSceneWidgets(); +} + +void CSVRender::WorldspaceWidget::updateSceneWidgets() +{ + std::map sceneWidgets = + CSVWorld::PhysicsSystem::instance()->sceneWidgets(); + + std::map::iterator iter = sceneWidgets.begin(); + for(; iter != sceneWidgets.end(); ++iter) + { + (*iter).second->updateScene(); + } } bool CSVRender::WorldspaceWidget::isDebug() diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index e69fbe08eb..e74c40e86e 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -130,12 +130,14 @@ namespace CSVRender virtual std::string getStartupInstruction() = 0; void placeObject(const std::string sceneNode, const Ogre::Vector3 &pos); - bool isDebug(); std::pair terrainUnderCursor(const int mouseX, const int mouseY); std::pair objectUnderCursor(const int mouseX, const int mouseY); std::pair mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane); void updateSelectionHighlight(const std::string sceneNode, const Ogre::Vector3 &position); + void updateSceneWidgets(); + bool isDebug(); + private slots: void selectNavigationMode (const std::string& mode); @@ -170,8 +172,6 @@ namespace CSVRender void closeRequest(); void dataDropped(const std::vector& data); - - void signalAsModified(); }; } diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 58d8e7662e..0342ede954 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -276,9 +276,15 @@ namespace CSVWorld return mSceneNodeToMesh[sceneNodeName]; } - void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr) + void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget * sceneWidget) { mSceneManagers.push_back(sceneMgr); + mSceneWidgets[sceneMgr] = sceneWidget; + } + + std::map PhysicsSystem::sceneWidgets() + { + return mSceneWidgets; } void PhysicsSystem::removeSceneManager(Ogre::SceneManager *sceneMgr) @@ -292,6 +298,7 @@ namespace CSVWorld break; } } + mSceneWidgets.erase(sceneMgr); } void PhysicsSystem::toggleDebugRendering(Ogre::SceneManager *sceneMgr) diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 0742bbf475..3232a5e90d 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -35,6 +35,8 @@ namespace CSVWorld std::map > mRefIdToSceneNode; std::map mSceneNodeToMesh; std::list mSceneManagers; // FIXME: change to list per OEngine + //std::list mSceneWidgets; // FIXME: change to list per OEngine + std::map mSceneWidgets; OEngine::Physic::PhysicEngine* mEngine; std::multimap mTerrain; @@ -45,7 +47,7 @@ namespace CSVWorld static PhysicsSystem *instance(); - void addSceneManager(Ogre::SceneManager *sceneMgr); + void addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget * scene); void removeSceneManager(Ogre::SceneManager *sceneMgr); void addObject(const std::string &mesh, @@ -80,6 +82,8 @@ namespace CSVWorld std::string sceneNodeToMesh(std::string sceneNodeName); + std::map sceneWidgets(); + private: void moveSceneNodeImpl(const std::string sceneNodeName, diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index b02c14f12c..433bb828f0 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -62,8 +62,6 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D makeConnections(newWidget); } - connect (worldspaceWidget, SIGNAL (signalAsModified()), this, SIGNAL (refreshSubViews())); - replaceToolbarAndWorldspace(worldspaceWidget, makeToolbar(worldspaceWidget, whatWidget)); layout->insertLayout (0, mLayout, 1); @@ -133,7 +131,6 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp void CSVWorld::SceneSubView::setEditLock (bool locked) { - } void CSVWorld::SceneSubView::updateEditorSetting(const QString &settingName, const QString &settingValue) @@ -151,11 +148,6 @@ void CSVWorld::SceneSubView::useHint (const std::string& hint) mScene->useViewHint (hint); } -void CSVWorld::SceneSubView::updateScene() -{ - if(mScene) mScene->updateScene(); -} - std::string CSVWorld::SceneSubView::getTitle() const { return mTitle; diff --git a/apps/opencs/view/world/scenesubview.hpp b/apps/opencs/view/world/scenesubview.hpp index 0bf19ee693..fc45347d0b 100644 --- a/apps/opencs/view/world/scenesubview.hpp +++ b/apps/opencs/view/world/scenesubview.hpp @@ -60,8 +60,6 @@ namespace CSVWorld virtual std::string getTitle() const; - virtual void updateScene(); - private: void makeConnections(CSVRender::PagedWorldspaceWidget* widget); From b328aa1fb94474bbc935e8b5dd5a6d9433f250cf Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 1 Nov 2014 18:57:39 +1100 Subject: [PATCH 37/56] Multiple document support. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/editor.cpp | 4 +- apps/opencs/editor.hpp | 4 +- apps/opencs/view/doc/view.cpp | 3 ++ apps/opencs/view/render/cell.cpp | 27 ++++------- apps/opencs/view/render/cell.hpp | 12 ++++- apps/opencs/view/render/object.cpp | 12 ++--- apps/opencs/view/render/object.hpp | 9 +++- .../view/render/pagedworldspacewidget.cpp | 2 +- apps/opencs/view/render/previewwidget.cpp | 2 +- apps/opencs/view/render/scenewidget.cpp | 6 --- .../view/render/unpagedworldspacewidget.cpp | 4 +- apps/opencs/view/render/worldspacewidget.cpp | 47 +++++++++++-------- apps/opencs/view/render/worldspacewidget.hpp | 9 ++++ apps/opencs/view/world/physicssystem.cpp | 14 +----- apps/opencs/view/world/physicssystem.hpp | 7 +-- 16 files changed, 83 insertions(+), 81 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8285844522..30e9203f5f 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -68,7 +68,7 @@ opencs_units (view/world opencs_units_noqt (view/world subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate - scripthighlighter idvalidator dialoguecreator physicssystem + scripthighlighter idvalidator dialoguecreator physicssystem physicsmanager ) opencs_units (view/widget diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index b566bbe5d6..591667ebb7 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -21,7 +21,7 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) : mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr), - mViewManager (mDocumentManager), mPhysicsSystem (0), + mViewManager (mDocumentManager), mPhysicsManager (0), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) { std::pair > config = readConfig(); @@ -34,7 +34,7 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string()); mOverlaySystem.reset (new CSVRender::OverlaySystem); - mPhysicsSystem.reset (new CSVWorld::PhysicsSystem); + mPhysicsManager.reset (new CSVWorld::PhysicsManager); Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, mFsStrict); diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index 4d2fdc2eb1..d55b0e873e 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -28,7 +28,7 @@ #include "view/settings/dialog.hpp" #include "view/render/overlaysystem.hpp" -#include "view/world/physicssystem.hpp" +#include "view/world/physicsmanager.hpp" namespace OgreInit { @@ -45,7 +45,7 @@ namespace CS Files::ConfigurationManager mCfgMgr; CSMSettings::UserSettings mUserSettings; std::auto_ptr mOverlaySystem; - std::auto_ptr mPhysicsSystem; + std::auto_ptr mPhysicsManager; CSMDoc::DocumentManager mDocumentManager; CSVDoc::ViewManager mViewManager; CSVDoc::StartupDialogue mStartup; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 8a6665cf26..8b5efbea7f 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -16,6 +16,7 @@ #include "../../model/world/idtable.hpp" #include "../world/subviews.hpp" +#include "../world/physicsmanager.hpp" #include "../tools/subviews.hpp" @@ -406,6 +407,8 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to mSubViewFactory.add (CSMWorld::UniversalId::Type_RunLog, new SubViewFactory); connect (mOperations, SIGNAL (abortOperation (int)), this, SLOT (abortOperation (int))); + + CSVWorld::PhysicsManager::instance()->setupPhysics(document); } CSVDoc::View::~View() diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 52e2335981..75e11cc10a 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -51,7 +51,7 @@ bool CSVRender::Cell::addObjects (int start, int end) std::string id = Misc::StringUtils::lowerCase (references.data ( references.index (i, idColumn)).toString().toUtf8().constData()); - mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false))); + mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics))); modified = true; } } @@ -60,8 +60,8 @@ bool CSVRender::Cell::addObjects (int start, int end) } CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, - const std::string& id, const Ogre::Vector3& origin) -: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager) + const std::string& id, CSVWorld::PhysicsSystem *physics, const Ogre::Vector3& origin) +: mData (data), mId (Misc::StringUtils::lowerCase (id)), mSceneMgr(sceneManager), mPhysics(physics) { mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode->setPosition (origin); @@ -88,26 +88,17 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, { float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; - CSVWorld::PhysicsSystem::instance()->addHeightField(sceneManager, - esmLand->mLandData->mHeights, esmLand->mX, esmLand->mY, 0, worldsize / (verts-1), verts); + mX = esmLand->mX; + mY = esmLand->mY; + mPhysics->addHeightField(sceneManager, + esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts); } } } CSVRender::Cell::~Cell() { - // TODO: maybe store the cell coordinates rather than searching for them in the destructor? - if(mTerrain.get()) - { - const CSMWorld::IdCollection& land = mData.getLand(); - int landIndex = land.searchId(mId); - if (landIndex != -1) - { - const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); - if(esmLand) - CSVWorld::PhysicsSystem::instance()->removeHeightField(mSceneMgr, esmLand->mX, esmLand->mY); - } - } + mPhysics->removeHeightField(mSceneMgr, mX, mY); for (std::map::iterator iter (mObjects.begin()); iter!=mObjects.end(); ++iter) @@ -201,7 +192,7 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft, for (std::map::iterator iter (ids.begin()); iter!=ids.end(); ++iter) { mObjects.insert (std::make_pair ( - iter->first, new Object (mData, mCellNode, iter->first, false))); + iter->first, new Object (mData, mCellNode, iter->first, false, mPhysics))); modified = true; } diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 2badc84d2f..8bc58714a8 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -23,6 +23,11 @@ namespace CSMWorld class Data; } +namespace CSVWorld +{ + class PhysicsSystem; +} + namespace CSVRender { class Cell @@ -32,7 +37,10 @@ namespace CSVRender Ogre::SceneNode *mCellNode; std::map mObjects; std::auto_ptr mTerrain; + CSVWorld::PhysicsSystem *mPhysics; Ogre::SceneManager *mSceneMgr; + int mX; + int mY; /// Ignored if cell does not have an object with the given ID. /// @@ -46,8 +54,8 @@ namespace CSVRender public: - Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, - const std::string& id, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); + Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, + CSVWorld::PhysicsSystem *physics, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0)); ~Cell(); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 474c79b353..395a4d57e0 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -34,7 +34,7 @@ void CSVRender::Object::clearSceneNode (Ogre::SceneNode *node) void CSVRender::Object::clear() { if(!mObject.isNull()) - CSVWorld::PhysicsSystem::instance()->removeObject(mBase->getName()); + mPhysics->removeObject(mBase->getName()); mObject.setNull(); @@ -79,7 +79,7 @@ void CSVRender::Object::update() mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model); mObject->setVisibilityFlags (Element_Reference); - if (!mReferenceId.empty()) + if (mPhysics && !mReferenceId.empty()) { const CSMWorld::CellRef& reference = getReference(); @@ -93,8 +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); - CSVWorld::PhysicsSystem::instance()->addObject("meshes\\" + model, - mBase->getName(), mReferenceId, reference.mScale, position, xr*yr*zr); + mPhysics->addObject("meshes\\" + model, mBase->getName(), mReferenceId, reference.mScale, position, xr*yr*zr); } } } @@ -133,8 +132,9 @@ const CSMWorld::CellRef& CSVRender::Object::getReference() const } CSVRender::Object::Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode, - const std::string& id, bool referenceable, bool forceBaseToZero) -: mData (data), mBase (0), mForceBaseToZero (forceBaseToZero) + const std::string& id, bool referenceable, CSVWorld::PhysicsSystem *physics, + bool forceBaseToZero) +: mData (data), mBase (0), mForceBaseToZero (forceBaseToZero), mPhysics(physics) { mBase = cellNode->createChildSceneNode(); diff --git a/apps/opencs/view/render/object.hpp b/apps/opencs/view/render/object.hpp index 6a8a933e51..eba2dc8148 100644 --- a/apps/opencs/view/render/object.hpp +++ b/apps/opencs/view/render/object.hpp @@ -16,6 +16,11 @@ namespace CSMWorld class CellRef; } +namespace CSVWorld +{ + class PhysicsSystem; +} + namespace CSVRender { class Object @@ -26,6 +31,7 @@ namespace CSVRender Ogre::SceneNode *mBase; NifOgre::ObjectScenePtr mObject; bool mForceBaseToZero; + CSVWorld::PhysicsSystem *mPhysics; /// Not implemented Object (const Object&); @@ -51,7 +57,8 @@ namespace CSVRender public: Object (const CSMWorld::Data& data, Ogre::SceneNode *cellNode, - const std::string& id, bool referenceable, bool forceBaseToZero = false); + const std::string& id, bool referenceable, + CSVWorld::PhysicsSystem *physics = NULL, bool forceBaseToZero = false); /// \param forceBaseToZero If this is a reference ignore the coordinates and place /// it at 0, 0, 0 instead. diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index b39f3733f7..49e7e1f097 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -109,7 +109,7 @@ bool CSVRender::PagedWorldspaceWidget::adjustCells() mCells.find (*iter)==mCells.end()) { Cell *cell = new Cell (mDocument.getData(), getSceneManager(), - iter->getId (mWorldspace)); + iter->getId (mWorldspace), getPhysics()); mCells.insert (std::make_pair (*iter, cell)); float height = cell->getTerrainHeightAt(Ogre::Vector3( diff --git a/apps/opencs/view/render/previewwidget.cpp b/apps/opencs/view/render/previewwidget.cpp index 75b4e93967..f972c6361b 100644 --- a/apps/opencs/view/render/previewwidget.cpp +++ b/apps/opencs/view/render/previewwidget.cpp @@ -10,7 +10,7 @@ CSVRender::PreviewWidget::PreviewWidget (CSMWorld::Data& data, const std::string& id, bool referenceable, QWidget *parent) : SceneWidget (parent), mData (data), - mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, true) + mObject (data, getSceneManager()->getRootSceneNode(), id, referenceable, NULL, true) { setNavigation (&mOrbit); diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 5611c22431..55cf039fcd 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -13,8 +13,6 @@ #include #include -#include "../world/physicssystem.hpp" - #include "../widget/scenetoolmode.hpp" #include "../../model/settings/usersettings.hpp" @@ -66,8 +64,6 @@ namespace CSVRender mOverlaySystem = OverlaySystem::instance().get(); mSceneMgr->addRenderQueueListener(mOverlaySystem); - CSVWorld::PhysicsSystem::instance()->addSceneManager(mSceneMgr, this); - QTimer *timer = new QTimer (this); connect (timer, SIGNAL (timeout()), this, SLOT (update())); @@ -166,8 +162,6 @@ namespace CSVRender SceneWidget::~SceneWidget() { - CSVWorld::PhysicsSystem::instance()->removeSceneManager(mSceneMgr); - if (mWindow) Ogre::Root::getSingleton().destroyRenderTarget (mWindow); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index aab3791fce..8012b1b246 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -56,7 +56,7 @@ CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& update(); - mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId)); + mCell.reset (new Cell (document.getData(), getSceneManager(), mCellId, getPhysics())); } void CSVRender::UnpagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft, @@ -98,7 +98,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); - mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId)); + mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId, getPhysics())); update(); emit cellChanged(*data.begin()); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 5656b2dd62..448153d372 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -24,6 +24,7 @@ #include "../widget/scenetooltoggle.hpp" #include "../widget/scenetoolrun.hpp" +#include "../world/physicsmanager.hpp" #include "../world/physicssystem.hpp" #include "elements.hpp" @@ -147,6 +148,10 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); + // associate WorldSpaceWidgets (and their SceneManagers with Documents, then create physics if new document + mPhysics = CSVWorld::PhysicsManager::instance()->addSceneWidget(document, this); + mPhysics->addSceneManager(getSceneManager(), this); + initDebug(); mMouseEventTimer = new QElapsedTimer(); mMouseEventTimer->invalidate(); @@ -166,6 +171,9 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg CSVRender::WorldspaceWidget::~WorldspaceWidget () { + mPhysics->removeSceneManager(getSceneManager()); + CSVWorld::PhysicsManager::instance()->removeSceneWidget(this); + delete mMouseEventTimer; // For debugging only @@ -457,6 +465,12 @@ void CSVRender::WorldspaceWidget::updateOverlay() { } +CSVWorld::PhysicsSystem *CSVRender::WorldspaceWidget::getPhysics() +{ + assert(mPhysics); + return mPhysics; +} + // mouse picking // FIXME: need to virtualise mouse buttons // @@ -525,8 +539,7 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) pos.z += mZOffset; getSceneManager()->getSceneNode(mGrabbedSceneNode)->setPosition(pos+planeResult.second-mOrigMousePos); mCurrentMousePos = planeResult.second; - CSVWorld::PhysicsSystem::instance()->moveSceneNodes(mGrabbedSceneNode, - pos+planeResult.second-mOrigMousePos); + mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+planeResult.second-mOrigMousePos); updateSceneWidgets(); } } @@ -634,8 +647,7 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) // print some debug info if(isDebug()) { - std::string referenceId = - CSVWorld::PhysicsSystem::instance()->sceneNodeToRefId(result.first); + std::string referenceId = mPhysics->sceneNodeToRefId(result.first); std::cout << "ReferenceId: " << referenceId << std::endl; const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); int index = references.searchId(referenceId); @@ -719,8 +731,8 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) // debug drawer. Hence only the first subview that creates the debug drawer // can view the debug lines. Will need to keep a map in OEngine if multiple // subviews are to be supported. - //CSVWorld::PhysicsSystem::instance()->setSceneManager(getSceneManager()); - CSVWorld::PhysicsSystem::instance()->toggleDebugRendering(getSceneManager()); + //mPhysics->setSceneManager(getSceneManager()); + mPhysics->toggleDebugRendering(getSceneManager()); flagAsModified(); } } @@ -746,8 +758,7 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) Ogre::Vector3 pos = mOrigObjPos; pos.z += mZOffset; getSceneManager()->getSceneNode(mGrabbedSceneNode)->setPosition(pos+mCurrentMousePos-mOrigMousePos); - CSVWorld::PhysicsSystem::instance()->moveSceneNodes(mGrabbedSceneNode, - pos+mCurrentMousePos-mOrigMousePos); + mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+mCurrentMousePos-mOrigMousePos); updateSceneWidgets(); } break; @@ -844,8 +855,7 @@ std::pair CSVRender::WorldspaceWidget::terrainUnderC float x = (float) mouseX / getCamera()->getViewport()->getActualWidth(); float y = (float) mouseY / getCamera()->getViewport()->getActualHeight(); - std::pair result = - CSVWorld::PhysicsSystem::instance()->castRay(x, y, getSceneManager(), getCamera()); + std::pair result = mPhysics->castRay(x, y, getSceneManager(), getCamera()); if(result.first != "") { // FIXME: is there a better way to distinguish terrain from objects? @@ -867,8 +877,7 @@ std::pair CSVRender::WorldspaceWidget::objectUnderCu float x = (float) mouseX / getCamera()->getViewport()->getActualWidth(); float y = (float) mouseY / getCamera()->getViewport()->getActualHeight(); - std::pair result = - CSVWorld::PhysicsSystem::instance()->castRay(x, y, getSceneManager(), getCamera()); + std::pair result = mPhysics->castRay(x, y, getSceneManager(), getCamera()); if(result.first != "") { // NOTE: anything not terrain is assumed to be an object @@ -910,17 +919,16 @@ void CSVRender::WorldspaceWidget::placeObject(const std::string sceneNode, const getSceneManager()->getSceneNode(sceneNode)->setPosition(pos); // update physics - std::string refId = CSVWorld::PhysicsSystem::instance()->sceneNodeToRefId(sceneNode); - const CSMWorld::CellRef& cellref = - mDocument.getData().getReferences().getRecord (refId).get(); + std::string refId = mPhysics->sceneNodeToRefId(sceneNode); + const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (refId).get(); Ogre::Quaternion xr (Ogre::Radian (-cellref.mPos.rot[0]), Ogre::Vector3::UNIT_X); Ogre::Quaternion yr (Ogre::Radian (-cellref.mPos.rot[1]), Ogre::Vector3::UNIT_Y); Ogre::Quaternion zr (Ogre::Radian (-cellref.mPos.rot[2]), Ogre::Vector3::UNIT_Z); // FIXME: adjustRigidBody() seems to lose objects, work around by deleting and recreating objects - //CSVWorld::PhysicsSystem::instance()->moveObject(sceneNode, pos, xr*yr*zr); - std::string mesh = CSVWorld::PhysicsSystem::instance()->sceneNodeToMesh(sceneNode); - CSVWorld::PhysicsSystem::instance()->replaceObject(mesh, sceneNode, refId, cellref.mScale, pos, xr*yr*zr); + //mPhysics->moveObject(sceneNode, pos, xr*yr*zr); + std::string mesh = mPhysics->sceneNodeToMesh(sceneNode); + mPhysics->replaceObject(mesh, sceneNode, refId, cellref.mScale, pos, xr*yr*zr); // update all SceneWidgets and their SceneManagers updateSceneWidgets(); @@ -928,8 +936,7 @@ void CSVRender::WorldspaceWidget::placeObject(const std::string sceneNode, const void CSVRender::WorldspaceWidget::updateSceneWidgets() { - std::map sceneWidgets = - CSVWorld::PhysicsSystem::instance()->sceneWidgets(); + std::map sceneWidgets = mPhysics->sceneWidgets(); std::map::iterator iter = sceneWidgets.begin(); for(; iter != sceneWidgets.end(); ++iter) diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index e74c40e86e..431a023be9 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -13,6 +13,7 @@ namespace CSMWorld { class UniversalId; } + namespace CSVWidget { class SceneToolMode; @@ -21,6 +22,11 @@ namespace CSVWidget class SceneToolRun; } +namespace CSVWorld +{ + class PhysicsSystem; +} + class QElapsedTimer; namespace CSVRender @@ -35,6 +41,7 @@ namespace CSVRender CSVWidget::SceneToolToggle *mSceneElements; CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; + CSVWorld::PhysicsSystem *mPhysics; enum MouseState { @@ -113,6 +120,8 @@ namespace CSVRender virtual void updateOverlay(); + CSVWorld::PhysicsSystem *getPhysics(); + virtual void mouseMoveEvent (QMouseEvent *event); virtual void mousePressEvent (QMouseEvent *event); virtual void mouseReleaseEvent (QMouseEvent *event); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 0342ede954..3203679069 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -13,13 +13,8 @@ namespace CSVWorld { - PhysicsSystem *PhysicsSystem::mPhysicsSystemInstance = 0; - PhysicsSystem::PhysicsSystem() { - assert(!mPhysicsSystemInstance); - mPhysicsSystemInstance = this; - // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); @@ -28,13 +23,6 @@ namespace CSVWorld PhysicsSystem::~PhysicsSystem() { delete mEngine; - // FIXME: update maps when SceneManagers are destroyed - } - - PhysicsSystem *PhysicsSystem::instance() - { - assert(mPhysicsSystemInstance); - return mPhysicsSystemInstance; } // FIXME: looks up the scene manager based on the scene node name (highly inefficient) @@ -60,7 +48,7 @@ namespace CSVWorld } if(!foundSceneManager) - return; // FIXME: this should be an exception + return; // FIXME: should this be an exception // update physics, only one physics model per referenceId if(mEngine->getRigidBody(referenceId, true) == NULL) diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 3232a5e90d..8fadf6c8ad 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -30,12 +30,10 @@ namespace CSVWorld { class PhysicsSystem { - static PhysicsSystem *mPhysicsSystemInstance; std::map mSceneNodeToRefId; std::map > mRefIdToSceneNode; std::map mSceneNodeToMesh; - std::list mSceneManagers; // FIXME: change to list per OEngine - //std::list mSceneWidgets; // FIXME: change to list per OEngine + std::list mSceneManagers; std::map mSceneWidgets; OEngine::Physic::PhysicEngine* mEngine; std::multimap mTerrain; @@ -44,9 +42,6 @@ namespace CSVWorld PhysicsSystem(); ~PhysicsSystem(); - - static PhysicsSystem *instance(); - void addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget * scene); void removeSceneManager(Ogre::SceneManager *sceneMgr); From 1ee64c7087d062e57b8e4821c4f2c2301e699725 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 1 Nov 2014 19:12:22 +1100 Subject: [PATCH 38/56] Add missing files for multi-document support. --- apps/opencs/view/world/physicsmanager.cpp | 87 +++++++++++++++++++++++ apps/opencs/view/world/physicsmanager.hpp | 58 +++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 apps/opencs/view/world/physicsmanager.cpp create mode 100644 apps/opencs/view/world/physicsmanager.hpp diff --git a/apps/opencs/view/world/physicsmanager.cpp b/apps/opencs/view/world/physicsmanager.cpp new file mode 100644 index 0000000000..ce71ac3150 --- /dev/null +++ b/apps/opencs/view/world/physicsmanager.cpp @@ -0,0 +1,87 @@ +#include "physicsmanager.hpp" + +#include + +#include "../render/worldspacewidget.hpp" +#include "physicssystem.hpp" + +namespace CSVWorld +{ + PhysicsManager *PhysicsManager::mPhysicsManagerInstance = 0; + + PhysicsManager::PhysicsManager() + { + assert(!mPhysicsManagerInstance); + mPhysicsManagerInstance = this; + } + + PhysicsManager::~PhysicsManager() + { + std::map::iterator iter = mPhysics.begin(); + for(; iter != mPhysics.end(); ++iter) + delete iter->second; // shouldn't be any left but just in case + } + + PhysicsManager *PhysicsManager::instance() + { + assert(mPhysicsManagerInstance); + return mPhysicsManagerInstance; + } + + // create a physics instance per document, called from CSVDoc::View() to get Document* + void PhysicsManager::setupPhysics(CSMDoc::Document *doc) + { + std::map >::iterator iter = mSceneWidgets.find(doc); + if(iter == mSceneWidgets.end()) + { + mSceneWidgets[doc] = std::list {}; // zero elements + mPhysics[doc] = new PhysicsSystem(); + } + } + + // called from CSVRender::WorldspaceWidget() to get widgets' association with Document& + PhysicsSystem *PhysicsManager::addSceneWidget(CSMDoc::Document &doc, CSVRender::WorldspaceWidget *widget) + { + CSVRender::SceneWidget *sceneWidget = static_cast(widget); + + std::map >::iterator iter = mSceneWidgets.begin(); + for(; iter != mSceneWidgets.end(); ++iter) + { + if((*iter).first == &doc) + { + (*iter).second.push_back(sceneWidget); + return mPhysics[(*iter).first]; // TODO: consider using shared_ptr instead + } + } + + throw std::runtime_error("No physics system found for the given document."); + } + + // delete physics when the last scene widget for the document is closed + void PhysicsManager::removeSceneWidget(CSVRender::WorldspaceWidget *widget) + { + CSVRender::SceneWidget *sceneWidget = static_cast(widget); + + std::map >::iterator iter = mSceneWidgets.begin(); + for(; iter != mSceneWidgets.end(); ++iter) + { + std::list::iterator itWidget = (*iter).second.begin(); + for(; itWidget != (*iter).second.end(); ++itWidget) + { + if((*itWidget) == sceneWidget) + { + (*iter).second.erase(itWidget); + + if((*iter).second.empty()) // last one for the document + { + delete mPhysics[(*iter).first]; + mPhysics.erase((*iter).first); + mSceneWidgets.erase(iter); + } + + break; + } + } + } + } +} diff --git a/apps/opencs/view/world/physicsmanager.hpp b/apps/opencs/view/world/physicsmanager.hpp new file mode 100644 index 0000000000..7bcd5d39de --- /dev/null +++ b/apps/opencs/view/world/physicsmanager.hpp @@ -0,0 +1,58 @@ +#ifndef CSV_WORLD_PHYSICSMANAGER_H +#define CSV_WORLD_PHYSICSMANAGER_H + +#include +#include + +namespace Ogre +{ + class SceneManager; +} + +namespace CSMDoc +{ + class Document; +} + +namespace CSVRender +{ + class WorldspaceWidget; + class SceneWidget; +} + +namespace CSVWorld +{ + class PhysicsSystem; +} + +namespace CSVWorld +{ + class PhysicsManager + { + static PhysicsManager *mPhysicsManagerInstance; + + //std::map mSceneManagers; + std::map > mSceneWidgets; + std::map mPhysics; + + public: + + PhysicsManager(); + ~PhysicsManager(); + + static PhysicsManager *instance(); + + void setupPhysics(CSMDoc::Document *); +#if 0 + void addSceneManager(CSVRender::SceneWidget *sceneWidget, Ogre::SceneManager *sceneMgr); + + void removeSceneManager(CSVRender::SceneWidget *sceneWidget); +#endif + + PhysicsSystem *addSceneWidget(CSMDoc::Document &doc, CSVRender::WorldspaceWidget *widget); + + void removeSceneWidget(CSVRender::WorldspaceWidget *widget); + }; +} + +#endif // CSV_WORLD_PHYSICSMANAGER_H From c6a2461fbd905713e566239e4ab55704c61bed2d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 1 Nov 2014 20:51:04 +1100 Subject: [PATCH 39/56] Delay removing physics until the document is closed. Also other general cleanup. --- apps/opencs/view/doc/viewmanager.cpp | 2 ++ apps/opencs/view/render/worldspacewidget.cpp | 3 +- apps/opencs/view/world/physicsmanager.cpp | 27 ++++++++++---- apps/opencs/view/world/physicsmanager.hpp | 8 ++--- apps/opencs/view/world/physicssystem.cpp | 38 +++++++++++--------- apps/opencs/view/world/physicssystem.hpp | 13 +++---- 6 files changed, 54 insertions(+), 37 deletions(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 5f6b6b46a4..c4fd668843 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -16,6 +16,7 @@ #include "../world/vartypedelegate.hpp" #include "../world/recordstatusdelegate.hpp" #include "../world/idtypedelegate.hpp" +#include "../world/physicsmanager.hpp" #include "../../model/settings/usersettings.hpp" @@ -218,6 +219,7 @@ void CSVDoc::ViewManager::removeDocAndView (CSMDoc::Document *document) mDocumentManager.removeDocument(document); (*iter)->deleteLater(); mViews.erase (iter); + CSVWorld::PhysicsManager::instance()->removeDocument(document); updateIndices(); return; diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 448153d372..fd6a23e2bb 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -927,8 +927,7 @@ void CSVRender::WorldspaceWidget::placeObject(const std::string sceneNode, const // FIXME: adjustRigidBody() seems to lose objects, work around by deleting and recreating objects //mPhysics->moveObject(sceneNode, pos, xr*yr*zr); - std::string mesh = mPhysics->sceneNodeToMesh(sceneNode); - mPhysics->replaceObject(mesh, sceneNode, refId, cellref.mScale, pos, xr*yr*zr); + mPhysics->replaceObject(sceneNode, refId, cellref.mScale, pos, xr*yr*zr); // update all SceneWidgets and their SceneManagers updateSceneWidgets(); diff --git a/apps/opencs/view/world/physicsmanager.cpp b/apps/opencs/view/world/physicsmanager.cpp index ce71ac3150..e6ee51da77 100644 --- a/apps/opencs/view/world/physicsmanager.cpp +++ b/apps/opencs/view/world/physicsmanager.cpp @@ -34,11 +34,28 @@ namespace CSVWorld std::map >::iterator iter = mSceneWidgets.find(doc); if(iter == mSceneWidgets.end()) { - mSceneWidgets[doc] = std::list {}; // zero elements + mSceneWidgets[doc] = std::list (); // zero elements mPhysics[doc] = new PhysicsSystem(); } } + // destroy physics, called from CSVDoc::ViewManager + void PhysicsManager::removeDocument(CSMDoc::Document *doc) + { + std::map::iterator iter = mPhysics.find(doc); + if(iter != mPhysics.end()) + { + delete iter->second; + mPhysics.erase(iter); + } + + std::map >::iterator it = mSceneWidgets.find(doc); + if(it != mSceneWidgets.end()) + { + mSceneWidgets.erase(it); + } + } + // called from CSVRender::WorldspaceWidget() to get widgets' association with Document& PhysicsSystem *PhysicsManager::addSceneWidget(CSMDoc::Document &doc, CSVRender::WorldspaceWidget *widget) { @@ -72,12 +89,8 @@ namespace CSVWorld { (*iter).second.erase(itWidget); - if((*iter).second.empty()) // last one for the document - { - delete mPhysics[(*iter).first]; - mPhysics.erase((*iter).first); - mSceneWidgets.erase(iter); - } + //if((*iter).second.empty()) // last one for the document + // NOTE: do not delete physics until the document itself is closed break; } diff --git a/apps/opencs/view/world/physicsmanager.hpp b/apps/opencs/view/world/physicsmanager.hpp index 7bcd5d39de..e17c9ac84a 100644 --- a/apps/opencs/view/world/physicsmanager.hpp +++ b/apps/opencs/view/world/physicsmanager.hpp @@ -31,7 +31,6 @@ namespace CSVWorld { static PhysicsManager *mPhysicsManagerInstance; - //std::map mSceneManagers; std::map > mSceneWidgets; std::map mPhysics; @@ -43,15 +42,12 @@ namespace CSVWorld static PhysicsManager *instance(); void setupPhysics(CSMDoc::Document *); -#if 0 - void addSceneManager(CSVRender::SceneWidget *sceneWidget, Ogre::SceneManager *sceneMgr); - - void removeSceneManager(CSVRender::SceneWidget *sceneWidget); -#endif PhysicsSystem *addSceneWidget(CSMDoc::Document &doc, CSVRender::WorldspaceWidget *widget); void removeSceneWidget(CSVRender::WorldspaceWidget *widget); + + void removeDocument(CSMDoc::Document *doc); }; } diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 3203679069..5776c32e93 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -25,10 +25,10 @@ namespace CSVWorld delete mEngine; } - // FIXME: looks up the scene manager based on the scene node name (highly inefficient) + // looks up the scene manager based on the scene node name (inefficient) // NOTE: referenceId is assumed to be unique per document - // NOTE: searching is done here rather than after rayTest, so slower to load but - // faster to find (not verified w/ perf test) + // NOTE: searching is done here rather than after rayTest, hence slower to load but + // faster to find (guessing, not verified w/ perf test) void PhysicsSystem::addObject(const std::string &mesh, const std::string &sceneNodeName, const std::string &referenceId, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) @@ -48,7 +48,12 @@ namespace CSVWorld } if(!foundSceneManager) - return; // FIXME: should this be an exception + { + std::cerr << "Attempt to add an object without a corresponding SceneManager: " + + referenceId + " : " + sceneNodeName << std::endl; + + return; + } // update physics, only one physics model per referenceId if(mEngine->getRigidBody(referenceId, true) == NULL) @@ -61,7 +66,7 @@ namespace CSVWorld placeable); // update other scene managers if they have the referenceId (may have moved) - // FIXME: this bit not needed if object has not moved + // NOTE: this part is not needed if object has not moved iter = mSceneManagers.begin(); for(; iter != mSceneManagers.end(); ++iter) { @@ -99,7 +104,12 @@ namespace CSVWorld } if(!sceneManager) - return; // FIXME: maybe this should be an exception + { + std::cerr << "Attempt to remove an object without a corresponding SceneManager: " + + sceneNodeName << std::endl; + + return; + } // illustration: erase the object "K" from the object map // @@ -123,7 +133,7 @@ namespace CSVWorld } } - // should the physics model be deleted? + // check whether the physics model be deleted if(force || mRefIdToSceneNode.find(referenceId) == mRefIdToSceneNode.end()) { mEngine->removeRigidBody(referenceId); @@ -132,10 +142,11 @@ namespace CSVWorld } } - void PhysicsSystem::replaceObject(const std::string &mesh, - const std::string &sceneNodeName, const std::string &referenceId, float scale, - const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) + void PhysicsSystem::replaceObject(const std::string &sceneNodeName, + const std::string &referenceId, float scale, const Ogre::Vector3 &position, + const Ogre::Quaternion &rotation, bool placeable) { + std::string mesh = mSceneNodeToMesh[sceneNodeName]; removeObject(sceneNodeName, true); // force delete addObject(mesh, sceneNodeName, referenceId, scale, position, rotation, placeable); } @@ -259,11 +270,6 @@ namespace CSVWorld return mSceneNodeToRefId[sceneNodeName]; } - std::string PhysicsSystem::sceneNodeToMesh(std::string sceneNodeName) - { - return mSceneNodeToMesh[sceneNodeName]; - } - void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget * sceneWidget) { mSceneManagers.push_back(sceneMgr); @@ -293,7 +299,7 @@ namespace CSVWorld { // FIXME: should check if sceneMgr is in the list if(!sceneMgr) - return; // FIXME: maybe this should be an exception + return; mEngine->setSceneManager(sceneMgr); diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 8fadf6c8ad..1c2acc6b90 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -42,7 +42,9 @@ namespace CSVWorld PhysicsSystem(); ~PhysicsSystem(); + void addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget * scene); + void removeSceneManager(Ogre::SceneManager *sceneMgr); void addObject(const std::string &mesh, @@ -52,10 +54,9 @@ namespace CSVWorld void removeObject(const std::string &sceneNodeName, bool force = false); - void replaceObject(const std::string &mesh, - const std::string &sceneNodeName, const std::string &referenceId, float scale, - const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - bool placeable=false); + void replaceObject(const std::string &sceneNodeName, + const std::string &referenceId, float scale, const Ogre::Vector3 &position, + const Ogre::Quaternion &rotation, bool placeable=false); void moveObject(const std::string &sceneNodeName, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation); @@ -75,8 +76,7 @@ namespace CSVWorld std::string sceneNodeToRefId(std::string sceneNodeName); - std::string sceneNodeToMesh(std::string sceneNodeName); - + // for multi-scene manager per physics engine std::map sceneWidgets(); private: @@ -85,6 +85,7 @@ namespace CSVWorld const std::string referenceId, const Ogre::Vector3 &position); void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); + std::string refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr); }; } From 998982b16a98ac4a92227936d5e02f37500ead54 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sat, 1 Nov 2014 21:04:53 +1100 Subject: [PATCH 40/56] Keep physics engines until physics code is moved out of OEngine. --- apps/opencs/view/world/physicssystem.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 5776c32e93..f4f4617718 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -22,7 +22,10 @@ namespace CSVWorld PhysicsSystem::~PhysicsSystem() { - delete mEngine; + // FIXME: OEngine does not behave well when multiple instances are created + // and deleted, sometimes resulting in crashes. Skip the deletion until the physics + // code is moved out of OEngine. + //delete mEngine; } // looks up the scene manager based on the scene node name (inefficient) From 8b4651f0556be383ffcd46de61a51804c1ab3a66 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 2 Nov 2014 08:22:27 +1100 Subject: [PATCH 41/56] Move mouse related functions and states out of WorldspaceWidget. --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/settings/usersettings.cpp | 16 + apps/opencs/view/render/mousestate.cpp | 648 +++++++++++++++++++ apps/opencs/view/render/mousestate.hpp | 82 +++ apps/opencs/view/render/worldspacewidget.cpp | 588 +---------------- apps/opencs/view/render/worldspacewidget.hpp | 34 +- 6 files changed, 763 insertions(+), 607 deletions(-) create mode 100644 apps/opencs/view/render/mousestate.cpp create mode 100644 apps/opencs/view/render/mousestate.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 30e9203f5f..ec6f802cfa 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -82,7 +82,7 @@ opencs_units (view/render opencs_units_noqt (view/render navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight - lightingbright object cell terrainstorage textoverlay overlaymask overlaysystem + lightingbright object cell terrainstorage textoverlay overlaymask overlaysystem mousestate ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 7dac660c35..1ecd39db0e 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -161,6 +161,22 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() ritd->setDeclaredValues (values); } + declareSection ("debug", "Debug Options"); + { + Setting *mousePicking = createSetting (Type_CheckBox, "mouse-picking", "Debug Render Mouse-Picking"); + mousePicking->setDefaultValue ("false"); + mousePicking->setToolTip ("Enable redering debug information for mouse picking. " + "This option may be removed in future once the mouse picking feature is completed."); + + QString defaultValue = "Closer/Further"; + QStringList values = QStringList() << defaultValue << "Up/Down" << "Left/Right"; + + Setting *mouseWheel = createSetting (Type_RadioButton, "mouse-wheel", + "For testing mouse movement directions."); + mouseWheel->setDefaultValue (defaultValue); + mouseWheel->setDeclaredValues (values); + } + declareSection ("table-input", "Table Input"); { QString inPlaceEdit ("Edit in Place"); diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp new file mode 100644 index 0000000000..059fab2a53 --- /dev/null +++ b/apps/opencs/view/render/mousestate.cpp @@ -0,0 +1,648 @@ +#include "mousestate.hpp" + +#include +#include +#include + +#include +#include // FIXME: for debugging +#include // FIXME: for debugging +#include // FIXME: for debugging + +#include +#include + +#include "../../model/settings/usersettings.hpp" +#include "../world/physicssystem.hpp" + +#include "elements.hpp" // FIXME: for debugging +#include "worldspacewidget.hpp" + +namespace +{ + // FIXME: this section should be removed once the debugging is completed + void showHitPoint(Ogre::SceneManager *sceneMgr, std::string name, Ogre::Vector3 point) + { + if(sceneMgr->hasManualObject("manual" + name)) + sceneMgr->destroyManualObject("manual" + name); + Ogre::ManualObject* manual = sceneMgr->createManualObject("manual" + name); + manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); + manual-> position(point.x, point.y, point.z-100); + manual-> position(point.x, point.y, point.z+100); + manual-> position(point.x, point.y-100, point.z); + manual-> position(point.x, point.y+100, point.z); + manual-> position(point.x-100, point.y, point.z); + manual-> position(point.x+100, point.y, point.z); + manual->end(); + sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); + } + + void removeHitPoint(Ogre::SceneManager *sceneMgr, std::string name) + { + if(sceneMgr->hasManualObject("manual" + name)) + sceneMgr->destroyManualObject("manual" + name); + } + + void initDebug() + { + // material for visual cue on selected objects + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTrans"); + if(texture.isNull()) + { + texture = Ogre::TextureManager::getSingleton().createManual( + "DynamicTrans", // name + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, // type + 8, 8, // width & height + 0, // number of mipmaps + Ogre::PF_BYTE_BGRA, // pixel format + Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for + // textures updated very often (e.g. each frame) + + Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); + pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); + const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); + + uint8_t* pDest = static_cast(pixelBox.data); + + // Fill in some pixel data. This will give a semi-transparent colour, + // but this is of course dependent on the chosen pixel format. + for (size_t j = 0; j < 8; j++) + { + for(size_t i = 0; i < 8; i++) + { + *pDest++ = 255; // B + *pDest++ = 255; // G + *pDest++ = 127; // R + *pDest++ = 63; // A + } + + pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format); + } + pixelBuffer->unlock(); + } + Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName( + "TransMaterial"); + if(material.isNull()) + { + Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create( + "TransMaterial", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); + Ogre::Pass *pass = material->getTechnique( 0 )->getPass( 0 ); + pass->setLightingEnabled( false ); + pass->setDepthWriteEnabled( false ); + pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); + + Ogre::TextureUnitState *tex = pass->createTextureUnitState("CustomState", 0); + tex->setTextureName("DynamicTrans"); + tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC ); + material->load(); + } + } + + //plane Z, upvector Y, mOffset z : x-y plane, wheel up/down + //plane Y, upvector X, mOffset y : y-z plane, wheel left/right + //plane X, upvector Y, mOffset x : x-z plane, wheel closer/further + std::pair planeAxis() + { + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + QString wheelDir = userSettings.setting("debug/mouse-wheel", QString("Closer/Further")); + if(wheelDir == "Up/Down") + return std::make_pair(Ogre::Vector3::UNIT_Z, Ogre::Vector3::UNIT_Y); + else if(wheelDir == "Left/Right") + return std::make_pair(Ogre::Vector3::UNIT_Y, Ogre::Vector3::UNIT_X); + else + return std::make_pair(Ogre::Vector3::UNIT_X, Ogre::Vector3::UNIT_Y); + } +} + +namespace CSVRender +{ + // mouse picking + // FIXME: need to virtualise mouse buttons + // + // State machine: + // + // [default] mousePressEvent->check if the mouse is pointing at an object + // if yes, create collision planes then go to [grab] + // else check for terrain + // + // [grab] mouseReleaseEvent->if same button and new obj, go to [edit] + // mouseMoveEvent->if same button, go to [drag] + // other mouse events or buttons, go back to [default] (i.e. like 'cancel') + // + // [drag] mouseReleaseEvent->if same button, place the object at the new + // location, update the document then go to [edit] + // mouseMoveEvent->update position to the user based on ray to the collision + // planes and render the object at the new location, but do not update + // the document yet + // + // [edit] TODO, probably fine positional adjustments or rotations; clone/delete? + // + // + // press press (obj) + // [default] --------> [grab] <-------------------- [edit] + // ^ (obj) | | ------> [drag] -----> ^ + // | | | move ^ | release | + // | | | | | | + // | | | +-+ | + // | | | move | + // +----------------+ +--------------------------+ + // release release + // (same obj) (new obj) + // + // + + MouseState::MouseState(WorldspaceWidget *parent) + : mParent(parent), mPhysics(parent->getPhysics()), mSceneManager(parent->getSceneManager()) + , mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) + , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) + , mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f) + { + initDebug(); + + mMouseEventTimer = new QElapsedTimer(); + mMouseEventTimer->invalidate(); + + std::pair planeRes = planeAxis(); + mPlane = new Ogre::Plane(planeRes.first, 0); + 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 + planeRes.second // upVector + ); + } + + MouseState::~MouseState () + { + delete mMouseEventTimer; + + // For debugging only + std::map >::iterator iter = mSelectedEntities.begin(); + for(;iter != mSelectedEntities.end(); ++iter) + { + removeHitPoint(mSceneManager, iter->first); + + if(mSceneManager->hasSceneNode(iter->first)) + { + Ogre::SceneNode *scene = mSceneManager->getSceneNode(iter->first); + + if(scene) + { + scene->removeAndDestroyAllChildren(); + mSceneManager->destroySceneNode(iter->first); + } + } + } + + delete mPlane; + } + + void MouseState::mouseMoveEvent (QMouseEvent *event) + { + switch(mMouseState) + { + case Mouse_Grab: + { + // check if min elapsed time to stop false detection of drag + if(!mMouseEventTimer->isValid() || !mMouseEventTimer->hasExpired(100)) // ms + break; + + mMouseEventTimer->invalidate(); + mMouseState = Mouse_Drag; + + /* FALL_THROUGH */ + } + case Mouse_Drag: + { + if(event->pos() != mOldPos) // TODO: maybe don't update less than a quantum? + { + mOldPos = event->pos(); + + // ray test against the plane to provide feedback to the user the + // relative movement of the object on the x-y plane + std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); + if(planeResult.first) + { + if(mGrabbedSceneNode != "") + { + std::pair planeRes = planeAxis(); + Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset; + //pos.z += mOffset; + mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+planeResult.second-mOrigMousePos); + mCurrentMousePos = planeResult.second; + mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+planeResult.second-mOrigMousePos); + updateSceneWidgets(); + } + } + } + break; + } + case Mouse_Edit: + case Mouse_Default: + { + break; // error event, ignore + } + /* NO_DEFAULT_CASE */ + } + } + + void MouseState::mousePressEvent (QMouseEvent *event) + { + switch(mMouseState) + { + case Mouse_Grab: + case Mouse_Drag: + { + if(0 /*event->buttons() & ~Qt::RightButton*/) + { + // cancel operation & return the object to the original position + placeObject(mGrabbedSceneNode, mOrigObjPos); + mMouseState = Mouse_Default; + + // reset states + mCurrentMousePos = Ogre::Vector3(); + mOrigMousePos = Ogre::Vector3(); + mOrigObjPos = Ogre::Vector3(); + mGrabbedSceneNode = ""; + mCurrentObj = ""; + mOldPos = QPoint(0, 0); + mMouseEventTimer->invalidate(); + mOffset = 0.0f; + } + break; + } + case Mouse_Edit: + case Mouse_Default: + { + if(event->buttons() & Qt::RightButton) + { + std::pair result = objectUnderCursor(event->x(), event->y()); + if(result.first == "") + break; + + mGrabbedSceneNode = result.first; + // ray test agaist the plane to get a starting position of the + // mouse in relation to the object position + //mPlane->redefine(Ogre::Vector3::UNIT_Z, result.second); + std::pair planeRes = planeAxis(); + mPlane->redefine(planeRes.first, result.second); + std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); + if(planeResult.first) + { + mOrigMousePos = planeResult.second; + mCurrentMousePos = planeResult.second; + mOffset = 0.0f; + } + + mOrigObjPos = mSceneManager->getSceneNode(mGrabbedSceneNode)->getPosition(); + mMouseEventTimer->start(); + + mMouseState = Mouse_Grab; + } + break; + } + /* NO_DEFAULT_CASE */ + } + } + + void MouseState::mouseReleaseEvent (QMouseEvent *event) + { + switch(mMouseState) + { + case Mouse_Grab: + { + std::pair result = objectUnderCursor(event->x(), event->y()); + if(result.first != "") + { + if(result.first == mCurrentObj) + { + // unselect object + mMouseState = Mouse_Default; + mCurrentObj = ""; + } + else + { + // select object + mMouseState = Mouse_Edit; + mCurrentObj = result.first; + + // print some debug info + if(isDebug()) + { + std::string referenceId = mPhysics->sceneNodeToRefId(result.first); + std::cout << "ReferenceId: " << referenceId << std::endl; + const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); + int index = references.searchId(referenceId); + if (index != -1) + { + int columnIndex = + references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); + std::cout << " index: " + QString::number(index).toStdString() + +", column index: " + QString::number(columnIndex).toStdString() + << std::endl; + } + } + } + // update highlighting the current object + if(isDebug()) + updateSelectionHighlight(result.first, result.second); + } + break; + } + case Mouse_Drag: + { + // final placement + std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); + if(planeResult.first) + { + if(mGrabbedSceneNode != "") + { + std::pair planeRes = planeAxis(); + //mOrigObjPos.z += mOffset; + Ogre::Vector3 pos = mOrigObjPos+planeRes.first*mOffset+planeResult.second-mOrigMousePos; + placeObject(mGrabbedSceneNode, pos); + //mCurrentObj = mGrabbedSceneNode; // FIXME + mCurrentObj = ""; // whether the object is selected + + // 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 + // on screen + + // FIXME: update document + // FIXME: highlight current object? + mMouseState = Mouse_Edit; + } + } + break; + } + case Mouse_Edit: + case Mouse_Default: + { + // probably terrain, check + std::pair result = terrainUnderCursor(event->x(), event->y()); + if(result.first != "") + { + if(isDebug()) + { + std::cout << "terrain: " << 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; + } + /* NO_DEFAULT_CASE */ + } + mMouseEventTimer->invalidate(); + } + + void MouseState::mouseDoubleClickEvent (QMouseEvent *event) + { + if(0 && isDebug()) // disable + { + // FIXME: OEngine::PhysicEngine creates only one child scene node for the + // debug drawer. Hence only the first subview that creates the debug drawer + // can view the debug lines. Will need to keep a map in OEngine if multiple + // subviews are to be supported. + mPhysics->addSceneManager(mSceneManager, mParent); + mPhysics->toggleDebugRendering(mSceneManager); + mParent->flagAsModified(); + } + } + + bool MouseState::wheelEvent (QWheelEvent *event) + { + switch(mMouseState) + { + case Mouse_Grab: + mMouseState = Mouse_Drag; + + /* FALL_THROUGH */ + case Mouse_Drag: + { + // move the object along the z axis 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? + + std::pair planeRes = planeAxis(); + Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset; + //pos.z += mOffset; + mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+mCurrentMousePos-mOrigMousePos); + mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+mCurrentMousePos-mOrigMousePos); + updateSceneWidgets(); + } + break; + } + case Mouse_Edit: + case Mouse_Default: + { + return false; + } + /* NO_DEFAULT_CASE */ + } + + return true; + } + + std::pair MouseState::mousePositionOnPlane(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 + getCamera()->setNearClipDistance(10.0f); // arbitrary number + Ogre::Ray mouseRay = getCamera()->getCameraToViewportRay( + (float) pos.x() / getViewport()->getActualWidth(), + (float) pos.y() / getViewport()->getActualHeight()); + getCamera()->setNearClipDistance(nearClipDistance); // restore + std::pair planeResult = mouseRay.intersects(plane); + + if(planeResult.first) + return std::make_pair(true, mouseRay.getPoint(planeResult.second)); + else + return std::make_pair(false, Ogre::Vector3()); // should only happen if the plane is too small + } + + std::pair MouseState::terrainUnderCursor(const int mouseX, const int mouseY) + { + if(!getViewport()) + return std::make_pair("", Ogre::Vector3()); + + float x = (float) mouseX / getViewport()->getActualWidth(); + float y = (float) mouseY / getViewport()->getActualHeight(); + + std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); + if(result.first != "") + { + // 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()); + } + + std::pair MouseState::objectUnderCursor(const int mouseX, const int mouseY) + { + if(!getViewport()) + return std::make_pair("", Ogre::Vector3()); + + float x = (float) mouseX / getViewport()->getActualWidth(); + float y = (float) mouseY / getViewport()->getActualHeight(); + + std::pair result = mPhysics->castRay(x, y, mSceneManager, getCamera()); + if(result.first != "") + { + // NOTE: anything not terrain is assumed to be an object + 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); + + if(!ignoreObjects && mSceneManager->hasSceneNode(result.first)) + { + return result; + } + } + } + + return std::make_pair("", Ogre::Vector3()); + } + + // FIXME: for debugging only + void MouseState::updateSelectionHighlight(const std::string sceneNode, const Ogre::Vector3 &position) + { + uint32_t visibilityMask = getViewport()->getVisibilityMask(); + bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); + + if(ignoreObjects || !mSceneManager->hasSceneNode(sceneNode) || !isDebug()) + return; + + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + bool debugCursor = userSettings.setting( + "debug/mouse-position", QString("false")) == "true" ? true : false; + + //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character + Ogre::SceneNode *scene = mSceneManager->getSceneNode(sceneNode); + std::map >::iterator iter = + mSelectedEntities.find(sceneNode); + if(iter != mSelectedEntities.end()) // currently selected + { + std::vector clonedEntities = mSelectedEntities[sceneNode]; + while(!clonedEntities.empty()) + { + if(mSceneManager->hasEntity(clonedEntities.back())) + { + scene->detachObject(clonedEntities.back()); + mSceneManager->destroyEntity(clonedEntities.back()); + } + clonedEntities.pop_back(); + } + mSelectedEntities.erase(iter); + + if(debugCursor) + removeHitPoint(mSceneManager, sceneNode); + } + else + { + std::vector clonedEntities; + Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); + iter.begin(); + while(iter.hasMoreElements()) + { + Ogre::MovableObject * element = iter.getNext(); + if(!element) + break; + + if(element->getMovableType() != "Entity") + continue; + + Ogre::Entity * entity = dynamic_cast(element); + if(mSceneManager->hasEntity(entity->getName()+"cover")) + { + // FIXME: this shouldn't really happen... but does :( + scene->detachObject(entity->getName()+"cover"); + mSceneManager->destroyEntity(entity->getName()+"cover"); + } + Ogre::Entity * clone = entity->clone(entity->getName()+"cover"); + + Ogre::MaterialPtr mat = + Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); + if(!mat.isNull()) + { + clone->setMaterial(mat); + scene->attachObject(clone); + clonedEntities.push_back(entity->getName()+"cover"); + } + } + mSelectedEntities[sceneNode] = clonedEntities; + + if(debugCursor) + showHitPoint(mSceneManager, sceneNode, position); + } + mParent->flagAsModified(); + } + + void MouseState::placeObject(const std::string sceneNode, const Ogre::Vector3 &pos) + { + mSceneManager->getSceneNode(sceneNode)->setPosition(pos); + + // update physics + std::string refId = mPhysics->sceneNodeToRefId(sceneNode); + const CSMWorld::CellRef& cellref = mParent->mDocument.getData().getReferences().getRecord (refId).get(); + Ogre::Quaternion xr (Ogre::Radian (-cellref.mPos.rot[0]), Ogre::Vector3::UNIT_X); + Ogre::Quaternion yr (Ogre::Radian (-cellref.mPos.rot[1]), Ogre::Vector3::UNIT_Y); + Ogre::Quaternion zr (Ogre::Radian (-cellref.mPos.rot[2]), Ogre::Vector3::UNIT_Z); + + // FIXME: adjustRigidBody() seems to lose objects, work around by deleting and recreating objects + //mPhysics->moveObject(sceneNode, pos, xr*yr*zr); + mPhysics->replaceObject(sceneNode, refId, cellref.mScale, pos, xr*yr*zr); + + // update all SceneWidgets and their SceneManagers + updateSceneWidgets(); + } + + void MouseState::updateSceneWidgets() + { + std::map sceneWidgets = mPhysics->sceneWidgets(); + + std::map::iterator iter = sceneWidgets.begin(); + for(; iter != sceneWidgets.end(); ++iter) + { + (*iter).second->updateScene(); + } + } + + Ogre::Camera *MouseState::getCamera() + { + return mParent->getCamera(); + } + + Ogre::Viewport *MouseState::getViewport() + { + return mParent->getCamera()->getViewport(); + } + + bool MouseState::isDebug() + { + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + + return userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false; + } +} diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp new file mode 100644 index 0000000000..e7eedf1d48 --- /dev/null +++ b/apps/opencs/view/render/mousestate.hpp @@ -0,0 +1,82 @@ +#ifndef OPENCS_VIEW_MOUSESTATE_H +#define OPENCS_VIEW_MOUSESTATE_H + +#include +#include +#include + +class QElapsedTimer; +class QMouseEvent; +class QWheelEvent; + +namespace Ogre +{ + class Plane; + class SceneManager; + class Camera; + class Viewport; +} + +namespace CSVWorld +{ + class PhysicsSystem; +} + +namespace CSVRender +{ + class WorldspaceWidget; + + class MouseState + { + enum MouseStates + { + Mouse_Grab, + Mouse_Drag, + Mouse_Edit, + Mouse_Default + }; + MouseStates mMouseState; + + WorldspaceWidget *mParent; + CSVWorld::PhysicsSystem *mPhysics; // local copy + Ogre::SceneManager *mSceneManager; // local copy + + QPoint mOldPos; + std::string mCurrentObj; + std::string mGrabbedSceneNode; + QElapsedTimer *mMouseEventTimer; + Ogre::Plane *mPlane; + Ogre::Vector3 mOrigObjPos; + Ogre::Vector3 mOrigMousePos; + Ogre::Vector3 mCurrentMousePos; + float mOffset; + + std::map > mSelectedEntities; + + public: + + MouseState(WorldspaceWidget *parent); + ~MouseState(); + + void mouseMoveEvent (QMouseEvent *event); + void mousePressEvent (QMouseEvent *event); + void mouseReleaseEvent (QMouseEvent *event); + void mouseDoubleClickEvent (QMouseEvent *event); + bool wheelEvent (QWheelEvent *event); + + private: + + std::pair mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane); + void placeObject(const std::string sceneNode, const Ogre::Vector3 &pos); + std::pair terrainUnderCursor(const int mouseX, const int mouseY); + std::pair objectUnderCursor(const int mouseX, const int mouseY); + void updateSelectionHighlight(const std::string sceneNode, const Ogre::Vector3 &position); + void updateSceneWidgets(); + bool isDebug(); + + Ogre::Camera *getCamera(); // friend access + Ogre::Viewport *getViewport(); // friend access + }; +} + +#endif // OPENCS_VIEW_MOUSESTATE_H diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index fd6a23e2bb..0503d4d63e 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -7,18 +7,10 @@ #include #include -#include -#include // FIXME: for debugging -#include // FIXME: for debugging -#include // FIXME: for debugging - -#include -#include #include #include "../../model/world/universalid.hpp" #include "../../model/world/idtable.hpp" -#include "../../model/settings/usersettings.hpp" #include "../widget/scenetoolmode.hpp" #include "../widget/scenetooltoggle.hpp" @@ -27,96 +19,11 @@ #include "../world/physicsmanager.hpp" #include "../world/physicssystem.hpp" +#include "mousestate.hpp" #include "elements.hpp" -namespace -{ - // FIXME: this section should be removed once the debugging is completed - void showHitPoint(Ogre::SceneManager *sceneMgr, std::string name, Ogre::Vector3 point) - { - if(sceneMgr->hasManualObject("manual" + name)) - sceneMgr->destroyManualObject("manual" + name); - Ogre::ManualObject* manual = sceneMgr->createManualObject("manual" + name); - manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); - manual-> position(point.x, point.y, point.z-100); - manual-> position(point.x, point.y, point.z+100); - manual-> position(point.x, point.y-100, point.z); - manual-> position(point.x, point.y+100, point.z); - manual-> position(point.x-100, point.y, point.z); - manual-> position(point.x+100, point.y, point.z); - manual->end(); - sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); - } - - void removeHitPoint(Ogre::SceneManager *sceneMgr, std::string name) - { - if(sceneMgr->hasManualObject("manual" + name)) - sceneMgr->destroyManualObject("manual" + name); - } - - void initDebug() - { - // material for visual cue on selected objects - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTrans"); - if(texture.isNull()) - { - texture = Ogre::TextureManager::getSingleton().createManual( - "DynamicTrans", // name - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, // type - 8, 8, // width & height - 0, // number of mipmaps - Ogre::PF_BYTE_BGRA, // pixel format - Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for - // textures updated very often (e.g. each frame) - - Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); - pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); - const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); - - uint8_t* pDest = static_cast(pixelBox.data); - - // Fill in some pixel data. This will give a semi-transparent colour, - // but this is of course dependent on the chosen pixel format. - for (size_t j = 0; j < 8; j++) - { - for(size_t i = 0; i < 8; i++) - { - *pDest++ = 255; // B - *pDest++ = 255; // G - *pDest++ = 127; // R - *pDest++ = 63; // A - } - - pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format); - } - pixelBuffer->unlock(); - } - Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName( - "TransMaterial"); - if(material.isNull()) - { - Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create( - "TransMaterial", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); - Ogre::Pass *pass = material->getTechnique( 0 )->getPass( 0 ); - pass->setLightingEnabled( false ); - pass->setDepthWriteEnabled( false ); - pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); - - Ogre::TextureUnitState *tex = pass->createTextureUnitState("CustomState", 0); - tex->setTextureName("DynamicTrans"); - tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC ); - material->load(); - } - } -} - CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), - mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0), - mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()), - mCurrentMousePos(Ogre::Vector3()), mZOffset(0.0f) +: SceneWidget (parent), mDocument(document), mSceneElements(0), mRun(0), mPhysics(0), mMouse(0) { setAcceptDrops(true); @@ -148,53 +55,18 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int))); - // associate WorldSpaceWidgets (and their SceneManagers with Documents, then create physics if new document + // associate WorldSpaceWidgets (and their SceneManagers) with Documents + // then create physics if there is a new document mPhysics = CSVWorld::PhysicsManager::instance()->addSceneWidget(document, this); mPhysics->addSceneManager(getSceneManager(), this); - - initDebug(); - mMouseEventTimer = new QElapsedTimer(); - mMouseEventTimer->invalidate(); - - mPlane = new Ogre::Plane(Ogre::Vector3::UNIT_Z, 0); - Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().createPlane("ground", - 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 - Ogre::Vector3::UNIT_Y // upVector - ); + mMouse = new MouseState(this); } CSVRender::WorldspaceWidget::~WorldspaceWidget () { + delete mMouse; mPhysics->removeSceneManager(getSceneManager()); CSVWorld::PhysicsManager::instance()->removeSceneWidget(this); - - delete mMouseEventTimer; - - // For debugging only - std::map >::iterator iter = mSelectedEntities.begin(); - for(;iter != mSelectedEntities.end(); ++iter) - { - removeHitPoint(getSceneManager(), iter->first); - - if(getSceneManager()->hasSceneNode(iter->first)) - { - Ogre::SceneNode *scene = getSceneManager()->getSceneNode(iter->first); - - if(scene) - { - scene->removeAndDestroyAllChildren(); - getSceneManager()->destroySceneNode(iter->first); - } - } - } - - delete mPlane; } void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) @@ -471,147 +343,18 @@ CSVWorld::PhysicsSystem *CSVRender::WorldspaceWidget::getPhysics() return mPhysics; } -// mouse picking -// FIXME: need to virtualise mouse buttons -// -// State machine: -// -// [default] mousePressEvent->check if the mouse is pointing at an object -// if yes, create collision planes then go to [grab] -// else check for terrain -// -// [grab] mouseReleaseEvent->if same button and new obj, go to [edit] -// mouseMoveEvent->if same button, go to [drag] -// other mouse events or buttons, go back to [default] (i.e. like 'cancel') -// -// [drag] mouseReleaseEvent->if same button, place the object at the new -// location, update the document then go to [edit] -// mouseMoveEvent->update position to the user based on ray to the collision -// planes and render the object at the new location, but do not update -// the document yet -// -// [edit] TODO, probably fine positional adjustments or rotations; clone/delete? -// -// -// press press (obj) -// [default] --------> [grab] <-------------------- [edit] -// ^ (obj) | | ------> [drag] -----> ^ -// | | | move ^ | release | -// | | | | | | -// | | | +-+ | -// | | | move | -// +----------------+ +--------------------------+ -// release release -// (same obj) (new obj) -// -// void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) { if(event->buttons() & Qt::RightButton) { - switch(mMouseState) - { - case Mouse_Grab: - { - // check if min elapsed time to stop false detection of drag - if(!mMouseEventTimer->isValid() || !mMouseEventTimer->hasExpired(100)) // ms - break; - - mMouseEventTimer->invalidate(); - mMouseState = Mouse_Drag; - - /* FALL_THROUGH */ - } - case Mouse_Drag: - { - if(event->pos() != mOldPos) // TODO: maybe don't update less than a quantum? - { - mOldPos = event->pos(); - - // ray test against the plane to provide feedback to the user the - // relative movement of the object on the x-y plane - std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); - if(planeResult.first) - { - if(mGrabbedSceneNode != "") - { - Ogre::Vector3 pos = mOrigObjPos; - pos.z += mZOffset; - getSceneManager()->getSceneNode(mGrabbedSceneNode)->setPosition(pos+planeResult.second-mOrigMousePos); - mCurrentMousePos = planeResult.second; - mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+planeResult.second-mOrigMousePos); - updateSceneWidgets(); - } - } - } - break; - } - case Mouse_Edit: - case Mouse_Default: - { - break; // error event, ignore - } - /* NO_DEFAULT_CASE */ - } + mMouse->mouseMoveEvent(event); } SceneWidget::mouseMoveEvent(event); } void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { - switch(mMouseState) - { - case Mouse_Grab: - case Mouse_Drag: - { - if(0 /*event->buttons() & ~Qt::RightButton*/) - { - // cancel operation & return the object to the original position - placeObject(mGrabbedSceneNode, mOrigObjPos); - mMouseState = Mouse_Default; - - // reset states - mCurrentMousePos = Ogre::Vector3(); - mOrigMousePos = Ogre::Vector3(); - mOrigObjPos = Ogre::Vector3(); - mGrabbedSceneNode = ""; - mCurrentObj = ""; - mOldPos = QPoint(0, 0); - mMouseEventTimer->invalidate(); - mZOffset = 0.0f; - } - break; - } - case Mouse_Edit: - case Mouse_Default: - { - if(event->buttons() & Qt::RightButton) - { - std::pair result = objectUnderCursor(event->x(), event->y()); - if(result.first == "") - break; - - mGrabbedSceneNode = result.first; - // ray test agaist the plane to get a starting position of the - // mouse in relation to the object position - mPlane->redefine(Ogre::Vector3::UNIT_Z, result.second); - std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); - if(planeResult.first) - { - mOrigMousePos = planeResult.second; - mCurrentMousePos = planeResult.second; - mZOffset = 0.0f; - } - - mOrigObjPos = getSceneManager()->getSceneNode(mGrabbedSceneNode)->getPosition(); - mMouseEventTimer->start(); - - mMouseState = Mouse_Grab; - } - break; - } - /* NO_DEFAULT_CASE */ - } + mMouse->mousePressEvent(event); //SceneWidget::mousePressEvent(event); } @@ -619,104 +362,12 @@ void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) { if(event->button() == Qt::RightButton) { - if(!getCamera()->getViewport()) + if(!getViewport()) { SceneWidget::mouseReleaseEvent(event); return; } - - switch(mMouseState) - { - case Mouse_Grab: - { - std::pair result = objectUnderCursor(event->x(), event->y()); - if(result.first != "") - { - if(result.first == mCurrentObj) - { - // unselect object - mMouseState = Mouse_Default; - mCurrentObj = ""; - } - else - { - // select object - mMouseState = Mouse_Edit; - mCurrentObj = result.first; - - // print some debug info - if(isDebug()) - { - std::string referenceId = mPhysics->sceneNodeToRefId(result.first); - std::cout << "ReferenceId: " << referenceId << std::endl; - const CSMWorld::RefCollection& references = mDocument.getData().getReferences(); - int index = references.searchId(referenceId); - if (index != -1) - { - int columnIndex = - references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); - std::cout << " index: " + QString::number(index).toStdString() - +", column index: " + QString::number(columnIndex).toStdString() - << std::endl; - } - } - } - // update highlighting the current object - if(isDebug()) - updateSelectionHighlight(result.first, result.second); - } - break; - } - case Mouse_Drag: - { - // final placement - std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); - if(planeResult.first) - { - if(mGrabbedSceneNode != "") - { - mOrigObjPos.z += mZOffset; - Ogre::Vector3 pos = mOrigObjPos+planeResult.second-mOrigMousePos; - placeObject(mGrabbedSceneNode, pos); - //mCurrentObj = mGrabbedSceneNode; // FIXME - mCurrentObj = ""; // whether the object is selected - - // 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 - mZOffset = 0.0f; // used for z-axis movement - mOldPos = QPoint(0, 0); // to calculate relative movement of mouse - // on screen - - // FIXME: update document - // FIXME: highlight current object? - mMouseState = Mouse_Edit; - } - } - break; - } - case Mouse_Edit: - case Mouse_Default: - { - // probably terrain, check - std::pair result = terrainUnderCursor(event->x(), event->y()); - if(result.first != "") - { - if(isDebug()) - { - std::cout << "terrain: " << 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; - } - /* NO_DEFAULT_CASE */ - } - mMouseEventTimer->invalidate(); + mMouse->mouseReleaseEvent(event); } SceneWidget::mouseReleaseEvent(event); } @@ -725,226 +376,13 @@ void CSVRender::WorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) { if(event->button() == Qt::RightButton) { - if(isDebug()) - { - // FIXME: OEngine::PhysicEngine creates only one child scene node for the - // debug drawer. Hence only the first subview that creates the debug drawer - // can view the debug lines. Will need to keep a map in OEngine if multiple - // subviews are to be supported. - //mPhysics->setSceneManager(getSceneManager()); - mPhysics->toggleDebugRendering(getSceneManager()); - flagAsModified(); - } + mMouse->mouseDoubleClickEvent(event); } //SceneWidget::mouseDoubleClickEvent(event); } void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) { - switch(mMouseState) - { - case Mouse_Grab: - mMouseState = Mouse_Drag; - - /* FALL_THROUGH */ - case Mouse_Drag: - { - // move the object along the z axis during Mouse_Drag or Mouse_Grab - if (event->delta()) - { - // seems positive is up and negative is down - mZOffset += (event->delta()/5); // FIXME: arbitrary number, make config option? - - Ogre::Vector3 pos = mOrigObjPos; - pos.z += mZOffset; - getSceneManager()->getSceneNode(mGrabbedSceneNode)->setPosition(pos+mCurrentMousePos-mOrigMousePos); - mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+mCurrentMousePos-mOrigMousePos); - updateSceneWidgets(); - } - break; - } - case Mouse_Edit: - case Mouse_Default: - { - SceneWidget::wheelEvent(event); - break; - } - /* NO_DEFAULT_CASE */ - } -} - -// FIXME: for debugging only -void CSVRender::WorldspaceWidget::updateSelectionHighlight(const std::string sceneNode, const Ogre::Vector3 &position) -{ - uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - - if(ignoreObjects || !getSceneManager()->hasSceneNode(sceneNode) || !isDebug()) - return; - - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debugCursor = userSettings.setting( - "debug/mouse-position", QString("false")) == "true" ? true : false; - - //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character - Ogre::SceneNode *scene = getSceneManager()->getSceneNode(sceneNode); - std::map >::iterator iter = - mSelectedEntities.find(sceneNode); - if(iter != mSelectedEntities.end()) // currently selected - { - std::vector clonedEntities = mSelectedEntities[sceneNode]; - while(!clonedEntities.empty()) - { - if(getSceneManager()->hasEntity(clonedEntities.back())) - { - scene->detachObject(clonedEntities.back()); - getSceneManager()->destroyEntity(clonedEntities.back()); - } - clonedEntities.pop_back(); - } - mSelectedEntities.erase(iter); - - if(debugCursor) - removeHitPoint(getSceneManager(), sceneNode); - } - else - { - std::vector clonedEntities; - Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); - iter.begin(); - while(iter.hasMoreElements()) - { - Ogre::MovableObject * element = iter.getNext(); - if(!element) - break; - - if(element->getMovableType() != "Entity") - continue; - - Ogre::Entity * entity = dynamic_cast(element); - if(getSceneManager()->hasEntity(entity->getName()+"cover")) - { - // FIXME: this shouldn't really happen... but does :( - scene->detachObject(entity->getName()+"cover"); - getSceneManager()->destroyEntity(entity->getName()+"cover"); - } - Ogre::Entity * clone = entity->clone(entity->getName()+"cover"); - - Ogre::MaterialPtr mat = - Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); - if(!mat.isNull()) - { - clone->setMaterial(mat); - scene->attachObject(clone); - clonedEntities.push_back(entity->getName()+"cover"); - } - } - mSelectedEntities[sceneNode] = clonedEntities; - - if(debugCursor) - showHitPoint(getSceneManager(), sceneNode, position); - } - flagAsModified(); -} - -std::pair CSVRender::WorldspaceWidget::terrainUnderCursor(const int mouseX, const int mouseY) -{ - if(!getCamera()->getViewport()) - return std::make_pair("", Ogre::Vector3()); - - float x = (float) mouseX / getCamera()->getViewport()->getActualWidth(); - float y = (float) mouseY / getCamera()->getViewport()->getActualHeight(); - - std::pair result = mPhysics->castRay(x, y, getSceneManager(), getCamera()); - 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()); -} - -std::pair CSVRender::WorldspaceWidget::objectUnderCursor(const int mouseX, const int mouseY) -{ - if(!getCamera()->getViewport()) - return std::make_pair("", Ogre::Vector3()); - - float x = (float) mouseX / getCamera()->getViewport()->getActualWidth(); - float y = (float) mouseY / getCamera()->getViewport()->getActualHeight(); - - std::pair result = mPhysics->castRay(x, y, getSceneManager(), getCamera()); - if(result.first != "") - { - // NOTE: anything not terrain is assumed to be an object - QString name = QString(result.first.c_str()); - if(!name.contains(QRegExp("^HeightField"))) - { - uint32_t visibilityMask = getCamera()->getViewport()->getVisibilityMask(); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - - if(!ignoreObjects && getSceneManager()->hasSceneNode(result.first)) - { - return result; - } - } - } - - return std::make_pair("", Ogre::Vector3()); -} - -std::pair CSVRender::WorldspaceWidget::mousePositionOnPlane(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 - getCamera()->setNearClipDistance(10.0f); // arbitrary number - Ogre::Ray mouseRay = getCamera()->getCameraToViewportRay( - (float) pos.x() / getCamera()->getViewport()->getActualWidth(), - (float) pos.y() / getCamera()->getViewport()->getActualHeight()); - getCamera()->setNearClipDistance(nearClipDistance); // restore - std::pair planeResult = mouseRay.intersects(plane); - - if(planeResult.first) - return std::make_pair(true, mouseRay.getPoint(planeResult.second)); - else - return std::make_pair(false, Ogre::Vector3()); // should only happen if the plane is too small -} - -void CSVRender::WorldspaceWidget::placeObject(const std::string sceneNode, const Ogre::Vector3 &pos) -{ - getSceneManager()->getSceneNode(sceneNode)->setPosition(pos); - - // update physics - std::string refId = mPhysics->sceneNodeToRefId(sceneNode); - const CSMWorld::CellRef& cellref = mDocument.getData().getReferences().getRecord (refId).get(); - Ogre::Quaternion xr (Ogre::Radian (-cellref.mPos.rot[0]), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yr (Ogre::Radian (-cellref.mPos.rot[1]), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zr (Ogre::Radian (-cellref.mPos.rot[2]), Ogre::Vector3::UNIT_Z); - - // FIXME: adjustRigidBody() seems to lose objects, work around by deleting and recreating objects - //mPhysics->moveObject(sceneNode, pos, xr*yr*zr); - mPhysics->replaceObject(sceneNode, refId, cellref.mScale, pos, xr*yr*zr); - - // update all SceneWidgets and their SceneManagers - updateSceneWidgets(); -} - -void CSVRender::WorldspaceWidget::updateSceneWidgets() -{ - std::map sceneWidgets = mPhysics->sceneWidgets(); - - std::map::iterator iter = sceneWidgets.begin(); - for(; iter != sceneWidgets.end(); ++iter) - { - (*iter).second->updateScene(); - } -} - -bool CSVRender::WorldspaceWidget::isDebug() -{ - return false; + if(!mMouse->wheelEvent(event)) + SceneWidget::wheelEvent(event); } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 431a023be9..2dfe2b8710 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -27,12 +27,12 @@ namespace CSVWorld class PhysicsSystem; } -class QElapsedTimer; - namespace CSVRender { class WorldspaceWidget : public SceneWidget { + friend class MouseState; + Q_OBJECT CSVRender::Navigation1st m1st; @@ -42,26 +42,7 @@ namespace CSVRender CSVWidget::SceneToolRun *mRun; CSMDoc::Document& mDocument; CSVWorld::PhysicsSystem *mPhysics; - - enum MouseState - { - Mouse_Grab, - Mouse_Drag, - Mouse_Edit, - Mouse_Default - }; - MouseState mMouseState; - - QPoint mOldPos; - std::string mCurrentObj; - std::string mGrabbedSceneNode; - QElapsedTimer *mMouseEventTimer; - Ogre::Plane *mPlane; - Ogre::Vector3 mOrigObjPos; - Ogre::Vector3 mOrigMousePos; - Ogre::Vector3 mCurrentMousePos; - float mZOffset; - std::map > mSelectedEntities; + MouseState *mMouse; public: @@ -138,15 +119,6 @@ namespace CSVRender virtual std::string getStartupInstruction() = 0; - void placeObject(const std::string sceneNode, const Ogre::Vector3 &pos); - std::pair terrainUnderCursor(const int mouseX, const int mouseY); - std::pair objectUnderCursor(const int mouseX, const int mouseY); - std::pair mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane); - void updateSelectionHighlight(const std::string sceneNode, const Ogre::Vector3 &position); - - void updateSceneWidgets(); - bool isDebug(); - private slots: void selectNavigationMode (const std::string& mode); From 89bb616cbc532857b4951a32bddd5d8ec2b44ec5 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 2 Nov 2014 08:33:32 +1100 Subject: [PATCH 42/56] Remove debugging code. --- apps/opencs/view/render/mousestate.cpp | 181 ------------------------- 1 file changed, 181 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 059fab2a53..9c087fd59c 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -20,86 +20,6 @@ namespace { - // FIXME: this section should be removed once the debugging is completed - void showHitPoint(Ogre::SceneManager *sceneMgr, std::string name, Ogre::Vector3 point) - { - if(sceneMgr->hasManualObject("manual" + name)) - sceneMgr->destroyManualObject("manual" + name); - Ogre::ManualObject* manual = sceneMgr->createManualObject("manual" + name); - manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); - manual-> position(point.x, point.y, point.z-100); - manual-> position(point.x, point.y, point.z+100); - manual-> position(point.x, point.y-100, point.z); - manual-> position(point.x, point.y+100, point.z); - manual-> position(point.x-100, point.y, point.z); - manual-> position(point.x+100, point.y, point.z); - manual->end(); - sceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); - } - - void removeHitPoint(Ogre::SceneManager *sceneMgr, std::string name) - { - if(sceneMgr->hasManualObject("manual" + name)) - sceneMgr->destroyManualObject("manual" + name); - } - - void initDebug() - { - // material for visual cue on selected objects - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTrans"); - if(texture.isNull()) - { - texture = Ogre::TextureManager::getSingleton().createManual( - "DynamicTrans", // name - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, // type - 8, 8, // width & height - 0, // number of mipmaps - Ogre::PF_BYTE_BGRA, // pixel format - Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for - // textures updated very often (e.g. each frame) - - Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); - pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); - const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); - - uint8_t* pDest = static_cast(pixelBox.data); - - // Fill in some pixel data. This will give a semi-transparent colour, - // but this is of course dependent on the chosen pixel format. - for (size_t j = 0; j < 8; j++) - { - for(size_t i = 0; i < 8; i++) - { - *pDest++ = 255; // B - *pDest++ = 255; // G - *pDest++ = 127; // R - *pDest++ = 63; // A - } - - pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format); - } - pixelBuffer->unlock(); - } - Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName( - "TransMaterial"); - if(material.isNull()) - { - Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create( - "TransMaterial", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); - Ogre::Pass *pass = material->getTechnique( 0 )->getPass( 0 ); - pass->setLightingEnabled( false ); - pass->setDepthWriteEnabled( false ); - pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); - - Ogre::TextureUnitState *tex = pass->createTextureUnitState("CustomState", 0); - tex->setTextureName("DynamicTrans"); - tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC ); - material->load(); - } - } - //plane Z, upvector Y, mOffset z : x-y plane, wheel up/down //plane Y, upvector X, mOffset y : y-z plane, wheel left/right //plane X, upvector Y, mOffset x : x-z plane, wheel closer/further @@ -159,8 +79,6 @@ namespace CSVRender , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) , mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f) { - initDebug(); - mMouseEventTimer = new QElapsedTimer(); mMouseEventTimer->invalidate(); @@ -181,25 +99,6 @@ namespace CSVRender MouseState::~MouseState () { delete mMouseEventTimer; - - // For debugging only - std::map >::iterator iter = mSelectedEntities.begin(); - for(;iter != mSelectedEntities.end(); ++iter) - { - removeHitPoint(mSceneManager, iter->first); - - if(mSceneManager->hasSceneNode(iter->first)) - { - Ogre::SceneNode *scene = mSceneManager->getSceneNode(iter->first); - - if(scene) - { - scene->removeAndDestroyAllChildren(); - mSceneManager->destroySceneNode(iter->first); - } - } - } - delete mPlane; } @@ -233,7 +132,6 @@ namespace CSVRender { std::pair planeRes = planeAxis(); Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset; - //pos.z += mOffset; mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+planeResult.second-mOrigMousePos); mCurrentMousePos = planeResult.second; mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+planeResult.second-mOrigMousePos); @@ -349,9 +247,6 @@ namespace CSVRender } } } - // update highlighting the current object - if(isDebug()) - updateSelectionHighlight(result.first, result.second); } break; } @@ -364,7 +259,6 @@ namespace CSVRender if(mGrabbedSceneNode != "") { std::pair planeRes = planeAxis(); - //mOrigObjPos.z += mOffset; Ogre::Vector3 pos = mOrigObjPos+planeRes.first*mOffset+planeResult.second-mOrigMousePos; placeObject(mGrabbedSceneNode, pos); //mCurrentObj = mGrabbedSceneNode; // FIXME @@ -440,7 +334,6 @@ namespace CSVRender std::pair planeRes = planeAxis(); Ogre::Vector3 pos = mOrigObjPos + planeRes.first*mOffset; - //pos.z += mOffset; mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(pos+mCurrentMousePos-mOrigMousePos); mPhysics->moveSceneNodes(mGrabbedSceneNode, pos+mCurrentMousePos-mOrigMousePos); updateSceneWidgets(); @@ -525,80 +418,6 @@ namespace CSVRender return std::make_pair("", Ogre::Vector3()); } - // FIXME: for debugging only - void MouseState::updateSelectionHighlight(const std::string sceneNode, const Ogre::Vector3 &position) - { - uint32_t visibilityMask = getViewport()->getVisibilityMask(); - bool ignoreObjects = !(visibilityMask & (uint32_t)CSVRender::Element_Reference); - - if(ignoreObjects || !mSceneManager->hasSceneNode(sceneNode) || !isDebug()) - return; - - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - bool debugCursor = userSettings.setting( - "debug/mouse-position", QString("false")) == "true" ? true : false; - - //TODO: Try http://www.ogre3d.org/tikiwiki/Create+outline+around+a+character - Ogre::SceneNode *scene = mSceneManager->getSceneNode(sceneNode); - std::map >::iterator iter = - mSelectedEntities.find(sceneNode); - if(iter != mSelectedEntities.end()) // currently selected - { - std::vector clonedEntities = mSelectedEntities[sceneNode]; - while(!clonedEntities.empty()) - { - if(mSceneManager->hasEntity(clonedEntities.back())) - { - scene->detachObject(clonedEntities.back()); - mSceneManager->destroyEntity(clonedEntities.back()); - } - clonedEntities.pop_back(); - } - mSelectedEntities.erase(iter); - - if(debugCursor) - removeHitPoint(mSceneManager, sceneNode); - } - else - { - std::vector clonedEntities; - Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); - iter.begin(); - while(iter.hasMoreElements()) - { - Ogre::MovableObject * element = iter.getNext(); - if(!element) - break; - - if(element->getMovableType() != "Entity") - continue; - - Ogre::Entity * entity = dynamic_cast(element); - if(mSceneManager->hasEntity(entity->getName()+"cover")) - { - // FIXME: this shouldn't really happen... but does :( - scene->detachObject(entity->getName()+"cover"); - mSceneManager->destroyEntity(entity->getName()+"cover"); - } - Ogre::Entity * clone = entity->clone(entity->getName()+"cover"); - - Ogre::MaterialPtr mat = - Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); - if(!mat.isNull()) - { - clone->setMaterial(mat); - scene->attachObject(clone); - clonedEntities.push_back(entity->getName()+"cover"); - } - } - mSelectedEntities[sceneNode] = clonedEntities; - - if(debugCursor) - showHitPoint(mSceneManager, sceneNode, position); - } - mParent->flagAsModified(); - } - void MouseState::placeObject(const std::string sceneNode, const Ogre::Vector3 &pos) { mSceneManager->getSceneNode(sceneNode)->setPosition(pos); From a21958d0075e2013c5fdf335b181850f2455db1a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 2 Nov 2014 10:30:44 +1100 Subject: [PATCH 43/56] Add option to move the mouse against the screen frame of reference. --- apps/opencs/model/settings/usersettings.cpp | 8 +++ apps/opencs/view/render/mousestate.cpp | 57 ++++++++++++--------- apps/opencs/view/render/mousestate.hpp | 1 + 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 1ecd39db0e..26c6aa5d6a 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -175,6 +175,14 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() "For testing mouse movement directions."); mouseWheel->setDefaultValue (defaultValue); mouseWheel->setDeclaredValues (values); + + defaultValue = "screen"; + values = QStringList() << defaultValue << "world"; + + Setting *mouseCoord = createSetting (Type_RadioButton, "mouse-reference", + "For testing mouse movement frame of reference."); + mouseCoord->setDefaultValue (defaultValue); + mouseCoord->setDeclaredValues (values); } declareSection ("table-input", "Table Input"); diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 9c087fd59c..5c5279b7a6 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -3,11 +3,7 @@ #include #include #include - #include -#include // FIXME: for debugging -#include // FIXME: for debugging -#include // FIXME: for debugging #include #include @@ -15,27 +11,9 @@ #include "../../model/settings/usersettings.hpp" #include "../world/physicssystem.hpp" -#include "elements.hpp" // FIXME: for debugging +#include "elements.hpp" #include "worldspacewidget.hpp" -namespace -{ - //plane Z, upvector Y, mOffset z : x-y plane, wheel up/down - //plane Y, upvector X, mOffset y : y-z plane, wheel left/right - //plane X, upvector Y, mOffset x : x-z plane, wheel closer/further - std::pair planeAxis() - { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - QString wheelDir = userSettings.setting("debug/mouse-wheel", QString("Closer/Further")); - if(wheelDir == "Up/Down") - return std::make_pair(Ogre::Vector3::UNIT_Z, Ogre::Vector3::UNIT_Y); - else if(wheelDir == "Left/Right") - return std::make_pair(Ogre::Vector3::UNIT_Y, Ogre::Vector3::UNIT_X); - else - return std::make_pair(Ogre::Vector3::UNIT_X, Ogre::Vector3::UNIT_Y); - } -} - namespace CSVRender { // mouse picking @@ -187,7 +165,6 @@ namespace CSVRender mGrabbedSceneNode = result.first; // ray test agaist the plane to get a starting position of the // mouse in relation to the object position - //mPlane->redefine(Ogre::Vector3::UNIT_Z, result.second); std::pair planeRes = planeAxis(); mPlane->redefine(planeRes.first, result.second); std::pair planeResult = mousePositionOnPlane(event->pos(), *mPlane); @@ -351,6 +328,38 @@ namespace CSVRender return true; } + //plane Z, upvector Y, mOffset z : x-y plane, wheel up/down + //plane Y, upvector X, mOffset y : y-z plane, wheel left/right + //plane X, upvector Y, mOffset x : x-z plane, wheel closer/further + std::pair MouseState::planeAxis() + { + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + QString coord = userSettings.setting("debug/mouse-reference", QString("screen")); + + QString wheelDir = userSettings.setting("debug/mouse-wheel", QString("Closer/Further")); + if(wheelDir == "Left/Right") + { + if(coord == "world") + return std::make_pair(Ogre::Vector3::UNIT_Y, Ogre::Vector3::UNIT_X); + else + return std::make_pair(getCamera()->getDerivedRight(), getCamera()->getDerivedDirection()); + } + else if(wheelDir == "Up/Down") + { + if(coord == "world") + return std::make_pair(Ogre::Vector3::UNIT_Z, Ogre::Vector3::UNIT_Y); + else + return std::make_pair(getCamera()->getDerivedUp(), getCamera()->getDerivedRight()); + } + else + { + if(coord == "world") + return std::make_pair(Ogre::Vector3::UNIT_X, Ogre::Vector3::UNIT_Y); + else + return std::make_pair(getCamera()->getDerivedDirection(), getCamera()->getDerivedRight()); + } + } + std::pair MouseState::mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane) { // using a really small value seems to mess up with the projections diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp index e7eedf1d48..498752db0a 100644 --- a/apps/opencs/view/render/mousestate.hpp +++ b/apps/opencs/view/render/mousestate.hpp @@ -71,6 +71,7 @@ namespace CSVRender std::pair terrainUnderCursor(const int mouseX, const int mouseY); std::pair objectUnderCursor(const int mouseX, const int mouseY); void updateSelectionHighlight(const std::string sceneNode, const Ogre::Vector3 &position); + std::pair planeAxis(); void updateSceneWidgets(); bool isDebug(); From 1eed180a5cf4633b0390cf16a30602b9fea5651a Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 2 Nov 2014 11:41:11 +1100 Subject: [PATCH 44/56] Fix Gcc/MSVC differences with friend class. Invert camera derived direction. --- apps/opencs/view/render/mousestate.cpp | 5 +++-- apps/opencs/view/render/worldspacewidget.cpp | 1 - apps/opencs/view/render/worldspacewidget.hpp | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 5c5279b7a6..90ca522c1c 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -335,6 +335,7 @@ namespace CSVRender { CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); QString coord = userSettings.setting("debug/mouse-reference", QString("screen")); + Ogre::Vector3 derived = getCamera()->getDerivedDirection(); QString wheelDir = userSettings.setting("debug/mouse-wheel", QString("Closer/Further")); if(wheelDir == "Left/Right") @@ -342,7 +343,7 @@ namespace CSVRender if(coord == "world") return std::make_pair(Ogre::Vector3::UNIT_Y, Ogre::Vector3::UNIT_X); else - return std::make_pair(getCamera()->getDerivedRight(), getCamera()->getDerivedDirection()); + return std::make_pair(getCamera()->getDerivedRight(), Ogre::Vector3(-derived.x, -derived.y, -derived.z)); } else if(wheelDir == "Up/Down") { @@ -356,7 +357,7 @@ namespace CSVRender if(coord == "world") return std::make_pair(Ogre::Vector3::UNIT_X, Ogre::Vector3::UNIT_Y); else - return std::make_pair(getCamera()->getDerivedDirection(), getCamera()->getDerivedRight()); + return std::make_pair(Ogre::Vector3(-derived.x, -derived.y, -derived.z), getCamera()->getDerivedRight()); } } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 0503d4d63e..ee119c939d 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -19,7 +19,6 @@ #include "../world/physicsmanager.hpp" #include "../world/physicssystem.hpp" -#include "mousestate.hpp" #include "elements.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 2dfe2b8710..40799d86a9 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -2,6 +2,7 @@ #define OPENCS_VIEW_WORLDSPACEWIDGET_H #include "scenewidget.hpp" +#include "mousestate.hpp" #include "navigation1st.hpp" #include "navigationfree.hpp" From e174428cc544576cd39b67afbae8031cc74d7998 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 2 Nov 2014 15:03:26 +1100 Subject: [PATCH 45/56] Minor tweaks. --- apps/opencs/view/render/mousestate.cpp | 40 +++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 90ca522c1c..ff9c0fe1b3 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -207,21 +207,21 @@ namespace CSVRender mMouseState = Mouse_Edit; mCurrentObj = result.first; - // print some debug info - if(isDebug()) + } + // print some debug info + if(isDebug()) + { + std::string referenceId = mPhysics->sceneNodeToRefId(result.first); + std::cout << "ReferenceId: " << referenceId << std::endl; + const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); + int index = references.searchId(referenceId); + if (index != -1) { - std::string referenceId = mPhysics->sceneNodeToRefId(result.first); - std::cout << "ReferenceId: " << referenceId << std::endl; - const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); - int index = references.searchId(referenceId); - if (index != -1) - { - int columnIndex = - references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); - std::cout << " index: " + QString::number(index).toStdString() - +", column index: " + QString::number(columnIndex).toStdString() - << std::endl; - } + int columnIndex = + references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); + std::cout << " index: " + QString::number(index).toStdString() + +", column index: " + QString::number(columnIndex).toStdString() + << std::endl; } } } @@ -335,29 +335,29 @@ namespace CSVRender { CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); QString coord = userSettings.setting("debug/mouse-reference", QString("screen")); - Ogre::Vector3 derived = getCamera()->getDerivedDirection(); + Ogre::Vector3 dir = getCamera()->getDerivedDirection(); QString wheelDir = userSettings.setting("debug/mouse-wheel", QString("Closer/Further")); if(wheelDir == "Left/Right") { if(coord == "world") - return std::make_pair(Ogre::Vector3::UNIT_Y, Ogre::Vector3::UNIT_X); + return std::make_pair(Ogre::Vector3::UNIT_Y, Ogre::Vector3::UNIT_Z); else - return std::make_pair(getCamera()->getDerivedRight(), Ogre::Vector3(-derived.x, -derived.y, -derived.z)); + return std::make_pair(getCamera()->getDerivedRight(), getCamera()->getDerivedUp()); } else if(wheelDir == "Up/Down") { if(coord == "world") - return std::make_pair(Ogre::Vector3::UNIT_Z, Ogre::Vector3::UNIT_Y); + return std::make_pair(Ogre::Vector3::UNIT_Z, Ogre::Vector3::UNIT_X); else - return std::make_pair(getCamera()->getDerivedUp(), getCamera()->getDerivedRight()); + return std::make_pair(getCamera()->getDerivedUp(), Ogre::Vector3(-dir.x, -dir.y, -dir.z)); } else { if(coord == "world") return std::make_pair(Ogre::Vector3::UNIT_X, Ogre::Vector3::UNIT_Y); else - return std::make_pair(Ogre::Vector3(-derived.x, -derived.y, -derived.z), getCamera()->getDerivedRight()); + return std::make_pair(Ogre::Vector3(-dir.x, -dir.y, -dir.z), getCamera()->getDerivedRight()); } } From 7f54dab6efa228098aaafb499d1940e91f991880 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 2 Nov 2014 15:34:45 +1100 Subject: [PATCH 46/56] Fix issue where objects were sometimes unresponsive after dragging. --- apps/opencs/view/render/mousestate.cpp | 2 +- apps/opencs/view/world/physicssystem.cpp | 36 ++++++++++++++++++++---- apps/opencs/view/world/physicssystem.hpp | 4 +-- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index ff9c0fe1b3..b9d6cc325e 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -441,7 +441,7 @@ namespace CSVRender // FIXME: adjustRigidBody() seems to lose objects, work around by deleting and recreating objects //mPhysics->moveObject(sceneNode, pos, xr*yr*zr); - mPhysics->replaceObject(sceneNode, refId, cellref.mScale, pos, xr*yr*zr); + mPhysics->replaceObject(sceneNode, cellref.mScale, pos, xr*yr*zr); // update all SceneWidgets and their SceneManagers updateSceneWidgets(); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index f4f4617718..ce4e74000f 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -85,7 +85,7 @@ namespace CSVWorld // normal delete (e.g closing a scene subview) // TODO: should think about using some kind of reference counting within RigidBody - void PhysicsSystem::removeObject(const std::string &sceneNodeName, bool force) + void PhysicsSystem::removeObject(const std::string &sceneNodeName) { std::string referenceId = mSceneNodeToRefId[sceneNodeName]; @@ -137,7 +137,7 @@ namespace CSVWorld } // check whether the physics model be deleted - if(force || mRefIdToSceneNode.find(referenceId) == mRefIdToSceneNode.end()) + if(mRefIdToSceneNode.find(referenceId) == mRefIdToSceneNode.end()) { mEngine->removeRigidBody(referenceId); mEngine->deleteRigidBody(referenceId); @@ -146,12 +146,38 @@ namespace CSVWorld } void PhysicsSystem::replaceObject(const std::string &sceneNodeName, - const std::string &referenceId, float scale, const Ogre::Vector3 &position, + float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) { + std::string referenceId = mSceneNodeToRefId[sceneNodeName]; std::string mesh = mSceneNodeToMesh[sceneNodeName]; - removeObject(sceneNodeName, true); // force delete - addObject(mesh, sceneNodeName, referenceId, scale, position, rotation, placeable); + + if(referenceId != "") + { + // delete the physics object + mEngine->removeRigidBody(referenceId); + mEngine->deleteRigidBody(referenceId); + + // create the physics object + mEngine->createAndAdjustRigidBody(mesh, + referenceId, scale, position, rotation, + 0, // scaledBoxTranslation + 0, // boxRotation + true, // raycasting + placeable); + + // update other scene managers if they have the referenceId + std::list::const_iterator iter = mSceneManagers.begin(); + for(; iter != mSceneManagers.end(); ++iter) + { + std::string name = refIdToSceneNode(referenceId, *iter); + if(name != sceneNodeName && (*iter)->hasSceneNode(name)) + { + // FIXME: rotation or scale not updated + (*iter)->getSceneNode(name)->setPosition(position); + } + } + } } void PhysicsSystem::moveObject(const std::string &sceneNodeName, diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 1c2acc6b90..e443941ea0 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -52,10 +52,10 @@ namespace CSVWorld const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable=false); - void removeObject(const std::string &sceneNodeName, bool force = false); + void removeObject(const std::string &sceneNodeName); void replaceObject(const std::string &sceneNodeName, - const std::string &referenceId, float scale, const Ogre::Vector3 &position, + float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable=false); void moveObject(const std::string &sceneNodeName, From 49d416353e203ec5e91ba7d70aad80b6324060d1 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 2 Nov 2014 17:56:28 +1100 Subject: [PATCH 47/56] Remove a redundant list. --- apps/opencs/view/render/mousestate.cpp | 1 + apps/opencs/view/world/physicsmanager.cpp | 1 - apps/opencs/view/world/physicssystem.cpp | 63 ++++++----------------- apps/opencs/view/world/physicssystem.hpp | 2 - 4 files changed, 16 insertions(+), 51 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index b9d6cc325e..5603daeb86 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -333,6 +333,7 @@ namespace CSVRender //plane X, upvector Y, mOffset x : x-z plane, wheel closer/further std::pair MouseState::planeAxis() { + // FIXME: explore using signals instread of retrieving each time CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); QString coord = userSettings.setting("debug/mouse-reference", QString("screen")); Ogre::Vector3 dir = getCamera()->getDerivedDirection(); diff --git a/apps/opencs/view/world/physicsmanager.cpp b/apps/opencs/view/world/physicsmanager.cpp index e6ee51da77..f8e022e5df 100644 --- a/apps/opencs/view/world/physicsmanager.cpp +++ b/apps/opencs/view/world/physicsmanager.cpp @@ -74,7 +74,6 @@ namespace CSVWorld throw std::runtime_error("No physics system found for the given document."); } - // delete physics when the last scene widget for the document is closed void PhysicsManager::removeSceneWidget(CSVRender::WorldspaceWidget *widget) { CSVRender::SceneWidget *sceneWidget = static_cast(widget); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index ce4e74000f..7c8a28b523 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -37,13 +37,13 @@ namespace CSVWorld const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) { bool foundSceneManager = false; - std::list::const_iterator iter = mSceneManagers.begin(); - for(; iter != mSceneManagers.end(); ++iter) + std::map::const_iterator iter = mSceneWidgets.begin(); + for(; iter != mSceneWidgets.end(); ++iter) { - if((*iter)->hasSceneNode(sceneNodeName)) + if((*iter).first->hasSceneNode(sceneNodeName)) { mSceneNodeToRefId[sceneNodeName] = referenceId; - mRefIdToSceneNode[referenceId][*iter] = sceneNodeName; + mRefIdToSceneNode[referenceId][(*iter).first] = sceneNodeName; mSceneNodeToMesh[sceneNodeName] = mesh; foundSceneManager = true; break; @@ -54,7 +54,6 @@ namespace CSVWorld { std::cerr << "Attempt to add an object without a corresponding SceneManager: " + referenceId + " : " + sceneNodeName << std::endl; - return; } @@ -67,19 +66,6 @@ namespace CSVWorld 0, // boxRotation true, // raycasting placeable); - - // update other scene managers if they have the referenceId (may have moved) - // NOTE: this part is not needed if object has not moved - iter = mSceneManagers.begin(); - for(; iter != mSceneManagers.end(); ++iter) - { - std::string name = refIdToSceneNode(referenceId, *iter); - if(name != sceneNodeName && (*iter)->hasSceneNode(name)) - { - // FIXME: rotation or scale not updated - (*iter)->getSceneNode(name)->setPosition(position); - } - } } } @@ -96,12 +82,12 @@ namespace CSVWorld // find which SceneManager has this object Ogre::SceneManager *sceneManager = NULL; - std::list::const_iterator iter = mSceneManagers.begin(); - for(; iter != mSceneManagers.end(); ++iter) + std::map::const_iterator iter = mSceneWidgets.begin(); + for(; iter != mSceneWidgets.end(); ++iter) { - if((*iter)->hasSceneNode(sceneNodeName)) + if((*iter).first->hasSceneNode(sceneNodeName)) { - sceneManager = *iter; + sceneManager = (*iter).first; break; } } @@ -110,7 +96,6 @@ namespace CSVWorld { std::cerr << "Attempt to remove an object without a corresponding SceneManager: " + sceneNodeName << std::endl; - return; } @@ -167,16 +152,8 @@ namespace CSVWorld placeable); // update other scene managers if they have the referenceId - std::list::const_iterator iter = mSceneManagers.begin(); - for(; iter != mSceneManagers.end(); ++iter) - { - std::string name = refIdToSceneNode(referenceId, *iter); - if(name != sceneNodeName && (*iter)->hasSceneNode(name)) - { - // FIXME: rotation or scale not updated - (*iter)->getSceneNode(name)->setPosition(position); - } - } + // FIXME: rotation or scale not updated + moveSceneNodeImpl(sceneNodeName, referenceId, position); } } @@ -190,13 +167,13 @@ namespace CSVWorld void PhysicsSystem::moveSceneNodeImpl(const std::string sceneNodeName, const std::string referenceId, const Ogre::Vector3 &position) { - std::list::const_iterator iter = mSceneManagers.begin(); - for(; iter != mSceneManagers.end(); ++iter) + std::map::const_iterator iter = mSceneWidgets.begin(); + for(; iter != mSceneWidgets.end(); ++iter) { - std::string name = refIdToSceneNode(referenceId, *iter); - if(name != sceneNodeName && (*iter)->hasSceneNode(name)) + std::string name = refIdToSceneNode(referenceId, (*iter).first); + if(name != sceneNodeName && (*iter).first->hasSceneNode(name)) { - (*iter)->getSceneNode(name)->setPosition(position); + (*iter).first->getSceneNode(name)->setPosition(position); } } } @@ -301,7 +278,6 @@ namespace CSVWorld void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget * sceneWidget) { - mSceneManagers.push_back(sceneMgr); mSceneWidgets[sceneMgr] = sceneWidget; } @@ -312,15 +288,6 @@ namespace CSVWorld void PhysicsSystem::removeSceneManager(Ogre::SceneManager *sceneMgr) { - std::list::iterator iter = mSceneManagers.begin(); - for(; iter != mSceneManagers.end(); ++iter) - { - if(*iter == sceneMgr) - { - mSceneManagers.erase(iter); - break; - } - } mSceneWidgets.erase(sceneMgr); } diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index e443941ea0..7b53956b2d 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -3,7 +3,6 @@ #include #include -#include namespace Ogre { @@ -33,7 +32,6 @@ namespace CSVWorld std::map mSceneNodeToRefId; std::map > mRefIdToSceneNode; std::map mSceneNodeToMesh; - std::list mSceneManagers; std::map mSceneWidgets; OEngine::Physic::PhysicEngine* mEngine; std::multimap mTerrain; From 3796240b19db5ac5a83952d73c8ab3f3086ed6ec Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 2 Nov 2014 18:13:25 +1100 Subject: [PATCH 48/56] Refactor duplicate code sections. --- apps/opencs/view/world/physicssystem.cpp | 66 +++++++++++------------- apps/opencs/view/world/physicssystem.hpp | 2 + 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 7c8a28b523..1f41dcb8cd 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -36,21 +36,15 @@ namespace CSVWorld const std::string &sceneNodeName, const std::string &referenceId, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) { - bool foundSceneManager = false; - std::map::const_iterator iter = mSceneWidgets.begin(); - for(; iter != mSceneWidgets.end(); ++iter) + Ogre::SceneManager *sceneManager = findSceneManager(sceneNodeName); + if(sceneManager) { - if((*iter).first->hasSceneNode(sceneNodeName)) - { - mSceneNodeToRefId[sceneNodeName] = referenceId; - mRefIdToSceneNode[referenceId][(*iter).first] = sceneNodeName; - mSceneNodeToMesh[sceneNodeName] = mesh; - foundSceneManager = true; - break; - } + // update maps + mSceneNodeToRefId[sceneNodeName] = referenceId; + mSceneNodeToMesh[sceneNodeName] = mesh; + mRefIdToSceneNode[referenceId][sceneManager] = sceneNodeName; } - - if(!foundSceneManager) + else { std::cerr << "Attempt to add an object without a corresponding SceneManager: " + referenceId + " : " + sceneNodeName << std::endl; @@ -81,17 +75,7 @@ namespace CSVWorld mSceneNodeToMesh.erase(sceneNodeName); // find which SceneManager has this object - Ogre::SceneManager *sceneManager = NULL; - std::map::const_iterator iter = mSceneWidgets.begin(); - for(; iter != mSceneWidgets.end(); ++iter) - { - if((*iter).first->hasSceneNode(sceneNodeName)) - { - sceneManager = (*iter).first; - break; - } - } - + Ogre::SceneManager *sceneManager = findSceneManager(sceneNodeName); if(!sceneManager) { std::cerr << "Attempt to remove an object without a corresponding SceneManager: " @@ -121,7 +105,7 @@ namespace CSVWorld } } - // check whether the physics model be deleted + // check whether the physics model should be deleted if(mRefIdToSceneNode.find(referenceId) == mRefIdToSceneNode.end()) { mEngine->removeRigidBody(referenceId); @@ -130,9 +114,8 @@ namespace CSVWorld } } - void PhysicsSystem::replaceObject(const std::string &sceneNodeName, - float scale, const Ogre::Vector3 &position, - const Ogre::Quaternion &rotation, bool placeable) + void PhysicsSystem::replaceObject(const std::string &sceneNodeName, float scale, + const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) { std::string referenceId = mSceneNodeToRefId[sceneNodeName]; std::string mesh = mSceneNodeToMesh[sceneNodeName]; @@ -143,13 +126,9 @@ namespace CSVWorld mEngine->removeRigidBody(referenceId); mEngine->deleteRigidBody(referenceId); - // create the physics object - mEngine->createAndAdjustRigidBody(mesh, - referenceId, scale, position, rotation, - 0, // scaledBoxTranslation - 0, // boxRotation - true, // raycasting - placeable); + // create a new physics object + mEngine->createAndAdjustRigidBody(mesh, referenceId, scale, position, rotation, + 0, 0, true, placeable); // update other scene managers if they have the referenceId // FIXME: rotation or scale not updated @@ -182,6 +161,7 @@ namespace CSVWorld { moveSceneNodeImpl(sceneNodeName, sceneNodeToRefId(sceneNodeName), position); } + void PhysicsSystem::addHeightField(Ogre::SceneManager *sceneManager, float* heights, int x, int y, float yoffset, float triSize, float sqrtVerts) { @@ -276,7 +256,7 @@ namespace CSVWorld return mSceneNodeToRefId[sceneNodeName]; } - void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget * sceneWidget) + void PhysicsSystem::addSceneManager(Ogre::SceneManager *sceneMgr, CSVRender::SceneWidget *sceneWidget) { mSceneWidgets[sceneMgr] = sceneWidget; } @@ -291,6 +271,20 @@ namespace CSVWorld mSceneWidgets.erase(sceneMgr); } + Ogre::SceneManager *PhysicsSystem::findSceneManager(std::string sceneNodeName) + { + std::map::const_iterator iter = mSceneWidgets.begin(); + for(; iter != mSceneWidgets.end(); ++iter) + { + if((*iter).first->hasSceneNode(sceneNodeName)) + { + return (*iter).first; + } + } + + return NULL; + } + void PhysicsSystem::toggleDebugRendering(Ogre::SceneManager *sceneMgr) { // FIXME: should check if sceneMgr is in the list diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 7b53956b2d..ccc9253d00 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -85,6 +85,8 @@ namespace CSVWorld void updateSelectionHighlight(std::string sceneNode, const Ogre::Vector3 &position); std::string refIdToSceneNode(std::string referenceId, Ogre::SceneManager *sceneMgr); + + Ogre::SceneManager *findSceneManager(std::string sceneNodeName); }; } From 85ef683319f8bbba4a3a08382ea94c1613888d55 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 3 Nov 2014 08:10:28 +1100 Subject: [PATCH 49/56] Fix deleting physics object when scene node is cleared. --- apps/opencs/view/render/object.cpp | 4 +++- apps/opencs/view/render/worldspacewidget.cpp | 5 ++++- apps/opencs/view/render/worldspacewidget.hpp | 4 ++-- apps/opencs/view/world/physicssystem.cpp | 23 +++++++++++++++++++- apps/opencs/view/world/physicssystem.hpp | 1 + 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index 395a4d57e0..f148bfe039 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -34,7 +34,7 @@ void CSVRender::Object::clearSceneNode (Ogre::SceneNode *node) void CSVRender::Object::clear() { if(!mObject.isNull()) - mPhysics->removeObject(mBase->getName()); + mPhysics->removePhysicsObject(mBase->getName()); mObject.setNull(); @@ -156,6 +156,8 @@ CSVRender::Object::~Object() { clear(); + mPhysics->removeObject(mBase->getName()); + if (mBase) mBase->getCreator()->destroySceneNode (mBase); } diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index ee119c939d..f8bec949c9 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -353,7 +353,10 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event) void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event) { - mMouse->mousePressEvent(event); + if(event->buttons() & Qt::RightButton) + { + mMouse->mousePressEvent(event); + } //SceneWidget::mousePressEvent(event); } diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 40799d86a9..14f0916200 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -32,8 +32,6 @@ namespace CSVRender { class WorldspaceWidget : public SceneWidget { - friend class MouseState; - Q_OBJECT CSVRender::Navigation1st m1st; @@ -154,6 +152,8 @@ namespace CSVRender void closeRequest(); void dataDropped(const std::vector& data); + + friend class MouseState; }; } diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 1f41dcb8cd..57a35168b6 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -63,7 +63,9 @@ namespace CSVWorld } } - // normal delete (e.g closing a scene subview) + // normal delete (e.g closing a scene subview or ~Object()) + // the scene node is destroyed so the mappings should be removed + // // TODO: should think about using some kind of reference counting within RigidBody void PhysicsSystem::removeObject(const std::string &sceneNodeName) { @@ -114,6 +116,25 @@ namespace CSVWorld } } + // Object::clear() is called when reference data is changed. It clears all + // contents of the SceneNode and removes the physics object + // + // A new physics object will be created and assigned to this sceneNodeName by + // Object::update() + void PhysicsSystem::removePhysicsObject(const std::string &sceneNodeName) + { + std::string referenceId = mSceneNodeToRefId[sceneNodeName]; + + if(referenceId != "") + { + if(mRefIdToSceneNode.find(referenceId) == mRefIdToSceneNode.end()) + { + mEngine->removeRigidBody(referenceId); + mEngine->deleteRigidBody(referenceId); + } + } + } + void PhysicsSystem::replaceObject(const std::string &sceneNodeName, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, bool placeable) { diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index ccc9253d00..0036bf769d 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -51,6 +51,7 @@ namespace CSVWorld bool placeable=false); void removeObject(const std::string &sceneNodeName); + void removePhysicsObject(const std::string &sceneNodeName); void replaceObject(const std::string &sceneNodeName, float scale, const Ogre::Vector3 &position, From d9755f82c3b716e0fd841fb77f66c568e0752fdb Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 3 Nov 2014 08:11:15 +1100 Subject: [PATCH 50/56] Position saving - work in progress. --- apps/opencs/view/render/mousestate.cpp | 31 +++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 5603daeb86..503d30c95a 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -9,6 +9,9 @@ #include #include "../../model/settings/usersettings.hpp" +#include "../../model/world/commands.hpp" +#include "../../model/world/idtable.hpp" +#include "../../model/world/universalid.hpp" #include "../world/physicssystem.hpp" #include "elements.hpp" @@ -237,20 +240,38 @@ namespace CSVRender { std::pair planeRes = planeAxis(); Ogre::Vector3 pos = mOrigObjPos+planeRes.first*mOffset+planeResult.second-mOrigMousePos; - placeObject(mGrabbedSceneNode, pos); - //mCurrentObj = mGrabbedSceneNode; // FIXME + //placeObject(mGrabbedSceneNode, pos); // FIXME: auto updated via signals + + // use the saved scene node name since the physics model has not moved yet + std::string referenceId = mPhysics->sceneNodeToRefId(mGrabbedSceneNode); + + QAbstractItemModel *model = mParent->mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Reference); + const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); + int columnIndexPosX = + references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionXPos); + mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*model, + static_cast(model)->getModelIndex(referenceId, columnIndexPosX), pos.x)); + int columnIndexPosY = + references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionYPos); + mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*model, + static_cast(model)->getModelIndex(referenceId, columnIndexPosY), pos.y)); + int columnIndexPosZ = + references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionZPos); + mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*model, + static_cast(model)->getModelIndex(referenceId, columnIndexPosZ), pos.z)); + + //mCurrentObj = mGrabbedSceneNode; // FIXME: doesn't work? mCurrentObj = ""; // whether the object is selected + // on screen // 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 + mOffset = 0.0f; // used for z-axis movement mOldPos = QPoint(0, 0); // to calculate relative movement of mouse - // on screen - // FIXME: update document // FIXME: highlight current object? mMouseState = Mouse_Edit; } From 358cac2f0a048a38938cec12eb139ab37670e508 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 3 Nov 2014 10:03:54 +1100 Subject: [PATCH 51/56] Fix deleting object physics again. --- apps/opencs/view/world/physicssystem.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 57a35168b6..fc75d8d2c0 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -39,7 +39,7 @@ namespace CSVWorld Ogre::SceneManager *sceneManager = findSceneManager(sceneNodeName); if(sceneManager) { - // update maps + // update maps (NOTE: sometimes replaced) mSceneNodeToRefId[sceneNodeName] = referenceId; mSceneNodeToMesh[sceneNodeName] = mesh; mRefIdToSceneNode[referenceId][sceneManager] = sceneNodeName; @@ -127,11 +127,8 @@ namespace CSVWorld if(referenceId != "") { - if(mRefIdToSceneNode.find(referenceId) == mRefIdToSceneNode.end()) - { - mEngine->removeRigidBody(referenceId); - mEngine->deleteRigidBody(referenceId); - } + mEngine->removeRigidBody(referenceId); + mEngine->deleteRigidBody(referenceId); } } From e3a000917c72bd03f5343691365519a5e38275dd Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 3 Nov 2014 10:04:24 +1100 Subject: [PATCH 52/56] Minor tidy up. --- apps/opencs/view/render/mousestate.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 503d30c95a..f93442fae3 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -245,20 +245,26 @@ namespace CSVRender // use the saved scene node name since the physics model has not moved yet std::string referenceId = mPhysics->sceneNodeToRefId(mGrabbedSceneNode); - QAbstractItemModel *model = mParent->mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Reference); - const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); + QAbstractItemModel *model = + mParent->mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Reference); + const CSMWorld::RefCollection& references = + mParent->mDocument.getData().getReferences(); + int columnIndexPosX = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionXPos); mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*model, - static_cast(model)->getModelIndex(referenceId, columnIndexPosX), pos.x)); + static_cast(model)->getModelIndex(referenceId, + columnIndexPosX), pos.x)); int columnIndexPosY = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionYPos); mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*model, - static_cast(model)->getModelIndex(referenceId, columnIndexPosY), pos.y)); + static_cast(model)->getModelIndex(referenceId, + columnIndexPosY), pos.y)); int columnIndexPosZ = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionZPos); mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*model, - static_cast(model)->getModelIndex(referenceId, columnIndexPosZ), pos.z)); + static_cast(model)->getModelIndex(referenceId, + columnIndexPosZ), pos.z)); //mCurrentObj = mGrabbedSceneNode; // FIXME: doesn't work? mCurrentObj = ""; // whether the object is selected From 4556eb74fe579da5df129e4fc3b4fbf5efb73442 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 3 Nov 2014 10:07:21 +1100 Subject: [PATCH 53/56] Fix saving position and rotation. --- apps/opencs/model/world/columnimp.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index a25e36fc10..6f830e6e3e 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -1299,7 +1299,7 @@ namespace CSMWorld { ESXRecordT record2 = record.get(); - ESM::Position& position = record.get().*mPosition; + ESM::Position& position = record2.*mPosition; position.pos[mIndex] = data.toFloat(); @@ -1333,7 +1333,7 @@ namespace CSMWorld { ESXRecordT record2 = record.get(); - ESM::Position& position = record.get().*mPosition; + ESM::Position& position = record2.*mPosition; position.rot[mIndex] = data.toFloat(); From bf5ba4122304d358b28ac35ef1f7668b372a0c98 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 3 Nov 2014 12:46:31 +1100 Subject: [PATCH 54/56] Fix deleting physics object when scene nodes were still referencing it. Remove unused code from MouseState. Items that do not change are fetched only once. --- apps/opencs/view/render/mousestate.cpp | 94 ++++++------------------ apps/opencs/view/render/mousestate.hpp | 12 ++- apps/opencs/view/render/object.cpp | 6 +- apps/opencs/view/world/physicssystem.cpp | 1 + 4 files changed, 36 insertions(+), 77 deletions(-) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index f93442fae3..5fda886378 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -59,7 +59,18 @@ namespace CSVRender , mCurrentObj(""), mMouseState(Mouse_Default), mOldPos(0,0), mMouseEventTimer(0), mPlane(0) , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) , mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f) + , mColIndexPosX(0), mColIndexPosY(0), mColIndexPosZ(0), mIdTableModel(0) + //, mModel(0) { + const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); + + mColIndexPosX = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionXPos); + mColIndexPosY = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionYPos); + mColIndexPosZ = references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionZPos); + + mIdTableModel = static_cast( + mParent->mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Reference)); + mMouseEventTimer = new QElapsedTimer(); mMouseEventTimer->invalidate(); @@ -138,22 +149,6 @@ namespace CSVRender case Mouse_Grab: case Mouse_Drag: { - if(0 /*event->buttons() & ~Qt::RightButton*/) - { - // cancel operation & return the object to the original position - placeObject(mGrabbedSceneNode, mOrigObjPos); - mMouseState = Mouse_Default; - - // reset states - mCurrentMousePos = Ogre::Vector3(); - mOrigMousePos = Ogre::Vector3(); - mOrigObjPos = Ogre::Vector3(); - mGrabbedSceneNode = ""; - mCurrentObj = ""; - mOldPos = QPoint(0, 0); - mMouseEventTimer->invalidate(); - mOffset = 0.0f; - } break; } case Mouse_Edit: @@ -216,16 +211,9 @@ namespace CSVRender { std::string referenceId = mPhysics->sceneNodeToRefId(result.first); std::cout << "ReferenceId: " << referenceId << std::endl; - const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); - int index = references.searchId(referenceId); - if (index != -1) - { - int columnIndex = - references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); - std::cout << " index: " + QString::number(index).toStdString() - +", column index: " + QString::number(columnIndex).toStdString() - << 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; @@ -240,35 +228,21 @@ namespace CSVRender { std::pair planeRes = planeAxis(); Ogre::Vector3 pos = mOrigObjPos+planeRes.first*mOffset+planeResult.second-mOrigMousePos; - //placeObject(mGrabbedSceneNode, pos); // FIXME: auto updated via signals - // use the saved scene node name since the physics model has not moved yet std::string referenceId = mPhysics->sceneNodeToRefId(mGrabbedSceneNode); - QAbstractItemModel *model = - mParent->mDocument.getData().getTableModel(CSMWorld::UniversalId::Type_Reference); - const CSMWorld::RefCollection& references = - mParent->mDocument.getData().getReferences(); - - int columnIndexPosX = - references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionXPos); - mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*model, - static_cast(model)->getModelIndex(referenceId, - columnIndexPosX), pos.x)); - int columnIndexPosY = - references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionYPos); - mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*model, - static_cast(model)->getModelIndex(referenceId, - columnIndexPosY), pos.y)); - int columnIndexPosZ = - references.findColumnIndex(CSMWorld::Columns::ColumnId_PositionZPos); - mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*model, - static_cast(model)->getModelIndex(referenceId, - columnIndexPosZ), pos.z)); + mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, + mIdTableModel->getModelIndex(referenceId, mColIndexPosX), pos.x)); + mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, + mIdTableModel->getModelIndex(referenceId, mColIndexPosY), pos.y)); + mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, + mIdTableModel->getModelIndex(referenceId, mColIndexPosZ), pos.z)); + // FIXME: highlight current object? //mCurrentObj = mGrabbedSceneNode; // FIXME: doesn't work? mCurrentObj = ""; // whether the object is selected - // on screen + + mMouseState = Mouse_Edit; // reset states mCurrentMousePos = Ogre::Vector3(); // mouse pos to use in wheel event @@ -277,9 +251,6 @@ namespace CSVRender 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? - mMouseState = Mouse_Edit; } } break; @@ -456,25 +427,6 @@ namespace CSVRender return std::make_pair("", Ogre::Vector3()); } - void MouseState::placeObject(const std::string sceneNode, const Ogre::Vector3 &pos) - { - mSceneManager->getSceneNode(sceneNode)->setPosition(pos); - - // update physics - std::string refId = mPhysics->sceneNodeToRefId(sceneNode); - const CSMWorld::CellRef& cellref = mParent->mDocument.getData().getReferences().getRecord (refId).get(); - Ogre::Quaternion xr (Ogre::Radian (-cellref.mPos.rot[0]), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yr (Ogre::Radian (-cellref.mPos.rot[1]), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zr (Ogre::Radian (-cellref.mPos.rot[2]), Ogre::Vector3::UNIT_Z); - - // FIXME: adjustRigidBody() seems to lose objects, work around by deleting and recreating objects - //mPhysics->moveObject(sceneNode, pos, xr*yr*zr); - mPhysics->replaceObject(sceneNode, cellref.mScale, pos, xr*yr*zr); - - // update all SceneWidgets and their SceneManagers - updateSceneWidgets(); - } - void MouseState::updateSceneWidgets() { std::map sceneWidgets = mPhysics->sceneWidgets(); diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp index 498752db0a..2493416ae8 100644 --- a/apps/opencs/view/render/mousestate.hpp +++ b/apps/opencs/view/render/mousestate.hpp @@ -22,6 +22,11 @@ namespace CSVWorld class PhysicsSystem; } +namespace CSMWorld +{ + class IdTable; +} + namespace CSVRender { class WorldspaceWidget; @@ -51,7 +56,10 @@ namespace CSVRender Ogre::Vector3 mCurrentMousePos; float mOffset; - std::map > mSelectedEntities; + CSMWorld::IdTable *mIdTableModel; + int mColIndexPosX; + int mColIndexPosY; + int mColIndexPosZ; public: @@ -67,10 +75,8 @@ namespace CSVRender private: std::pair mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane); - void placeObject(const std::string sceneNode, const Ogre::Vector3 &pos); std::pair terrainUnderCursor(const int mouseX, const int mouseY); std::pair objectUnderCursor(const int mouseX, const int mouseY); - void updateSelectionHighlight(const std::string sceneNode, const Ogre::Vector3 &position); std::pair planeAxis(); void updateSceneWidgets(); bool isDebug(); diff --git a/apps/opencs/view/render/object.cpp b/apps/opencs/view/render/object.cpp index f148bfe039..21219db8f4 100644 --- a/apps/opencs/view/render/object.cpp +++ b/apps/opencs/view/render/object.cpp @@ -33,9 +33,6 @@ void CSVRender::Object::clearSceneNode (Ogre::SceneNode *node) void CSVRender::Object::clear() { - if(!mObject.isNull()) - mPhysics->removePhysicsObject(mBase->getName()); - mObject.setNull(); clearSceneNode (mBase); @@ -43,6 +40,9 @@ void CSVRender::Object::clear() void CSVRender::Object::update() { + if(!mObject.isNull()) + mPhysics->removePhysicsObject(mBase->getName()); + clear(); std::string model; diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index fc75d8d2c0..73063b6bee 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -154,6 +154,7 @@ namespace CSVWorld } } + // FIXME: adjustRigidBody() seems to lose objects, work around by deleting and recreating objects void PhysicsSystem::moveObject(const std::string &sceneNodeName, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) { From 092080c69cd1f9667da6062eee0052c536dfbb38 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 3 Nov 2014 13:57:57 +1100 Subject: [PATCH 55/56] Group the commands with begin/end macros. --- apps/opencs/view/render/mousestate.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 5fda886378..21f3aca781 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "../../model/settings/usersettings.hpp" #include "../../model/world/commands.hpp" @@ -231,12 +232,14 @@ namespace CSVRender // use the saved scene node name since the physics model has not moved yet std::string referenceId = mPhysics->sceneNodeToRefId(mGrabbedSceneNode); + mParent->mDocument.getUndoStack().beginMacro (QObject::tr("Move Object")); mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, mIdTableModel->getModelIndex(referenceId, mColIndexPosX), pos.x)); mParent->mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*mIdTableModel, mIdTableModel->getModelIndex(referenceId, mColIndexPosY), pos.y)); 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? From bd6e54dde337a1bdbac1865b547627519c053539 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 3 Nov 2014 21:24:47 +1100 Subject: [PATCH 56/56] Add function to cancel drag by pressing ESC. Remove debug code. --- apps/opencs/model/settings/usersettings.cpp | 24 ----- apps/opencs/view/render/mousestate.cpp | 95 ++++++++++---------- apps/opencs/view/render/mousestate.hpp | 3 +- apps/opencs/view/render/scenewidget.hpp | 4 +- apps/opencs/view/render/worldspacewidget.cpp | 10 +++ apps/opencs/view/render/worldspacewidget.hpp | 1 + 6 files changed, 63 insertions(+), 74 deletions(-) diff --git a/apps/opencs/model/settings/usersettings.cpp b/apps/opencs/model/settings/usersettings.cpp index 26c6aa5d6a..7dac660c35 100644 --- a/apps/opencs/model/settings/usersettings.cpp +++ b/apps/opencs/model/settings/usersettings.cpp @@ -161,30 +161,6 @@ void CSMSettings::UserSettings::buildSettingModelDefaults() ritd->setDeclaredValues (values); } - declareSection ("debug", "Debug Options"); - { - Setting *mousePicking = createSetting (Type_CheckBox, "mouse-picking", "Debug Render Mouse-Picking"); - mousePicking->setDefaultValue ("false"); - mousePicking->setToolTip ("Enable redering debug information for mouse picking. " - "This option may be removed in future once the mouse picking feature is completed."); - - QString defaultValue = "Closer/Further"; - QStringList values = QStringList() << defaultValue << "Up/Down" << "Left/Right"; - - Setting *mouseWheel = createSetting (Type_RadioButton, "mouse-wheel", - "For testing mouse movement directions."); - mouseWheel->setDefaultValue (defaultValue); - mouseWheel->setDeclaredValues (values); - - defaultValue = "screen"; - values = QStringList() << defaultValue << "world"; - - Setting *mouseCoord = createSetting (Type_RadioButton, "mouse-reference", - "For testing mouse movement frame of reference."); - mouseCoord->setDefaultValue (defaultValue); - mouseCoord->setDeclaredValues (values); - } - declareSection ("table-input", "Table Input"); { QString inPlaceEdit ("Edit in Place"); diff --git a/apps/opencs/view/render/mousestate.cpp b/apps/opencs/view/render/mousestate.cpp index 21f3aca781..af835d0a54 100644 --- a/apps/opencs/view/render/mousestate.cpp +++ b/apps/opencs/view/render/mousestate.cpp @@ -61,7 +61,6 @@ namespace CSVRender , mGrabbedSceneNode(""), mOrigObjPos(Ogre::Vector3()), mOrigMousePos(Ogre::Vector3()) , mCurrentMousePos(Ogre::Vector3()), mOffset(0.0f) , mColIndexPosX(0), mColIndexPosY(0), mColIndexPosZ(0), mIdTableModel(0) - //, mModel(0) { const CSMWorld::RefCollection& references = mParent->mDocument.getData().getReferences(); @@ -207,15 +206,6 @@ namespace CSVRender mCurrentObj = result.first; } - // print some debug info - if(isDebug()) - { - std::string referenceId = mPhysics->sceneNodeToRefId(result.first); - std::cout << "ReferenceId: " << referenceId << 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; } @@ -265,13 +255,7 @@ namespace CSVRender std::pair result = terrainUnderCursor(event->x(), event->y()); if(result.first != "") { - if(isDebug()) - { - std::cout << "terrain: " << 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: terrain editing } break; } @@ -282,16 +266,7 @@ namespace CSVRender void MouseState::mouseDoubleClickEvent (QMouseEvent *event) { - if(0 && isDebug()) // disable - { - // FIXME: OEngine::PhysicEngine creates only one child scene node for the - // debug drawer. Hence only the first subview that creates the debug drawer - // can view the debug lines. Will need to keep a map in OEngine if multiple - // subviews are to be supported. - mPhysics->addSceneManager(mSceneManager, mParent); - mPhysics->toggleDebugRendering(mSceneManager); - mParent->flagAsModified(); - } + event->ignore(); } bool MouseState::wheelEvent (QWheelEvent *event) @@ -329,37 +304,70 @@ namespace CSVRender return true; } + void MouseState::cancelDrag() + { + switch(mMouseState) + { + case Mouse_Grab: + case Mouse_Drag: + { + // cancel operation & return the object to the original position + mSceneManager->getSceneNode(mGrabbedSceneNode)->setPosition(mOrigObjPos); + // update all SceneWidgets and their SceneManagers + mPhysics->moveSceneNodes(mGrabbedSceneNode, mOrigObjPos); + updateSceneWidgets(); + + // reset states + mMouseState = Mouse_Default; + mCurrentMousePos = Ogre::Vector3(); + mOrigMousePos = Ogre::Vector3(); + mOrigObjPos = Ogre::Vector3(); + mGrabbedSceneNode = ""; + mCurrentObj = ""; + mOldPos = QPoint(0, 0); + mMouseEventTimer->invalidate(); + mOffset = 0.0f; + + break; + } + case Mouse_Edit: + case Mouse_Default: + { + break; + } + /* NO_DEFAULT_CASE */ + } + } + //plane Z, upvector Y, mOffset z : x-y plane, wheel up/down //plane Y, upvector X, mOffset y : y-z plane, wheel left/right //plane X, upvector Y, mOffset x : x-z plane, wheel closer/further std::pair MouseState::planeAxis() { - // FIXME: explore using signals instread of retrieving each time - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - QString coord = userSettings.setting("debug/mouse-reference", QString("screen")); + bool screenCoord = true; Ogre::Vector3 dir = getCamera()->getDerivedDirection(); - QString wheelDir = userSettings.setting("debug/mouse-wheel", QString("Closer/Further")); + QString wheelDir = "Closer/Further"; if(wheelDir == "Left/Right") { - if(coord == "world") - return std::make_pair(Ogre::Vector3::UNIT_Y, Ogre::Vector3::UNIT_Z); - else + if(screenCoord) return std::make_pair(getCamera()->getDerivedRight(), getCamera()->getDerivedUp()); + else + return std::make_pair(Ogre::Vector3::UNIT_Y, Ogre::Vector3::UNIT_Z); } else if(wheelDir == "Up/Down") { - if(coord == "world") - return std::make_pair(Ogre::Vector3::UNIT_Z, Ogre::Vector3::UNIT_X); - else + if(screenCoord) return std::make_pair(getCamera()->getDerivedUp(), Ogre::Vector3(-dir.x, -dir.y, -dir.z)); + else + return std::make_pair(Ogre::Vector3::UNIT_Z, Ogre::Vector3::UNIT_X); } else { - if(coord == "world") - return std::make_pair(Ogre::Vector3::UNIT_X, Ogre::Vector3::UNIT_Y); - else + if(screenCoord) return std::make_pair(Ogre::Vector3(-dir.x, -dir.y, -dir.z), getCamera()->getDerivedRight()); + else + return std::make_pair(Ogre::Vector3::UNIT_X, Ogre::Vector3::UNIT_Y); } } @@ -450,11 +458,4 @@ namespace CSVRender { return mParent->getCamera()->getViewport(); } - - bool MouseState::isDebug() - { - CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); - - return userSettings.setting("debug/mouse-picking", QString("false")) == "true" ? true : false; - } } diff --git a/apps/opencs/view/render/mousestate.hpp b/apps/opencs/view/render/mousestate.hpp index 2493416ae8..27907bb331 100644 --- a/apps/opencs/view/render/mousestate.hpp +++ b/apps/opencs/view/render/mousestate.hpp @@ -72,6 +72,8 @@ namespace CSVRender void mouseDoubleClickEvent (QMouseEvent *event); bool wheelEvent (QWheelEvent *event); + void cancelDrag(); + private: std::pair mousePositionOnPlane(const QPoint &pos, const Ogre::Plane &plane); @@ -79,7 +81,6 @@ namespace CSVRender std::pair objectUnderCursor(const int mouseX, const int mouseY); std::pair planeAxis(); void updateSceneWidgets(); - bool isDebug(); Ogre::Camera *getCamera(); // friend access Ogre::Viewport *getViewport(); // friend access diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index a3b8cd4b05..699d6a7a56 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -77,13 +77,13 @@ namespace CSVRender void wheelEvent (QWheelEvent *event); + void keyPressEvent (QKeyEvent *event); + private: void paintEvent(QPaintEvent* e); void resizeEvent(QResizeEvent* e); bool event(QEvent* e); - void keyPressEvent (QKeyEvent *event); - void keyReleaseEvent (QKeyEvent *event); void focusOutEvent (QFocusEvent *event); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index f8bec949c9..9c86760640 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -388,3 +388,13 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event) if(!mMouse->wheelEvent(event)) SceneWidget::wheelEvent(event); } + +void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event) +{ + if(event->key() == Qt::Key_Escape) + { + mMouse->cancelDrag(); + } + else + SceneWidget::keyPressEvent(event); +} diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index 14f0916200..5bad3933d8 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -107,6 +107,7 @@ namespace CSVRender virtual void mouseReleaseEvent (QMouseEvent *event); virtual void mouseDoubleClickEvent (QMouseEvent *event); virtual void wheelEvent (QWheelEvent *event); + virtual void keyPressEvent (QKeyEvent *event); private: