/* Intermediate Tutorial 3 * Mouse Picking (3D Object Selection) and SceneQuery Masks (Part 2 of 2) */ #ifndef OGREWIDGET11_H #define OGREWIDGET11_H #include <QWidget> #include <Ogre.h> class OgreWidget11 : public QWidget { Q_OBJECT public: enum QueryFlags {NINJA_MASK = 1 << 0, ROBOT_MASK = 1 << 1}; explicit OgreWidget11(QWidget *parent = 0); ~OgreWidget11(); 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); 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; }; #endif // OGREWIDGET11_H /* Intermediate Tutorial 3 * Mouse Picking (3D Object Selection) and SceneQuery Masks (Part 2 of 2) */ #include <QtGui> #include "ogrewidget11.h" OgreWidget11::OgreWidget11(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) { 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 ")); } OgreWidget11::~OgreWidget11() { if (mRenderWindow) mRenderWindow->removeAllViewports(); if (mRoot) { mRoot->detachRenderTarget(mRenderWindow); if (mSceneMgr) { mSceneMgr->destroyQuery(mRaySceneQuery); mRoot->destroySceneManager(mSceneMgr); } delete mRoot; mRoot = 0; } } QPaintEngine *OgreWidget11::paintEngine() const { return NULL; } void OgreWidget11::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 OgreWidget11::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 OgreWidget11::createScene() { mSceneMgr->setAmbientLight(Ogre::ColourValue(0.5, 0.5, 0.5)); mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8); mSceneMgr->setWorldGeometry("terrain.cfg"); mCamera->setPosition(40, 100, 580); mCamera->pitch(Ogre::Degree(-30)); mCamera->yaw(Ogre::Degree(-45)); } void OgreWidget11::chooseSceneManager() { // create a scene manager that is meant for handling outdoor scenes mSceneMgr = mRoot->createSceneManager(Ogre::ST_EXTERIOR_CLOSE); } void OgreWidget11::createFrameListener() { } bool OgreWidget11::frameRenderingQueued(const Ogre::FrameEvent &evt) { } void OgreWidget11::showEvent(QShowEvent *e) { if (!mRoot) initOgre(); QWidget::showEvent(e); } void OgreWidget11::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 OgreWidget11::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 OgreWidget11::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 OgreWidget11::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(); Ogre::Ray ray = mCamera->getCameraToViewportRay(x, y); mRaySceneQuery->setRay(ray); mRaySceneQuery->setSortByDistance(true); mRaySceneQuery->setQueryMask(isRobotMode ? ROBOT_MASK : NINJA_MASK); Ogre::RaySceneQueryResult &result = mRaySceneQuery->execute(); Ogre::RaySceneQueryResult::iterator itr = result.begin(); // if (itr != result.end() && itr->worldFragment) { // Ogre::Entity *ent; // char name[16]; // Ogre::Real scaling; // if (isRobotMode) { // sprintf(name, "Robot%d", mCount++); // ent = mSceneMgr->createEntity(name, "robot.mesh"); // scaling = 0.2; // } else { // sprintf(name, "Ninja%d", mCount++); // ent = mSceneMgr->createEntity(name, "ninja.mesh"); // scaling = 0.1; // } // mCurrentObject = mSceneMgr->getRootSceneNode()->createChildSceneNode(std::string(name) + "Node", itr->worldFragment->singleIntersection); // mCurrentObject->attachObject(ent); // mCurrentObject->setScale(scaling, scaling, scaling); // update(); // } // 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 OgreWidget11::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(); 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 OgreWidget11::mouseReleaseEvent(QMouseEvent *e) { } void OgreWidget11::wheelEvent(QWheelEvent *e) { }