OSGWidget.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. #include "OSGWidget.hpp"
  2. #include "PickHandler.hpp"
  3. #include <osgViewer/Viewer>
  4. #include <osg/ShapeDrawable>
  5. #include <osg/Geode>
  6. #include <osgDB/ReadFile>
  7. #include <osg/Group>
  8. #include <osg/Switch>
  9. #include <osg/MatrixTransform>
  10. #include <osg/Matrix>
  11. #include <osgGA/TrackballManipulator>
  12. #include <osgUtil/LineSegmentIntersector>
  13. #include <osgUtil/IntersectionVisitor>
  14. #include <osg/PolygonMode>
  15. #include <osgDB/WriteFile>
  16. #include <osg/Material>
  17. #include <osg/StateSet>
  18. #include <cassert>
  19. #include <stdexcept>
  20. #include <vector>
  21. #include <QDebug>
  22. #include <QKeyEvent>
  23. #include <QPainter>
  24. #include <QWheelEvent>
  25. namespace osgWidget {
  26. void Viewer::setupThreading() {
  27. if (_threadingModel == SingleThreaded) {
  28. if (_threadsRunning) {
  29. stopThreading();
  30. }
  31. } else {
  32. if (!_threadsRunning) {
  33. startThreading();
  34. }
  35. }
  36. }
  37. }
  38. OSGWidget::OSGWidget(QWidget* parent): QOpenGLWidget(parent),
  39. graphicsWindow_(new osgViewer::GraphicsWindowEmbedded(this->x(), this->y(), this->width(), this->height())),
  40. _viewer(new osgWidget::Viewer),
  41. selectionActive_(false),
  42. selectionFinished_(true)
  43. {
  44. this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  45. // Root node of the scene
  46. _root = new osg::Group;
  47. // Create the camera
  48. float aspectRatio = static_cast<float>(this->width()) / static_cast<float>(this->height());
  49. auto pixelRatio = this->devicePixelRatio();
  50. osg::Camera* camera = new osg::Camera;
  51. camera->setViewport(0, 0, this->width() * pixelRatio, this->height() * pixelRatio);
  52. camera->setClearColor(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
  53. camera->setProjectionMatrixAsPerspective(30.0f, aspectRatio, 1.0f, 1000.0f);
  54. camera->setGraphicsContext(graphicsWindow_);
  55. // Create the viewer
  56. _view = new osgViewer::View;
  57. _view->setCamera(camera);
  58. _view->setSceneData(_root);
  59. // Add axesNode under root
  60. _axesNode = osgDB::readNodeFile("../../testdata/testbutton.stl");
  61. if (!_axesNode) {
  62. printf("Origin node not loaded, model not found\n");
  63. }
  64. // Set material for basic lighting and enable depth tests. Else, the sphere
  65. // will suffer from rendering errors.
  66. {
  67. osg::StateSet* stateSet = _axesNode->getOrCreateStateSet();
  68. osg::Material* material = new osg::Material;
  69. material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
  70. stateSet->setAttributeAndModes(material, osg::StateAttribute::ON);
  71. stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
  72. }
  73. _root->addChild(_axesNode);
  74. // Attach a manipulator (it's usually done for us when we use viewer.run())
  75. osg::ref_ptr<osgGA::TrackballManipulator> tm = new osgGA::TrackballManipulator;
  76. tm->setAllowThrow(false);
  77. _view->setCameraManipulator(tm);
  78. _viewer->addView(_view);
  79. _viewer->setThreadingModel(osgViewer::CompositeViewer::SingleThreaded);
  80. _viewer->realize();
  81. _storeHandler = new StoreHandler(_root);
  82. _openScadRenderer = new OpenScadRenderer();
  83. _threeMFWriter = new ThreeMFWriter();
  84. osg::ref_ptr<PickHandler> picker = new PickHandler(_storeHandler, _openScadRenderer, _threeMFWriter, _axesNode);
  85. _root->addChild(picker->getOrCreateSelectionCylinder());
  86. _view->addEventHandler(picker.get());
  87. // This ensures that the widget will receive keyboard events. This focus
  88. // policy is not set by default. The default, Qt::NoFocus, will result in
  89. // keyboard events that are ignored.
  90. this->setFocusPolicy(Qt::StrongFocus);
  91. this->setMinimumSize(100, 100);
  92. // Ensures that the widget receives mouse move events even though no
  93. // mouse button has been pressed. We require this in order to let the
  94. // graphics window switch viewports properly.
  95. this->setMouseTracking(true);
  96. }
  97. OSGWidget::~OSGWidget() {
  98. }
  99. void OSGWidget::paintEvent(QPaintEvent*) {
  100. this->makeCurrent();
  101. QPainter painter(this);
  102. painter.setRenderHint(QPainter::Antialiasing);
  103. this->paintGL();
  104. painter.end();
  105. this->doneCurrent();
  106. }
  107. void OSGWidget::paintGL() {
  108. _viewer->frame();
  109. }
  110. void OSGWidget::resizeGL(int width, int height) {
  111. this->getEventQueue()->windowResize(this->x(), this->y(), width, height);
  112. graphicsWindow_->resized(this->x(), this->y(), width, height);
  113. this->onResize(width, height);
  114. }
  115. void OSGWidget::keyPressEvent( QKeyEvent* event )
  116. {
  117. QString keyString = event->text();
  118. const char* keyData = keyString.toLocal8Bit().data();
  119. if( event->key() == Qt::Key_S )
  120. {
  121. // Further processing is required for the statistics handler here, so we do
  122. // not return right away.
  123. }
  124. else if( event->key() == Qt::Key_D )
  125. {
  126. osgDB::writeNodeFile( *_viewer->getView(0)->getSceneData(),
  127. "/tmp/sceneGraph.osg" );
  128. return;
  129. }
  130. else if( event->key() == Qt::Key_H )
  131. {
  132. this->onHome();
  133. return;
  134. }
  135. this->getEventQueue()->keyPress( osgGA::GUIEventAdapter::KeySymbol( *keyData ) );
  136. }
  137. void OSGWidget::keyReleaseEvent( QKeyEvent* event )
  138. {
  139. QString keyString = event->text();
  140. const char* keyData = keyString.toLocal8Bit().data();
  141. this->getEventQueue()->keyRelease( osgGA::GUIEventAdapter::KeySymbol( *keyData ) );
  142. }
  143. void OSGWidget::mouseMoveEvent( QMouseEvent* event )
  144. {
  145. // Note that we have to check the buttons mask in order to see whether the
  146. // left button has been pressed. A call to `button()` will only result in
  147. // `Qt::NoButton` for mouse move events.
  148. /*if( selectionActive_ && event->buttons() & Qt::LeftButton )
  149. {
  150. selectionEnd_ = event->pos();
  151. // Ensures that new paint events are created while the user moves the
  152. // mouse.
  153. this->update();
  154. }
  155. else
  156. {*/
  157. auto pixelRatio = this->devicePixelRatio();
  158. this->getEventQueue()->mouseMotion( static_cast<float>( event->x() * pixelRatio ),
  159. static_cast<float>( event->y() * pixelRatio ) );
  160. //}
  161. }
  162. void OSGWidget::mousePressEvent( QMouseEvent* event )
  163. {
  164. // Selection processing
  165. /*if( selectionActive_ && event->button() == Qt::LeftButton )
  166. {
  167. selectionStart_ = event->pos();
  168. selectionEnd_ = selectionStart_; // Deletes the old selection
  169. selectionFinished_ = false; // As long as this is set, the rectangle will be drawn
  170. }
  171. // Normal processing
  172. else
  173. {*/
  174. // 1 = left mouse button
  175. // 2 = middle mouse button
  176. // 3 = right mouse button
  177. unsigned int button = 0;
  178. switch( event->button() )
  179. {
  180. case Qt::LeftButton:
  181. button = 1;
  182. break;
  183. case Qt::MiddleButton:
  184. button = 2;
  185. break;
  186. case Qt::RightButton:
  187. button = 3;
  188. break;
  189. default:
  190. break;
  191. }
  192. auto pixelRatio = this->devicePixelRatio();
  193. this->getEventQueue()->mouseButtonPress( static_cast<float>( event->x() * pixelRatio ),
  194. static_cast<float>( event->y() * pixelRatio ),
  195. button );
  196. //}
  197. }
  198. void OSGWidget::mouseReleaseEvent(QMouseEvent* event)
  199. {
  200. // Selection processing: Store end position and obtain selected objects
  201. // through polytope intersection.
  202. /*if( selectionActive_ && event->button() == Qt::LeftButton )
  203. {
  204. selectionEnd_ = event->pos();
  205. selectionFinished_ = true; // Will force the painter to stop drawing the
  206. // selection rectangle
  207. }
  208. // Normal processing
  209. else
  210. {*/
  211. // 1 = left mouse button
  212. // 2 = middle mouse button
  213. // 3 = right mouse button
  214. unsigned int button = 0;
  215. switch( event->button() )
  216. {
  217. case Qt::LeftButton:
  218. button = 1;
  219. break;
  220. case Qt::MiddleButton:
  221. button = 2;
  222. break;
  223. case Qt::RightButton:
  224. button = 3;
  225. break;
  226. default:
  227. break;
  228. }
  229. auto pixelRatio = this->devicePixelRatio();
  230. this->getEventQueue()->mouseButtonRelease( static_cast<float>( pixelRatio * event->x() ),
  231. static_cast<float>( pixelRatio * event->y() ),
  232. button );
  233. //}
  234. }
  235. void OSGWidget::wheelEvent( QWheelEvent* event )
  236. {
  237. // Ignore wheel events as long as the selection is active.
  238. if( selectionActive_ )
  239. return;
  240. event->accept();
  241. int delta = event->angleDelta().y();
  242. osgGA::GUIEventAdapter::ScrollingMotion motion = delta > 0 ? osgGA::GUIEventAdapter::SCROLL_UP
  243. : osgGA::GUIEventAdapter::SCROLL_DOWN;
  244. this->getEventQueue()->mouseScroll( motion );
  245. }
  246. bool OSGWidget::event(QEvent* event) {
  247. bool handled = QOpenGLWidget::event(event);
  248. // This ensures that the OSG widget is always going to be repainted after the
  249. // user performed some interaction. Doing this in the event handler ensures
  250. // that we don't forget about some event and prevents duplicate code.
  251. switch(event->type()) {
  252. case QEvent::KeyPress:
  253. case QEvent::KeyRelease:
  254. case QEvent::MouseButtonDblClick:
  255. case QEvent::MouseButtonPress:
  256. case QEvent::MouseButtonRelease:
  257. case QEvent::MouseMove:
  258. case QEvent::Wheel:
  259. this->update();
  260. break;
  261. case QEvent::Resize:
  262. this->onResize(this->width(), this->height());
  263. break;
  264. default:
  265. break;
  266. }
  267. return handled;
  268. }
  269. void OSGWidget::onHome() {
  270. osgViewer::ViewerBase::Views views;
  271. _viewer->getViews( views );
  272. for(std::size_t i = 0; i < views.size(); i++) {
  273. osgViewer::View* view = views.at(i);
  274. view->home();
  275. }
  276. }
  277. void OSGWidget::onResize(int width, int height) {
  278. std::vector<osg::Camera*> cameras;
  279. _viewer->getCameras(cameras);
  280. assert(cameras.size() == 1);
  281. auto pixelRatio = this->devicePixelRatio();
  282. cameras[0]->setViewport(0, 0, width * pixelRatio, height * pixelRatio);
  283. }
  284. osgGA::EventQueue* OSGWidget::getEventQueue() const {
  285. osgGA::EventQueue* eventQueue = graphicsWindow_->getEventQueue();
  286. if (eventQueue) {
  287. return eventQueue;
  288. } else {
  289. throw std::runtime_error("Unable to obtain valid event queue");
  290. }
  291. }