]> git.sur5r.net Git - fstl/blobdiff - src/canvas.cpp
New upstream version 0.10.0
[fstl] / src / canvas.cpp
index dd645a538838f790a1ea61e75ffbe67f3762187b..4da41a7e0cc17c8e049182fdb2c287205c2a7c9d 100644 (file)
@@ -1,41 +1,89 @@
 #include <QMouseEvent>
 #include <QMouseEvent>
-#include <QDebug>
 
 #include <cmath>
 
 #include "canvas.h"
 #include "backdrop.h"
 
 #include <cmath>
 
 #include "canvas.h"
 #include "backdrop.h"
+#include "axis.h"
 #include "glmesh.h"
 #include "mesh.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(" ")
+const float Canvas::P_PERSPECTIVE = 0.25f;
+const float Canvas::P_ORTHOGRAPHIC = 0.0f;
+
+Canvas::Canvas(const QSurfaceFormat& format, QWidget *parent)
+    : QOpenGLWidget(parent), mesh(nullptr),
+      scale(1), zoom(1), tilt(90), yaw(0),
+      anim(this, "perspective"), status(" "),
+      meshInfo("")
 {
 {
-    // Nothing to do here
+    setFormat(format);
+    QFile styleFile(":/qt/style.qss");
+    styleFile.open( QFile::ReadOnly );
+    setStyleSheet(styleFile.readAll());
+
+    anim.setDuration(100);
 }
 
 Canvas::~Canvas()
 {
 }
 
 Canvas::~Canvas()
 {
+    makeCurrent();
     delete mesh;
     delete mesh;
+    delete mesh_vertshader;
+    delete backdrop;
+    delete axis;
+    doneCurrent();
+}
+
+void Canvas::view_anim(float v)
+{
+    anim.setStartValue(perspective);
+    anim.setEndValue(v);
+    anim.start();
+}
+
+void Canvas::view_perspective(float p, bool animate){
+    if(animate)
+    {
+        view_anim(p);
+    }
+    else
+    {
+        set_perspective(p);
+    }
+}
+
+void Canvas::draw_axes(bool d)
+{
+    drawAxes = d;
+    update();
+}
+
+void Canvas::invert_zoom(bool d)
+{
+    invertZoom = d;
+    update();
 }
 
 }
 
-void Canvas::load_mesh(Mesh* m)
+void Canvas::load_mesh(Mesh* m, bool is_reload)
 {
 {
+    delete mesh;
     mesh = new GLMesh(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));
-
-    // Reset other camera parameters
-    zoom = 1;
-    yaw = 0;
-    tilt = 90;
+    QVector3D lower(m->xmin(), m->ymin(), m->zmin());
+    QVector3D upper(m->xmax(), m->ymax(), m->zmax());
+    if (!is_reload)
+    {
+        center = (lower + upper) / 2;
+        scale = 2 / (upper - lower).length();
 
 
+        // Reset other camera parameters
+        zoom = 1;
+        yaw = 0;
+        tilt = 90;
+    }
+    meshInfo = QStringLiteral("Triangles: %1\nX: [%2, %3]\nY: [%4, %5]\nZ: [%6, %7]").arg(m->triCount());
+    for(int dIdx = 0; dIdx < 3; dIdx++) meshInfo = meshInfo.arg(lower[dIdx]).arg(upper[dIdx]);
+    axis->setScale(lower, upper);
     update();
 
     delete m;
     update();
 
     delete m;
@@ -47,6 +95,18 @@ void Canvas::set_status(const QString &s)
     update();
 }
 
     update();
 }
 
