10 Canvas::Canvas(const QSurfaceFormat& format, QWidget *parent)
11 : QOpenGLWidget(parent), mesh(nullptr),
12 scale(1), zoom(1), tilt(90), yaw(0),
13 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);
30 void Canvas::view_anim(float v)
32 anim.setStartValue(perspective);
37 void Canvas::view_orthographic()
42 void Canvas::view_perspective()
47 void Canvas::draw_shaded()
52 void Canvas::draw_wireframe()
57 void Canvas::load_mesh(Mesh* m, bool is_reload)
63 QVector3D lower(m->xmin(), m->ymin(), m->zmin());
64 QVector3D upper(m->xmax(), m->ymax(), m->zmax());
65 center = (lower + upper) / 2;
66 scale = 2 / (upper - lower).length();
68 // Reset other camera parameters
79 void Canvas::set_status(const QString &s)
85 void Canvas::set_perspective(float p)
91 void Canvas::set_drawMode(int mode)
97 void Canvas::clear_status()
103 void Canvas::initializeGL()
105 initializeOpenGLFunctions();
107 mesh_shader.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/gl/mesh.vert");
108 mesh_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/gl/mesh.frag");
110 mesh_wireframe_shader.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/gl/mesh.vert");
111 mesh_wireframe_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/gl/mesh_wireframe.frag");
112 mesh_wireframe_shader.link();
114 backdrop = new Backdrop();
118 void Canvas::paintGL()
120 glClearColor(0.0, 0.0, 0.0, 0.0);
121 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
122 glEnable(GL_DEPTH_TEST);
125 if (mesh) draw_mesh();
127 if (status.isNull()) return;
129 QPainter painter(this);
130 painter.setRenderHint(QPainter::Antialiasing);
131 painter.drawText(10, height() - 10, status);
134 void Canvas::draw_mesh()
136 QOpenGLShaderProgram* selected_mesh_shader = NULL;
140 selected_mesh_shader = &mesh_wireframe_shader;
141 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
145 selected_mesh_shader = &mesh_shader;
146 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
149 selected_mesh_shader->bind();
151 // Load the transform and view matrices into the shader
153 selected_mesh_shader->uniformLocation("transform_matrix"),
154 1, GL_FALSE, transform_matrix().data());
156 selected_mesh_shader->uniformLocation("view_matrix"),
157 1, GL_FALSE, view_matrix().data());
159 // Compensate for z-flattening when zooming
160 glUniform1f(selected_mesh_shader->uniformLocation("zoom"), 1/zoom);
162 // Find and enable the attribute location for vertex position
163 const GLuint vp = selected_mesh_shader->attributeLocation("vertex_position");
164 glEnableVertexAttribArray(vp);
166 // Then draw the mesh with that vertex position
169 // Reset draw mode for the background and anything else that needs to be drawn
170 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
172 // Clean up state machine
173 glDisableVertexAttribArray(vp);
174 selected_mesh_shader->release();
177 QMatrix4x4 Canvas::transform_matrix() const
180 m.rotate(tilt, QVector3D(1, 0, 0));
181 m.rotate(yaw, QVector3D(0, 0, 1));
182 m.scale(-scale, scale, -scale);
183 m.translate(-center);
187 QMatrix4x4 Canvas::view_matrix() const
190 if (width() > height())
192 m.scale(-height() / float(width()), 1, 0.5);
196 m.scale(-1, width() / float(height()), 0.5);
198 m.scale(zoom, zoom, 1);
199 m(3, 2) = perspective;
203 void Canvas::mousePressEvent(QMouseEvent* event)
205 if (event->button() == Qt::LeftButton ||
206 event->button() == Qt::RightButton)
208 mouse_pos = event->pos();
209 setCursor(Qt::ClosedHandCursor);
213 void Canvas::mouseReleaseEvent(QMouseEvent* event)
215 if (event->button() == Qt::LeftButton ||
216 event->button() == Qt::RightButton)
222 void Canvas::mouseMoveEvent(QMouseEvent* event)
224 auto p = event->pos();
225 auto d = p - mouse_pos;
228 if (event->buttons() & Qt::LeftButton)
230 yaw = fmod(yaw - d.x(), 360);
231 tilt = fmod(tilt - d.y(), 360);
234 else if (event->buttons() & Qt::RightButton)
236 center = transform_matrix().inverted() *
237 view_matrix().inverted() *
238 QVector3D(-d.x() / (0.5*width()),
239 d.y() / (0.5*height()), 0);
245 void Canvas::wheelEvent(QWheelEvent *event)
247 // Find GL position before the zoom operation
248 // (to zoom about mouse cursor)
249 auto p = event->pos();
250 QVector3D v(1 - p.x() / (0.5*width()),
251 p.y() / (0.5*height()) - 1, 0);
252 QVector3D a = transform_matrix().inverted() *
253 view_matrix().inverted() * v;
255 if (event->delta() < 0)
257 for (int i=0; i > event->delta(); --i)
260 else if (event->delta() > 0)
262 for (int i=0; i < event->delta(); ++i)
266 // Then find the cursor's GL position post-zoom and adjust center.
267 QVector3D b = transform_matrix().inverted() *
268 view_matrix().inverted() * v;
273 void Canvas::resizeGL(int width, int height)
275 glViewport(0, 0, width, height);