/
Shader.cpp
165 lines (138 loc) · 6.13 KB
/
Shader.cpp
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
#include "shader.h"
#include <string>
#include <fstream>
#include <iostream>
#ifdef _WIN32
#include <windows.h>
#endif
#include <GL/glew.h>
#include <GL/glut.h>
#include <glm/glm.hpp>
using namespace std; // Include the standard namespace
/**
textFileRead loads in a standard text file from a given filename and
then returns it as a string.
*/
static string textFileRead(const char *fileName) {
string fileString = string(); // A string for storing the file contents
string line = string(); // A string for holding the current line
ifstream file(fileName); // Open an input stream with the selected file
if (file.is_open()) { // If the file opened successfully
while (!file.eof()) { // While we are not at the end of the file
getline(file, line); // Get the current line
fileString.append(line); // Append the line to our file string
fileString.append("\n"); // Appand a new line character
}
file.close(); // Close the file
}
return fileString; // Return our string
}
/**
Given a shader and the filename associated with it, validateShader will
then get information from OpenGl on whether or not the shader was compiled successfully
and if it wasn't, it will output the file with the problem, as well as the problem.
*/
static void validateShader(GLuint shader, const char* file = 0) {
const unsigned int BUFFER_SIZE = 512;
char buffer[BUFFER_SIZE];
memset(buffer, 0, BUFFER_SIZE);
GLsizei length = 0;
glGetShaderiv(shader,GL_COMPILE_STATUS,&length);
if (GL_FALSE == length){ // If we didn't compile
glGetShaderInfoLog(shader, BUFFER_SIZE, &length, buffer); // Ask OpenGL to give us the log associated with the shader
cout << "Shader " << shader << " (" << (file?file:"") << ") compile error: " << buffer << endl; // Output the information
}
}
/**
Given a shader program, validateProgram will request from OpenGL, any information
related to the validation or linking of the program with it's attached shaders. It will
then output any issues that have occurred.
*/
static void validateProgram(GLuint program) {
const unsigned int BUFFER_SIZE = 512;
char buffer[BUFFER_SIZE];
memset(buffer, 0, BUFFER_SIZE);
GLsizei length = 0;
glValidateProgram(program); // Get OpenGL to try validating the program
GLint status;
glGetProgramiv(program, GL_VALIDATE_STATUS, &status); // Find out if the shader program validated correctly
if (status == GL_FALSE){ // If there was a problem validating
cout << "Error validating shader " << program << endl; // Output which program had the error
glGetProgramInfoLog(program, BUFFER_SIZE, &length, buffer); // Ask OpenGL to give us the log associated with the program
cout << "Program " << program << " link error: " << buffer << endl; // Output the information
}
}
/**
Default constructor for the Shader class, at the moment it does nothing
*/
Shader::Shader() {
}
/**
Constructor for a Shader object which creates a GLSL shader based on a given
vertex and fragment shader file.
*/
Shader::Shader(const char *vsFile, const char *fsFile) {
inited = false; // Declare we have not initialized the shader yet
init(vsFile, fsFile); // Initialize the shader
}
/**
init will take a vertex shader file and fragment shader file, and then attempt to create a valid
shader program from these. It will also check for any shader compilation issues along the way.
*/
void Shader::init(const char *vsFile, const char *fsFile) {
if (inited) // If we have already initialized the shader
return;
inited = true; // Mark that we have initialized the shader
shader_vp = glCreateShader(GL_VERTEX_SHADER); // Create a vertex shader
shader_fp = glCreateShader(GL_FRAGMENT_SHADER); // Create a fragment shader
string vsText = textFileRead(vsFile); // Read in the vertex shader
string fsText = textFileRead(fsFile); // Read in the fragment shader
const char *vertexText = vsText.c_str();
const char *fragmentText = fsText.c_str();
if (vertexText == NULL || fragmentText == NULL) { // If either the vertex or fragment shader wouldn't load
cout << "Either vertex shader or fragment shader file not found." << endl; // Output the error
return;
}
glShaderSource(shader_vp, 1, &vertexText, 0); // Set the source for the vertex shader to the loaded text
glCompileShader(shader_vp); // Compile the vertex shader
validateShader(shader_vp, vsFile); // Validate the vertex shader
glShaderSource(shader_fp, 1, &fragmentText, 0); // Set the source for the fragment shader to the loaded text
glCompileShader(shader_fp); // Compile the fragment shader
validateShader(shader_fp, fsFile); // Validate the fragment shader
shader_id = glCreateProgram(); // Create a GLSL program
glAttachShader(shader_id, shader_vp); // Attach a vertex shader to the program
glAttachShader(shader_id, shader_fp); // Attach the fragment shader to the program
glBindAttribLocation(shader_id, 0, "in_Position"); // Bind a constant attribute location for positions of vertices
glBindAttribLocation(shader_id, 1, "in_Color"); // Bind another constant attribute location, this time for color
glLinkProgram(shader_id); // Link the vertex and fragment shaders in the program
validateProgram(shader_id); // Validate the shader program
}
/**
Deconstructor for the Shader object which cleans up by detaching the shaders, deleting them
and finally deleting the GLSL program.
*/
Shader::~Shader() {
glDetachShader(shader_id, shader_fp); // Detach the fragment shader
glDetachShader(shader_id, shader_vp); // Detach the vertex shader
glDeleteShader(shader_fp); // Delete the fragment shader
glDeleteShader(shader_vp); // Delete the vertex shader
glDeleteProgram(shader_id); // Delete the shader program
}
/**
id returns the integer value associated with the shader program
*/
unsigned int Shader::id() {
return shader_id; // Return the shaders identifier
}
/**
bind attaches the shader program for use by OpenGL
*/
void Shader::bind() {
glUseProgram(shader_id);
}
/**
unbind deattaches the shader program from OpenGL
*/
void Shader::unbind() {
glUseProgram(0);
}