+void Canvas::set_perspective(float p)
+{
+    perspective = p;
+    update();
+}
+
+void Canvas::set_drawMode(enum DrawMode mode)
+{
+    drawMode = mode;
+    update();
+}
+
 void Canvas::clear_status()
 {
     status = "";
 void Canvas::clear_status()
 {
     status = "";
@@ -55,72 +115,107 @@ void Canvas::clear_status()
 
 void Canvas::initializeGL()
 {
 
 void Canvas::initializeGL()
 {
-    initializeGLFunctions();
+    initializeOpenGLFunctions();
 
 
-    mesh_shader.addShaderFromSourceFile(QGLShader::Vertex, ":/gl/mesh.vert");
-    mesh_shader.addShaderFromSourceFile(QGLShader::Fragment, ":/gl/mesh.frag");
+    mesh_vertshader = new QOpenGLShader(QOpenGLShader::Vertex);
+    mesh_vertshader->compileSourceFile(":/gl/mesh.vert");
+    mesh_shader.addShader(mesh_vertshader);
+    mesh_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/gl/mesh.frag");
     mesh_shader.link();
     mesh_shader.link();
+    mesh_wireframe_shader.addShader(mesh_vertshader);
+    mesh_wireframe_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/gl/mesh_wireframe.frag");
+    mesh_wireframe_shader.link();
+    mesh_surfaceangle_shader.addShader(mesh_vertshader);
+    mesh_surfaceangle_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/gl/mesh_surfaceangle.frag");
+    mesh_surfaceangle_shader.link();
 
     backdrop = new Backdrop();
 
     backdrop = new Backdrop();
+    axis = new Axis();
 }
 
 }
 
-void Canvas::paintEvent(QPaintEvent *event)
-{
-    Q_UNUSED(event);
 
 
+void Canvas::paintGL()
+{
     glClearColor(0.0, 0.0, 0.0, 0.0);
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glEnable(GL_DEPTH_TEST);
     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();
     backdrop->draw();
     if (mesh)  draw_mesh();
-
-    if (status.isNull())    return;
+    if (drawAxes) axis->draw(transform_matrix(), view_matrix(),
+        orient_matrix(), aspect_matrix(), width() / float(height()));
 
     QPainter painter(this);
     painter.setRenderHint(QPainter::Antialiasing);
 
     QPainter painter(this);
     painter.setRenderHint(QPainter::Antialiasing);
-    painter.drawText(10, height() - 10, status);
+    float textHeight = painter.fontInfo().pointSize();
+    if (drawAxes) painter.drawText(QRect(10, textHeight, width(), height()), meshInfo);
+    painter.drawText(10, height() - textHeight, status);
 }
 
 }
 
-
 void Canvas::draw_mesh()
 {
 void Canvas::draw_mesh()
 {
-    mesh_shader.bind();
+    QOpenGLShaderProgram* selected_mesh_shader = NULL;
+    if(drawMode == wireframe)
+    {
+        selected_mesh_shader = &mesh_wireframe_shader;
+        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+    }
+    else
+    {
+        if(drawMode == shaded)
+        {
+            selected_mesh_shader = &mesh_shader;
+        }
+        else
+        {
+            selected_mesh_shader = &mesh_surfaceangle_shader;
+        }
+        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+    }
+
+    selected_mesh_shader->bind();
 
     // Load the transform and view matrices into the shader
     glUniformMatrix4fv(
 
     // Load the transform and view matrices into the shader
     glUniformMatrix4fv(
-                mesh_shader.uniformLocation("transform_matrix"),
+                selected_mesh_shader->uniformLocation("transform_matrix"),
                 1, GL_FALSE, transform_matrix().data());
     glUniformMatrix4fv(
                 1, GL_FALSE, transform_matrix().data());
     glUniformMatrix4fv(
-                mesh_shader.uniformLocation("view_matrix"),
+                selected_mesh_shader->uniformLocation("view_matrix"),
                 1, GL_FALSE, view_matrix().data());
 
     // Compensate for z-flattening when zooming
                 1, GL_FALSE, view_matrix().data());
 
     // Compensate for z-flattening when zooming
-    glUniform1f(mesh_shader.uniformLocation("zoom"), 1/zoom);
+    glUniform1f(selected_mesh_shader->uniformLocation("zoom"), 1/zoom);
 
     // Find and enable the attribute location for vertex position
 
     // Find and enable the attribute location for vertex position
-    const GLuint vp = mesh_shader.attributeLocation("vertex_position");
+    const GLuint vp = selected_mesh_shader->attributeLocation("vertex_position");
     glEnableVertexAttribArray(vp);
 
     // Then draw the mesh with that vertex position
     mesh->draw(vp);
 
     glEnableVertexAttribArray(vp);
 
     // Then draw the mesh with that vertex position
     mesh->draw(vp);
 
+    // Reset draw mode for the background and anything else that needs to be drawn
+    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
     // Clean up state machine
     glDisableVertexAttribArray(vp);
     // Clean up state machine
     glDisableVertexAttribArray(vp);
-    mesh_shader.release();
+    selected_mesh_shader->release();
 }
 }
-
-QMatrix4x4 Canvas::transform_matrix() const
+QMatrix4x4 Canvas::orient_matrix() const
 {
     QMatrix4x4 m;
     m.rotate(tilt, QVector3D(1, 0, 0));
     m.rotate(yaw,  QVector3D(0, 0, 1));
 {
     QMatrix4x4 m;
     m.rotate(tilt, QVector3D(1, 0, 0));
     m.rotate(yaw,  QVector3D(0, 0, 1));
+    //We want the x axis to the right, and the z axis up
+    m.scale(-1, 1, -1);
+    return m;
+}
+QMatrix4x4 Canvas::transform_matrix() const
+{
+    QMatrix4x4 m = orient_matrix();
     m.scale(scale);
     m.translate(-center);
     return m;
 }
     m.scale(scale);
     m.translate(-center);
     return m;
 }
-
-QMatrix4x4 Canvas::view_matrix() const
+QMatrix4x4 Canvas::aspect_matrix() const
 {
     QMatrix4x4 m;
     if (width() > height())
 {
     QMatrix4x4 m;
     if (width() > height())
@@ -131,7 +226,13 @@ QMatrix4x4 Canvas::view_matrix() const
     {
         m.scale(-1, width() / float(height()), 0.5);
     }
     {
         m.scale(-1, width() / float(height()), 0.5);
     }
+    return m;
+}
+QMatrix4x4 Canvas::view_matrix() const
+{
+    QMatrix4x4 m = aspect_matrix();
     m.scale(zoom, zoom, 1);
     m.scale(zoom, zoom, 1);
+    m(3, 2) = perspective;
     return m;
 }
 
     return m;
 }
 
@@ -159,10 +260,11 @@ void Canvas::mouseMoveEvent(QMouseEvent* event)
     auto p = event->pos();
     auto d = p - mouse_pos;
 
     auto p = event->pos();
     auto d = p - mouse_pos;
 
+
     if (event->buttons() & Qt::LeftButton)
     {
         yaw = fmod(yaw - d.x(), 360);
     if (event->buttons() & Qt::LeftButton)
     {
         yaw = fmod(yaw - d.x(), 360);
-        tilt = fmax(0, fmin(180, tilt - d.y()));
+        tilt = fmod(tilt - d.y(), 360);
         update();
     }
     else if (event->buttons() & Qt::RightButton)
         update();
     }
     else if (event->buttons() & Qt::RightButton)
@@ -180,21 +282,27 @@ void Canvas::wheelEvent(QWheelEvent *event)
 {
     // Find GL position before the zoom operation
     // (to zoom about mouse cursor)
 {
     // Find GL position before the zoom operation
     // (to zoom about mouse cursor)
-    auto p = event->pos();
+    auto p = event->position();
     QVector3D v(1 - p.x() / (0.5*width()),
                 p.y() / (0.5*height()) - 1, 0);
     QVector3D a = transform_matrix().inverted() *
                   view_matrix().inverted() * v;
 
     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)
+    if (event->angleDelta().y() < 0)
     {
     {
-        for (int i=0; i > event->delta(); --i)
-            zoom *= 1.001;
+        for (int i=0; i > event->angleDelta().y(); --i)
+            if (invertZoom)
+                zoom /= 1.001;
+            else 
+                zoom *= 1.001;
     }
     }
-    else if (event->delta() > 0)
+    else if (event->angleDelta().y() > 0)
     {
     {
-        for (int i=0; i < event->delta(); ++i)
-            zoom /= 1.001;
+        for (int i=0; i < event->angleDelta().y(); ++i)
+            if (invertZoom) 
+                zoom *= 1.001;
+            else 
+                zoom /= 1.001;
     }
 
     // Then find the cursor's GL position post-zoom and adjust center.
     }
 
     // Then find the cursor's GL position post-zoom and adjust center.
@@ -203,3 +311,8 @@ void Canvas::wheelEvent(QWheelEvent *event)
     center += b - a;
     update();
 }
     center += b - a;
     update();
 }
+
+void Canvas::resizeGL(int width, int height)
+{
+    glViewport(0, 0, width, height);
+}