From a01a921644162fbd67087e78db65fbcad49b7497 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 28 Oct 2014 06:01:19 +1100 Subject: [PATCH 1/3] 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 b33c83342..4f653f6fd 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; + } + + // 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; - debugMousePicking((float) event->x() / getCamera()->getViewport()->getActualWidth(), - (float) event->y() / getCamera()->getViewport()->getActualHeight()); + + // 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 2c46729a8..1467395b0 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 1adbf3f17..5f023a7ad 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 2/3] 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 4f653f6fd..9d8dd56bd 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 1467395b0..db666ebac 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 8e2a0ea90a6a678914f28fe698ff7eb40b846f75 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 29 Oct 2014 08:13:13 +1100 Subject: [PATCH 3/3] Implemented moving objects around x-y plane. --- .../view/render/pagedworldspacewidget.cpp | 121 +++++++++++++++--- .../view/render/pagedworldspacewidget.hpp | 5 + apps/opencs/view/world/physicssystem.cpp | 46 ++++--- apps/opencs/view/world/physicssystem.hpp | 25 ++-- 4 files changed, 155 insertions(+), 42 deletions(-) diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 9d8dd56bd..bc297a690 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(); - - //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 + 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: @@ -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 db666ebac..defd7638a 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 154cc6273..a422147a9 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 &referenceId) + { + mEngine->removeRigidBody(referenceId); + mEngine->deleteRigidBody(referenceId); } - void PhysicsSystem::removeObject(const std::string& name) + void PhysicsSystem::moveObject(const std::string &referenceId, + const Ogre::Vector3 &position, const Ogre::Quaternion &rotation) { - mEngine->removeRigidBody(name); - mEngine->deleteRigidBody(name); + mEngine->adjustRigidBody(mEngine->getRigidBody(referenceId, true /*raycasting*/), + position, rotation); } - void PhysicsSystem::addHeightField(float* heights, int x, int y, float yoffset, - float triSize, float sqrtVerts) + 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[referenceId]; + } + + std::string PhysicsSystem::sceneNodeToMesh(std::string sceneNodeName) { - return mRefToSceneNode[reference]; + 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 c19486d17..983f1a2a7 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: