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