m2-ar-projet/src/opengl_widget.cc

247 lines
8.2 KiB
C++
Raw Normal View History

2020-12-22 13:15:23 +01:00
#include "opengl_widget.hh"
2020-12-28 17:36:45 +01:00
#include "load_obj.hh"
2020-12-26 21:46:12 +01:00
2020-12-28 17:36:45 +01:00
#include <QMouseEvent>
#include <QOpenGLBuffer>
2020-12-22 13:15:23 +01:00
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;
2020-12-28 17:36:45 +01:00
// Those are a bit too verbose
if (!QString((const char *) message).startsWith("Shader Stats:")) {
qDebug() << "OpenGL debug output:" << message;
}
2020-12-22 13:15:23 +01:00
}
OpenGLWidget *OpenGLWidget::instance = nullptr;
OpenGLWidget::OpenGLWidget(QWidget *parent)
:QOpenGLWidget(parent) {
OpenGLWidget::instance = this;
}
OpenGLWidget::~OpenGLWidget() {
OpenGLWidget::instance = nullptr;
}
2020-12-28 17:36:45 +01:00
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();
}
2020-12-22 13:15:23 +01:00
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);
2020-12-28 17:36:45 +01:00
if (!main_program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/main.vert")) {
qFatal("Error compiling main.vert: %s", main_program.log().toLocal8Bit().constData());
2020-12-22 13:15:23 +01:00
}
2020-12-28 17:36:45 +01:00
if (!main_program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/main.frag")) {
qFatal("Error compiling main.frag: %s", main_program.log().toLocal8Bit().constData());
2020-12-22 13:15:23 +01:00
}
2020-12-28 17:36:45 +01:00
if (!main_program.link()) {
qFatal("Error linking the main shader program: %s", main_program.log().toLocal8Bit().constData());
2020-12-22 13:15:23 +01:00
}
2020-12-28 17:36:45 +01:00
main_program.bind();
main_program.setUniformValue("tex", 0);
main_program.release();
2020-12-22 13:15:23 +01:00
2020-12-28 17:36:45 +01:00
loadSkybox();
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) {
2020-12-28 17:36:45 +01:00
proj.setToIdentity();
proj.perspective(FOV, (float) w/h, .01, 1000);
2020-12-22 13:15:23 +01:00
}
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;
2020-12-28 17:36:45 +01:00
// 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);
2020-12-28 17:36:45 +01:00
// 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);
2020-12-22 13:15:23 +01:00
for (const OpenGLMesh &mesh : meshes) {
2020-12-28 17:36:45 +01:00
main_program.setUniformValue("model", mesh.mat);
2020-12-22 13:15:23 +01:00
glBindVertexArray(mesh.vao);
mesh.tex->bind();
2020-12-22 13:15:23 +01:00
glDrawArrays(GL_TRIANGLES, 0, mesh.nverts);
2020-12-28 17:36:45 +01:00
mesh.tex->release();
2020-12-22 13:15:23 +01:00
}
2020-12-28 17:36:45 +01:00
main_program.release();
2020-12-22 13:15:23 +01:00
}
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();
}