OpenGL Evolution
Over recent years, OpenGL has tremendously evolved and a significant change occurred in the year 2003. With its new programmable pipeline (OpenGL 2.0), it allows you to have direct access to the GPU and these programs are known as Shaders.

As this previous version was using the fixed pipeline but appearance of this constitutional way changed the face of OpenGL programming which makes it far more difficult to program but gave a robust tool.
Fixed Pipeline vs Programmable Pipeline
Maths
In fixed-pipeline OpenGL, all your matrix math is handled by OpenGL itself inside its APIs but in programmable pipeline OpenGL you have to manually apply this math to your vertex shader.
Operations
Shaders

Types/Stages of Shaders
Vertex Shaders
Geometry Shaders
Fragment Shaders
Compute Shaders
Building Application
class Window : QOpenGLWidget
{
Window()
{
}
void initializeGL()
{
QOpenGLWindow::initializeGL();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void resizeGL(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
update();
}
void paintGL()
{
glClear(GL_COLOR_BUFFERBIT);
glBegin(GL_TRIANGLES);
glColor3f(1.0, 0.0 0.0); glColor3f(-1.0, -1.0, 0.0);
glColor3f(0.0, 1.0 0.0); glColor3f( 0.0, 1.0, 0.0);
glColor3f(0.0, 0.0 1.0); glColor3f( 1.0, -1.0, 0.0);
glEnd();
glutSwapBuffers();
}
}
Modern OpenGL code block
class Window: public QOpenGLWidget, public QOpenGLFunctions
{
Window() :
m_vbo(QOpenGLBuffer::VertexBuffer)
{
}
void createGeometry()
{
// Initialize and bind the VAO that's going to capture all this vertex state
m_vao.create();
m_vao.bind();
struct Vertex {
GLfloat position[3],
color[3];
} attribs[3] = {
{ { -1.0, -1.0, 0.0 },{ 1.0, 0.0, 0.0 } }, // left-bottom, red
{ { 0.0, 1.0, 0.0 },{ 0.0, 1.0, 0.0 } }, // center-top, blue
{ { 1.0, -1.0, 0.0 },{ 0.0, 0.0, 1.0 } }, // right-bottom, green
};
// Put all the attribute data in a FBO
m_vbo.create();
m_vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
m_vbo.bind();
m_vbo.allocate(attribs, sizeof(attribs));
// Configure the vertex streams for this attribute data layout
m_pgm.enableAttributeArray("position");
m_pgm.setAttributeBuffer("position", GL_FLOAT, offsetof(Vertex, position), 3, sizeof(Vertex));
m_pgm.enableAttributeArray("color");
m_pgm.setAttributeBuffer("color", GL_FLOAT, offsetof(Vertex, color), 3, sizeof(Vertex));
// Okay, we've finished setting up the vao
m_vao.release();
}
void initializeGL()
{
QOpenGLFunctions::initializeOpenGLFunctions();
createGeometry();
}
void resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
update();
}
void paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
m_vao.bind();
glDrawArrays(GL_TRIANGLES, 0, 3);
}
QOpenGLShaderProgram m_pgm;
QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer m_vbo;
};
void createGeometry()
{
// Initialize and bind the VAO that's going to capture all this vertex state
m_vao.create();
m_vao.bind();
struct Vertex {
GLfloat position[3],
color[3];
} attribs[3] = {
{ { -1.0, -1.0, 0.0 },{ 1.0, 0.0, 0.0 } }, // left-bottom, red
{ { 0.0, 1.0, 0.0 },{ 0.0, 1.0, 0.0 } }, // center-top, blue
{ { 1.0, -1.0, 0.0 },{ 0.0, 0.0, 1.0 } }, // right-bottom, green
};
// Put all the attribute data in a FBO
m_vbo.create();
m_vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
m_vbo.bind();
m_vbo.allocate(attribs, sizeof(attribs));
// Configure the vertex streams for this attribute data layout
m_pgm.enableAttributeArray("position");
m_pgm.setAttributeBuffer("position", GL_FLOAT, offsetof(Vertex, position), 3, sizeof(Vertex));
m_pgm.enableAttributeArray("color");
m_pgm.setAttributeBuffer("color", GL_FLOAT, offsetof(Vertex, color), 3, sizeof(Vertex));
// Okay, we've finished setting up the vao
m_vao.release();
}
static QString vertexShader =
"#version 100\n"
"\n"
"attribute vec3 position;\n"
"attribute vec3 color;\n"
"\n"
"varying vec3 v_color;\n"
"\n"
"void main()\n"
"{\n"
" v_color = color;\n"
" gl_Position = vec4(position, 1);\n"
"}\n"
;
static QString fragmentShader =
"#version 100\n"
"\n"
"varying vec3 v_color;\n"
"\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(v_color, 1);\n"
"}\n"
;
void Window::createShaderProgram()
{
if (!m_pgm.addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShader)) {
qDebug() << "Error in vertex shader:" << m_pgm.log();
exit(1);
}
if (!m_pgm.addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShader)) {
qDebug() << "Error in fragment shader:" << m_pgm.log();
exit(1);
}
if (!m_pgm.link()) {
qDebug() << "Error linking shader program:" << m_pgm.log();
exit(1);
}
}
Output
