123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464 |
- // Include own headers
- #include "OSGWidget.hpp"
- // Include modules
- #include "PickHandler.hpp"
- #include "TrackPointRenderer.hpp"
- #include "HudCallback.hpp"
- #include "resources.hpp"
- #include "MeshTools.hpp"
- // Include dependencies
- #include <osgViewer/Viewer>
- #include <osg/ShapeDrawable>
- #include <osg/Geode>
- #include <osgDB/ReadFile>
- #include <osg/Group>
- #include <osg/Switch>
- #include <osg/MatrixTransform>
- #include <osg/Matrix>
- #include <osgGA/TrackballManipulator>
- #include <osgUtil/LineSegmentIntersector>
- #include <osgUtil/IntersectionVisitor>
- #include <osgUtil/MeshOptimizers>
- #include <osg/PolygonMode>
- #include <osgDB/WriteFile>
- #include <osg/Material>
- #include <osg/StateSet>
- #include <cassert>
- #include <stdexcept>
- #include <vector>
- #include <QDebug>
- #include <QKeyEvent>
- #include <QPainter>
- #include <QWheelEvent>
- namespace osgWidget {
- void Viewer::setupThreading() {
- if (_threadingModel == SingleThreaded) {
- if (_threadsRunning) {
- stopThreading();
- }
- } else {
- if (!_threadsRunning) {
- startThreading();
- }
- }
- }
- }
- void OSGWidget::fixMaterialState(osg::ref_ptr<osg::Node> node, osg::Vec4* color) {
- osg::StateSet* stateSet = node->getOrCreateStateSet();
- osg::Material* material = new osg::Material;
- material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
- if (color) {
- material->setDiffuse(osg::Material::FRONT_AND_BACK, *color);
- }
- stateSet->setAttributeAndModes(material, osg::StateAttribute::ON);
- stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
- }
- OSGWidget::OSGWidget(QWidget* parent): QOpenGLWidget(parent),
- graphicsWindow_(new osgViewer::GraphicsWindowEmbedded(this->x(), this->y(), this->width(), this->height())),
- _viewer(new osgWidget::Viewer),
- selectionActive_(false),
- selectionFinished_(true)
- {
- this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
- // Root node of the scene
- _root = new osg::Group;
- // Create the camera
- float aspectRatio = static_cast<float>(this->width()) / static_cast<float>(this->height());
- auto pixelRatio = this->devicePixelRatio();
- osg::Camera* camera = new osg::Camera;
- camera->setViewport(0, 0, this->width() * pixelRatio, this->height() * pixelRatio);
- camera->setClearColor(osg::Vec4(0.2f, 0.1875f, 0.375f, 1.0f));
- camera->setProjectionMatrixAsPerspective(30.0f, aspectRatio, 1.0f, 1000.0f);
- camera->setGraphicsContext(graphicsWindow_);
- // Create the viewer
- _view = new osgViewer::View;
- _view->setCamera(camera);
- _view->setSceneData(_root);
- // Create coordinate axes
- _coordinateAxes = new osg::Group;
- osg::Vec4 axesColor = osg::Vec4(0.7f, 0.7f, 0.7f, 1.0f);
- osg::ref_ptr<osg::MatrixTransform> xRotation = new osg::MatrixTransform;
- xRotation->setMatrix(osg::Matrix::rotate(osg::Vec3f(0.0f, 0.0f, 1.0f), osg::Vec3f(1.0f, 0.0f, 0.0f)));
- osg::ref_ptr<osg::Geode> xAxis = new osg::Geode;
- osg::ref_ptr<osg::ShapeDrawable> xAxisShape = new osg::ShapeDrawable();
- xAxisShape->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.0f), 0.05f, 100.0f));
- xAxisShape->setColor(axesColor);
- xAxis->addDrawable(xAxisShape.get());
- osg::ref_ptr<osg::ShapeDrawable> xConeShape = new osg::ShapeDrawable();
- xConeShape->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 50.0f), 0.2f, 1.0f));
- xConeShape->setColor(axesColor);
- xAxis->addDrawable(xConeShape.get());
- xRotation->addChild(xAxis.get());
- osg::ref_ptr<osg::MatrixTransform> yRotation = new osg::MatrixTransform;
- yRotation->setMatrix(osg::Matrix::rotate(osg::Vec3f(0.0f, 0.0f, 1.0f), osg::Vec3f(0.0f, 1.0f, 0.0f)));
- osg::ref_ptr<osg::Geode> yAxis = new osg::Geode;
- osg::ref_ptr<osg::ShapeDrawable> yAxisShape = new osg::ShapeDrawable();
- yAxisShape->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.0f), 0.05f, 100.0f));
- yAxisShape->setColor(axesColor);
- yAxis->addDrawable(yAxisShape.get());
- osg::ref_ptr<osg::ShapeDrawable> yConeShape = new osg::ShapeDrawable();
- yConeShape->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 50.0f), 0.2f, 1.0f));
- yConeShape->setColor(axesColor);
- yAxis->addDrawable(yConeShape.get());
- yRotation->addChild(yAxis.get());
- osg::ref_ptr<osg::Geode> zAxis = new osg::Geode;
- osg::ref_ptr<osg::ShapeDrawable> zAxisShape = new osg::ShapeDrawable();
- zAxisShape->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.0f), 0.05f, 100.0f));
- zAxisShape->setColor(axesColor);
- osg::ref_ptr<osg::ShapeDrawable> zConeShape = new osg::ShapeDrawable();
- zConeShape->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 50.0f), 0.2f, 1.0f));
- zConeShape->setColor(axesColor);
- zAxis->addDrawable(zConeShape.get());
- zAxis->addDrawable(zAxisShape.get());
- _coordinateAxes->addChild(xRotation.get());
- _coordinateAxes->addChild(yRotation.get());
- _coordinateAxes->addChild(zAxis.get());
- OSGWidget::fixMaterialState(_coordinateAxes);
- _root->addChild(_coordinateAxes);
- _mesh = new osg::Geode;
- // Add axes preview
- osg::ref_ptr<osg::Camera> hudCamera = new osg::Camera;
- int width = 1024;
- int height = 1024;
- hudCamera->setProjectionMatrixAsOrtho(0, width, 0, height, 1, 100);
- hudCamera->setRenderOrder(osg::Camera::POST_RENDER);
- hudCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
- hudCamera->setClearMask(GL_DEPTH_BUFFER_BIT);
- osg::ref_ptr<osg::Group> axesPreview = createAxesPreview();
- osg::MatrixTransform* pTM = new osg::MatrixTransform;
- pTM->addChild(axesPreview.get());
- axesPreview->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- pTM->setMatrix(osg::Matrix::scale(osg::Vec3(width/12, width/12, width/12)) * osg::Matrix::translate(osg::Vec3(width/20, width/20, 1)));
- pTM->setUpdateCallback(new HudCallback(camera));
- hudCamera->addChild(pTM);
- hudCamera->setViewMatrixAsLookAt(osg::Vec3(0, 0, 1), osg::Vec3(0, 0, 0), osg::Vec3(0, 1, 0)); // opengl default camera position
- _root->addChild(hudCamera.release());
- // Attach a manipulator (it's usually done for us when we use viewer.run())
- osg::ref_ptr<osgGA::TrackballManipulator> tm = new osgGA::TrackballManipulator;
- tm->setAllowThrow(false);
- _view->setCameraManipulator(tm);
- _viewer->addView(_view);
- _viewer->setThreadingModel(osgViewer::CompositeViewer::SingleThreaded);
- _viewer->realize();
- _picker = new PickHandler(this, _root);
- _root->addChild(_picker->getPickerRoot());
- _view->addEventHandler(_picker);
- // This ensures that the widget will receive keyboard events. This focus
- // policy is not set by default. The default, Qt::NoFocus, will result in
- // keyboard events that are ignored.
- this->setFocusPolicy(Qt::StrongFocus);
- this->setMinimumSize(100, 100);
- // Ensures that the widget receives mouse move events even though no
- // mouse button has been pressed. We require this in order to let the
- // graphics window switch viewports properly.
- this->setMouseTracking(true);
- _pointRoot = new osg::Group;
- _root->addChild(_pointRoot.get());
- _pointRenderer = new TrackPointRenderer(this, _pointRoot);
- }
- OSGWidget::~OSGWidget() {
- }
- void OSGWidget::renderBaseMesh(const osg::ref_ptr<osg::Vec3Array> vertices, const osg::ref_ptr<osg::Vec3Array> normals) {
- _root->removeChild(_mesh);
- osg::ref_ptr<osg::Geometry> meshGeometry = new osg::Geometry;
- meshGeometry->setVertexArray(vertices.get());
- meshGeometry->setNormalArray(normals.get(), osg::Array::BIND_PER_VERTEX);
- meshGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, vertices->getNumElements()));
- osgUtil::optimizeMesh(meshGeometry.get());
- _mesh->addDrawable(meshGeometry.get());
- OSGWidget::fixMaterialState(_mesh);
- _root->addChild(_mesh);
- _picker->updateRenderer();
- }
- osg::ref_ptr<osg::Geode> OSGWidget::getMesh() {
- return _mesh;
- }
- PickHandler* OSGWidget::getPicker() {
- return _picker;
- }
- TrackPointRenderer* OSGWidget::getPointRenderer() {
- return _pointRenderer;
- }
- void OSGWidget::loadSteamvrThread() {
- if (!_steamvrLoaded) {
- std::vector<Lib3MF::sPosition> verticesBuffer;
- std::vector<Lib3MF::sTriangle> triangleBuffer;
- for (unsigned int i = 0; i < sizeof(steamvrthread_VERTICES) / sizeof(float); i += 3) {
- Lib3MF::sPosition vertex = {steamvrthread_VERTICES[i], steamvrthread_VERTICES[i + 1], steamvrthread_VERTICES[i + 2]};
- verticesBuffer.push_back(vertex);
- }
- for (unsigned int i = 0; i < sizeof(steamvrthread_TRIANGLES) / sizeof(unsigned int); i += 3) {
- Lib3MF::sTriangle triangle = {steamvrthread_TRIANGLES[i], steamvrthread_TRIANGLES[i + 1], steamvrthread_TRIANGLES[i + 2]};
- triangleBuffer.push_back(triangle);
- }
- osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
- osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
- MeshTools::calculateNormals(verticesBuffer, triangleBuffer, vertices, normals);
- _steamvrThreadMesh = new osg::Geometry;
- _steamvrThreadMesh->setVertexArray(vertices.get());
- _steamvrThreadMesh->setNormalArray(normals.get(), osg::Array::BIND_PER_VERTEX);
- _steamvrThreadMesh->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, vertices->getNumElements()));
- osgUtil::optimizeMesh(_steamvrThreadMesh.get());
- _steamvrLoaded = true;
- }
- }
- void OSGWidget::paintEvent(QPaintEvent*) {
- this->makeCurrent();
- QPainter painter(this);
- painter.setRenderHint(QPainter::Antialiasing);
- this->paintGL();
- painter.end();
- this->doneCurrent();
- }
- void OSGWidget::paintGL() {
- _viewer->frame();
- }
- void OSGWidget::resizeGL(int width, int height) {
- auto pixelRatio = this->devicePixelRatio();
- this->getEventQueue()->windowResize(this->x(), this->y(), width * pixelRatio, height * pixelRatio);
- graphicsWindow_->resized(this->x(), this->y(), width * pixelRatio, height * pixelRatio);
- this->onResize(width, height);
- }
- void OSGWidget::keyPressEvent(QKeyEvent* event) {
- QString keyString = event->text();
- const char* keyData = keyString.toLocal8Bit().data();
- if (event->key() == Qt::Key_H) {
- this->onHome();
- return;
- }
- this->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KeySymbol(*keyData));
- }
- void OSGWidget::keyReleaseEvent(QKeyEvent* event) {
- QString keyString = event->text();
- const char* keyData = keyString.toLocal8Bit().data();
- this->getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KeySymbol(*keyData));
- }
- void OSGWidget::mouseMoveEvent(QMouseEvent* event) {
- auto pixelRatio = this->devicePixelRatio();
- this->getEventQueue()->mouseMotion(static_cast<float>(event->position().x() * pixelRatio), static_cast<float>(event->position().y() * pixelRatio));
- }
- void OSGWidget::mousePressEvent(QMouseEvent* event) {
- unsigned int button = 0;
- switch(event->button()) {
- case Qt::LeftButton:
- button = 1;
- break;
- case Qt::MiddleButton:
- button = 2;
- break;
- case Qt::RightButton:
- button = 3;
- break;
- default:
- break;
- }
- auto pixelRatio = this->devicePixelRatio();
- this->getEventQueue()->mouseButtonPress(static_cast<float>(event->position().x() * pixelRatio), static_cast<float>(event->position().y() * pixelRatio), button);
- }
- void OSGWidget::mouseReleaseEvent(QMouseEvent* event) {
- unsigned int button = 0;
- switch(event->button()) {
- case Qt::LeftButton:
- button = 1;
- break;
- case Qt::MiddleButton:
- button = 2;
- break;
- case Qt::RightButton:
- button = 3;
- break;
- default:
- break;
- }
- auto pixelRatio = this->devicePixelRatio();
- this->getEventQueue()->mouseButtonRelease(static_cast<float>(event->position().x() * pixelRatio), static_cast<float>(event->position().y() * pixelRatio), button);
- }
- void OSGWidget::wheelEvent(QWheelEvent* event) {
- event->accept();
- int delta = event->angleDelta().y();
- osgGA::GUIEventAdapter::ScrollingMotion motion = delta > 0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN;
- this->getEventQueue()->mouseScroll(motion);
- }
- bool OSGWidget::event(QEvent* event) {
- bool handled = QOpenGLWidget::event(event);
- // This ensures that the OSG widget is always going to be repainted after the
- // user performed some interaction. Doing this in the event handler ensures
- // that we don't forget about some event and prevents duplicate code.
- switch(event->type()) {
- case QEvent::KeyPress:
- case QEvent::KeyRelease:
- case QEvent::MouseButtonDblClick:
- case QEvent::MouseButtonPress:
- case QEvent::MouseButtonRelease:
- case QEvent::MouseMove:
- case QEvent::Wheel:
- this->update();
- break;
- case QEvent::Resize:
- this->onResize(this->width(), this->height());
- break;
- default:
- break;
- }
- return handled;
- }
- void OSGWidget::onHome() {
- osgViewer::ViewerBase::Views views;
- _viewer->getViews( views );
- for(std::size_t i = 0; i < views.size(); i++) {
- osgViewer::View* view = views.at(i);
- view->home();
- }
- }
- void OSGWidget::onResize(int width, int height) {
- std::vector<osg::Camera*> cameras;
- _viewer->getCameras(cameras);
- assert(cameras.size() == 1);
- auto pixelRatio = this->devicePixelRatio();
- cameras[0]->setViewport(0, 0, width * pixelRatio, height * pixelRatio);
- }
- osgGA::EventQueue* OSGWidget::getEventQueue() const {
- osgGA::EventQueue* eventQueue = graphicsWindow_->getEventQueue();
- if (eventQueue) {
- return eventQueue;
- } else {
- throw std::runtime_error("Unable to obtain valid event queue");
- }
- }
- osg::ref_ptr<osg::Group> OSGWidget::createAxesPreview() {
- osg::ref_ptr<osg::Group> axesPreview = new osg::Group;
- osg::Vec4 red = osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
- osg::Vec4 green = osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
- osg::Vec4 blue = osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f);
- osg::ref_ptr<osg::MatrixTransform> xRotation = new osg::MatrixTransform;
- xRotation->setMatrix(osg::Matrix::rotate(osg::Vec3f(0.0f, 0.0f, 1.0f), osg::Vec3f(1.0f, 0.0f, 0.0f)));
- osg::ref_ptr<osg::Geode> xAxis = new osg::Geode;
- osg::ref_ptr<osg::ShapeDrawable> xAxisShape = new osg::ShapeDrawable();
- xAxisShape->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.5f), 0.01f, 1.0f));
- xAxisShape->setColor(red);
- xAxis->addDrawable(xAxisShape.get());
- osg::ref_ptr<osg::ShapeDrawable> xConeShape = new osg::ShapeDrawable();
- xConeShape->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 1.0f), 0.05f, 0.2f));
- xConeShape->setColor(red);
- xAxis->addDrawable(xConeShape.get());
- xRotation->addChild(xAxis.get());
- osg::ref_ptr<osg::MatrixTransform> yRotation = new osg::MatrixTransform;
- yRotation->setMatrix(osg::Matrix::rotate(osg::Vec3f(0.0f, 0.0f, 1.0f), osg::Vec3f(0.0f, 1.0f, 0.0f)));
- osg::ref_ptr<osg::Geode> yAxis = new osg::Geode;
- osg::ref_ptr<osg::ShapeDrawable> yAxisShape = new osg::ShapeDrawable();
- yAxisShape->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.5f), 0.01f, 1.0f));
- yAxisShape->setColor(green);
- yAxis->addDrawable(yAxisShape.get());
- osg::ref_ptr<osg::ShapeDrawable> yConeShape = new osg::ShapeDrawable();
- yConeShape->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 1.0f), 0.05f, 0.2f));
- yConeShape->setColor(green);
- yAxis->addDrawable(yConeShape.get());
- yRotation->addChild(yAxis.get());
- osg::ref_ptr<osg::Geode> zAxis = new osg::Geode;
- osg::ref_ptr<osg::ShapeDrawable> zAxisShape = new osg::ShapeDrawable();
- zAxisShape->setShape(new osg::Cylinder(osg::Vec3(0.0f, 0.0f, 0.5f), 0.01f, 1.0f));
- zAxisShape->setColor(blue);
- osg::ref_ptr<osg::ShapeDrawable> zConeShape = new osg::ShapeDrawable();
- zConeShape->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 1.0f), 0.05f, 0.2f));
- zConeShape->setColor(blue);
- zAxis->addDrawable(zConeShape.get());
- zAxis->addDrawable(zAxisShape.get());
- axesPreview->addChild(xRotation.get());
- axesPreview->addChild(yRotation.get());
- axesPreview->addChild(zAxis.get());
- OSGWidget::fixMaterialState(axesPreview);
- return axesPreview;
- }
|