1 // glshader.cpp
2 //
3 // Copyright (C) 2001-2006, Chris Laurel <claurel@shatters.net>
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9
10 #include <iostream>
11 #include "glshader.h"
12 #include "gl.h"
13 #include "glext.h"
14
15 using namespace std;
16
17
18 static const string GetInfoLog(GLhandleARB obj);
19
20
21 ostream* g_shaderLogFile = NULL;
22
23
GLShader(GLhandleARB _id)24 GLShader::GLShader(GLhandleARB _id) :
25 id(_id)
26 {
27 }
28
29
30 GLhandleARB
getID() const31 GLShader::getID() const
32 {
33 return id;
34 }
35
36
37 GLShaderStatus
compile(const vector<string> & source)38 GLShader::compile(const vector<string>& source)
39 {
40 if (source.empty())
41 return ShaderStatus_EmptyProgram;
42
43 // Convert vector of shader source strings to an array for OpenGL
44 const char** sourceStrings = new const char*[source.size()];
45 for (unsigned int i = 0; i < source.size(); i++)
46 sourceStrings[i] = source[i].c_str();
47
48 // Copy shader source to OpenGL
49 glx::glShaderSourceARB(id, source.size(), sourceStrings, NULL);
50 delete[] sourceStrings;
51
52 // Actually compile the shader
53 glx::glCompileShaderARB(id);
54
55 GLint compileSuccess;
56 glx::glGetObjectParameterivARB(id, GL_OBJECT_COMPILE_STATUS_ARB,
57 &compileSuccess);
58 if (compileSuccess == GL_FALSE)
59 return ShaderStatus_CompileError;
60
61 return ShaderStatus_OK;
62 }
63
64
~GLShader()65 GLShader::~GLShader()
66 {
67 glx::glDeleteObjectARB(id);
68 }
69
70
71
72 //************* GLxxxProperty **********
73
FloatShaderParameter()74 FloatShaderParameter::FloatShaderParameter() :
75 slot(-1)
76 {
77 }
78
FloatShaderParameter(GLhandleARB obj,const char * name)79 FloatShaderParameter::FloatShaderParameter(GLhandleARB obj, const char* name)
80 {
81 slot = glx::glGetUniformLocationARB(obj, name);
82 }
83
84 FloatShaderParameter&
operator =(float f)85 FloatShaderParameter::operator=(float f)
86 {
87 if (slot != -1)
88 glx::glUniform1fARB(slot, f);
89 return *this;
90 }
91
92
Vec3ShaderParameter()93 Vec3ShaderParameter::Vec3ShaderParameter() :
94 slot(-1)
95 {
96 }
97
Vec3ShaderParameter(GLhandleARB obj,const char * name)98 Vec3ShaderParameter::Vec3ShaderParameter(GLhandleARB obj, const char* name)
99 {
100 slot = glx::glGetUniformLocationARB(obj, name);
101 }
102
103 Vec3ShaderParameter&
operator =(const Vec3f & v)104 Vec3ShaderParameter::operator=(const Vec3f& v)
105 {
106 if (slot != -1)
107 glx::glUniform3fARB(slot, v.x, v.y, v.z);
108 return *this;
109 }
110
111 Vec3ShaderParameter&
operator =(const Point3f & p)112 Vec3ShaderParameter::operator=(const Point3f& p)
113 {
114 if (slot != -1)
115 glx::glUniform3fARB(slot, p.x, p.y, p.z);
116 return *this;
117 }
118
119
Vec4ShaderParameter()120 Vec4ShaderParameter::Vec4ShaderParameter() :
121 slot(-1)
122 {
123 }
124
Vec4ShaderParameter(GLhandleARB obj,const char * name)125 Vec4ShaderParameter::Vec4ShaderParameter(GLhandleARB obj, const char* name)
126 {
127 slot = glx::glGetUniformLocationARB(obj, name);
128 }
129
130 Vec4ShaderParameter&
operator =(const Vec4f & v)131 Vec4ShaderParameter::operator=(const Vec4f& v)
132 {
133 if (slot != -1)
134 glx::glUniform4fARB(slot, v.x, v.y, v.z, v.w);
135 return *this;
136 }
137
138
139 //************* GLProgram **************
140
GLProgram(GLhandleARB _id)141 GLProgram::GLProgram(GLhandleARB _id) :
142 id(_id)
143 {
144 }
145
146
~GLProgram()147 GLProgram::~GLProgram()
148 {
149 glx::glDeleteObjectARB(id);
150 }
151
152
153 void
use() const154 GLProgram::use() const
155 {
156 glx::glUseProgramObjectARB(id);
157 }
158
159
160 void
attach(const GLShader & shader)161 GLProgram::attach(const GLShader& shader)
162 {
163 glx::glAttachObjectARB(id, shader.getID());
164 }
165
166
167 GLShaderStatus
link()168 GLProgram::link()
169 {
170 glx::glLinkProgramARB(id);
171
172 GLint linkSuccess;
173 glx::glGetObjectParameterivARB(id, GL_OBJECT_LINK_STATUS_ARB,
174 &linkSuccess);
175 if (linkSuccess == GL_FALSE)
176 {
177 if (g_shaderLogFile != NULL)
178 {
179 *g_shaderLogFile << "Error linking shader program:\n";
180 *g_shaderLogFile << GetInfoLog(getID());
181 }
182 return ShaderStatus_LinkError;
183 }
184
185 return ShaderStatus_OK;
186 }
187
188
189 //************* GLShaderLoader ************
190
191 GLShaderStatus
CreateVertexShader(const vector<string> & source,GLVertexShader ** vs)192 GLShaderLoader::CreateVertexShader(const vector<string>& source,
193 GLVertexShader** vs)
194 {
195 GLhandleARB vsid = glx::glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
196
197 GLVertexShader* shader = new GLVertexShader(vsid);
198 if (!shader)
199 return ShaderStatus_OutOfMemory;
200
201 GLShaderStatus status = shader->compile(source);
202 if (status != ShaderStatus_OK)
203 {
204 if (g_shaderLogFile != NULL)
205 {
206 *g_shaderLogFile << "Error compiling vertex shader:\n";
207 *g_shaderLogFile << GetInfoLog(shader->getID());
208 }
209 return status;
210 }
211
212 *vs = shader;
213
214 return ShaderStatus_OK;
215 }
216
217
218 GLShaderStatus
CreateFragmentShader(const vector<string> & source,GLFragmentShader ** fs)219 GLShaderLoader::CreateFragmentShader(const vector<string>& source,
220 GLFragmentShader** fs)
221 {
222 GLhandleARB fsid = glx::glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
223
224 GLFragmentShader* shader = new GLFragmentShader(fsid);
225 if (!shader)
226 return ShaderStatus_OutOfMemory;
227
228 GLShaderStatus status = shader->compile(source);
229 if (status != ShaderStatus_OK)
230 {
231 if (g_shaderLogFile != NULL)
232 {
233 *g_shaderLogFile << "Error compiling fragment shader:\n";
234 *g_shaderLogFile << GetInfoLog(shader->getID());
235 }
236 return status;
237 }
238
239 *fs = shader;
240
241 return ShaderStatus_OK;
242 }
243
244
245 GLShaderStatus
CreateVertexShader(const string & source,GLVertexShader ** vs)246 GLShaderLoader::CreateVertexShader(const string& source,
247 GLVertexShader** vs)
248
249 {
250 vector<string> v;
251 v.push_back(source);
252 return CreateVertexShader(v, vs);
253 }
254
255
256 GLShaderStatus
CreateFragmentShader(const string & source,GLFragmentShader ** fs)257 GLShaderLoader::CreateFragmentShader(const string& source,
258 GLFragmentShader** fs)
259 {
260 vector<string> v;
261 v.push_back(source);
262 return CreateFragmentShader(v, fs);
263 }
264
265
266 GLShaderStatus
CreateProgram(const GLVertexShader & vs,const GLFragmentShader & fs,GLProgram ** progOut)267 GLShaderLoader::CreateProgram(const GLVertexShader& vs,
268 const GLFragmentShader& fs,
269 GLProgram** progOut)
270 {
271 GLhandleARB progid = glx::glCreateProgramObjectARB();
272
273 GLProgram* prog = new GLProgram(progid);
274 if (!prog)
275 return ShaderStatus_OutOfMemory;
276
277 prog->attach(vs);
278 prog->attach(fs);
279
280 *progOut = prog;
281
282 return ShaderStatus_OK;
283 }
284
285
286 GLShaderStatus
CreateProgram(const vector<string> & vsSource,const vector<string> & fsSource,GLProgram ** progOut)287 GLShaderLoader::CreateProgram(const vector<string>& vsSource,
288 const vector<string>& fsSource,
289 GLProgram** progOut)
290 {
291 GLVertexShader* vs = NULL;
292 GLShaderStatus status = CreateVertexShader(vsSource, &vs);
293 if (status != ShaderStatus_OK)
294 return status;
295
296 GLFragmentShader* fs = NULL;
297 status = CreateFragmentShader(fsSource, &fs);
298 if (status != ShaderStatus_OK)
299 {
300 delete vs;
301 return status;
302 }
303
304 GLProgram* prog = NULL;
305 status = CreateProgram(*vs, *fs, &prog);
306 if (status != ShaderStatus_OK)
307 {
308 delete vs;
309 delete fs;
310 return status;
311 }
312
313 *progOut = prog;
314
315 // No need to keep these around--the program doesn't reference them
316 delete vs;
317 delete fs;
318
319 return ShaderStatus_OK;
320 }
321
322
323 GLShaderStatus
CreateProgram(const string & vsSource,const string & fsSource,GLProgram ** progOut)324 GLShaderLoader::CreateProgram(const string& vsSource,
325 const string& fsSource,
326 GLProgram** progOut)
327 {
328 vector<string> vsSourceVec;
329 vsSourceVec.push_back(vsSource);
330 vector<string> fsSourceVec;
331 fsSourceVec.push_back(fsSource);
332
333 return CreateProgram(vsSourceVec, fsSourceVec, progOut);
334 }
335
336
337 const string
GetInfoLog(GLhandleARB obj)338 GetInfoLog(GLhandleARB obj)
339 {
340 GLint logLength = 0;
341 GLsizei charsWritten = 0;
342
343 glx::glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB,
344 &logLength);
345 if (logLength <= 0)
346 return string();
347
348 char* log = new char[logLength];
349 if (log == NULL)
350 return string();
351
352 glx::glGetInfoLogARB(obj, logLength, &charsWritten, log);
353
354 string s(log, charsWritten);
355 delete[] log;
356
357 return s;
358 }
359