#include "MapView3D.h" #include #include #include "elements/Walls.h" #include "elements/Ground.h" #include "elements/Handrails.h" #include "elements/Stairs.h" #include "elements/Doors.h" #include "elements/Path.h" #include "elements/ColorPoints.h" #include "elements/Object.h" #include "../Settings.h" #include #include /** * before adding elements to the MapView via setMap(), * the MapViews openGL context must be initialized * that means: the MapView must have been added to a window, * which is already visible! */ MapView3D::MapView3D(QWidget* parent) : QOpenGLWidget(parent) { }; void MapView3D::clear() { for (Renderable* r : elements) {delete r;} elements.clear(); } void MapView3D::setMap(Floorplan::IndoorMap* map) { clear(); if (!isGLInitialized) {throw Exception("openGL is not yet initialized. add mapView to a visible window!");} // first to be rendered -> the colored debug points this->colorPoints = new ColorPoints(); elements.push_back(this->colorPoints); // 2nd is the path to the destination (if any) this->pathToDest = new Path(); elements.push_back(this->pathToDest); this->pathWalked = new Path(); this->pathWalked->setWidth(0.3); this->pathWalked->setColor(Qt::yellow); elements.push_back(this->pathWalked); // 3rd is the dude, walking along the path //leDude = new Object("/mnt/firma/tmp/3D/minion/minion.obj", "/mnt/firma/tmp/3D/minion/minion.png", "", 0.35); //leDude = new Object("/mnt/firma/tmp/3D/gnome/gnome.obj", "/mnt/firma/tmp/3D/gnome/gnome_diffuse.jpg", "/mnt/firma/tmp/3D/gnome/gnome_normal.jpg", 0.033); //leDude = new Object("/mnt/firma/tmp/3D/squirrel/squirrel.obj", "/mnt/firma/tmp/3D/squirrel/squirrel.jpg", "/mnt/firma/tmp/3D/squirrel/squirrel_normal.jpg", 0.033); //elements.push_back(leDude); // hereafter follows the floorplan (floors, doors, walls, stairs, ..) for (Floorplan::Floor* floor : map->floors) { elements.push_back(new Ground(floor)); elements.push_back(new Walls(floor)); elements.push_back(new Handrails(floor)); elements.push_back(new Stairs(floor)); elements.push_back(new Doors(floor)); } // initialize the OpenGL context of all contained elements for (Renderable* r : elements) { r->initGL(); } // i want the focus! needed for key-events setFocusPolicy(Qt::StrongFocus); } void MapView3D::setPathToDestination(const std::vector& path) { this->pathToDest->set(path); } void MapView3D::setPathWalked(const std::vector& path) { this->pathWalked->set(path); } void MapView3D::timerEvent(QTimerEvent *) { update(); } void MapView3D::initializeGL() { initializeOpenGLFunctions(); // basic config glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); // start background update timer timer.start(Settings::MapView::msPerFrame.ms(), this); // OpenGL is now initialized isGLInitialized = true; } void MapView3D::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw(); } void MapView3D::resizeGL(int w, int h) { // Calculate aspect ratio qreal aspect = qreal(w) / qreal(h ? h : 1); // viewing frustrum [0:50] meter const qreal zNear = 0.02, zFar = 50, fov = 50.0; // Reset projection matProject.setToIdentity(); matProject.scale(-1, 1, 1); glCullFace(GL_FRONT); //matProject.scale(0.05, 0.05, 0.05); matProject.perspective(fov, aspect, zNear, zFar); //matProject.scale(-0.01, 0.01, 0.01); } void MapView3D::rebuildLookat() { // QVector3D qDir(lookAt.dir.x, lookAt.dir.z, lookAt.dir.y); // QVector3D at = QVector3D(lookAt.pos.x, lookAt.pos.z, lookAt.pos.y); // QVector3D eye = at + qDir * 0.1; // QVector3D up = QVector3D(0,1,0); // matView.setToIdentity(); // //matView.scale(0.01, 0.01, 0.01); // matView.lookAt(eye, at, up); // //matView.scale(0.99, 1, 1); // //matView.translate(0.7, 0, 0); // lightPos = eye + QVector3D(0.0, 4.0, 0.0); // eyePos = eye; const QVector3D qDir = lookAt.getDir(); //QVector3D qDir(dir.x, dir.z, dir.y); const QVector3D eye = lookAt.eye_m;//(lookAt.eye_m.x, lookAt.eye_m.z, lookAt.eye_m.y); const QVector3D at = eye + qDir * 0.5; const QVector3D up = QVector3D(0,1,0); matView.setToIdentity(); matView.lookAt(eye, at, up); lightPos = eye + QVector3D(0.0, 0.5, 0.0) + qDir * 1.2; eyePos = eye; } void MapView3D::setCurrentEstimation(const Point3 pos, const Point3 dir) { const float angle = std::atan2(dir.y, dir.x) * 180 / M_PI; if (leDude) { leDude->setPosition(pos.x, pos.y, pos.z); leDude->setRotation(0, 0, -angle + 90); } } void MapView3D::setLookAt(const Point3 pos_m, const Point3 dir) { lookAt.eye_m = QVector3D(pos_m.x, pos_m.z, pos_m.y) + QVector3D(dir.x, dir.z, dir.y) * 0.1; lookAt.dir = QVector3D(dir.x, dir.z, dir.y); rebuildLookat(); } void MapView3D::setLookDir(const Point3 dir) { lookAt.dir = QVector3D(dir.x, dir.z, dir.y); rebuildLookat(); } void MapView3D::setLookEye(const Point3 eye_m) { lookAt.eye_m = QVector3D(eye_m.x, eye_m.z, eye_m.y); rebuildLookat(); } void MapView3D::mousePressEvent(QMouseEvent* evt) { mouseState.down = true; mouseState.x = evt->x(); mouseState.y = evt->y(); } void MapView3D::mouseMoveEvent(QMouseEvent* evt) { const float dx = evt->x() - mouseState.x; const float dy = evt->y() - mouseState.y; mouseState.x = evt->x(); mouseState.y = evt->y(); // PI*0.3 head movement left/right and up/down //const float yFac = (this->height() / 2) / (M_PI * 0.3); //const float xFac = (this->width() / 2) / (M_PI * 0.3); const float angleX = dx/3.0f; const float angleY = dy/3.0f; lookAt.ax += angleX; lookAt.ay += angleY; lookAt.dirRot.setToIdentity(); lookAt.dirRot.rotate(lookAt.ax, QVector3D(0,1,0)); lookAt.dirRot.rotate(lookAt.ay, QVector3D(0,0,1)); //lookAt.dirRot.rotate(angleX, QVector3D(0,1,0)); //lookAt.dirRot.rotate(angleY, QVector3D(0,0,1)); rebuildLookat(); } void MapView3D::mouseReleaseEvent(QMouseEvent* evt) { (void) evt; mouseState.down = false; } void MapView3D::keyPressEvent(QKeyEvent* evt) { const QVector3D dir = lookAt.getDir() * 0.5; const QVector3D side(-dir.z(), 0, dir.x()); if (evt->key() == Qt::Key_W) {lookAt.eye_m += dir; rebuildLookat();} if (evt->key() == Qt::Key_S) {lookAt.eye_m -= dir; rebuildLookat();} if (evt->key() == Qt::Key_A) {lookAt.eye_m += side; rebuildLookat();} if (evt->key() == Qt::Key_D) {lookAt.eye_m -= side; rebuildLookat();} } void MapView3D::toggleRenderMode() { renderMode = (RenderMode) (((int)renderMode + 1) % 2); // normally %3 but lines crash the smartphone for (Renderable* r : elements) { switch (renderMode) { case RenderMode::OUTLINE: r->setOutlineOnly(true); r->setTransparent(false); break; case RenderMode::TRANSPARENT: r->setOutlineOnly(false); r->setTransparent(true); break; case RenderMode::NORMAL: r->setOutlineOnly(false); r->setTransparent(false); break; } } } void MapView3D::draw() { //const Timestamp ts1 = Timestamp::fromUnixTime(); // clear everything glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); for (Renderable* r : elements) { QOpenGLShaderProgram& program = r->getProgram(); program.bind(); // set the matrices program.setUniformValue("m_matrix", r->modelMatrix.mat); program.setUniformValue("mv_matrix", matView * r->modelMatrix.mat); program.setUniformValue("mvp_matrix", matProject * matView * r->modelMatrix.mat); program.setUniformValue("lightWorldPos", lightPos); program.setUniformValue("eyeWorldPos", eyePos); r->render(renderParams); } //const Timestamp ts2 = Timestamp::fromUnixTime(); //qDebug("%d ms", (ts2-ts1).ms()); }