From 8e2a0ea90a6a678914f28fe698ff7eb40b846f75 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 29 Oct 2014 08:13:13 +1100 Subject: [PATCH] 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: