bloboland

view src/shaders.cc @ 1:cfe68befb7cc

some progress
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 15 Dec 2012 23:43:03 +0200
parents
children
line source
1 #include <stdio.h>
2 #include <assert.h>
3 #include <map>
4 #ifdef _MSC_VER
5 #include <memory.h>
6 #else
7 #include <alloca.h>
8 #endif
9 #include <GL/glew.h>
10 #include "shaders.h"
12 Shader::Shader(unsigned int type)
13 {
14 sdr = glCreateShader(type);
15 compiled = false;
17 assert(glGetError() == GL_NO_ERROR);
18 }
20 Shader::~Shader()
21 {
22 glDeleteShader(sdr);
23 }
25 void Shader::set_source(const char *src)
26 {
27 glShaderSource(sdr, 1, &src, 0);
28 compiled = false;
30 assert(glGetError() == GL_NO_ERROR);
31 }
33 bool Shader::compile()
34 {
35 if(compiled) {
36 return true;
37 }
39 glCompileShader(sdr);
41 int len;
42 glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &len);
43 if(len) {
44 char *buf = (char*)alloca(len + 1);
45 glGetShaderInfoLog(sdr, len, &len, buf);
46 fprintf(stderr, "compiler: %s\n", buf);
47 }
49 int status;
50 glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
51 if(!status) {
52 fprintf(stderr, "shader compilation failed\n");
53 return false;
54 }
56 compiled = true;
57 return true;
58 }
60 bool Shader::is_compiled() const
61 {
62 return compiled;
63 }
65 bool Shader::load(const char *fname)
66 {
67 FILE *fp;
69 if(!(fp = fopen(fname, "rb"))) {
70 fprintf(stderr, "failed to open shader file: %s\n", fname);
71 return false;
72 }
74 fseek(fp, 0, SEEK_END);
75 long sz = ftell(fp);
76 rewind(fp);
78 char *buf = new char[sz + 1];
79 if((long)fread(buf, 1, sz, fp) < sz) {
80 fprintf(stderr, "failed to read shader contents\n");
81 fclose(fp);
82 return false;
83 }
84 fclose(fp);
86 set_source(buf);
87 delete [] buf;
89 return compile();
90 }
92 // ---- shader manager ----
93 static std::map<std::string, Shader*> sdrcache;
95 Shader *get_shader(const char *fname, unsigned int type)
96 {
97 std::map<std::string, Shader*>::const_iterator it;
99 if((it = sdrcache.find(std::string(fname))) != sdrcache.end()) {
100 return it->second;
101 }
103 Shader *sdr = new Shader(type);
104 if(!sdr->load(fname)) {
105 delete sdr;
106 return 0;
107 }
108 sdrcache[fname] = sdr;
109 return sdr;
110 }
113 // ---- class SdrProg ----
115 SdrProg::SdrProg()
116 {
117 prog = glCreateProgram();
118 linked = false;
119 assert(glGetError() == GL_NO_ERROR);
120 }
122 SdrProg::~SdrProg()
123 {
124 glDeleteProgram(prog);
125 }
127 void SdrProg::add_shader(Shader *sdr)
128 {
129 if(sdr->compile()) {
130 glAttachShader(prog, sdr->sdr);
131 assert(glGetError() == GL_NO_ERROR);
133 shaders.push_back(sdr);
134 linked = false;
135 }
136 }
138 bool SdrProg::link()
139 {
140 if(linked) {
141 return true;
142 }
144 glLinkProgram(prog);
146 int len;
147 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len);
148 if(len) {
149 char *buf = (char*)alloca(len + 1);
150 glGetProgramInfoLog(prog, len, &len, buf);
151 assert(glGetError() == GL_NO_ERROR);
152 fprintf(stderr, "linker: %s\n", buf);
153 }
155 int status;
156 glGetProgramiv(prog, GL_LINK_STATUS, &status);
157 if(!status) {
158 fprintf(stderr, "program linking failed\n");
159 return false;
160 }
162 linked = true;
163 return true;
164 }
166 bool SdrProg::load(const char *vsfname, const char *psfname)
167 {
168 Shader *sdr;
170 if(vsfname) {
171 if(!(sdr = get_shader(vsfname, GL_VERTEX_SHADER))) {
172 return false;
173 }
174 add_shader(sdr);
175 }
177 if(psfname) {
178 if(!(sdr = get_shader(psfname, GL_FRAGMENT_SHADER))) {
179 return false;
180 }
181 add_shader(sdr);
182 }
183 return link();
184 }
186 int SdrProg::get_uniform_location(const char *name)
187 {
188 bind_program(this);
189 return glGetUniformLocation(prog, name);
190 }
192 int SdrProg::get_attribute_location(const char *name)
193 {
194 bind_program(this);
195 return glGetAttribLocation(prog, name);
196 }
198 void SdrProg::set_uniform(const char *name, int val)
199 {
200 set_uniform(get_uniform_location(name), val);
201 }
203 void SdrProg::set_uniform(const char *name, float val)
204 {
205 set_uniform(get_uniform_location(name), val);
206 }
208 void SdrProg::set_uniform(const char *name, const Vector2 &v)
209 {
210 set_uniform(get_uniform_location(name), v);
211 }
213 void SdrProg::set_uniform(const char *name, const Vector3 &v)
214 {
215 set_uniform(get_uniform_location(name), v);
216 }
218 void SdrProg::set_uniform(const char *name, const Vector4 &v)
219 {
220 set_uniform(get_uniform_location(name), v);
221 }
223 void SdrProg::set_uniform(const char *name, const Matrix4x4 &mat)
224 {
225 set_uniform(get_uniform_location(name), mat);
226 }
229 void SdrProg::set_uniform(int loc, int val)
230 {
231 if(loc >= 0) {
232 bind_program(this);
233 glUniform1i(loc, val);
234 }
235 }
237 void SdrProg::set_uniform(int loc, float val)
238 {
239 if(loc >= 0) {
240 bind_program(this);
241 glUniform1f(loc, val);
242 }
243 }
245 void SdrProg::set_uniform(int loc, const Vector2 &v)
246 {
247 if(loc >= 0) {
248 bind_program(this);
249 glUniform2f(loc, v.x, v.y);
250 }
251 }
253 void SdrProg::set_uniform(int loc, const Vector3 &v)
254 {
255 if(loc >= 0) {
256 bind_program(this);
257 glUniform3f(loc, v.x, v.y, v.z);
258 }
259 }
261 void SdrProg::set_uniform(int loc, const Vector4 &v)
262 {
263 if(loc >= 0) {
264 bind_program(this);
265 glUniform4f(loc, v.x, v.y, v.z, v.w);
266 }
267 }
269 void SdrProg::set_uniform(int loc, const Matrix4x4 &mat)
270 {
271 if(loc >= 0) {
272 bind_program(this);
273 // loading transpose matrix (3rd arg true)
274 #ifdef SINGLE_PRECISION_MATH
275 glUniformMatrix4fv(loc, 1, GL_TRUE, (float*)mat.m);
276 #else
277 glUniformMatrix4dv(loc, 1, GL_TRUE, (double*)mat.m);
278 #endif
279 }
280 }
282 bool bind_program(const SdrProg *prog)
283 {
284 if(!prog) {
285 glUseProgram(0);
286 return true;
287 }
289 if(!((SdrProg*)prog)->link()) {
290 return false;
291 }
292 glUseProgram(prog->prog);
293 if(glGetError()) {
294 return false;
295 }
296 return true;
297 }