11 const float Canvas::P_PERSPECTIVE = 0.25f;
12 const float Canvas::P_ORTHOGRAPHIC = 0.0f;
14 Canvas::Canvas(const QSurfaceFormat& format, QWidget *parent)
15 : QOpenGLWidget(parent), mesh(nullptr),
16 scale(1), zoom(1), tilt(90), yaw(0),
17 anim(this, "perspective"), status(" "),
21 QFile styleFile(":/qt/style.qss");
22 styleFile.open( QFile::ReadOnly );
23 setStyleSheet(styleFile.readAll());
25 anim.setDuration(100);
32 delete mesh_vertshader;
38 void Canvas::view_anim(float v)
40 anim.setStartValue(perspective);
45 void Canvas::view_perspective(float p, bool animate){
56 void Canvas::draw_axes(bool d)
62 void Canvas::invert_zoom(bool d)
68 void Canvas::load_mesh(Mesh* m, bool is_reload)
72 QVector3D lower(m->xmin(), m->ymin(), m->zmin());
73 QVector3D upper(m->xmax(), m->ymax(), m->zmax());
76 center = (lower + upper) / 2;
77 scale = 2 / (upper - lower).length();
79 // Reset other camera parameters
84 meshInfo = QStringLiteral("Triangles: %1\nX: [%2, %3]\nY: [%4, %5]\nZ: [%6, %7]").arg(m->triCount());
85 for(int dIdx = 0; dIdx < 3; dIdx++) meshInfo = meshInfo.arg(lower[dIdx]).arg(upper[dIdx]);
86 axis->setScale(lower, upper);
92 void Canvas::set_status(const QString &s)
98 void Canvas::set_perspective(float p)
104 void Canvas::set_drawMode(enum DrawMode mode)
110 void Canvas::clear_status()
116 void Canvas::initializeGL()
118 initializeOpenGLFunctions();
120 mesh_vertshader = new QOpenGLShader(QOpenGLShader::Vertex);
121 mesh_vertshader->compileSourceFile(":/gl/mesh.vert");
122 mesh_shader.addShader(mesh_vertshader);
123 mesh_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/gl/mesh.frag");
125 mesh_wireframe_shader.addShader(mesh_vertshader);
126 mesh_wireframe_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/gl/mesh_wireframe.frag");
127 mesh_wireframe_shader.link();
128 mesh_surfaceangle_shader.addShader(mesh_vertshader);
129 mesh_surfaceangle_shader.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/gl/mesh_surfaceangle.frag");
130 mesh_surfaceangle_shader.link();
132 backdrop = new Backdrop();
137 void Canvas::paintGL()
139 glClearColor(0.0, 0.0, 0.0, 0.0);
140 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
141 glEnable(GL_DEPTH_TEST);
143 if (mesh) draw_mesh();
144 if (drawAxes) axis->draw(transform_matrix(), view_matrix(),
145 orient_matrix(), aspect_matrix(), width() / float(height()));
147 QPainter painter(this);
148 painter.setRenderHint(QPainter::Antialiasing);
149 float textHeight = painter.fontInfo().pointSize();
150 if (drawAxes) painter.drawText(QRect(10, textHeight, width(), height()), meshInfo);
151 painter.drawText(10, height() - textHeight, status);
154 void Canvas::draw_mesh()
156 QOpenGLShaderProgram* selected_mesh_shader = NULL;
157 if(drawMode == wireframe)
159 selected_mesh_shader = &mesh_wireframe_shader;
160 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
164 if(drawMode == shaded)
166 selected_mesh_shader = &mesh_shader;
170 selected_mesh_shader = &mesh_surfaceangle_shader;
172 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
175 selected_mesh_shader->bind();
177 // Load the transform and view matrices into the shader
179 selected_mesh_shader->uniformLocation("transform_matrix"),
180 1, GL_FALSE, transform_matrix().data());
182 selected_mesh_shader->uniformLocation("view_matrix"),
183 1, GL_FALSE, view_matrix().data());
185 // Compensate for z-flattening when zooming
186 glUniform1f(selected_mesh_shader->uniformLocation("zoom"), 1/zoom);
188 // Find and enable the attribute location for vertex position
189 const GLuint vp = selected_mesh_shader->attributeLocation("vertex_position");
190 glEnableVertexAttribArray(vp);
192 // Then draw the mesh with that vertex position
195 // Reset draw mode for the background and anything else that needs to be drawn
196 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
198 // Clean up state machine
199 glDisableVertexAttribArray(vp);
200 selected_mesh_shader->release();
202 QMatrix4x4 Canvas::orient_matrix() const
205 m.rotate(tilt, QVector3D(1, 0, 0));
206 m.rotate(yaw, QVector3D(0, 0, 1));
207 //We want the x axis to the right, and the z axis up
211 QMatrix4x4 Canvas::transform_matrix() const
213 QMatrix4x4 m = orient_matrix();
215 m.translate(-center);
218 QMatrix4x4 Canvas::aspect_matrix() const
221 if (width() > height())
223 m.scale(-height() / float(width()), 1, 0.5);
227 m.scale(-1, width() / float(height()), 0.5);
231 QMatrix4x4 Canvas::view_matrix() const
233 QMatrix4x4 m = aspect_matrix();
234 m.scale(zoom, zoom, 1);
235 m(3, 2) = perspective;
239 void Canvas::mousePressEvent(QMouseEvent* event)
241 if (event->button() == Qt::LeftButton ||
242 event->button() == Qt::RightButton)
244 mouse_pos = event->pos();
245 setCursor(Qt::ClosedHandCursor);
249 void Canvas::mouseReleaseEvent(QMouseEvent* event)
251 if (event->button() == Qt::LeftButton ||
252 event->button() == Qt::RightButton)
258 void Canvas::mouseMoveEvent(QMouseEvent* event)
260 auto p = event->pos();
261 auto d = p - mouse_pos;
264 if (event->buttons() & Qt::LeftButton)
266 yaw = fmod(yaw - d.x(), 360);
267 tilt = fmod(tilt - d.y(), 360);
270 else if (event->buttons() & Qt::RightButton)
272 center = transform_matrix().inverted() *
273 view_matrix().inverted() *
274 QVector3D(-d.x() / (0.5*width()),
275 d.y() / (0.5*height()), 0);
281 void Canvas::wheelEvent(QWheelEvent *event)
283 // Find GL position before the zoom operation
284 // (to zoom about mouse cursor)
285 auto p = event->position();
286 QVector3D v(1 - p.x() / (0.5*width()),
287 p.y() / (0.5*height()) - 1, 0);
288 QVector3D a = transform_matrix().inverted() *
289 view_matrix().inverted() * v;
291 if (event->angleDelta().y() < 0)
293 for (int i=0; i > event->angleDelta().y(); --i)
299 else if (event->angleDelta().y() > 0)
301 for (int i=0; i < event->angleDelta().y(); ++i)
308 // Then find the cursor's GL position post-zoom and adjust center.
309 QVector3D b = transform_matrix().inverted() *
310 view_matrix().inverted() * v;
315 void Canvas::resizeGL(int width, int height)
317 glViewport(0, 0, width, height);