]> git.sur5r.net Git - fstl/blob - src/canvas.cpp
Compensate for z-flattening when zooming
[fstl] / src / canvas.cpp
1 #include <QMouseEvent>
2 #include <QDebug>
3
4 #include <cmath>
5
6 #include "canvas.h"
7 #include "backdrop.h"
8 #include "glmesh.h"
9 #include "mesh.h"
10
11 Canvas::Canvas(const QGLFormat& format, QWidget *parent)
12     : QGLWidget(format, parent), mesh(NULL),
13       scale(1), zoom(1), tilt(90), yaw(0), status(" ")
14 {
15     // Nothing to do here
16 }
17
18 Canvas::~Canvas()
19 {
20     delete mesh;
21 }
22
23 void Canvas::load_mesh(Mesh* m)
24 {
25     mesh = new GLMesh(m);
26     center = QVector3D(m->xmin() + m->xmax(),
27                        m->ymin() + m->ymax(),
28                        m->zmin() + m->zmax()) / 2;
29     scale = 2 / sqrt(
30                 pow(m->xmax() - m->xmin(), 2) +
31                 pow(m->ymax() - m->ymin(), 2) +
32                 pow(m->zmax() - m->zmin(), 2));
33     update();
34
35     delete m;
36 }
37
38 void Canvas::set_status(const QString &s)
39 {
40     status = s;
41     update();
42 }
43
44 void Canvas::clear_status()
45 {
46     status = "";
47     update();
48 }
49
50 void Canvas::initializeGL()
51 {
52     initializeGLFunctions();
53
54     mesh_shader.addShaderFromSourceFile(QGLShader::Vertex, ":/gl/mesh.vert");
55     mesh_shader.addShaderFromSourceFile(QGLShader::Fragment, ":/gl/mesh.frag");
56     mesh_shader.link();
57
58     backdrop = new Backdrop();
59 }
60
61 void Canvas::paintEvent(QPaintEvent *event)
62 {
63     Q_UNUSED(event);
64
65     glClearColor(0.0, 0.0, 0.0, 0.0);
66     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
67     glEnable(GL_DEPTH_TEST);
68
69     backdrop->draw();
70     if (mesh)  draw_mesh();
71
72     if (status.isNull())    return;
73
74     QPainter painter(this);
75     painter.setRenderHint(QPainter::Antialiasing);
76     painter.drawText(10, height() - 10, status);
77 }
78
79
80 void Canvas::draw_mesh()
81 {
82     mesh_shader.bind();
83
84     // Load the transform and view matrices into the shader
85     glUniformMatrix4fv(
86                 mesh_shader.uniformLocation("transform_matrix"),
87                 1, GL_FALSE, transform_matrix().data());
88     glUniformMatrix4fv(
89                 mesh_shader.uniformLocation("view_matrix"),
90                 1, GL_FALSE, view_matrix().data());
91
92     // Compensate for z-flattening when zooming
93     glUniform1f(mesh_shader.uniformLocation("zoom"), 1/zoom);
94
95     // Find and enable the attribute location for vertex position
96     const GLuint vp = mesh_shader.attributeLocation("vertex_position");
97     glEnableVertexAttribArray(vp);
98
99     // Then draw the mesh with that vertex position
100     mesh->draw(vp);
101
102     // Clean up state machine
103     glDisableVertexAttribArray(vp);
104     mesh_shader.release();
105 }
106
107 QMatrix4x4 Canvas::transform_matrix() const
108 {
109     QMatrix4x4 m;
110     m.rotate(tilt, QVector3D(1, 0, 0));
111     m.rotate(yaw,  QVector3D(0, 0, 1));
112     m.scale(scale);
113     m.translate(-center);
114     return m;
115 }
116
117 QMatrix4x4 Canvas::view_matrix() const
118 {
119     QMatrix4x4 m;
120     if (width() > height())
121     {
122         m.scale(-height() / float(width()), 1, 0.5);
123     }
124     else
125     {
126         m.scale(-1, width() / float(height()), 0.5);
127     }
128     m.scale(zoom, zoom, 1);
129     return m;
130 }
131
132 void Canvas::mousePressEvent(QMouseEvent* event)
133 {
134     if (event->button() == Qt::LeftButton ||
135         event->button() == Qt::RightButton)
136     {
137         mouse_pos = event->pos();
138         setCursor(Qt::ClosedHandCursor);
139     }
140 }
141
142 void Canvas::mouseReleaseEvent(QMouseEvent* event)
143 {
144     if (event->button() == Qt::LeftButton ||
145         event->button() == Qt::RightButton)
146     {
147         unsetCursor();
148     }
149 }
150
151 void Canvas::mouseMoveEvent(QMouseEvent* event)
152 {
153     auto p = event->pos();
154     auto d = p - mouse_pos;
155
156     if (event->buttons() & Qt::LeftButton)
157     {
158         yaw = fmod(yaw - d.x(), 360);
159         tilt = fmax(0, fmin(180, tilt - d.y()));
160         update();
161     }
162     else if (event->buttons() & Qt::RightButton)
163     {
164         qDebug() << d;
165         center = transform_matrix().inverted() *
166                  view_matrix().inverted() *
167                  QVector3D(-d.x() / (0.5*width()),
168                             d.y() / (0.5*height()), 0);
169         update();
170     }
171     mouse_pos = p;
172 }
173
174 void Canvas::wheelEvent(QWheelEvent *event)
175 {
176     if (event->delta() < 0)
177     {
178         for (int i=0; i > event->delta(); --i)
179             zoom *= 1.001;
180     }
181     else if (event->delta() > 0)
182     {
183         for (int i=0; i < event->delta(); ++i)
184             zoom /= 1.001;
185     }
186     update();
187 }