#pragma once
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <glm/glm.hpp>
#include "GL/Program.h"
#include "GL/VAO.h"
class OGLWidget : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core
{
Q_OBJECT
protected:
void initializeGL() override;
void paintGL() override;
void resizeGL(int width, int height) override;
private:
GL::VAO* _current_vao;
GL::Program* _current_program;
float _uniform;
void clear_color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 1.0);
public:
OGLWidget(QWidget* parent = nullptr);
~OGLWidget();
void timerEvent(QTimerEvent*) override;
public slots:
};
#include "oglwidget.h"
OGLWidget::OGLWidget(QWidget* parent)
: QOpenGLWidget(parent)
{
_uniform = 0.0f;
this->startTimer(10);
}
OGLWidget::~OGLWidget()
{
delete _current_vao;
delete _current_program;
}
void OGLWidget::initializeGL()
{
if(!initializeOpenGLFunctions())
{
throw std::runtime_error("Could not initialize QOpenGLFunctions!");
}
auto* functions = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
_current_vao = new GL::VAO(functions);
_current_program = new GL::Program(functions, "first");
//Vertices
_current_vao->add_VBO(
{
{-0.5f, 0.5f, 0.f},
{-0.5f, -0.5f, 0.f},
{ 0.5f, 0.5f, 0.f},
{ 0.5f, -0.5f, 0.f},
});
_current_vao->add_vertices(
{
0, 1, 2,
2, 1, 3
});
//Colors
_current_vao->add_VBO(
{
{ 1, 0, 0},
{ 0, 0, 1},
{ 0, 1, 0},
{ 1, 0, 0},
});
_current_program->bind_attribute(0, "position");
_current_program->bind_attribute(1, "color");
_current_program->link();
_current_program->use();
}
void OGLWidget::resizeGL(int width, int height)
{
glViewport(0, 0, width, height);
}
void OGLWidget::paintGL()
{
_uniform += 0.05f;
_current_program->set_float("animation", glm::sin(_uniform) * 0.5f + 0.5f);
clear_color(50, 50, 50);
glClear(GL_COLOR_BUFFER_BIT);
_current_vao->draw(GL_TRIANGLES);
}
void OGLWidget::timerEvent(QTimerEvent*)
{
repaint();
}
void OGLWidget::clear_color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
{
glClearColor((GLclampf)(red / 255.0),
(GLclampf)(green / 255.0),
(GLclampf)(blue / 255.0),
(GLclampf)(alpha / 255.0));
}
#pragma once
#include <string>
#include <QOpenGLFunctions_3_3_Core>
#include <glm/glm.hpp>
#include <glm/ext.hpp>
namespace GL
{
class Program
{
private:
QOpenGLFunctions_3_3_Core* _functions;
GLuint _program;
GLuint _vertex_shader;
GLuint _fragment_shader;
GLint get_location(const std::string &name);
GLuint load_shader(const std::string &path, GLenum shader_type);
public:
Program(QOpenGLFunctions_3_3_Core* functions, const std::string &name);
~Program();
void link();
void bind_attribute(GLuint index, const std::string &name);
void use();
void set_float(const std::string &name, const float &value);
void set_matrix(const std::string &name, const glm::mat4 &matrix);
};
}
#include "Program.h"
#include <iostream>
#include <fstream>
GL::Program::Program(QOpenGLFunctions_3_3_Core* functions, const std::string &name)
{
_functions = functions;
_program = _functions->glCreateProgram();
_vertex_shader = load_shader("res/glsl/" + name + ".vert", GL_VERTEX_SHADER);
_fragment_shader = load_shader("res/glsl/" + name + ".frag", GL_FRAGMENT_SHADER);
if (_vertex_shader == 0 || _fragment_shader == 0)
{
throw std::runtime_error("Failed to create shaders!");
}
}
GL::Program::~Program()
{
_functions->glDetachShader(_program, _vertex_shader);
_functions->glDetachShader(_program, _fragment_shader);
_functions->glDeleteShader(_vertex_shader);
_functions->glDeleteShader(_fragment_shader);
_functions->glDeleteProgram(_program);
}
void GL::Program::link()
{
_functions->glAttachShader(_program, _vertex_shader);
_functions->glAttachShader(_program, _fragment_shader);
_functions->glLinkProgram(_program);
}
void GL::Program::bind_attribute(GLuint index, const std::string &name)
{
_functions->glBindAttribLocation(_program, index, name.c_str());
}
void GL::Program::use()
{
_functions->glUseProgram(_program);
}
void GL::Program::set_float(const std::string &name, const float &value)
{
_functions->glUniform1f(get_location(name), value);
}
void GL::Program::set_matrix(const std::string &name, const glm::mat4 &matrix)
{
_functions->glUniformMatrix4fv(get_location(name), 1, GL_FALSE, glm::value_ptr(matrix));
}
GLint GL::Program::get_location(const std::string &name)
{
return _functions->glGetUniformLocation(_program, name.c_str());
}
GLuint GL::Program::load_shader(const std::string &path, GLenum shader_type)
{
GLuint shader = _functions->glCreateShader(shader_type);
std::ifstream fis(path);
std::string shaderCode = {std::istreambuf_iterator<char>(fis), std::istreambuf_iterator<char>()};
const char *c = shaderCode.c_str();
_functions->glShaderSource(shader, 1, &c, nullptr);
GLint status;
_functions->glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
char buf[0x1000];
GLsizei length;
_functions->glGetShaderInfoLog(shader, sizeof(buf), &length, buf);
if (length > 0)
{
std::cerr << "Failed to comile shader " << path << std::endl << buf << std::endl;
return 0;
}
return shader;
}