aboutsummaryrefslogtreecommitdiff
path: root/src/opengl_widget.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl_widget.cc')
-rw-r--r--src/opengl_widget.cc257
1 files changed, 149 insertions, 108 deletions
diff --git a/src/opengl_widget.cc b/src/opengl_widget.cc
index 42bc612..8d7cab5 100644
--- a/src/opengl_widget.cc
+++ b/src/opengl_widget.cc
@@ -1,53 +1,9 @@
#include "opengl_widget.hh"
-#include <QMouseEvent>
-
-
-static const GLchar *vertex_shader_source = R"glsl(
-#version 330 core
-
-layout(location = 0) in vec3 in_pos;
-layout(location = 1) in vec3 in_norm;
-layout(location = 2) in vec2 in_uv;
-
-out vec3 norm;
-out vec2 uv;
-out vec3 frag_pos;
-
-uniform mat4 proj;
-uniform mat4 view;
-uniform mat4 model;
-
-void main() {
- gl_Position = proj * view * model * vec4(in_pos, 1.0);
- norm = in_norm;
- uv = in_uv;
- frag_pos = vec3(model * vec4(in_pos, 1.0));
-}
-)glsl";
-
-static const GLchar *fragment_shader_source = R"glsl(
-#version 330 core
-
-in vec3 norm;
-in vec2 uv;
-in vec3 frag_pos;
+#include "load_obj.hh"
-out vec4 final_col;
-
-uniform sampler2D tex;
-
-void main() {
- 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);
-}
-)glsl";
+#include <QMouseEvent>
+#include <QOpenGLBuffer>
static void GLAPIENTRY opengl_debug_cb(GLenum source, GLenum type, GLuint id,
@@ -56,7 +12,10 @@ static void GLAPIENTRY opengl_debug_cb(GLenum source, GLenum type, GLuint id,
const void* userParam) {
(void) source; (void) type; (void) id; (void) severity; (void) length;
(void) userParam;
- qDebug() << "OpenGL debug output:" << message;
+ // Those are a bit too verbose
+ if (!QString((const char *) message).startsWith("Shader Stats:")) {
+ qDebug() << "OpenGL debug output:" << message;
+ }
}
@@ -74,6 +33,93 @@ OpenGLWidget::~OpenGLWidget() {
}
+void OpenGLWidget::loadSkybox() {
+ if (!skybox_program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/skybox.vert")) {
+ qFatal("Error compiling skybox.vert: %s", skybox_program.log().toLocal8Bit().constData());
+ }
+ if (!skybox_program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/skybox.frag")) {
+ qFatal("Error compiling skybox.frag: %s", skybox_program.log().toLocal8Bit().constData());
+ }
+ if (!skybox_program.link()) {
+ qFatal("Error linking the skybox shader program: %s", skybox_program.log().toLocal8Bit().constData());
+ }
+ skybox_program.bind();
+ skybox_program.setUniformValue("skybox", 0);
+
+ // GLfloat skybox_verts[] = {
+ // -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0,
+ // -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0,
+ // 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0,
+ // -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0,
+ // -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0,
+ // -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0
+ // };
+ QVector<GLfloat> skybox_verts = load_obj(":/mdl/cube.obj", 0);
+
+ // OpenGL native VAO version
+ glGenVertexArrays(1, &skybox_vao);
+ glBindVertexArray(skybox_vao);
+ glGenBuffers(1, &skybox_vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, skybox_vbo);
+ glBufferData(GL_ARRAY_BUFFER, skybox_verts.size() * sizeof (GLfloat), skybox_verts.data(), GL_STATIC_DRAW);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
+ glEnableVertexAttribArray(0);
+ glBindVertexArray(0);
+
+ // // QOpenGLVertexArrayObject version
+ // skybox_vao.create();
+ // skybox_vao.bind();
+ // QOpenGLBuffer skybox_vbo(QOpenGLBuffer::VertexBuffer);
+ // skybox_vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
+ // skybox_vbo.allocate((void *) skybox_verts.data(), skybox_verts.size() * sizeof (GLfloat));
+ // skybox_program.setAttributeBuffer(0, GL_FLOAT, 0, 3, 0);
+ // skybox_program.enableAttributeArray(0);
+
+ // Skybox texture images
+ QVector<QImage> skybox_img {
+ QImage(":/img/clouds1_west.jpg").convertToFormat(QImage::Format_RGB888),
+ QImage(":/img/clouds1_east.jpg").convertToFormat(QImage::Format_RGB888),
+ QImage(":/img/clouds1_up.jpg").convertToFormat(QImage::Format_RGB888),
+ QImage(":/img/clouds1_down.jpg").convertToFormat(QImage::Format_RGB888),
+ QImage(":/img/clouds1_south.jpg").convertToFormat(QImage::Format_RGB888),
+ QImage(":/img/clouds1_north.jpg").convertToFormat(QImage::Format_RGB888)
+ };
+ size_t width = skybox_img[0].width();
+ size_t height = skybox_img[0].height();
+
+ // OpenGL native texture version
+ glGenTextures(1, &skybox_tex);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_tex);
+ for (int i = 0; i < 6; i++) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE,
+ (const GLvoid *) skybox_img[i].constBits());
+ }
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+
+ // // QOpenGLTexture skybox texture version
+ // skybox_tex = new QOpenGLTexture(QOpenGLTexture::TargetCubeMap);
+ // skybox_tex->create();
+ // skybox_tex->setSize(width, skybox_img[0].height(), height);
+ // skybox_tex->setFormat(QOpenGLTexture::RGBA8_UNorm);
+ // skybox_tex->allocateStorage();
+ // for (int i = 0; i < 6; i++) {
+ // skybox_tex->setData(0, 0, (QOpenGLTexture::CubeMapFace) (QOpenGLTexture::CubeMapPositiveX + i),
+ // QOpenGLTexture::RGBA, QOpenGLTexture::UInt8,
+ // (const void*) skybox_img[i].constBits(), 0);
+ // }
+ // skybox_tex->setWrapMode(QOpenGLTexture::ClampToEdge);
+ // skybox_tex->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
+ // skybox_tex->setMagnificationFilter(QOpenGLTexture::LinearMipMapLinear);
+
+ skybox_program.release();
+}
+
+
void OpenGLWidget::initializeGL() {
initializeOpenGLFunctions();
GLint major, minor;
@@ -84,67 +130,22 @@ void OpenGLWidget::initializeGL() {
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);
+ if (!main_program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/main.vert")) {
+ qFatal("Error compiling main.vert: %s", main_program.log().toLocal8Bit().constData());
}
-
- /* 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);
+ if (!main_program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/main.frag")) {
+ qFatal("Error compiling main.frag: %s", main_program.log().toLocal8Bit().constData());
}
-
- /* Link the shader program. */
- GLuint shader_program = glCreateProgram();
- glAttachShader(shader_program, vertex_shader);
- glAttachShader(shader_program, fragment_shader);
- glBindFragDataLocation(shader_program, 0, "final_col");
- 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);
+ if (!main_program.link()) {
+ qFatal("Error linking the main shader program: %s", main_program.log().toLocal8Bit().constData());
}
+ main_program.bind();
+ main_program.setUniformValue("tex", 0);
+ main_program.release();
- /* 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());
-
- glUniform1i(glGetUniformLocation(shader_program, "tex"), 0);
+ loadSkybox();
glClearColor(1, 1, 1, 0);
-
glEnable(GL_DEPTH_TEST);
glEnable(GL_MULTISAMPLE);
@@ -153,9 +154,8 @@ void OpenGLWidget::initializeGL() {
void OpenGLWidget::resizeGL(int w, int h) {
- QMatrix4x4 projection;
- projection.perspective(FOV, (float) w/h, .01, 1000);
- glUniformMatrix4fv(proj_attr, 1, GL_FALSE, projection.data());
+ proj.setToIdentity();
+ proj.perspective(FOV, (float) w/h, .01, 1000);
}
@@ -164,14 +164,55 @@ void OpenGLWidget::paintGL() {
QMatrix4x4 trans;
trans.translate(0, 0, -cam_dist);
QMatrix4x4 view = trans * rot;
- glUniformMatrix4fv(view_attr, 1, GL_FALSE, view.data());
+
+ // skybox_vao.bind();
+ // glActiveTexture(GL_TEXTURE0);
+ // glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_tex);
+ // // skybox_tex->bind();
+ // glDrawArrays(GL_TRIANGLES, 0, 36);
+ // // skybox_tex->release();
+ // skybox_vao.release();
+
+ glDepthMask(GL_FALSE);
+ glDepthFunc(GL_LEQUAL);
+ skybox_program.bind();
+ skybox_program.setUniformValue("proj", proj);
+ skybox_program.setUniformValue("view", view);
+ // skybox_program.setUniformValue("model", QMatrix4x4());
+ glBindVertexArray(skybox_vao);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_tex);
+ // skybox_tex->bind();
+ // skybox_vao.bind();
+ glDrawArrays(GL_TRIANGLES, 0, 36);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+ // skybox_tex->release();
+ skybox_program.release();
+ glDepthMask(GL_TRUE);
+ glDepthFunc(GL_LESS);
+
+ main_program.bind();
+ main_program.setUniformValue("proj", proj);
+ main_program.setUniformValue("view", view);
glActiveTexture(GL_TEXTURE0);
+
+ // main_program.setUniformValue("model", QMatrix4x4());
+ // skybox_vao.bind();
+ // glDrawArrays(GL_TRIANGLES, 0, 36);
+
+ // skybox_program.bind();
+ // skybox_program.setUniformValue("proj", proj);
+ // skybox_program.setUniformValue("view", view);
+
for (const OpenGLMesh &mesh : meshes) {
- glUniformMatrix4fv(model_attr, 1, GL_FALSE, mesh.mat.data());
+ main_program.setUniformValue("model", mesh.mat);
glBindVertexArray(mesh.vao);
mesh.tex->bind();
glDrawArrays(GL_TRIANGLES, 0, mesh.nverts);
+ mesh.tex->release();
}
+ main_program.release();
+
}