From 1741043f20a0916b27c9adc5eef3f6f39a6b3923 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 29 Oct 2014 23:02:38 +1100 Subject: [PATCH] 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 7dba068f8..474c79b35 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 e102801a2..26f460446 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 17b6d10c5..fe79e761e 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 65abe09c3..d11a9bb60 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(); - + mOrigMousePos = planeResult.second; + mCurrentMousePos = planeResult.second; + mZOffset = 0.0f; + } - mMouseEventTimer->start(); + mOrigObjPos = getSceneManager()->getSceneNode(mGrabbedSceneNode)->getPosition(); + mMouseEventTimer->start(); - mMouseState = Mouse_Grab; - //std::cout << "default/edit->grab" << std::endl; - } - break; + 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(); - - // 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); + mOrigObjPos.z += mZOffset; + Ogre::Vector3 pos = mOrigObjPos+planeResult.second-mOrigMousePos; + placeObject(mGrabbedSceneNode, pos); + //mCurrentObj = mGrabbedSceneNode; // FIXME + mCurrentObj = ""; + + // reset states + mCurrentMousePos = Ogre::Vector3(); + mOrigMousePos = Ogre::Vector3(); + mOrigObjPos = Ogre::Vector3(); + mGrabbedSceneNode = ""; + mOldPos = QPoint(0, 0); + mZOffset = 0.0f; + + // 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"))) - { - // 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); + case Mouse_Grab: + mMouseState = Mouse_Drag; - 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) + /* FALL_THROUGH */ + case Mouse_Drag: + { + // move the object along the z axis during Mouse_Drag or Mouse_Grab + if (event->delta()) { - int columnIndex = - references.findColumnIndex(CSMWorld::Columns::ColumnId_ReferenceableId); + // seems positive is up and negative is down + mZOffset += (event->delta()/5); // FIXME: arbitrary number, make config option? - std::cout << " index: " + QString::number(index).toStdString() - +", column index: " + QString::number(columnIndex).toStdString() << std::endl; + Ogre::Vector3 pos = mOrigObjPos; + pos.z += mZOffset; + getSceneManager()->getSceneNode(mGrabbedSceneNode)->setPosition(pos+mCurrentMousePos-mOrigMousePos); + flagAsModified(); } - flagAsModified(); + break; } + case Mouse_Edit: + case Mouse_Default: + { + 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"))) + if(name.contains(QRegExp("^HeightField"))) { - std::string sceneNode = - CSVWorld::PhysicsSystem::instance()->referenceToSceneNode(result.first); + 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"))) + { 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 756debfe5..48f5e98d4 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 a422147a9..0e3790d93 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 983f1a2a7..5cf568784 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: