00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "platform/shader.hpp"
00035 #include "platform/extensions.hpp"
00036
00037 #include "data/log.hpp"
00038 #include "data/pointer.hpp"
00039 #include "data/array.hpp"
00040 #include "data/file.hpp"
00041 #include "data/fstream.hpp"
00042
00043 namespace gsgl
00044 {
00045
00046 using namespace data;
00047 using namespace io;
00048
00049 namespace platform
00050 {
00051
00052 static const int INFO_BUF_SIZE = 4096;
00053
00054
00055
00056 class shader_base
00057 {
00058 protected:
00059 const string fname;
00060 int opengl_id;
00061 list<string> lines;
00062
00063 public:
00064 shader_base(const string & fname);
00065 virtual ~shader_base();
00066
00067 int get_id() { return opengl_id; }
00068 void compile();
00069
00070 void read_file(const string & fname);
00071 void unload();
00072
00073 protected:
00074 virtual void create() = 0;
00075 };
00076
00077
00078
00079
00080
00081 class vertex_shader
00082 : public shader_base
00083 {
00084 public:
00085 vertex_shader(const gsgl::string & fname);
00086
00087 protected:
00088 void create();
00089 };
00090
00091
00092
00093
00094
00095 class fragment_shader
00096 : public shader_base
00097 {
00098 public:
00099 fragment_shader(const gsgl::string & fname);
00100
00101 protected:
00102 void create();
00103 };
00104
00105
00106
00107
00108
00109 shader_base::shader_base(const string & fname)
00110 : fname(fname), opengl_id(0)
00111 {
00112 read_file(fname);
00113 }
00114
00115
00116 shader_base::~shader_base()
00117 {
00118 unload();
00119 }
00120
00121
00122 void shader_base::read_file(const string & fname)
00123 {
00124 ft_stream f(fname);
00125 string line;
00126
00127 for (f >> line; !f.at_end(); f >> line)
00128 {
00129 lines.append(line + L"\n");
00130 }
00131 }
00132
00133
00134 void shader_base::unload()
00135 {
00136 if (opengl_id)
00137 {
00138 glDeleteShader(opengl_id); CHECK_GL_ERRORS();
00139 opengl_id = 0;
00140 }
00141 }
00142
00143
00144 void shader_base::compile()
00145 {
00146 if (!opengl_id)
00147 {
00148 this->create();
00149
00150 simple_array<char *> src_lines;
00151
00152 for (list<string>::iterator i = lines.iter(); i.is_valid(); ++i)
00153 {
00154 if (i->size())
00155 src_lines.append(::strdup(i->c_string()));
00156 }
00157
00158 glShaderSource(opengl_id, src_lines.size(), (const GLchar **) src_lines.ptr(), 0); CHECK_GL_ERRORS();
00159
00160 for (int i = 0; i < src_lines.size(); ++i)
00161 ::free(src_lines[i]);
00162 }
00163
00164 glCompileShader(opengl_id); CHECK_GL_ERRORS();
00165
00166 GLint compile_status;
00167 glGetShaderiv(opengl_id, GL_COMPILE_STATUS, &compile_status); CHECK_GL_ERRORS();
00168
00169 if (!compile_status)
00170 {
00171 int len;
00172 smart_pointer<char, true> buf(new char[INFO_BUF_SIZE]);
00173 glGetShaderInfoLog(opengl_id, INFO_BUF_SIZE, &len, buf); CHECK_GL_ERRORS();
00174
00175 string error_msg = fname + L"\n\n" + string(buf);
00176
00177 throw runtime_exception(error_msg.w_string());
00178 }
00179 }
00180
00181
00182
00183
00184 vertex_shader::vertex_shader(const string & fname)
00185 : shader_base(fname)
00186 {
00187 }
00188
00189
00190 void vertex_shader::create()
00191 {
00192 if (!opengl_id)
00193 {
00194 opengl_id = glCreateShader(GL_VERTEX_SHADER); CHECK_GL_ERRORS();
00195
00196 if (!opengl_id)
00197 throw runtime_exception(L"Unable to create vertex shader %ls", fname.w_string());
00198 }
00199 }
00200
00201
00202
00203
00204
00205 fragment_shader::fragment_shader(const string & fname)
00206 : shader_base(fname)
00207 {
00208 }
00209
00210
00211 void fragment_shader::create()
00212 {
00213 if (!opengl_id)
00214 {
00215 opengl_id = glCreateShader(GL_FRAGMENT_SHADER); CHECK_GL_ERRORS();
00216
00217 if (!opengl_id)
00218 throw runtime_exception(L"Unable to create fragment shader %ls", fname.w_string());
00219 }
00220 }
00221
00222
00223
00224
00225 shader_program::shader_program()
00226 : opengl_id(0)
00227 {
00228 }
00229
00230
00231 shader_program::~shader_program()
00232 {
00233 unload();
00234
00235 for (gsgl::data::list<shader_base *>::iterator i = shaders.iter(); i.is_valid(); ++i)
00236 delete *i;
00237 }
00238
00239
00240 void shader_program::add_vertex_shader(const string & fname)
00241 {
00242 shaders.append(new vertex_shader(io::file::get_full_path(fname)));
00243 }
00244
00245
00246 void shader_program::add_fragment_shader(const string & fname)
00247 {
00248 shaders.append(new fragment_shader(io::file::get_full_path(fname)));
00249 }
00250
00251
00252 void shader_program::load()
00253 {
00254 if (!opengl_id)
00255 {
00256 opengl_id = glCreateProgram(); CHECK_GL_ERRORS();
00257
00258 if (!opengl_id && opengl_id != GL_INVALID_VALUE)
00259 throw runtime_exception(L"Unable to create shader program.");
00260
00261
00262 for (list<shader_base *>::iterator i = shaders.iter(); i.is_valid(); ++i)
00263 {
00264 (*i)->compile();
00265 }
00266
00267
00268 for (list<shader_base *>::iterator i = shaders.iter(); i.is_valid(); ++i)
00269 {
00270 glAttachShader(opengl_id, (*i)->get_id()); CHECK_GL_ERRORS();
00271 }
00272
00273
00274 int len, status;
00275 smart_pointer<char, true> buf(new char[INFO_BUF_SIZE]);
00276
00277 glValidateProgram(opengl_id); CHECK_GL_ERRORS();
00278 glGetProgramiv(opengl_id, GL_VALIDATE_STATUS, &status);
00279
00280 if (!status)
00281 {
00282 glGetProgramInfoLog(opengl_id, INFO_BUF_SIZE, &len, buf);
00283 throw runtime_exception(string(buf).w_string());
00284 }
00285
00286
00287 glLinkProgram(opengl_id); CHECK_GL_ERRORS();
00288 glGetProgramiv(opengl_id, GL_LINK_STATUS, &status);
00289
00290 if (!status)
00291 {
00292 glGetProgramInfoLog(opengl_id, INFO_BUF_SIZE, &len, buf);
00293 throw runtime_exception(string(buf).w_string());
00294 }
00295 }
00296 }
00297
00298
00299 void shader_program::unload()
00300 {
00301 if (opengl_id)
00302 {
00303 for (list<shader_base *>::iterator i = shaders.iter(); i.is_valid(); ++i)
00304 (*i)->unload();
00305
00306 glDeleteProgram(opengl_id); CHECK_GL_ERRORS();
00307 opengl_id = 0;
00308 }
00309 }
00310
00311
00312 void shader_program::bind()
00313 {
00314
00315 if (opengl_id)
00316 {
00317 glUseProgram(opengl_id); CHECK_GL_ERRORS();
00318 }
00319 else
00320 {
00321 throw internal_exception(__FILE__, __LINE__, L"Unable to use shader program.");
00322 }
00323 }
00324
00325
00326 void shader_program::unbind()
00327 {
00328 glUseProgram(0); CHECK_GL_ERRORS();
00329 }
00330
00331
00332
00333
00334 void shader_program::set_uniform(const char *name, const int & i)
00335 {
00336 glUniform1i(get_uniform_loc(name), i); CHECK_GL_ERRORS();
00337 }
00338
00339
00340 void shader_program::set_uniform(const char *name, const float & f)
00341 {
00342 glUniform1f(get_uniform_loc(name), f); CHECK_GL_ERRORS();
00343 }
00344
00345
00346 void shader_program::set_uniform(const char *name, const float ff[4])
00347 {
00348 glUniform4fv(get_uniform_loc(name), 1, ff); CHECK_GL_ERRORS();
00349 }
00350
00351
00352 void shader_program::set_uniform(const char *name, const bool b)
00353 {
00354 glUniform1i(get_uniform_loc(name), b);
00355 }
00356
00357
00358 int shader_program::get_uniform_loc(const char *name)
00359 {
00360 assert(opengl_id);
00361 int loc = glGetUniformLocation(opengl_id, name); CHECK_GL_ERRORS();
00362 if (loc == -1)
00363 throw runtime_exception(L"Unable to set uniform value '%hs' in shader program!", name);
00364 else
00365 return loc;
00366 }
00367
00368 }
00369
00370 }