199 lines
4.6 KiB
C++
199 lines
4.6 KiB
C++
#include <QMouseEvent>
|
|
#include <QDebug>
|
|
|
|
#include <cmath>
|
|
|
|
#include "canvas.h"
|
|
#include "backdrop.h"
|
|
#include "glmesh.h"
|
|
#include "mesh.h"
|
|
|
|
Canvas::Canvas(const QGLFormat& format, QWidget *parent)
|
|
: QGLWidget(format, parent), mesh(NULL),
|
|
scale(1), zoom(1), tilt(90), yaw(0), status(" ")
|
|
{
|
|
// Nothing to do here
|
|
}
|
|
|
|
Canvas::~Canvas()
|
|
{
|
|
delete mesh;
|
|
}
|
|
|
|
void Canvas::load_mesh(Mesh* m)
|
|
{
|
|
mesh = new GLMesh(m);
|
|
center = QVector3D(m->xmin() + m->xmax(),
|
|
m->ymin() + m->ymax(),
|
|
m->zmin() + m->zmax()) / 2;
|
|
scale = 2 / sqrt(
|
|
pow(m->xmax() - m->xmin(), 2) +
|
|
pow(m->ymax() - m->ymin(), 2) +
|
|
pow(m->zmax() - m->zmin(), 2));
|
|
update();
|
|
|
|
delete m;
|
|
}
|
|
|
|
void Canvas::set_status(const QString &s)
|
|
{
|
|
status = s;
|
|
update();
|
|
}
|
|
|
|
void Canvas::clear_status()
|
|
{
|
|
status = "";
|
|
update();
|
|
}
|
|
|
|
void Canvas::initializeGL()
|
|
{
|
|
initializeGLFunctions();
|
|
|
|
mesh_shader.addShaderFromSourceFile(QGLShader::Vertex, ":/gl/mesh.vert");
|
|
mesh_shader.addShaderFromSourceFile(QGLShader::Fragment, ":/gl/mesh.frag");
|
|
mesh_shader.link();
|
|
|
|
backdrop = new Backdrop();
|
|
}
|
|
|
|
void Canvas::paintEvent(QPaintEvent *event)
|
|
{
|
|
Q_UNUSED(event);
|
|
|
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
backdrop->draw();
|
|
if (mesh) draw_mesh();
|
|
|
|
if (status.isNull()) return;
|
|
|
|
QPainter painter(this);
|
|
painter.setRenderHint(QPainter::Antialiasing);
|
|
painter.drawText(10, height() - 10, status);
|
|
}
|
|
|
|
|
|
void Canvas::draw_mesh()
|
|
{
|
|
mesh_shader.bind();
|
|
|
|
// Load the transform and view matrices into the shader
|
|
glUniformMatrix4fv(
|
|
mesh_shader.uniformLocation("transform_matrix"),
|
|
1, GL_FALSE, transform_matrix().data());
|
|
glUniformMatrix4fv(
|
|
mesh_shader.uniformLocation("view_matrix"),
|
|
1, GL_FALSE, view_matrix().data());
|
|
|
|
// Compensate for z-flattening when zooming
|
|
glUniform1f(mesh_shader.uniformLocation("zoom"), 1/zoom);
|
|
|
|
// Find and enable the attribute location for vertex position
|
|
const GLuint vp = mesh_shader.attributeLocation("vertex_position");
|
|
glEnableVertexAttribArray(vp);
|
|
|
|
// Then draw the mesh with that vertex position
|
|
mesh->draw(vp);
|
|
|
|
// Clean up state machine
|
|
glDisableVertexAttribArray(vp);
|
|
mesh_shader.release();
|
|
}
|
|
|
|
QMatrix4x4 Canvas::transform_matrix() const
|
|
{
|
|
QMatrix4x4 m;
|
|
m.rotate(tilt, QVector3D(1, 0, 0));
|
|
m.rotate(yaw, QVector3D(0, 0, 1));
|
|
m.scale(scale);
|
|
m.translate(-center);
|
|
return m;
|
|
}
|
|
|
|
QMatrix4x4 Canvas::view_matrix() const
|
|
{
|
|
QMatrix4x4 m;
|
|
if (width() > height())
|
|
{
|
|
m.scale(-height() / float(width()), 1, 0.5);
|
|
}
|
|
else
|
|
{
|
|
m.scale(-1, width() / float(height()), 0.5);
|
|
}
|
|
m.scale(zoom, zoom, 1);
|
|
return m;
|
|
}
|
|
|
|
void Canvas::mousePressEvent(QMouseEvent* event)
|
|
{
|
|
if (event->button() == Qt::LeftButton ||
|
|
event->button() == Qt::RightButton)
|
|
{
|
|
mouse_pos = event->pos();
|
|
setCursor(Qt::ClosedHandCursor);
|
|
}
|
|
}
|
|
|
|
void Canvas::mouseReleaseEvent(QMouseEvent* event)
|
|
{
|
|
if (event->button() == Qt::LeftButton ||
|
|
event->button() == Qt::RightButton)
|
|
{
|
|
unsetCursor();
|
|
}
|
|
}
|
|
|
|
void Canvas::mouseMoveEvent(QMouseEvent* event)
|
|
{
|
|
auto p = event->pos();
|
|
auto d = p - mouse_pos;
|
|
|
|
if (event->buttons() & Qt::LeftButton)
|
|
{
|
|
yaw = fmod(yaw - d.x(), 360);
|
|
tilt = fmax(0, fmin(180, tilt - d.y()));
|
|
update();
|
|
}
|
|
else if (event->buttons() & Qt::RightButton)
|
|
{
|
|
center = transform_matrix().inverted() *
|
|
view_matrix().inverted() *
|
|
QVector3D(-d.x() / (0.5*width()),
|
|
d.y() / (0.5*height()), 0);
|
|
update();
|
|
}
|
|
mouse_pos = p;
|
|
}
|
|
|
|
void Canvas::wheelEvent(QWheelEvent *event)
|
|
{
|
|
// Find GL position before the zoom operation
|
|
// (to zoom about mouse cursor)
|
|
auto p = event->pos();
|
|
QVector3D v(1 - p.x() / (0.5*width()),
|
|
p.y() / (0.5*height()) - 1, 0);
|
|
QVector3D a = transform_matrix().inverted() *
|
|
view_matrix().inverted() * v;
|
|
|
|
if (event->delta() < 0)
|
|
{
|
|
for (int i=0; i > event->delta(); --i)
|
|
zoom *= 1.001;
|
|
}
|
|
else if (event->delta() > 0)
|
|
{
|
|
for (int i=0; i < event->delta(); ++i)
|
|
zoom /= 1.001;
|
|
}
|
|
|
|
// Then find the cursor's GL position post-zoom and adjust center.
|
|
QVector3D b = transform_matrix().inverted() *
|
|
view_matrix().inverted() * v;
|
|
center += b - a;
|
|
update();
|
|
}
|