gKit2 light

- Main Page
- Related Pages
- Modules
- Classes
- Files

- File List
- File Members

program.cpp
1
2 #include <fstream>
3 #include <sstream>
4 #include <string>
5 #include <vector>
6 #include <algorithm>
7
8 #include <climits>
9 #include <cstdio>
10
11 #include "program.h"
12
13
14 // charge un fichier texte.
15 static
16 std::string read( const char *filename )
17 {
18 std::stringbuf source;
19 std::ifstream in(filename);
20 if(in.good() == false)
21 printf("[error] loading program '%s'...\n", filename);
22 else
23 printf("loading program '%s'...\n", filename);
24
25 in.get(source, 0); // lire tout le fichier, le caractere '\0' ne peut pas se trouver dans le source de shader
26 return source.str();
27 }
28
29 // insere les definitions apres la ligne contenant #version
30 static
31 std::string prepare_source( std::string file, const std::string& definitions )
32 {
33 if(file.empty())
34 return std::string();
35
36 // un peu de gymnastique, #version doit rester sur la premiere ligne, meme si on insere des #define dans le source
37 std::string source;
38
39 // recupere la ligne #version
40 std::string version;
41 size_t b= file.find("#version");
42 if(b != std::string::npos)
43 {
44 size_t e = file.find( '\n', b );
45 if(e != std::string::npos)
46 {
47 version= file.substr(0, e +1);
48 file.erase(0, e +1);
49
50 if(file.find("#version") != std::string::npos)
51 {
52 printf("[error] found several #version directives. failed.\n");
53 return std::string();
54 }
55 }
56 }
57 else
58 {
59 printf("[error] no #version directive found. failed.\n");
60 return std::string();
61 }
62
63 // reconstruit le source complet
64 if(definitions.empty() == false)
65 {
66 source.append(version); // insere la version
67 source.append(definitions).append("\n"); // insere les definitions
68 source.append(file); // insere le source
69 }
70 else
71 {
72 source.append(version); // re-insere la version (supprimee de file)
73 source.assign(file); // insere le source
74 }
75
76 return source;
77 }
78
79 static
80 GLuint compile_shader( const GLuint program, const GLenum shader_type, const std::string& source )
81 {
82 if(source.size() == 0)
83 return 0;
84
85 GLuint shader= glCreateShader(shader_type);
86 glAttachShader(program, shader);
87
88 const char *sources= source.c_str();
89 glShaderSource(shader, 1, &sources, NULL);
90 glCompileShader(shader);
91
92 GLint status;
93 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
94 return (status == GL_TRUE) ? shader : 0;
95 }
96
97
98 int reload_program( GLuint program, const char *filename, const char *definitions )
99 {
100 if(program == 0)
101 return -1;
102
103 // supprime les shaders attaches au program
104 int shaders_max= 0;
105 glGetProgramiv(program, GL_ATTACHED_SHADERS, &shaders_max);
106 if(shaders_max > 0)
107 {
108 std::vector<GLuint> shaders(shaders_max, 0);
109 glGetAttachedShaders(program, shaders_max, NULL, &shaders.front());
110 for (int i = 0; i < shaders_max; i++)
111 {
112 glDetachShader(program, shaders[i]);
113 glDeleteShader(shaders[i]);
114 }
115 }
116
117 #ifdef GL_VERSION_4_3
118 glObjectLabel(GL_PROGRAM, program, -1, filename);
119 #endif
120
121 // prepare les sources
122 std::string common_source= read(filename);
123 std::string vertex_source= prepare_source(common_source, std::string(definitions).append("#define VERTEX_SHADER\n"));
124 std::string fragment_source= prepare_source(common_source, std::string(definitions).append("#define FRAGMENT_SHADER\n"));
125
126 // cree et compile un vertex shader et un fragment shader
127 GLuint vertex_shader= compile_shader(program, GL_VERTEX_SHADER, vertex_source);
128 GLuint fragment_shader= compile_shader(program, GL_FRAGMENT_SHADER, fragment_source);
129 // linke les shaders
130 glLinkProgram(program);
131
132 // verifie les erreurs
133 GLint status;
134 glGetProgramiv(program, GL_LINK_STATUS, &status);
135 if(status == GL_FALSE)
136 {
137 if(vertex_shader == 0)
138 printf("[error] compiling vertex shader...\n%s\n", definitions);
139 if(fragment_shader == 0)
140 printf("[error] compiling fragment shader...\n%s\n", definitions);
141 printf("[error] linking program %u '%s'...\n", program, filename);
142 return -1;
143 }
144
145 // pour etre coherent avec les autres fonctions de creation, active l'objet gl qui vient d'etre cree.
146 glUseProgram(program);
147 return 0;
148 }
149
150 GLuint read_program( const char *filename, const char *definitions )
151 {
152 GLuint program= glCreateProgram();
153 reload_program(program, filename, definitions);
154 return program;
155 }
156
157 int release_program( const GLuint program )
158 {
159 if(program == 0)
160 return -1;
161
162 // recupere les shaders
163 int shaders_max= 0;
164 glGetProgramiv(program, GL_ATTACHED_SHADERS, &shaders_max);
165
166 std::vector<GLuint> shaders(shaders_max, 0);
167 glGetAttachedShaders(program, shaders_max, NULL, &shaders.front());
168 for(int i= 0; i < shaders_max; i++)
169 {
170 glDetachShader(program, shaders[i]);
171 glDeleteShader(shaders[i]);
172 }
173
174 glDeleteProgram(program);
175 return 0;
176 }
177
178
179 // formatage des erreurs de compilation des shaders
180
181 static
182 void print_line( std::string& errors, const char *source, const int begin_id, const int line_id )
183 {
184 int line= 0;
185 char last= '\n';
186 for(unsigned int i= 0; source[i] != 0; i++)
187 {
188 if(line > line_id)
189 break;
190
191 if(last == '\n')
192 {
193 line++;
194 if(line >= begin_id && line <= line_id)
195 {
196 errors.append(" ");
197 errors.push_back('0' + (line / 1000) % 10);
198 errors.push_back('0' + (line / 100) % 10);
199 errors.push_back('0' + (line / 10) % 10);
200 errors.push_back('0' + (line / 1) % 10);
201 errors.append(" ");
202 }
203 }
204
205 if(line >= begin_id && line <= line_id)
206 {
207 if(source[i] == '\t')
208 errors.append(" ");
209 else
210 errors.push_back(source[i]);
211 }
212 last= source[i];
213 }
214 }
215
216 static
217 int print_errors( std::string& errors, const char *log, const char *source )
218 {
219 printf("[error log]\n%s\n", log);
220
221 int first_error= INT_MAX;
222 int last_string= -1;
223 int last_line= -1;
224 for(int i= 0; log[i] != 0; i++)
225 {
226 // recupere la ligne assiciee a l'erreur
227 int string_id= 0, line_id= 0, position= 0;
228 if(sscanf(&log[i], "%d ( %d ) : %n", &string_id, &line_id, &position) == 2 // nvidia syntax
229 || sscanf(&log[i], "%d : %d (%*d) : %n", &string_id, &line_id, &position) == 2 // mesa syntax
230 || sscanf(&log[i], "ERROR : %d : %d : %n", &string_id, &line_id, &position) == 2 // ati syntax
231 || sscanf(&log[i], "WARNING : %d : %d : %n", &string_id, &line_id, &position) == 2) // ati syntax
232 {
233 if(string_id != last_string || line_id != last_line)
234 {
235 // conserve la premiere erreur
236 first_error= std::min(first_error, line_id);
237
238 // extrait la ligne du source...
239 errors.append("\n");
240 print_line(errors, source, last_line +1, line_id);
241 errors.append("\n");
242 }
243 }
244 // et affiche l'erreur associee...
245 for(i+= position; log[i] != 0; i++)
246 {
247 errors.push_back(log[i]);
248 if(log[i] == '\n')
249 break;
250 }
251
252 last_string= string_id;
253 last_line= line_id;
254 }
255 errors.append("\n");
256 print_line(errors, source, last_line +1, 1000);
257 errors.append("\n");
258
259 return first_error;
260 }
261
262 int program_format_errors( const GLuint program, std::string& errors )
263 {
264 errors.clear();
265
266 if(program == 0)
267 {
268 errors.append("[error] no program...\n");
269 return -1;
270 }
271
272 GLint status;
273 glGetProgramiv(program, GL_LINK_STATUS, &status);
274 if(status == GL_TRUE)
275 return 0;
276
277 int first_error= INT_MAX;
278
279 // recupere les shaders
280 int shaders_max= 0;
281 glGetProgramiv(program, GL_ATTACHED_SHADERS, &shaders_max);
282
283 std::vector<GLuint> shaders(shaders_max, 0);
284 glGetAttachedShaders(program, shaders_max, NULL, &shaders.front());
285 for(int i= 0; i < shaders_max; i++)
286 {
287 GLint value;
288 glGetShaderiv(shaders[i], GL_COMPILE_STATUS, &value);
289 if(value == GL_FALSE)
290 {
291 // recupere les erreurs de compilation des shaders
292 glGetShaderiv(shaders[i], GL_INFO_LOG_LENGTH, &value);
293 std::vector<char>log(value+1, 0);
294 glGetShaderInfoLog(shaders[i], (GLsizei) log.size(), NULL, &log.front());
295
296 // recupere le source
297 glGetShaderiv(shaders[i], GL_SHADER_SOURCE_LENGTH, &value);
298 std::vector<char> source(value+1, 0);
299 glGetShaderSource(shaders[i], source.size(), NULL, &source.front());
300
301 glGetShaderiv(shaders[i], GL_SHADER_TYPE, &value);
302 errors.append("[error] compiling ");
303 if(value == GL_VERTEX_SHADER)
304 errors.append("vertex shader...\n");
305 else if(value == GL_FRAGMENT_SHADER)
306 errors.append("fragment shader...\n");
307 else
308 errors.append("shader...\n");
309
310 // formatte les erreurs
311 int last_error= print_errors(errors, &log.front(), &source.front());
312 first_error= std::min(first_error, last_error);
313 }
314 }
315
316 // recupere les erreurs de link du program
317 {
318 GLint value= 0;
319 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &value);
320
321 std::vector<char>log(value+1, 0);
322 glGetProgramInfoLog(program, (GLsizei) log.size(), NULL, &log.front());
323
324 errors.append("[error] linking program...\n").append(log.begin(), log.end());
325 }
326
327 return first_error;
328 }
329
330 int program_print_errors( const GLuint program )
331 {
332 std::string errors;
333 int code= program_format_errors(program, errors);
334 if(errors.size() > 0)
335 printf("%s\n", errors.c_str());
336 return code;
337 }
338
program.h
program_print_errors
int program_print_errors(const GLuint program)
affiche les erreurs de compilation.
Definition: program.cpp:330
read_program
GLuint read_program(const char *filename, const char *definitions)
Definition: program.cpp:150
value
bool value(Widgets &w, const char *label, int &value, const int value_min, const int value_max, const int value_step)
valeur editable par increment.
Definition: widgets.cpp:191
program_format_errors
int program_format_errors(const GLuint program, std::string &errors)
renvoie les erreurs de compilation.
Definition: program.cpp:262
printf
void printf(Text &text, const int px, const int py, const char *format,...)
affiche un texte a la position x, y. meme utilisation que printf().
Definition: text.cpp:140
release_program
int release_program(const GLuint program)
detruit les shaders et le program.
Definition: program.cpp:157
reload_program
int reload_program(GLuint program, const char *filename, const char *definitions)
recharge les sources et recompile un shader program.
Definition: program.cpp:98