362 lines
8.6 KiB
C++
362 lines
8.6 KiB
C++
#include "../../fixC11.h"
|
|
|
|
#include "MapView3D.h"
|
|
|
|
#include "../model/MapModelElement.h"
|
|
#include "../model/MapModel.h"
|
|
|
|
#include "../3D/grid/GridModel.h"
|
|
#include "../3D/grid/GridRenderer.h"
|
|
|
|
#include "../3D/navMesh/NavMeshModel.h"
|
|
#include "../3D/navMesh/NavMeshRenderer.h"
|
|
|
|
#include "../3D/floorplan/FloorplanRenderer.h"
|
|
#include "../3D/floorplan/FloorplanRendererModel.h"
|
|
|
|
#include <QPushButton>
|
|
|
|
MapView3D::MapView3D(QWidget *parent) : QOpenGLWidget(parent) {
|
|
|
|
rot.x = 0;
|
|
rot.y = 0;
|
|
rot.z = 0;
|
|
|
|
center.x = 0;
|
|
center.y = 0;
|
|
center.z = 0;
|
|
|
|
scale.x = 1.0f;
|
|
scale.y = 1.0f;
|
|
scale.z = 1.0f;
|
|
|
|
gridRenderer = new GridRenderer();
|
|
|
|
floorplanRenderer = new FloorplanRenderer();
|
|
floorplanRendererModel = new FloorplanRendererModel();
|
|
|
|
QString style = "QPushButton:checked{\
|
|
background-color: rgb(200, 200, 230);\
|
|
border: none; \
|
|
}";
|
|
|
|
QPushButton* btnFloorplan = new QPushButton(UIHelper::getIcon("floorplan"), "", this);
|
|
btnFloorplan->setGeometry(16, 16, 32, 32);
|
|
btnFloorplan->setCheckable(true);
|
|
btnFloorplan->setChecked(true);
|
|
btnFloorplan->setStyleSheet(style);
|
|
connect(btnFloorplan, &QPushButton::toggled, [btnFloorplan,this] () {
|
|
emit onShow3DFloorplan(btnFloorplan->isChecked());
|
|
});
|
|
|
|
QPushButton* btnPerspective = new QPushButton(UIHelper::getIcon("perspective"), "", this);
|
|
btnPerspective->setGeometry(16, 16+8+32, 32, 32);
|
|
connect(btnPerspective, &QPushButton::clicked, [this] () {
|
|
usePerspectiveProjection = !usePerspectiveProjection;
|
|
emit update();
|
|
});
|
|
|
|
QPushButton* btnWireframe = new QPushButton(UIHelper::getIcon("wireframe"), "", this);
|
|
btnWireframe->setCheckable(true);
|
|
btnWireframe->setStyleSheet(style);
|
|
btnWireframe->setGeometry(16, 16+8+32+8+32, 32, 32);
|
|
connect(btnWireframe, &QPushButton::clicked, [this] () {
|
|
useWireframe = !useWireframe;
|
|
emit update();
|
|
});
|
|
|
|
QPushButton* btnExp3D = new QPushButton(UIHelper::getIcon("save"), "", this);
|
|
btnExp3D->setStyleSheet(style);
|
|
btnExp3D->setGeometry(16, 16+8+32+8+32+8+32, 32, 32);
|
|
connect(btnExp3D, &QPushButton::clicked, [this] () {
|
|
floorplanRendererModel->getMesh().exportOBJsimple("/tmp/map.obj");
|
|
floorplanRendererModel->getMesh().exportOBJcomplex("/tmp/map_complex", "map_complex");
|
|
floorplanRendererModel->getMesh().exportPLY("/tmp/map.ply");
|
|
});
|
|
|
|
|
|
|
|
|
|
QPushButton* btnGrid = new QPushButton(UIHelper::getIcon("grid"), "", this);
|
|
btnGrid->setCheckable(true);
|
|
btnGrid->setChecked(false);
|
|
btnGrid->setGeometry(16+16+32, 16, 32, 32);
|
|
btnGrid->setStyleSheet(style);
|
|
connect(btnGrid, &QPushButton::toggled, [btnGrid, this] () {
|
|
emit onShow3DGrid(btnGrid->isChecked());
|
|
});
|
|
|
|
QPushButton* btnNavMesh = new QPushButton(UIHelper::getIcon("mesh"), "", this);
|
|
btnNavMesh->setCheckable(true);
|
|
btnNavMesh->setChecked(false);
|
|
btnNavMesh->setGeometry(16+16+32+16+32, 16, 32, 32);
|
|
btnNavMesh->setStyleSheet(style);
|
|
connect(btnNavMesh, &QPushButton::toggled, [btnNavMesh, this] () {
|
|
emit onShow3DNavMesh(btnNavMesh->isChecked());
|
|
});
|
|
|
|
|
|
// android
|
|
setAttribute(Qt::WA_AcceptTouchEvents, true);
|
|
grabGesture(Qt::PanGesture);
|
|
grabGesture(Qt::PinchGesture);
|
|
|
|
auto format = QSurfaceFormat();
|
|
//format.setVersion(4,3);
|
|
format.setSamples(2);
|
|
//format.setProfile(QSurfaceFormat::CoreProfile);
|
|
|
|
setFormat(format);
|
|
|
|
}
|
|
|
|
|
|
void MapView3D::initializeGL() {
|
|
|
|
//setFormat(QGLFormat(QGL::SampleBuffers));
|
|
|
|
QOpenGLWidget::initializeGL();
|
|
|
|
// this should be the default!!
|
|
glCullFace(GL_BACK);
|
|
glFrontFace(GL_CCW);
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
// additional settings
|
|
glEnable(GL_DEPTH_TEST);
|
|
glClearColor(0.9, 0.9, 1.0, 1.0);
|
|
|
|
}
|
|
|
|
void MapView3D::paintGL() {
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
draw();
|
|
}
|
|
|
|
void MapView3D::resizeGL(int width, int height) {
|
|
glViewport(0, 0, width, height);
|
|
}
|
|
|
|
|
|
void MapView3D::mousePressEvent(QMouseEvent* e) {
|
|
mouse.btn = e->button();
|
|
mouse.x = e->x();
|
|
mouse.y = e->y();
|
|
update();
|
|
}
|
|
|
|
void MapView3D::mouseMoveEvent(QMouseEvent* e) {
|
|
float dx = mouse.x - e->x();
|
|
float dy = mouse.y - e->y();
|
|
if (mouse.btn == 1) {
|
|
rot.z -= dx/2.0f;
|
|
rot.x -= dy/2.0f;
|
|
} else if (mouse.btn == 4) {
|
|
moveXY(dx, dy);
|
|
}
|
|
mouse.x = e->x();
|
|
mouse.y = e->y();
|
|
update();
|
|
}
|
|
|
|
void MapView3D::moveXY(float dx, float dy) {
|
|
//Point3 vec(-dx / width() * 2 * viewport.size.x, 0, +dy / height() * 2 * viewport.size.y);
|
|
Point3 vec(-dx / width() * 2 * viewport.size.x, +dy / height() * 2 * viewport.size.y, 0);
|
|
//Point3 vec(-dx * 2 / width() , 0, +dy * 2 / height());
|
|
vec = vec.rot(-rot.x/180*M_PI, -rot.y/180*M_PI, -rot.z/180*M_PI);
|
|
vec /= scale;
|
|
center += vec;
|
|
}
|
|
|
|
void MapView3D::mouseReleaseEvent(QMouseEvent* e) {
|
|
(void) e;
|
|
update();
|
|
}
|
|
|
|
void MapView3D::wheelEvent(QWheelEvent* e) {
|
|
float f = e->delta() / 120.0f;
|
|
scale *= (f > 0) ? (2) : (0.5);
|
|
update();
|
|
}
|
|
|
|
// android
|
|
bool MapView3D::event(QEvent* event) {
|
|
if (event->type() == QEvent::Gesture) {
|
|
return gestureEvent(static_cast<QGestureEvent*>(event));
|
|
//} else if (event->type() == QEvent::TouchBegin) {
|
|
// return true;
|
|
//} else if (event->type() == QEvent::TouchUpdate) {
|
|
// return true;
|
|
} else {
|
|
return QWidget::event(event);
|
|
}
|
|
}
|
|
|
|
bool MapView3D::gestureEvent(QGestureEvent* event) {
|
|
if (QGesture *swipe = event->gesture(Qt::SwipeGesture)) {
|
|
//swipeTriggered(static_cast<QSwipeGesture *>(swipe));
|
|
} else if (QGesture *pan = event->gesture(Qt::PanGesture))
|
|
panTriggered(static_cast<QPanGesture *>(pan));
|
|
return true;
|
|
if (QGesture *pinch = event->gesture(Qt::PinchGesture)) {
|
|
pinchTriggered(static_cast<QPinchGesture *>(pinch));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void MapView3D::pinchTriggered(QPinchGesture* gesture) {
|
|
update();
|
|
}
|
|
|
|
void MapView3D::panTriggered(QPanGesture* gesture) {
|
|
moveXY(gesture->delta().x(), gesture->delta().y());
|
|
update();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MapView3D::setShowFloorplan(bool show) {
|
|
|
|
this->showFloorplan = show;
|
|
if (!show) {update(); return;}
|
|
|
|
// refresh
|
|
layerChange();
|
|
|
|
}
|
|
|
|
void MapView3D::setShowGrid(bool show) {
|
|
|
|
this->showGrid = show;
|
|
if (!show) {update(); return;}
|
|
|
|
// delete the previous grid (if any)
|
|
if (gridModel) {delete gridModel; gridModel = nullptr;}
|
|
|
|
// build a new model
|
|
GridModel* gm = new GridModel();
|
|
Floorplan::IndoorMap* im = getModel()->getMap();
|
|
gm->rebuild(im);
|
|
|
|
// remember
|
|
this->gridModel = gm;
|
|
|
|
// update UI
|
|
update();
|
|
|
|
}
|
|
|
|
void MapView3D::setShowNavMesh(bool show) {
|
|
|
|
this->showNavMesh = show;
|
|
if (!show) {update(); return;}
|
|
|
|
// delete the previous grid (if any)
|
|
if (navMeshModel) {delete navMeshModel; navMeshModel = nullptr;}
|
|
|
|
// build a new model
|
|
NavMeshModel* nm = new NavMeshModel();
|
|
Floorplan::IndoorMap* im = getModel()->getMap();
|
|
nm->rebuild(im);
|
|
|
|
// remember
|
|
this->navMeshModel = nm;
|
|
|
|
// update UI
|
|
update();
|
|
|
|
}
|
|
|
|
void MapView3D::layerChange() {
|
|
|
|
// todo: layers??
|
|
Floorplan::IndoorMap* im = getModel()->getMap();
|
|
this->floorplanRendererModel->rebuild(im);
|
|
update();
|
|
|
|
}
|
|
|
|
#include "misc/Shader.h"
|
|
|
|
void MapView3D::draw() {
|
|
|
|
static RenderSettings rs = RenderSettings(new Shader());
|
|
|
|
// view
|
|
QMatrix4x4 V;
|
|
|
|
V.translate(0,0,-50); // above the building
|
|
V.scale(scale.x, scale.y, scale.z);
|
|
V.rotate(rot.x, 1.0, 0.0, 0.0);
|
|
V.rotate(rot.y, 0.0, 1.0, 0.0);
|
|
V.rotate(rot.z, 0.0, 0.0, 1.0);
|
|
V.translate(center.x, center.y, center.z);
|
|
|
|
float farPlane = 200; // TODO
|
|
|
|
// projection
|
|
QMatrix4x4 P;
|
|
float aspect = (float) width() / (float) height();
|
|
|
|
if (usePerspectiveProjection) {
|
|
float w = width() / 30;
|
|
float h = height() / 30;
|
|
viewport.size.x = w;
|
|
viewport.size.y = h;
|
|
P.perspective(45.0f, aspect, 0.01, farPlane);
|
|
} else {
|
|
// default size: 50 * 50/aspect meters
|
|
float w = 50.0f;
|
|
float h = 50.0f * height() / width();
|
|
viewport.size.x = w;
|
|
viewport.size.y = h;
|
|
P.ortho(-w, +w, -h, +h, 0.1f, +farPlane);
|
|
}
|
|
|
|
rs.shader->bind();
|
|
rs.shader->setViewMatrix(V);
|
|
rs.shader->setProjectionMatrix(P);
|
|
|
|
if (showFloorplan && floorplanRendererModel) {
|
|
floorplanRenderer->renderSolid(rs, floorplanRendererModel->getTriaSolid(), useWireframe );
|
|
}
|
|
|
|
// // solid floorplan parts
|
|
// if (showFloorplan) {
|
|
|
|
// std::vector<MapModelElement*> elements = getModel()->getVisibleElements();
|
|
// for (MapModelElement* el : elements) {
|
|
// if (el->getMV3D() && !el->getMV3D()->isTransparent()) {el->getMV3D()->render(rs);}
|
|
// }
|
|
|
|
// }
|
|
|
|
// if (showGrid && gridModel) {
|
|
// gridRenderer->paintGL(gridModel->getGrid());
|
|
// }
|
|
|
|
if (showNavMesh && navMeshModel) {
|
|
navMeshRenderer->render(rs, navMeshModel->getNavMesh(), this);
|
|
}
|
|
|
|
// // transparant floorplan parts
|
|
// if (showFloorplan) {
|
|
|
|
// std::vector<MapModelElement*> elements = getModel()->getVisibleElements();
|
|
// for (MapModelElement* el : elements) {
|
|
// if (el->getMV3D() && el->getMV3D()->isTransparent()) {el->getMV3D()->render(rs);}
|
|
// }
|
|
|
|
// }
|
|
|
|
if (showFloorplan && floorplanRendererModel) {
|
|
floorplanRenderer->renderTransp(rs, floorplanRendererModel->getTriaTransp(), useWireframe);
|
|
}
|
|
|
|
|
|
|
|
}
|