Last active
April 3, 2018 06:22
-
-
Save RobertHue/2d576315adabc875fb1b676aaca56cc7 to your computer and use it in GitHub Desktop.
OpenGL - GLSL source loader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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