]> git.sur5r.net Git - fstl/blob - src/canvas.cpp
New upstream version 0.9.3
[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),
14       perspective(0.25), anim(this, "perspective"), status(" ")
15 {
16     QFile styleFile(":/qt/style.qss");
17     styleFile.open( QFile::ReadOnly );
18     setStyleSheet(styleFile.readAll());
19
20     anim.setDuration(100);
21 }
22
23 Canvas::~Canvas()
24 {
25     delete mesh;
26 }
27
28 void Canvas::view_anim(float v)
29 {
30     anim.setStartValue(perspective);
31     anim.setEndValue(v);
32     anim.start();
33 }
34
35 void Canvas::view_orthographic()
36 {
37     view_anim(0);
38 }
39
40 void Canvas::view_perspective()
41 {
42     view_anim(0.25);
43 }
44
45 void Canvas::load_mesh(Mesh* m, bool is_reload)
46 {
47     mesh = new GLMesh(m);
48
49     if (!is_reload)
50     {
51         QVector3D lower(m->xmin(), m->ymin(), m->zmin());
52         QVector3D upper(m->xmax(), m->ymax(), m->zmax());
53         center = (lower + upper) / 2;
54         scale = 2 / (upper - lower).length();
55
56         // Reset other camera parameters
57         zoom = 1;
58         yaw = 0;
59         tilt = 90;
60     }
61
62     update();
63
64     delete m;
65 }
66
67 void Canvas::set_status(const QString &s)
68 {
69     status = s;
70     update();
71 }
72
73 void Canvas::set_perspective(float p)
74 {
75     perspective = p;
76     update();
77 }
78
79 void Canvas::clear_status()
80 {
81     status = "";
82     update();
83 }
84
85 void Canvas::initializeGL()
86 {
87     initializeGLFunctions();
88
89     mesh_shader.addShaderFromSourceFile(QGLShader::Vertex, ":/gl/mesh.vert");
90     mesh_shader.addShaderFromSourceFile(QGLShader::Fragment, ":/gl/mesh.frag");
91     mesh_shader.link();
92
93     backdrop = new Backdrop();
94 }
95
96 void Canvas::paintEvent(QPaintEvent *event)
97 {
98     Q_UNUSED(event);
99
100     glClearColor(0.0, 0.0, 0.0, 0.0);
101     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
102     glEnable(GL_DEPTH_TEST);
103
104     backdrop->draw();
105     if (mesh)  draw_mesh();
106
107     if (status.isNull())    return;
108
109     QPainter painter(this);
110     painter.setRenderHint(QPainter::Antialiasing);
111     painter.drawText(10, height() - 10, status);
112 }
113
114
115 void Canvas::draw_mesh()
116 {
117     mesh_shader.bind();
118
119     // Load the transform and view matrices into the shader
120     glUniformMatrix4fv(
121                 mesh_shader.uniformLocation("transform_matrix"),
122                 1, GL_FALSE, transform_matrix().data());
123     glUniformMatrix4fv(
124                 mesh_shader.uniformLocation("view_matrix"),
125                 1, GL_FALSE, view_matrix().data());
126
127     // Compensate for z-flattening when zooming
128     glUniform1f(mesh_shader.uniformLocation("zoom"), 1/zoom);
129
130     // Find and enable the attribute location for vertex position
131     const GLuint vp = mesh_shader.attributeLocation("vertex_position");
132     glEnableVertexAttribArray(vp);
133
134     // Then draw the mesh with that vertex position
135     mesh->draw(vp);
136
137     // Clean up state machine
138     glDisableVertexAttribArray(vp);
139     mesh_shader.release();
140 }
141
142 QMatrix4x4 Canvas::transform_matrix() const
143 {
144     QMatrix4x4 m;
145     m.rotate(tilt, QVector3D(1, 0, 0));
146     m.rotate(yaw,  QVector3D(0, 0, 1));
147     m.scale(-scale, scale, -scale);
148     m.translate(-center);
149     return m;
150 }
151
152 QMatrix4x4 Canvas::view_matrix() const
153 {
154     QMatrix4x4 m;
155     if (width() > height())
156     {
157         m.scale(-height() / float(width()), 1, 0.5);
158     }
159     else
160     {
161         m.scale(-1, width() / float(height()), 0.5);
162     }
163     m.scale(zoom, zoom, 1);
164     m(3, 2) = perspective;
165     return m;
166 }
167
168 void Canvas::mousePressEvent(QMouseEvent* event)
169 {
170     if (event->button() == Qt::LeftButton ||
171         event->button() == Qt::RightButton)
172     {
173         mouse_pos = event->pos();
174         setCursor(Qt::ClosedHandCursor);
175     }
176 }
177
178 void Canvas::mouseReleaseEvent(QMouseEvent* event)
179 {
180     if (event->button() == Qt::LeftButton ||
181         event->button() == Qt::RightButton)
182     {
183         unsetCursor();
184     }
185 }
186
187 void Canvas::mouseMoveEvent(QMouseEvent* event)
188 {
189     auto p = event->pos();
190     auto d = p - mouse_pos;
191
192
193     if (event->buttons() & Qt::LeftButton)
194     {
195         yaw = fmod(yaw - d.x(), 360);
196         tilt = fmod(tilt - d.y(), 360);
197         update();
198     }
199     else if (event->buttons() & Qt::RightButton)
200     {
201         center = transform_matrix().inverted() *
202                  view_matrix().inverted() *
203                  QVector3D(-d.x() / (0.5*width()),
204                             d.y() / (0.5*height()), 0);
205         update();
206     }
207     mouse_pos = p;
208 }
209
210 void Canvas::wheelEvent(QWheelEvent *event)
211 {
212     // Find GL position before the zoom operation
213     // (to zoom about mouse cursor)
214     auto p = event->pos();
215     QVector3D v(1 - p.x() / (0.5*width()),
216                 p.y() / (0.5*height()) - 1, 0);
217     QVector3D a = transform_matrix().inverted() *
218                   view_matrix().inverted() * v;
219
220     if (event->delta() < 0)
221     {
222         for (int i=0; i > event->delta(); --i)
223             zoom *= 1.001;
224     }
225     else if (event->delta() > 0)
226     {
227         for (int i=0; i < event->delta(); ++i)
228             zoom /= 1.001;
229     }
230
231     // Then find the cursor's GL position post-zoom and adjust center.
232     QVector3D b = transform_matrix().inverted() *
233                   view_matrix().inverted() * v;
234     center += b - a;
235     update();
236 }
237
238 void Canvas::resizeGL(int width, int height)
239 {
240     glViewport(0, 0, width, height);
241 }