/* Intermediate Tutorial 4 * Volume Selection and Basic Manual Objects */ #ifndef OGREWIDGET12_H #define OGREWIDGET12_H #include <QWidget> #include <Ogre.h> #include "selectionbox.h" class OgreWidget12 : public QWidget { Q_OBJECT public: enum QueryFlags {NINJA_MASK = 1 << 0, ROBOT_MASK = 1 << 1}; explicit OgreWidget12(QWidget *parent = 0); ~OgreWidget12(); QPaintEngine *paintEngine() const; signals: public slots: protected: void initOgre(); void loadOgreResources(); void createScene(); void chooseSceneManager(); void createFrameListener(); bool frameRenderingQueued(const Ogre::FrameEvent &evt); void showEvent(QShowEvent *e); void paintEvent(QPaintEvent *e); void resizeEvent(QResizeEvent *e); void keyPressEvent(QKeyEvent *e); void mousePressEvent(QMouseEvent *e); void mouseMoveEvent(QMouseEvent *e); void mouseReleaseEvent(QMouseEvent *e); void wheelEvent(QWheelEvent *e); void performSelection(const Ogre::Vector2 &first, const Ogre::Vector2 &second); void deselectObjects(); void selectObject(Ogre::MovableObject *obj); private: Ogre::Root *mRoot; Ogre::SceneManager *mSceneMgr; Ogre::RenderWindow *mRenderWindow; Ogre::Camera *mCamera; Ogre::Real mCameraSpeed; Ogre::Viewport *mViewport; Ogre::SceneNode *mCurrentObject; // pointer to our currently selected object Ogre::RaySceneQuery *mRaySceneQuery; int mCount; // number of objects created float mRotateSpeed; // the rotation speed for the camera bool isRobotMode; QPoint lastPos; Ogre::Vector2 mStart, mStop; Ogre::PlaneBoundedVolumeListSceneQuery *mVolQuery; std::list<Ogre::MovableObject *> mSelected; bool mSelecting; SelectionBox *mSelectionBox; }; #endif // OGREWIDGET12_H /* Intermediate Tutorial 4 * Volume Selection and Basic Manual Objects */ #include <QtGui> #include "ogrewidget12.h" OgreWidget12::OgreWidget12(QWidget *parent) : QWidget(parent), mRoot(0), mSceneMgr(0), mRenderWindow(0), mCamera(0), mCameraSpeed(5.0), mViewport(0), mRaySceneQuery(0), mCount(0), mCurrentObject(0), mRotateSpeed(0.1), isRobotMode(true), mVolQuery(0), mSelecting(false), mSelectionBox(0) { setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_PaintOnScreen); setFocusPolicy(Qt::StrongFocus); setMinimumSize(250, 250); resize(800, 600); QRect r = qApp->desktop()->availableGeometry(); move((r.width() - width()) / 2, (r.height() - height()) / 2); setWindowTitle(tr("Mouse Picking (3D Object Selection) and SceneQuery Masks ")); } OgreWidget12::~OgreWidget12() { if (mRenderWindow) mRenderWindow->removeAllViewports(); if (mRoot) { mRoot->detachRenderTarget(mRenderWindow); if (mSceneMgr) { mSceneMgr->destroyQuery(mRaySceneQuery); mSceneMgr->destroyQuery(mVolQuery); mRoot->destroySceneManager(mSceneMgr); } delete mRoot; mRoot = 0; } // if (mSelectionBox) // delete mSelectionBox; } QPaintEngine *OgreWidget12::paintEngine() const { return NULL; } void OgreWidget12::initOgre() { mRoot = new Ogre::Root(); Ogre::RenderSystem *renderSystem = mRoot->getRenderSystemByName("OpenGL Rendering Subsystem"); mRoot->setRenderSystem(renderSystem); // chooseSceneManager(); mRoot->initialise(false); Ogre::NameValuePairList viewConfig; Ogre::String widgetHandle; widgetHandle = Ogre::StringConverter::toString((size_t)((HWND)winId())); viewConfig["externalWindowHandle"] = widgetHandle; mRenderWindow = mRoot->createRenderWindow("Ogre rendering window", width(), height(), false, &viewConfig); chooseSceneManager(); mCamera = mSceneMgr->createCamera("PlayerCam"); mCamera->setPosition(0, 50, 150); mCamera->lookAt(0, 80, 0); mCamera->setNearClipDistance(5); mViewport = mRenderWindow->addViewport(mCamera); mViewport->setBackgroundColour(Ogre::ColourValue(0.0, 0.0, 0.0)); mCamera->setAspectRatio(Ogre::Real(width()) / Ogre::Real(height())); // chooseSceneManager(); loadOgreResources(); createScene(); mRaySceneQuery = mSceneMgr->createRayQuery(Ogre::Ray()); } void OgreWidget12::loadOgreResources() { Ogre::ConfigFile cf; cf.load("resources.cfg"); Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator(); Ogre::String secName, typeName, archName; while (seci.hasMoreElements()) { secName = seci.peekNextKey(); Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext(); Ogre::ConfigFile::SettingsMultiMap::iterator i; for (i = settings->begin(); i != settings->end(); ++i) { typeName = i->first; archName = i->second; Ogre::ResourceGroupManager::getSingleton().addResourceLocation(archName, typeName, secName); } } Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); } void OgreWidget12::createScene() { mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5)); // mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8); // mSceneMgr->setWorldGeometry("terrain.cfg"); for (int i = 0; i < 10; ++i) { for (int j = 0; j < 10; ++j) { Ogre::Entity *ent = mSceneMgr->createEntity("Robot" + Ogre::StringConverter::toString(i + j * 10), "robot.mesh"); Ogre::SceneNode *node = mSceneMgr->getRootSceneNode()->createChildSceneNode(Ogre::Vector3(i * 15, 0, j * 15)); node->attachObject(ent); node->setScale(0.1, 0.1, 0.1); } } mCamera->setPosition(200, 80, 200); mCamera->lookAt(-80, -20, -80); // mCamera->pitch(Ogre::Degree(-30)); // mCamera->yaw(Ogre::Degree(-45)); mSelectionBox = new SelectionBox("SelectionBox"); mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(mSelectionBox); mVolQuery = mSceneMgr->createPlaneBoundedVolumeQuery(Ogre::PlaneBoundedVolumeList()); } void OgreWidget12::chooseSceneManager() { // create a scene manager that is meant for handling outdoor scenes mSceneMgr = mRoot->createSceneManager(Ogre::ST_EXTERIOR_CLOSE); } void OgreWidget12::createFrameListener() { } bool OgreWidget12::frameRenderingQueued(const Ogre::FrameEvent &evt) { } void OgreWidget12::showEvent(QShowEvent *e) { if (!mRoot) initOgre(); QWidget::showEvent(e); } void OgreWidget12::paintEvent(QPaintEvent *e) { // Setup the scene query Ogre::Vector3 camPos = mCamera->getPosition(); Ogre::Ray cameraRay(Ogre::Vector3(camPos.x, 5000.0, camPos.z), Ogre::Vector3::NEGATIVE_UNIT_Y); mRaySceneQuery->setRay(cameraRay); // Perform the scene query mRaySceneQuery->setSortByDistance(false); Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute(); Ogre::RaySceneQueryResult::iterator itr = result.begin(); // Get the results, set the camera height // if (itr != result.end() && itr->worldFragment) { // Ogre::Real terrainHeight = itr->worldFragment->singleIntersection.y; // if ((terrainHeight + 10.0) > camPos.y) // mCamera->setPosition(camPos.x, terrainHeight + 10.0, camPos.z); // } for (itr; itr != result.end(); itr++) { if (itr->worldFragment) { Ogre::Real terrainHeight = itr->worldFragment->singleIntersection.y; if ((terrainHeight + 10.0) > camPos.y) mCamera->setPosition(camPos.x, terrainHeight + 10.0, camPos.z); break; } } mRoot->_fireFrameStarted(); mRenderWindow->update(); mRoot->_fireFrameEnded(); e->accept(); } void OgreWidget12::resizeEvent(QResizeEvent *e) { QWidget::resizeEvent(e); if (e->isAccepted() && mRenderWindow) { mRenderWindow->resize(width(), height()); mRenderWindow->windowMovedOrResized(); for (int i = 0; i < mRenderWindow->getNumViewports(); ++i) { Ogre::Viewport *viewport = mRenderWindow->getViewport(i); Ogre::Camera *camera = viewport->getCamera(); camera->setAspectRatio(static_cast<Ogre::Real>(width()) / static_cast<Ogre::Real>(height())); } } update(); } void OgreWidget12::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_Escape: close(); case Qt::Key_W: mCamera->setPosition(mCamera->getPosition() + mCamera->getDirection() * mCameraSpeed); update(); break; case Qt::Key_S: mCamera->setPosition(mCamera->getPosition() - mCamera->getDirection() * mCameraSpeed); update(); break; case Qt::Key_A: mCamera->setPosition(mCamera->getPosition() - mCamera->getRight() * mCameraSpeed); update(); break; case Qt::Key_D: mCamera->setPosition(mCamera->getPosition() + mCamera->getRight() * mCameraSpeed); update(); break; case Qt::Key_Space: isRobotMode = !isRobotMode; update(); break; default: QWidget::keyPressEvent(e); } } void OgreWidget12::mousePressEvent(QMouseEvent *e) { // show that the current object has been deselected by removing the bounding box visual // if (mCurrentObject) // mCurrentObject->showBoundingBox(false); if (e->buttons().testFlag(Qt::RightButton)) { lastPos = e->pos(); } else if (e->buttons().testFlag(Qt::LeftButton)) { // setup the ray scene query Ogre::Real x = e->pos().x() / (float)width(); Ogre::Real y = e->pos().y() / (float)height(); mStart.x = x; mStart.y = y; mStop = mStart; mSelecting = true; mSelectionBox->clear(); mSelectionBox->setVisible(true); // Ogre::Ray ray = mCamera->getCameraToViewportRay(x, y); // mRaySceneQ/uery->setRay(ray); // mRaySceneQuery->setSortByDistance(true); // mRaySceneQuery->setQueryMask(isRobotMode ? ROBOT_MASK : NINJA_MASK); // Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute(); // Ogre::RaySceneQueryResult::iterator itr = result.begin(); // Get results, create a node/entity on the position // for (itr; itr != result.end(); itr++) { // if (itr->movable && itr->movable->getName().substr(0, 5) != "tile[") { // mCurrentObject = itr->movable->getParentSceneNode(); // break; // } else if (itr->worldFragment) { // Ogre::Entity *ent; // char name[16]; // Ogre::Real scaling; // if (isRobotMode) { // sprintf(name, "Robot%d", mCount++); // ent = mSceneMgr->createEntity(name, "robot.mesh"); // ent->setQueryFlags(ROBOT_MASK); // scaling = 0.2; // } else { // sprintf(name, "Ninja%d", mCount++); // ent = mSceneMgr->createEntity(name, "ninja.mesh"); // ent->setQueryFlags(NINJA_MASK); // scaling = 0.1; // } // mCurrentObject = mSceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", itr->worldFragment->singleIntersection); // mCurrentObject->attachObject(ent); // mCurrentObject->setScale(scaling, scaling, scaling); // update(); // break; // } // } } // now we show the bounding box so the user can see that this object is selected // if (mCurrentObject) // mCurrentObject->showBoundingBox(true); update(); } void OgreWidget12::mouseMoveEvent(QMouseEvent *e) { if (e->buttons().testFlag(Qt::RightButton)) { QPoint mouseDelta = e->pos() - lastPos; mCamera->yaw(Ogre::Radian(-mouseDelta.x() * 0.005)); mCamera->pitch(Ogre::Radian(-mouseDelta.y() * 0.005)); lastPos = e->pos(); update(); } else if (e->buttons().testFlag(Qt::LeftButton)) { Ogre::Real x = e->pos().x() / (float)width(); Ogre::Real y = e->pos().y() / (float)height(); if (mSelecting) { mStop.x = x; mStop.y = y; mSelectionBox->setCorners(mStart, mStop); } // Ogre::Ray ray = mCamera->getCameraToViewportRay(x, y); // mRaySceneQuery->setRay(ray); // mRaySceneQuery->setSortByDistance(false); // Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute(); // Ogre::RaySceneQueryResult::iterator itr = result.begin(); // for (itr; itr != result.end(); itr++) { // if (itr->worldFragment) { // mCurrentObject->setPosition(itr->worldFragment->singleIntersection); // break; // } // } update(); } } void OgreWidget12::mouseReleaseEvent(QMouseEvent *e) { // if (e->buttons().testFlag(Qt::LeftButton)) { if (mSelecting) { performSelection(mStart, mStop); mSelecting = false; mSelectionBox->setVisible(false); // mRenderWindow->update(); update(); } // } } void OgreWidget12::wheelEvent(QWheelEvent *e) { } void OgreWidget12::performSelection(const Ogre::Vector2 &first, const Ogre::Vector2 &second) { float left = first.x; float right = second.x; float top = first.y; float bottom = second.y; if (left > right) std::swap(left, right); if (top > bottom) std::swap(top, bottom); if ((right - left) * (bottom - top) < 0.0001) return; Ogre::Ray topLeft = mCamera->getCameraToViewportRay(left, top); Ogre::Ray topRight = mCamera->getCameraToViewportRay(right, top); Ogre::Ray bottomLeft = mCamera->getCameraToViewportRay(left, bottom); Ogre::Ray bottomRight = mCamera->getCameraToViewportRay(right, bottom); Ogre::PlaneBoundedVolume vol; vol.planes.push_back(Ogre::Plane(topLeft.getPoint(3), topRight.getPoint(3), bottomRight.getPoint(3))); // front plane vol.planes.push_back(Ogre::Plane(topLeft.getOrigin(), topLeft.getPoint(100), topRight.getPoint(100))); // top plane vol.planes.push_back(Ogre::Plane(topLeft.getOrigin(), bottomLeft.getPoint(100), topLeft.getPoint(100))); // left plane vol.planes.push_back(Ogre::Plane(bottomLeft.getOrigin(), bottomRight.getPoint(100), bottomLeft.getPoint(100))); // bottom plane vol.planes.push_back(Ogre::Plane(topRight.getOrigin(), topRight.getPoint(100), bottomRight.getPoint(100))); // right plane Ogre::PlaneBoundedVolumeList volList; volList.push_back(vol); mVolQuery->setVolumes(volList); Ogre::SceneQueryResult result = mVolQuery->execute(); deselectObjects(); Ogre::SceneQueryResultMovableList::iterator iter; for (iter = result.movables.begin(); iter != result.movables.end(); ++iter) selectObject(*iter); update(); } void OgreWidget12::deselectObjects() { std::list<Ogre::MovableObject *>::iterator iter = mSelected.begin(); for (iter; iter != mSelected.end(); iter++) (*iter)->getParentSceneNode()->showBoundingBox(false); update(); } void OgreWidget12::selectObject(Ogre::MovableObject *obj) { obj->getParentSceneNode()->showBoundingBox(true); mSelected.push_back(obj); update(); } #ifndef SELECTIONBOX_H #define SELECTIONBOX_H #include <Ogre.h> class SelectionBox : public Ogre::ManualObject { public: SelectionBox(const Ogre::String &name); ~SelectionBox(); void setCorners(float left, float top, float right, float bottom); void setCorners(const Ogre::Vector2 &topLeft, const Ogre::Vector2 &bottomRight); }; #endif // SELECTIONBOX_H #include "selectionbox.h" SelectionBox::SelectionBox(const Ogre::String &name) : Ogre::ManualObject(name) { setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY); // when using this, be sure Depth Check is off in the material setUseIdentityProjection(true); setUseIdentityView(true); setQueryFlags(0); } SelectionBox::~SelectionBox() { } void SelectionBox::setCorners(float left, float top, float right, float bottom) { left = left * 2 - 1; right = right * 2 - 1; top = 1 - top * 2; bottom = 1 - bottom * 2; clear(); begin("", Ogre::RenderOperation::OT_LINE_STRIP); position(left, top, -1); position(right, top, -1); position(right, bottom, -1); position(left, bottom, -1); position(left, top, -1); end(); setBoundingBox(Ogre::AxisAlignedBox::BOX_INFINITE); } void SelectionBox::setCorners(const Ogre::Vector2 &topLeft, const Ogre::Vector2 &bottomRight) { setCorners(topLeft.x, topLeft.y, bottomRight.x, bottomRight.y); } http://www.ogre3d.org/tikiwiki/Intermediate+Tutorial+4