2020-12-22 13:15:23 +01:00
|
|
|
#include "opengl_widget.hh"
|
|
|
|
|
2020-12-22 16:35:25 +01:00
|
|
|
#include <QMouseEvent>
|
|
|
|
|
2020-12-22 13:15:23 +01:00
|
|
|
|
|
|
|
static const GLchar *vertex_shader_source = R"glsl(
|
|
|
|
#version 330 core
|
|
|
|
|
2020-12-26 01:21:28 +01:00
|
|
|
layout(location = 0) in vec3 in_pos;
|
2020-12-26 21:46:12 +01:00
|
|
|
layout(location = 1) in vec3 in_norm;
|
|
|
|
layout(location = 2) in vec2 in_uv;
|
2020-12-26 01:21:28 +01:00
|
|
|
|
2020-12-26 21:46:12 +01:00
|
|
|
out vec3 norm;
|
2020-12-26 01:21:28 +01:00
|
|
|
out vec2 uv;
|
2020-12-26 21:46:12 +01:00
|
|
|
out vec3 frag_pos;
|
2020-12-22 13:15:23 +01:00
|
|
|
|
|
|
|
uniform mat4 proj;
|
|
|
|
uniform mat4 view;
|
|
|
|
uniform mat4 model;
|
|
|
|
|
|
|
|
void main() {
|
2020-12-26 01:21:28 +01:00
|
|
|
gl_Position = proj * view * model * vec4(in_pos, 1.0);
|
2020-12-26 21:46:12 +01:00
|
|
|
norm = in_norm;
|
2020-12-26 01:21:28 +01:00
|
|
|
uv = in_uv;
|
2020-12-26 21:46:12 +01:00
|
|
|
frag_pos = vec3(model * vec4(in_pos, 1.0));
|
2020-12-22 13:15:23 +01:00
|
|
|
}
|
|
|
|
)glsl";
|
|
|
|
|
|
|
|
static const GLchar *fragment_shader_source = R"glsl(
|
|
|
|
#version 330 core
|
|
|
|
|
2020-12-26 21:46:12 +01:00
|
|
|
in vec3 norm;
|
2020-12-26 01:21:28 +01:00
|
|
|
in vec2 uv;
|
2020-12-26 21:46:12 +01:00
|
|
|
in vec3 frag_pos;
|
|
|
|
|
2020-12-22 13:15:23 +01:00
|
|
|
out vec4 final_col;
|
|
|
|
|
2020-12-26 01:21:28 +01:00
|
|
|
uniform sampler2D tex;
|
|
|
|
|
2020-12-22 13:15:23 +01:00
|
|
|
void main() {
|
2020-12-26 21:46:12 +01:00
|
|
|
vec3 light_col = vec3(1, .964, .783);
|
|
|
|
vec3 ambient = light_col * .2;
|
|
|
|
|
|
|
|
vec3 light_dir = normalize(vec3(5, 10, -8));
|
|
|
|
float diff = max(dot(normalize(norm), light_dir), 0.0);
|
|
|
|
vec3 diffuse = diff * light_col;
|
|
|
|
|
|
|
|
final_col = texture(tex, uv) * vec4(ambient + diffuse, 1);
|
2020-12-22 13:15:23 +01:00
|
|
|
}
|
|
|
|
)glsl";
|
|
|
|
|
|
|
|
|
|
|
|
static 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
OpenGLWidget *OpenGLWidget::instance = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
OpenGLWidget::OpenGLWidget(QWidget *parent)
|
|
|
|
:QOpenGLWidget(parent) {
|
|
|
|
OpenGLWidget::instance = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
OpenGLWidget::~OpenGLWidget() {
|
|
|
|
OpenGLWidget::instance = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void OpenGLWidget::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);
|
2020-12-26 01:21:28 +01:00
|
|
|
glBindFragDataLocation(shader_program, 0, "final_col");
|
2020-12-22 13:15:23 +01:00
|
|
|
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");
|
|
|
|
|
|
|
|
proj_attr = glGetUniformLocation(shader_program, "proj");
|
|
|
|
view_attr = glGetUniformLocation(shader_program, "view");
|
|
|
|
model_attr = glGetUniformLocation(shader_program, "model");
|
|
|
|
|
|
|
|
QMatrix4x4 view;
|
|
|
|
view.translate(0, 0, 5);
|
|
|
|
glUniformMatrix4fv(view_attr, 1, GL_FALSE, view.data());
|
|
|
|
|
|
|
|
QMatrix4x4 trans;
|
|
|
|
trans.translate(0, 0, -5);
|
|
|
|
glUniformMatrix4fv(view_attr, 1, GL_FALSE, trans.data());
|
|
|
|
|
2020-12-26 01:21:28 +01:00
|
|
|
glUniform1i(glGetUniformLocation(shader_program, "tex"), 0);
|
|
|
|
|
2020-12-22 13:15:23 +01:00
|
|
|
glClearColor(1, 1, 1, 0);
|
|
|
|
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_MULTISAMPLE);
|
|
|
|
|
|
|
|
emit initialized();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void OpenGLWidget::resizeGL(int w, int h) {
|
|
|
|
QMatrix4x4 projection;
|
2020-12-26 21:46:12 +01:00
|
|
|
projection.perspective(FOV, (float) w/h, .01, 1000);
|
2020-12-22 13:15:23 +01:00
|
|
|
glUniformMatrix4fv(proj_attr, 1, GL_FALSE, projection.data());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void OpenGLWidget::paintGL() {
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
2020-12-22 16:35:25 +01:00
|
|
|
QMatrix4x4 trans;
|
|
|
|
trans.translate(0, 0, -cam_dist);
|
|
|
|
QMatrix4x4 view = trans * rot;
|
|
|
|
glUniformMatrix4fv(view_attr, 1, GL_FALSE, view.data());
|
2020-12-26 01:21:28 +01:00
|
|
|
glActiveTexture(GL_TEXTURE0);
|
2020-12-22 13:15:23 +01:00
|
|
|
for (const OpenGLMesh &mesh : meshes) {
|
|
|
|
glUniformMatrix4fv(model_attr, 1, GL_FALSE, mesh.mat.data());
|
|
|
|
glBindVertexArray(mesh.vao);
|
2020-12-26 01:21:28 +01:00
|
|
|
mesh.tex->bind();
|
2020-12-22 13:15:23 +01:00
|
|
|
glDrawArrays(GL_TRIANGLES, 0, mesh.nverts);
|
|
|
|
}
|
|
|
|
}
|
2020-12-22 16:35:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
void OpenGLWidget::mousePressEvent(QMouseEvent *e) {
|
|
|
|
if (e->button() == Qt::LeftButton) {
|
|
|
|
mouse_pos = e->pos();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void OpenGLWidget::mouseReleaseEvent(QMouseEvent *e) {
|
|
|
|
(void) e;
|
|
|
|
rot_start = rot;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void OpenGLWidget::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 OpenGLWidget::wheelEvent(QWheelEvent *e) {
|
|
|
|
cam_dist -= e->angleDelta().y() / 1000. * cam_dist;
|
|
|
|
update();
|
|
|
|
}
|