Skip to content

Instantly share code, notes, and snippets.

@RobertHue
Last active April 3, 2018 06:22
Show Gist options
  • Save RobertHue/2d576315adabc875fb1b676aaca56cc7 to your computer and use it in GitHub Desktop.
Save RobertHue/2d576315adabc875fb1b676aaca56cc7 to your computer and use it in GitHub Desktop.
OpenGL - GLSL source loader
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream> // std::cout std::cin
#include <fstream> // std::ifstream
#include <string> // std::string
#include <sstream> // std::stringstream
/// @brief reads the file give by its path filePath
/// @return a copy of the content of the file
static std::string readFile(const std::string& filePath) {
std::ifstream fs(filePath, std::ios::in);
if (!fs.is_open()) {
std::cerr << "Could not read file " << filePath << ". File does not exist." << std::endl;
return "";
}
std::stringstream buffer;
std::string line;
while (std::getline(fs, line)) {
// debug:
// std::cout << line << "\n";
buffer << line << "\n";
}
fs.close();
return buffer.str();
}
/// @brief compiles a shader of give type with give GLSL source code as string
/// @param type GL_VERTEX_SHADER or GL_FRAGMENT_SHADER
/// @param source a reference to the GLSL source code as std::string
/// @return hShader if succeeded, otherwhise 0
static GLuint compileShader(GLuint type, const std::string& source)
{
// creates an empty shader obj, ready to accept source-code and be compiled
GLuint hShader = glCreateShader(type);
// hands the shader source code to the shader object so that it can keep a copy of it
const char* src = source.c_str();
glShaderSource(hShader, 1, &src, nullptr);
// compiles whatever source code is contained in the shader object
glCompileShader(hShader);
// Error Handling: Check whether the shader has been compiled
GLint result;
glGetShaderiv(hShader, GL_COMPILE_STATUS, &result); // assigns result with compile operation status
if (result == GL_FALSE)
{
int length;
glGetShaderiv(hShader, GL_INFO_LOG_LENGTH, &length); // assigns length with length of information log
char* infoLog = (char*)alloca(length * sizeof(char)); // allocate on stack frame of caller
glGetShaderInfoLog(hShader, length, &length, infoLog); // returns the information log for a shader object
std::cout << "Failed to compile shader!"
<< (type == GL_VERTEX_SHADER ? "vertex" : "fragment")
<< std::endl;
std::cout << infoLog << std::endl;
glDeleteShader(hShader);
return static_cast<GLuint>(0);
}
return hShader;
}
/// @brief compiles and links a GLSL-Shader-Pair
/// @note to activate the shader created by this use glUseProgram(hProgram);
/// @return hProgram the program object which can be used to activate the shader, On error its 0
static GLuint createShader(const std::string& vertexShader, const std::string& fragmentShader) {
// compile the two shaders given as string reference
GLuint vs = compileShader(GL_VERTEX_SHADER, vertexShader);
GLuint fs = compileShader(GL_FRAGMENT_SHADER, fragmentShader);
if (vs == 0 || fs == 0) { return static_cast<GLuint>(0); }
// create a container for the program-object to which you can attach shader objects
GLuint hProgram = glCreateProgram();
// attaches the shader objects to the program object
glAttachShader(hProgram, vs);
glAttachShader(hProgram, fs);
// links all the shader objects, that are attached to a program object, together
glLinkProgram(hProgram);
// Error Handling: Check whether program has been linked successfully
GLint result;
glGetShaderiv(hProgram, GL_COMPILE_STATUS, &result); // assigns result with compile operation status
if (result == GL_FALSE)
{
int length;
glGetShaderiv(hProgram, GL_INFO_LOG_LENGTH, &length); // assigns length with length of information log
char* infoLog = (char*)alloca(length * sizeof(char)); // allocate on stack frame of caller
glGetShaderInfoLog(hProgram, length, &length, infoLog); // returns the information log for a shader object
std::cout << "Failed to link vertex and fragment shader!"
<< std::endl;
std::cout << infoLog << std::endl;
glDeleteProgram(hProgram);
return static_cast<GLuint>(0);
}
glValidateProgram(hProgram);
// deletes intermediate objects
glDeleteShader(vs);
glDeleteShader(fs);
// activate the program into the state machine of opengl
// glUseProgram(hProgram);
return hProgram;
}
int main(int argc, char *argv[])
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
/* initialize the extension entry points (after the context has been created) */
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
std::cout << "Error: " << glewGetErrorString(err) << std::endl;
return -1;
}
std::cout << "GLEW-Status: Using GLEW " << glewGetString(GLEW_VERSION) << std::endl;
std::cout << "GL-Status: Using OpenGL " << glGetString(GL_VERSION) << std::endl;
float positions[6] = { // for the triangle (is a buffer on the stack)
-0.5f, -0.5f,
0.0f, 0.5f,
0.5f, -0.5f
};
unsigned int vertexBufferID;
glGenBuffers(1, &vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); // select/bind a buffer ID
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), positions, GL_STATIC_DRAW); // gives the graphics card (opengl) the data
// stores memory on the gpu and then shader takes data and displays it
// shader reads that buffer and needs to know the layout of the buffer
// tex coords normals? what is in the buffer!?
// a memory content can be interpreted as anything!!!
// specify the layout of the buffer
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, 0);
// read compile link and load a GLSL shader as a program
std::string vertexShader = readFile("res/shaders/Vertex.shader");
std::string fragmentShader = readFile("res/shaders/Fragment.shader");
GLuint shader = createShader(vertexShader, fragmentShader);
glUseProgram(shader);
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3); // draws the currently selected buffer
// also calls the vertex and fragment shaders and other things inbetween (result: pixels on our screen)
// vertex shader gets called for each vertex we are trying to render
// triangles = 3 vertices = vertex shader gets called 3 times
// tell the vertex shader where the triangle needs to be drawn in our viewport
// takes all the vertex attributes we specified in our buffer
// a shader is a program and does not have to do with shadows or colors or so
// fragment shader gets called for each pixel that needs to be drawn on the screen
// decides which color the pixel should be
// you can pass data from vertex to fragment shader and it needs to be decided where to calculate the things,
// because it all depends on how many times things get called
//
// in summary:
// vertex shader run for each vertex and determine its position on the screen
// fragment shader run for each pixel and determine its color output (also called pixel shader)
//
// generating shaders depending on whats happening in your game is very often used
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glDeleteProgram(shader);
glfwTerminate();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment