mod_geo-tp/src/mesh_viewer.cpp

257 lines
6.5 KiB
C++
Raw Normal View History

2021-09-20 20:36:29 +02:00
#include "mesh_viewer.h"
#include <tgmath.h>
#include <utility>
const GLchar *vertex_shader_source = R"glsl(
attribute vec3 pos;
attribute vec3 col;
2021-09-20 20:36:29 +02:00
varying vec3 frag_col;
2021-09-20 20:36:29 +02:00
uniform mat4 proj;
uniform mat4 view;
uniform mat4 model;
void main() {
gl_Position = proj * view * model * vec4(pos, 1.0);
frag_col = col;
}
)glsl";
const GLchar *fragment_shader_source = R"glsl(
varying vec3 frag_col;
2021-09-20 20:36:29 +02:00
uniform vec3 wf_col;
uniform bool wireframe;
uniform float alpha;
void main() {
if (wireframe)
gl_FragColor = vec4(wf_col, alpha);
2021-09-20 20:36:29 +02:00
else
gl_FragColor = vec4(frag_col, alpha);
2021-09-20 20:36:29 +02:00
}
)glsl";
MeshViewer::MeshViewer(QWidget *parent) : QOpenGLWidget(parent) {
setMouseTracking(true);
setFocus();
}
void GLAPIENTRY
opengl_debug_cb(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam) {
(void) source;
(void) type;
(void) id;
(void) severity;
(void) length;
(void) userParam;
qDebug() << "OpenGL debug output:" << message;
}
void MeshViewer::initializeGL() {
// initializeOpenGLFunctions();
GLint major, minor;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
qDebug("OpenGL version %d.%d", major, minor);
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(opengl_debug_cb, 0);
/* Compile the vertex shader. */
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
glCompileShader(vertex_shader);
GLint status;
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
char log[1024];
glGetShaderInfoLog(vertex_shader, sizeof log, NULL, log);
fprintf(stderr, "Failed to compile the vertex shader: %s\n", log);
exit(1);
}
/* Compile the fragment shader. */
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
char log[1024];
glGetShaderInfoLog(fragment_shader, sizeof log, NULL, log);
fprintf(stderr, "Failed to compile the fragment shader: %s\n", log);
exit(1);
}
/* Link the shader program. */
GLuint shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
glAttachShader(shader_program, fragment_shader);
glBindFragDataLocation(shader_program, 0, "out_color");
glLinkProgram(shader_program);
glGetProgramiv(shader_program, GL_LINK_STATUS, &status);
if (status != GL_TRUE) {
char log[1024];
glGetProgramInfoLog(shader_program, sizeof log, NULL, log);
fprintf(stderr, "Failed to link the shader program: %s\n", log);
exit(1);
}
/* Use it. */
glUseProgram(shader_program);
/* Get the position attribute. */
pos_attr = glGetAttribLocation(shader_program, "pos");
col_attr = glGetAttribLocation(shader_program, "col");
proj_attr = glGetUniformLocation(shader_program, "proj");
view_attr = glGetUniformLocation(shader_program, "view");
model_attr = glGetUniformLocation(shader_program, "model");
wf_col_attr = glGetUniformLocation(shader_program, "wf_col");
wireframe_attr = glGetUniformLocation(shader_program, "wireframe");
alpha_attr = glGetUniformLocation(shader_program, "alpha");
glUniform1f(alpha_attr, 1);
glUniform3f(wf_col_attr, WIREFRAME_COLOR);
glClearColor(1, 1, 1, 0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_MULTISAMPLE);
emit initialized();
}
void MeshViewer::resizeGL(int w, int h) {
QMatrix4x4 projection;
projection.perspective(FOV, (float) w/h, .01, 100);
glUniformMatrix4fv(proj_attr, 1, GL_FALSE, projection.data());
}
void MeshViewer::paintGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 trans;
trans.translate(0, 0, -cam_dist);
QMatrix4x4 view = trans * rot;
glUniformMatrix4fv(view_attr, 1, GL_FALSE, view.data());
for (const OpenGLMesh m : meshes) {
glUniformMatrix4fv(model_attr, 1, GL_FALSE, m.mat.data());
/* Mesh */
glBindVertexArray(m.vao);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0, 2);
glDrawArrays(GL_TRIANGLES, 0, m.nverts);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_POLYGON_OFFSET_FILL);
/* Wireframe */
glUniform1f(wireframe_attr, 1);
glDrawArrays(GL_TRIANGLES, 0, m.nverts);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glLineWidth(1);
glUniform1f(wireframe_attr, 0);
}
}
OpenGLMesh *MeshViewer::addOpenGLMesh(size_t nverts, const GLfloat *verts, QMatrix4x4 mat, QColor col) {
makeCurrent();
GLuint vao, vbo;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, nverts * 6 * sizeof (GLfloat), verts, GL_DYNAMIC_DRAW);
glVertexAttribPointer(pos_attr, 3, GL_FLOAT, GL_FALSE, 6 * sizeof (GLfloat), 0);
glEnableVertexAttribArray(pos_attr);
glVertexAttribPointer(col_attr, 3, GL_FLOAT, GL_FALSE, 6 * sizeof (GLfloat),
(const void *) (3 * sizeof (GLfloat)));
glEnableVertexAttribArray(col_attr);
glBindVertexArray(0);
meshes.append({vao, vbo, nverts, mat, col});
doneCurrent();
update();
return &meshes.last();
}
OpenGLMesh *MeshViewer::addOpenGLMeshFromOpenMesh(MyMesh* mesh, QMatrix4x4 mat, QColor col) {
GLfloat *verts = new GLfloat[mesh->n_faces() * 3 * 6];
size_t i = 0;
for (MyMesh::FaceHandle face : mesh->faces()) {
for (MyMesh::VertexHandle vec : mesh->fv_range(face)) {
verts[6*i + 0] = mesh->point(vec)[0];
verts[6*i + 1] = mesh->point(vec)[1];
verts[6*i + 2] = mesh->point(vec)[2];
verts[6*i + 3] = mesh->color(vec)[0];
verts[6*i + 4] = mesh->color(vec)[1];
verts[6*i + 5] = mesh->color(vec)[2];
i++;
}
}
OpenGLMesh *ret = addOpenGLMesh(i, verts, mat, col);
delete[] verts;
return ret;
}
void MeshViewer::removeOpenGLMesh(OpenGLMesh *mesh) {
glDeleteVertexArrays(1, &mesh->vao);
glDeleteBuffers(1, &mesh->vbo);
for (int i = 0; i < meshes.size(); i++) {
if (&meshes[i] == mesh) meshes.removeAt(i);
}
}
void MeshViewer::mousePressEvent(QMouseEvent *e) {
if (e->button() == Qt::LeftButton) {
mouse_pos = e->pos();
}
}
void MeshViewer::mouseReleaseEvent(QMouseEvent *e) {
(void) e;
rot_start = rot;
}
void MeshViewer::mouseMoveEvent(QMouseEvent *e) {
if (e->buttons() & Qt::LeftButton) {
QPoint delta = e->pos() - mouse_pos;
rot = rot_start;
rot.rotate(delta.x() / 5., 0, 1, 0);
rot.rotate(delta.y() / 5., QVector3D(1, 0, 0) * rot);
update();
}
}
void MeshViewer::wheelEvent(QWheelEvent *e) {
cam_dist -= e->angleDelta().y() / 1000. * cam_dist;
update();
}