Rational<Arbint> now passes realops.test
[ipdf/code.git] / src / shaderprogram.cpp
1 #include "shaderprogram.h"
2 #include "log.h"
3
4 using namespace IPDF;
5
6 /**
7  * Initialise a shader program using GLSL source files
8  * @param geometry_file GLSL source for Geometry shader (optional)
9  * @param vertex_file GLSL source for vertex shader
10  * @param fragment_file GLSL source for fragment shader
11  * If a filename is the empty string it will be ignored
12  */
13 bool ShaderProgram::InitialiseShaders(const char * vertex_file, const char * fragment_file, const char * geometry_file)
14 {
15         if (m_valid)
16         {
17                 Error("Shader already valid?");
18         }
19         m_program = glCreateProgram();
20         if (m_program == 0)
21         {
22                 Error("glCreateProgram failed");
23                 m_valid = false;
24                 return m_valid;
25         }
26         m_valid = true;
27         if (geometry_file != NULL && geometry_file[0] != '\0')
28                 m_valid &= AttachShader(geometry_file, GL_GEOMETRY_SHADER);
29         if (vertex_file != NULL && vertex_file[0] != '\0')
30                 m_valid &= AttachShader(vertex_file, GL_VERTEX_SHADER);
31         if (fragment_file != NULL && fragment_file[0] != '\0')
32                 m_valid &= AttachShader(fragment_file, GL_FRAGMENT_SHADER);
33
34         if (!m_valid)
35         {
36                 Warn("One or more AttachShader calls failed but we will link the shader anyway");
37         }
38         glLinkProgram(m_program);
39         return m_valid;
40 }
41
42
43
44 /**
45  * Destroy a shader program
46  */
47 ShaderProgram::~ShaderProgram()
48 {
49         m_valid = false;
50         for(auto shader : m_shaders)
51         {
52                 glDetachShader(m_program, shader.obj);
53                 glDeleteShader(shader.obj);
54         }
55
56         if (m_program)
57                 glDeleteProgram(m_program);
58 }
59
60 /**
61  * Get GLSL shader source from a file as a string
62  * @param src_file filename to get the shader source from
63  * @returns a char* string allocated with new[] (remember to delete[] it)
64  */
65 char * ShaderProgram::GetShaderSource(const char * src_file) const
66 {
67         char * src = NULL;
68         FILE * file = fopen(src_file, "r");
69         if (file == NULL)
70         {
71                 Error("Could not open shader source file \"%s\": %s", src_file, strerror(errno));
72                 return NULL;
73         }
74         long start = ftell(file);
75
76         if (fseek(file, 0, SEEK_END) != 0)
77         {
78                 Error("Couldn't seek to end of file \"%s\": %s", src_file, strerror(errno));
79                 return NULL;
80         }
81         long end = ftell(file);
82         if (start < 0 || end < 0 || end < start)
83         {
84                 // I bet that now I've put this message here, it will occur at least once in the life of this code
85                 Error("Insane results from ftell(3) on file \"%s\"", src_file);
86                 return NULL;
87         }
88         size_t size = end - start;
89         src = new char[size+1]; // Warning! Allocation of memory occuring! We might all die!
90         rewind(file);
91         if (fread(src, 1,size, file) != size)
92         {
93                 Error("Error in fread on \"%s\": %s", src_file, strerror(errno));
94                 fclose(file);
95                 delete [] src;
96                 return NULL;
97         }
98         src[size] = '\0';
99         fclose(file);
100         return src;
101         
102 }
103
104 bool ShaderProgram::AttachShader(const char * src_file, GLenum type)
105 {
106         GLuint shader_obj = glCreateShader(type);
107         char * src = GetShaderSource(src_file);
108         if (src == NULL)
109         {
110                 Error("Couldn't get shader source.");
111                 return false;
112         }
113         
114
115         glShaderSource(shader_obj, 1, &src, 0);
116         glCompileShader(shader_obj);
117         int did_compile = 0;
118         glGetShaderiv(shader_obj, GL_COMPILE_STATUS, &did_compile);
119         delete [] src; // Oh my goodness memory management is hard guys
120         if (!did_compile)
121         {
122                 char info_log[2048];
123
124                 glGetShaderInfoLog(shader_obj, 2048, nullptr, info_log);
125                 Error("Shader compile error (file \"%s\"): %s (type %d)", src_file, info_log, type);
126                 return false;
127         }
128
129         m_shaders.push_back(Shader{type, shader_obj});
130         glAttachShader(m_program, shader_obj);
131         return true;
132 }
133
134 const void ShaderProgram::Use() const
135 {
136         glUseProgram(m_program);
137 }
138
139 const GLint ShaderProgram::GetUniformLocation(const char *name) const
140 {
141         return glGetUniformLocation(m_program, name);
142 }

UCC git Repository :: git.ucc.asn.au