forked from Barnold1953/GraphicsTutorials
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGLSLProgram.cpp
More file actions
169 lines (131 loc) · 5.54 KB
/
Copy pathGLSLProgram.cpp
File metadata and controls
169 lines (131 loc) · 5.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#include "GLSLProgram.h"
#include "BengineErrors.h"
#include <vector>
#include <fstream>
namespace Bengine {
//The : _numAttributes(0) ect. is an initialization list. It is a better way to initialize variables, since it avoids an extra copy.
GLSLProgram::GLSLProgram() : _numAttributes(0), _programID(0), _vertexShaderID(0), _fragmentShaderID(0)
{
}
GLSLProgram::~GLSLProgram()
{
}
//Compiles the shaders into a form that your GPU can understand
void GLSLProgram::compileShaders(const std::string& vertexShaderFilePath, const std::string& fragmentShaderFilepath) {
//Vertex and fragment shaders are successfully compiled.
//Now time to link them together into a program.
//Get a program object.
_programID = glCreateProgram();
//Create the vertex shader object, and store its ID
_vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
if (_vertexShaderID == 0) {
fatalError("Vertex shader failed to be created!");
}
//Create the fragment shader object, and store its ID
_fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
if (_fragmentShaderID == 0) {
fatalError("Fragment shader failed to be created!");
}
//Compile each shader
compileShader(vertexShaderFilePath, _vertexShaderID);
compileShader(fragmentShaderFilepath, _fragmentShaderID);
}
void GLSLProgram::linkShaders() {
//Attach our shaders to our program
glAttachShader(_programID, _vertexShaderID);
glAttachShader(_programID, _fragmentShaderID);
//Link our program
glLinkProgram(_programID);
//Note the different functions here: glGetProgram* instead of glGetShader*.
GLint isLinked = 0;
glGetProgramiv(_programID, GL_LINK_STATUS, (int *)&isLinked);
if (isLinked == GL_FALSE)
{
GLint maxLength = 0;
glGetProgramiv(_programID, GL_INFO_LOG_LENGTH, &maxLength);
//The maxLength includes the NULL character
std::vector<char> errorLog(maxLength);
glGetProgramInfoLog(_programID, maxLength, &maxLength, &errorLog[0]);
//We don't need the program anymore.
glDeleteProgram(_programID);
//Don't leak shaders either.
glDeleteShader(_vertexShaderID);
glDeleteShader(_fragmentShaderID);
//print the error log and quit
std::printf("%s\n", &(errorLog[0]));
fatalError("Shaders failed to link!");
}
//Always detach shaders after a successful link.
glDetachShader(_programID, _vertexShaderID);
glDetachShader(_programID, _fragmentShaderID);
glDeleteShader(_vertexShaderID);
glDeleteShader(_fragmentShaderID);
}
//Adds an attribute to our shader. SHould be called between compiling and linking.
void GLSLProgram::addAttribute(const std::string& attributeName) {
glBindAttribLocation(_programID, _numAttributes++, attributeName.c_str());
}
GLint GLSLProgram::getUniformLocation(const std::string& uniformName) {
GLint location = glGetUniformLocation(_programID, uniformName.c_str());
if (location == GL_INVALID_INDEX) {
fatalError("Uniform " + uniformName + " not found in shader!");
}
return location;
}
//enable the shader, and all its attributes
void GLSLProgram::use() {
glUseProgram(_programID);
//enable all the attributes we added with addAttribute
for (int i = 0; i < _numAttributes; i++) {
glEnableVertexAttribArray(i);
}
}
//disable the shader
void GLSLProgram::unuse() {
glUseProgram(0);
for (int i = 0; i < _numAttributes; i++) {
glDisableVertexAttribArray(i);
}
}
//Compiles a single shader file
void GLSLProgram::compileShader(const std::string& filePath, GLuint id) {
//Open the file
std::ifstream shaderFile(filePath);
if (shaderFile.fail()) {
perror(filePath.c_str());
fatalError("Failed to open " + filePath);
}
//File contents stores all the text in the file
std::string fileContents = "";
//line is used to grab each line of the file
std::string line;
//Get all the lines in the file and add it to the contents
while (std::getline(shaderFile, line)) {
fileContents += line + "\n";
}
shaderFile.close();
//get a pointer to our file contents c string;
const char* contentsPtr = fileContents.c_str();
//tell opengl that we want to use fileContents as the contents of the shader file
glShaderSource(id, 1, &contentsPtr, nullptr);
//compile the shader
glCompileShader(id);
//check for errors
GLint success = 0;
glGetShaderiv(id, GL_COMPILE_STATUS, &success);
if (success == GL_FALSE)
{
GLint maxLength = 0;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &maxLength);
//The maxLength includes the NULL character
std::vector<char> errorLog(maxLength);
glGetShaderInfoLog(id, maxLength, &maxLength, &errorLog[0]);
//Provide the infolog in whatever manor you deem best.
//Exit with failure.
glDeleteShader(id); //Don't leak the shader.
//Print error log and quit
std::printf("%s\n", &(errorLog[0]));
fatalError("Shader " + filePath + " failed to compile");
}
}
}