From 792fbd119f45e5bac066a4c8885d77f4261405f8 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 29 Oct 2014 10:43:55 +1100 Subject: [PATCH] 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);