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(" ")
16 QFile styleFile(":/qt/style.qss");
17 styleFile.open( QFile::ReadOnly );
18 setStyleSheet(styleFile.readAll());
20 anim.setDuration(100);
28 void Canvas::view_anim(float v)
30 anim.setStartValue(perspective);
35 void Canvas::view_orthographic()
40 void Canvas::view_perspective()
45 void Canvas::load_mesh(Mesh* m, bool is_reload)
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();
56 // Reset other camera parameters
67 void Canvas::set_status(const QString &s)
73 void Canvas::set_perspective(float p)
79 void Canvas::clear_status()
85 void Canvas::initializeGL()
87 initializeGLFunctions();
89 mesh_shader.addShaderFromSourceFile(QGLShader::Vertex, ":/gl/mesh.vert");
90 mesh_shader.addShaderFromSourceFile(QGLShader::Fragment, ":/gl/mesh.frag");
93 backdrop = new Backdrop();
96 void Canvas::paintEvent(QPaintEvent *event)
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);
105 if (mesh) draw_mesh();
107 if (status.isNull()) return;
109 QPainter painter(this);
110 painter.setRenderHint(QPainter::Antialiasing);
111 painter.drawText(10, height() - 10, status);
115 void Canvas::draw_mesh()
119 // Load the transform and view matrices into the shader
121 mesh_shader.uniformLocation("transform_matrix"),
122 1, GL_FALSE, transform_matrix().data());
124 mesh_shader.uniformLocation("view_matrix"),
125 1, GL_FALSE, view_matrix().data());
127 // Compensate for z-flattening when zooming
128 glUniform1f(mesh_shader.uniformLocation("zoom"), 1/zoom);
130 // Find and enable the attribute location for vertex position
131 const GLuint vp = mesh_shader.attributeLocation("vertex_position");
132 glEnableVertexAttribArray(vp);
134 // Then draw the mesh with that vertex position
137 // Clean up state machine
138 glDisableVertexAttribArray(vp);
139 mesh_shader.release();
142 QMatrix4x4 Canvas::transform_matrix() const
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);
152 QMatrix4x4 Canvas::view_matrix() const
155 if (width() > height())
157 m.scale(-height() / float(width()), 1, 0.5);
161 m.scale(-1, width() / float(height()), 0.5);
163 m.scale(zoom, zoom, 1);
164 m(3, 2) = perspective;
168 void Canvas::mousePressEvent(QMouseEvent* event)
170 if (event->button() == Qt::LeftButton ||
171 event->button() == Qt::RightButton)
173 mouse_pos = event->pos();
174 setCursor(Qt::ClosedHandCursor);
178 void Canvas::mouseReleaseEvent(QMouseEvent* event)
180 if (event->button() == Qt::LeftButton ||
181 event->button() == Qt::RightButton)
187 void Canvas::mouseMoveEvent(QMouseEvent* event)
189 auto p = event->pos();
190 auto d = p - mouse_pos;
193 if (event->buttons() & Qt::LeftButton)
195 yaw = fmod(yaw - d.x(), 360);
196 tilt = fmod(tilt - d.y(), 360);
199 else if (event->buttons() & Qt::RightButton)
201 center = transform_matrix().inverted() *
202 view_matrix().inverted() *
203 QVector3D(-d.x() / (0.5*width()),
204 d.y() / (0.5*height()), 0);
210 void Canvas::wheelEvent(QWheelEvent *event)
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;
220 if (event->delta() < 0)
222 for (int i=0; i > event->delta(); --i)
225 else if (event->delta() > 0)
227 for (int i=0; i < event->delta(); ++i)
231 // Then find the cursor's GL position post-zoom and adjust center.
232 QVector3D b = transform_matrix().inverted() *
233 view_matrix().inverted() * v;
238 void Canvas::resizeGL(int width, int height)
240 glViewport(0, 0, width, height);