hello
i'm recently learning opengl and shader language and SFML. i have create my first GLSL program that draw colored rectangle on screen.
i'm looking for best practice in both SFML and openGL in this code
#include <GL/glew.h>
#include <SFML/Window.hpp>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <stdexcept>
#include <cassert>
#define GLSL(src) "#version 400 core\n" #src
#define GETERROR() getError(__FILE__,__LINE__)
namespace
{
const unsigned CurrentWidth = 800;
const unsigned CurrentHeight = 600;
}
void getError(const char *file, int line)
{
GLenum error(glGetError());
while (error != GL_NO_ERROR)
{
std::string errorString;
switch (error)
{
case GL_INVALID_OPERATION: errorString = "INVALID_OPERATION"; break;
case GL_INVALID_ENUM: errorString = "INVALID_ENUM"; break;
case GL_INVALID_VALUE: errorString = "INVALID_VALUE"; break;
case GL_OUT_OF_MEMORY: errorString = "OUT_OF_MEMORY"; break;
case GL_INVALID_FRAMEBUFFER_OPERATION: errorString = "INVALID_FRAMEBUFFER_OPERATION"; break;
}
throw std::runtime_error("GL_" + errorString + " - " + std::string(file) + ":" + std::to_string(line));
error = glGetError();
}
}
class Tutorial
{
public:
Tutorial();
~Tutorial();
void run();
private:
void processEvent();
void render();
void createVBO();
void destroyVBO();
void createShaders();
void destroyShaders();
private:
sf::Window mWindow;
GLuint mVertexShaderID;
GLuint mFragmentShaderID;
GLuint mProgramID;
GLuint mVAOID;
GLuint mVBOID;
GLuint mColorBufferID;
const std::vector<GLchar*> mVertexShader =
{
{
GLSL(
layout(location = 0) in vec4 in_Position;
layout(location = 1) in vec4 in_Color;
out vec4 ex_Color;
void main(void)
{
gl_Position = in_Position;
ex_Color = in_Color;
}
)
}
};
const std::vector<GLchar*> mFragmentShader =
{
{
GLSL(
in vec4 ex_Color;
out vec4 out_Color;
void main(void)
{
out_Color = ex_Color;
}
)
}
};
};
Tutorial::Tutorial()
: mWindow(sf::VideoMode(CurrentWidth, CurrentHeight), "Example 00")
{
glewExperimental = true; // Needed in core profile
if (glewInit() != GLEW_OK)
{
throw std::runtime_error("Failed to initialize GLEW\n");
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
createShaders();
createVBO();
}
void Tutorial::run()
{
while (mWindow.isOpen())
{
processEvent();
render();
}
}
void Tutorial::processEvent()
{
sf::Event event;
while (mWindow.pollEvent(event))
{
if (event.type == sf::Event::Closed)
mWindow.close();
if (event.type == sf::Event::Resized)
glViewport(0, 0, mWindow.getSize().x, mWindow.getSize().y);
}
}
void Tutorial::render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
mWindow.display();
}
Tutorial::~Tutorial()
{
destroyShaders();
destroyVBO();
}
void Tutorial::createVBO()
{
GLfloat Vertices[] =
{
-0.8f, -0.8f, 0.0f, 1.0f,
0.0f, 0.8f, 0.0f, 1.0f,
0.8f, -0.8f, 0.0f, 1.0f
};
GLfloat Colors[] =
{
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
glGenVertexArrays(1, &mVAOID);
glBindVertexArray(mVAOID);
glGenBuffers(1, &mVBOID);
glBindBuffer(GL_ARRAY_BUFFER, mVBOID);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glGenBuffers(1, &mColorBufferID);
glBindBuffer(GL_ARRAY_BUFFER, mColorBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(Colors), Colors, GL_STATIC_DRAW);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
GETERROR();
}
void Tutorial::destroyVBO()
{
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDeleteBuffers(1, &mColorBufferID);
glDeleteBuffers(1, &mVBOID);
glBindVertexArray(0);
glDeleteVertexArrays(1, &mVAOID);
GETERROR();
}
void Tutorial::createShaders()
{
mVertexShaderID = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(mVertexShaderID, 1, &mVertexShader[0], NULL);
glCompileShader(mVertexShaderID);
mFragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(mFragmentShaderID, 1, &mFragmentShader[0], NULL);
glCompileShader(mFragmentShaderID);
mProgramID = glCreateProgram();
glAttachShader(mProgramID, mVertexShaderID);
glAttachShader(mProgramID, mFragmentShaderID);
glLinkProgram(mProgramID);
glUseProgram(mProgramID);
GETERROR();
}
void Tutorial::destroyShaders()
{
glUseProgram(0);
glDetachShader(mProgramID, mVertexShaderID);
glDetachShader(mProgramID, mFragmentShaderID);
glDeleteShader(mFragmentShaderID);
glDeleteShader(mVertexShaderID);
glDeleteProgram(mProgramID);
GETERROR();
}
int main()
{
try
{
Tutorial tut;
tut.run();
}
catch (std::runtime_error& e)
{
std::cout << "\nException: " << e.what() << std::endl;
return 1;
}
}