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
161 lines (125 loc) · 5.4 KB
/
GLSLProgram.cpp
File metadata and controls
161 lines (125 loc) · 5.4 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
#include "GLSLProgram.h"
#include "BengineErrors.h"
#include "IOManager.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) {
std::string vertSource;
std::string fragSource;
IOManager::readFileToBuffer(vertexShaderFilePath, vertSource);
IOManager::readFileToBuffer(fragmentShaderFilePath, fragSource);
compileShadersFromSource(vertSource.c_str(), fragSource.c_str());
}
void GLSLProgram::compileShadersFromSource(const char* vertexSource, const char* fragmentSource) {
//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(vertexSource, "Vertex Shader", _vertexShaderID);
compileShader(fragmentSource, "Fragment Shader", _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);
}
}
void GLSLProgram::dispose() {
if (_programID) glDeleteProgram(_programID);
}
//Compiles a single shader file
void GLSLProgram::compileShader(const char* source, const std::string& name, GLuint id) {
//tell opengl that we want to use fileContents as the contents of the shader file
glShaderSource(id, 1, &source, 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 " + name + " failed to compile");
}
}
}