gKit2 light
framebuffer.cpp
Go to the documentation of this file.
1 
3 
4 #include <cstdio>
5 #include <cstring>
6 
7 #include "glcore.h"
8 #include "texture.h"
9 #include "uniforms.h"
10 #include "framebuffer.h"
11 
12 
13 GLuint Framebuffer::create( const int width, const int height )
14 {
15  glGenFramebuffers(1, &m_fbo);
16 
17  // etat par defaut
18  m_draw_buffers= std::vector<GLenum>(8, GL_NONE);
19  m_color_textures= std::vector<GLuint>(8, 0);
20  m_depth_texture= 0;
21 
22  m_clear_colors= std::vector< std::array<unsigned, 4> >(8);
23  m_clear_depth= 1;
24 
25  m_color_units= std::vector<int>(8, -1);
26  m_depth_unit= -1;
27 
28  m_width= width;
29  m_height= height;
30  return m_fbo;
31 }
32 
34 {
35  glDeleteTextures(8, m_color_textures.data());
36  glDeleteTextures(1, &m_depth_texture);
37  glDeleteFramebuffers(1, &m_fbo);
38 }
39 
40 int Framebuffer::width( ) const
41 {
42  return m_width;
43 }
44 
45 int Framebuffer::height( ) const
46 {
47  return m_height;
48 }
49 
50 
51 void Framebuffer::bind( const GLuint program, const bool color, const bool depth, const bool position, const bool texcoord, const bool normal, const bool material_id )
52 {
53  if(m_fbo == 0)
54  create(m_width, m_height);
55 
56  // desactive les textures associees au framebuffer, si necessaire (ie l'application ne l'a pas fait... mais non ca n'arrive jamais)
57  // todo ou generer une erreur ?
59 
60  // selectionne le framebuffer
61  assert(m_fbo > 0);
62  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
63 
64  // verifier que le fragment shader declare chaque sortie...
65  // openGL 4.3 / glGetProgramInterface() et glGetProgramResoucre()
66  // uniquement en mode debug...
67 #ifndef GK_RELEASE
68  if(program > 0)
69  {
70  // recuperer le nom du shader... si possible
71  char label[2048]= { 0 };
72  #ifdef GL_VERSION_4_3
73  {
74  char tmp[1024];
75  glGetObjectLabel(GL_PROGRAM, program, sizeof(tmp), nullptr, tmp);
76  sprintf(label, "program( %u '%s' )", program, tmp);
77  }
78  #else
79  sprintf(label, "program( %u )", program);
80  #endif
81 
82  #if 0
83  // verifie que le program est selectionne
84  GLuint current;
85  glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *) &current);
86  if(current != program)
87  printf("[oops] %s: not active... undefined draw !!\n", label);
88  #endif
89 
90  #ifdef GL_VERSION_4_3
91  // lister les sorties du fragment shader
92  // fonctionnalite openGL 4.3, n'existe pas sur mac...
93  GLint outputs= 0;
94  glGetProgramInterfaceiv(program, GL_PROGRAM_OUTPUT, GL_ACTIVE_RESOURCES, &outputs);
95 
96  char name[1024];
97  for(int i= 0; i < outputs; i++)
98  {
99  int location= -1;
100  GLenum props[]= { GL_LOCATION };
101  glGetProgramResourceiv(program, GL_PROGRAM_OUTPUT, i, 1, props, 1, nullptr, &location);
102  glGetProgramResourceName(program, GL_PROGRAM_OUTPUT, i, sizeof(name), nullptr, name);
103 
104  if(location == 0) // sortie color
105  {
106  if(!color)
107  printf("[oops] color output '%s' in %s not stored...\n", name, label);
108  }
109  else if(location == 1) // sortie position
110  {
111  if(!position)
112  printf("[oops] position output '%s' in %s not stored...\n", name, label);
113  }
114  else if(location == 2) // sortie texcoord
115  {
116  if(!texcoord)
117  printf("[oops] texcoord output '%s' in %s not stored...\n", name, label);
118  }
119  else if(location == 3) // sortie normal
120  {
121  if(!normal)
122  printf("[oops] normal output '%s' in %s not stored...\n", name, label);
123  }
124  else if(location == 4) // sortie material_id
125  {
126  if(!material_id)
127  printf("[oops] material output '%s' in %s not stored...\n", name, label);
128  }
129  }
130  #endif
131  }
132 #endif
133 
134  // configuration du framebuffer, et creation des textures, si necessaire
135  if(depth)
136  {
137  if(m_depth_texture == 0)
138  m_depth_texture= make_depth_texture(0, m_width, m_height);
139 
140  assert(m_depth_texture > 0);
141  glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_depth_texture, /* mipmap */ 0);
142  }
143  else
144  {
145  glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 0, /* mipmap */ 0);
146  }
147 
148  //
149  bool draw_buffers= false;
150  if(color)
151  {
152  if(m_color_textures[0] == 0)
153  m_color_textures[0]= make_vec4_texture(0, m_width, m_height);
154 
155  assert(m_color_textures[0] > 0);
156  if(m_draw_buffers[0] == GL_NONE)
157  {
158  glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_color_textures[0], /* mipmap */ 0);
159  m_draw_buffers[0]= GL_COLOR_ATTACHMENT0;
160  draw_buffers= true;
161  }
162  }
163  else
164  {
165  glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, /* mipmap */ 0);
166  m_draw_buffers[0]= GL_NONE;
167  draw_buffers= true;
168  }
169 
170  if(position)
171  {
172  if(m_color_textures[1] == 0)
173  m_color_textures[1]= make_vec3_texture(0, m_width, m_height);
174 
175  assert(m_color_textures[1] > 0);
176  if(m_draw_buffers[1] == GL_NONE)
177  {
178  glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, m_color_textures[1], /* mipmap */ 0);
179  m_draw_buffers[1]= GL_COLOR_ATTACHMENT1;
180  draw_buffers= true;
181  }
182  }
183  else
184  {
185  glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, 0, /* mipmap */ 0);
186  m_draw_buffers[1]= GL_NONE;
187  draw_buffers= true;
188  }
189 
190  if(texcoord)
191  {
192  if(m_color_textures[2] == 0)
193  m_color_textures[2]= make_vec2_texture(0, m_width, m_height);
194 
195  assert(m_color_textures[2] > 0);
196  if(m_draw_buffers[2] == GL_NONE)
197  {
198  glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, m_color_textures[2], /* mipmap */ 0);
199  m_draw_buffers[2]= GL_COLOR_ATTACHMENT2;
200  draw_buffers= true;
201  }
202  }
203  else
204  {
205  glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, 0, /* mipmap */ 0);
206  m_draw_buffers[2]= GL_NONE;
207  draw_buffers= true;
208  }
209 
210  if(normal)
211  {
212  if(m_color_textures[3] == 0)
213  m_color_textures[3]= make_vec3_texture(0, m_width, m_height);
214 
215  assert(m_color_textures[3] > 0);
216  if(m_draw_buffers[3] == GL_NONE)
217  {
218  glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, m_color_textures[3], /* mipmap */ 0);
219  m_draw_buffers[3]= GL_COLOR_ATTACHMENT3;
220  draw_buffers= true;
221  }
222  }
223  else
224  {
225  glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, 0, /* mipmap */ 0);
226  m_draw_buffers[3]= GL_NONE;
227  draw_buffers= true;
228  }
229 
230  if(material_id)
231  {
232  if(m_color_textures[4] == 0)
233  m_color_textures[4]= make_uint_texture(0, m_width, m_height);
234 
235  assert(m_color_textures[4] > 0);
236  if(m_draw_buffers[4] == GL_NONE)
237  {
238  glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, m_color_textures[4], /* mipmap */ 0);
239  m_draw_buffers[4]= GL_COLOR_ATTACHMENT4;
240  draw_buffers= true;
241  }
242  }
243  else
244  {
245  glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, 0, /* mipmap */ 0);
246  m_draw_buffers[4]= GL_NONE;
247  draw_buffers= true;
248  }
249 
250  if(draw_buffers)
251  glDrawBuffers(8, m_draw_buffers.data());
252 
253  // verifie la configuration du framebuffer
254  if(!status())
255  return;
256 
257  // prepare le rendu dans le framebuffer
258  glViewport(0, 0, m_width, m_height);
259 
260  // pas joli, mais plus simple que declarer n variables du bon type...
261  if(depth)
262  glClearBufferfv(GL_DEPTH, 0, &m_clear_depth);
263  if(color)
264  glClearBufferfv(GL_COLOR, 0, (const GLfloat *) &m_clear_colors[0]);
265  if(position)
266  glClearBufferfv(GL_COLOR, 1, (const GLfloat *) &m_clear_colors[1]);
267  if(texcoord)
268  glClearBufferfv(GL_COLOR, 2, (const GLfloat *) &m_clear_colors[2]);
269  if(normal)
270  glClearBufferfv(GL_COLOR, 3, (const GLfloat *) &m_clear_colors[3]);
271  if(material_id)
272  glClearBufferuiv(GL_COLOR, 4, (const GLuint *) &m_clear_colors[4]);
273 }
274 
275 
276 void Framebuffer::unbind( const int width, const int height )
277 {
278  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
279  glViewport(0, 0, width, height);
280 }
281 
282 
284 {
285  // desactive les textures associees au framebuffer, si necessaire
286  // le pipeline ne peut pas lire et modifier les textures en meme temps.
287  for(int i= 0; i < 8; i++)
288  if(m_color_units[i] != -1)
289  {
290  glActiveTexture(GL_TEXTURE0 + m_color_units[i]);
291  glBindTexture(GL_TEXTURE_2D, 0);
292 
293  m_color_units[i]= -1;
294  }
295 
296  if(m_depth_unit != -1)
297  {
298  glActiveTexture(GL_TEXTURE0 + m_depth_unit);
299  glBindTexture(GL_TEXTURE_2D, 0);
300 
301  m_depth_unit= -1;
302  }
303 }
304 
305 
306 
307 void Framebuffer::clear_depth( const float value )
308 {
309  if(m_fbo == 0)
310  printf("[error] uninitialized framebuffer...\n");
311 
312  m_clear_depth= value;
313 }
314 
316 {
317  if(m_fbo == 0)
318  printf("[error] uninitialized framebuffer...\n");
319 
320  float values[4]= { value.r, value.g, value.b, value.a };
321  memcpy(&m_clear_colors[0], values, sizeof(values));
322 }
323 
325 {
326  if(m_fbo == 0)
327  printf("[error] uninitialized framebuffer...\n");
328 
329  float values[4]= { value.x, value.y, value.z, 0 };
330  memcpy(&m_clear_colors[1], values, sizeof(values));
331 }
332 
334 {
335  if(m_fbo == 0)
336  printf("[error] uninitialized framebuffer...\n");
337 
338  float values[4]= { value.x, value.y, 0, 0 };
339  memcpy(&m_clear_colors[2], values, sizeof(values));
340 }
341 
343 {
344  if(m_fbo == 0)
345  printf("[error] uninitialized framebuffer...\n");
346 
347  float values[4]= { value.x, value.y, value.z, 0 };
348  memcpy(&m_clear_colors[3], values, sizeof(values));
349 }
350 
351 void Framebuffer::clear_material( const unsigned value )
352 {
353  if(m_fbo == 0)
354  printf("[error] uninitialized framebuffer...\n");
355 
356  unsigned values[4]= { value, 0, 0, 0 };
357  memcpy(&m_clear_colors[4], values, sizeof(values));
358 }
359 
360 
361 bool Framebuffer::status( )
362 {
363  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
364  GLenum code= glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
365 
366  if(code == GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER)
367  printf("[error] framebuffer: incomplete draw buffer... can't draw!\n");
368  else if(code == GL_FRAMEBUFFER_UNSUPPORTED)
369  printf("[error] framebuffer: unsupported format... can't draw!\n");
370 
371  return (code == GL_FRAMEBUFFER_COMPLETE);
372 }
373 
374 
375 void Framebuffer::use_depth_texture( const GLuint program, const char *uniform, const int unit, const GLuint sampler )
376 {
377  m_depth_unit= unit;
378  program_use_texture(program, uniform, unit, m_depth_texture, sampler);
379 }
380 
381 void Framebuffer::use_color_texture( const GLuint program, const char *uniform, const int unit, const GLuint sampler )
382 {
383  m_color_units[0]= unit;
384  program_use_texture(program, uniform, unit, m_color_textures[0], sampler);
385 }
386 
387 void Framebuffer::use_position_texture( const GLuint program, const char *uniform, const int unit, const GLuint sampler )
388 {
389  m_color_units[1]= unit;
390  program_use_texture(program, uniform, unit, m_color_textures[1], sampler);
391 }
392 
393 void Framebuffer::use_texcoord_texture( const GLuint program, const char *uniform, const int unit, const GLuint sampler )
394 {
395  m_color_units[2]= unit;
396  program_use_texture(program, uniform, unit, m_color_textures[2], sampler);
397 }
398 
399 void Framebuffer::use_normal_texture( const GLuint program, const char *uniform, const int unit, const GLuint sampler )
400 {
401  m_color_units[3]= unit;
402  program_use_texture(program, uniform, unit, m_color_textures[3], sampler);
403 }
404 
405 void Framebuffer::use_material_texture( const GLuint program, const char *uniform, const int unit, const GLuint sampler )
406 {
407  m_color_units[4]= unit;
408  program_use_texture(program, uniform, unit, m_color_textures[4], sampler);
409 }
410 
411 
412 
413 void Framebuffer::blit_depth( const int dstX0, const int dstY0, const int dstX1, const int dstY1 )
414 {
415  glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
416 
417  glBlitFramebuffer(0, 0, m_width, m_height, dstX0, dstY0, dstX1, dstY1, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
418 
419  glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
420 }
421 
422 void Framebuffer::blit_color( const int dstX0, const int dstY0, const int dstX1, const int dstY1 )
423 {
424  glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
425  glReadBuffer(GL_COLOR_ATTACHMENT0);
426 
427  glBlitFramebuffer(0, 0, m_width, m_height, dstX0, dstY0, dstX1, dstY1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
428 
429  glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
430 }
431 
432 void Framebuffer::blit_position( const int dstX0, const int dstY0, const int dstX1, const int dstY1 )
433 {
434  glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
435  glReadBuffer(GL_COLOR_ATTACHMENT1);
436 
437  glBlitFramebuffer(0, 0, m_width, m_height, dstX0, dstY0, dstX1, dstY1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
438 
439  glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
440 }
441 
442 void Framebuffer::blit_texcoord( const int dstX0, const int dstY0, const int dstX1, const int dstY1 )
443 {
444  glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
445  glReadBuffer(GL_COLOR_ATTACHMENT2);
446 
447  glBlitFramebuffer(0, 0, m_width, m_height, dstX0, dstY0, dstX1, dstY1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
448 
449  glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
450 }
451 
452 void Framebuffer::blit_normal( const int dstX0, const int dstY0, const int dstX1, const int dstY1 )
453 {
454  glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
455  glReadBuffer(GL_COLOR_ATTACHMENT3);
456 
457  glBlitFramebuffer(0, 0, m_width, m_height, dstX0, dstY0, dstX1, dstY1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
458 
459  glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
460 }
461 
462 
463 // marche pas, utiliser un shader pour convertir les valeurs en couleurs...
464 //~ void Framebuffer::blit_material( const int dstX0, const int dstY0, const int dstX1, const int dstY1 )
465 //~ {
466  //~ glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo);
467  //~ glReadBuffer(GL_COLOR_ATTACHMENT4);
468 
469  //~ glBlitFramebuffer(0, 0, m_width, m_height, dstX0, dstY0, dstX1, dstY1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
470 
471  //~ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
472 //~ }
473 
void label(Widgets &w, const char *format,...)
cree un texte. meme fonctionnement que printf().
Definition: widgets.cpp:142
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
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
GLuint make_vec2_texture(const int unit, const int width, const int height, const GLenum texel_type)
creation de textures pour stocker des donnees (autres qu'une couleur).
Definition: texture.cpp:171
GLuint make_vec3_texture(const int unit, const int width, const int height, const GLenum texel_type)
creation de textures pour stocker des donnees (autres qu'une couleur).
Definition: texture.cpp:176
GLuint make_vec4_texture(const int unit, const int width, const int height, const GLenum texel_type)
creation de textures pour stocker des donnees (autres qu'une couleur).
Definition: texture.cpp:181
void program_use_texture(const GLuint program, const char *uniform, const int unit, const GLuint texture, const GLuint sampler)
configure le pipeline et le shader program pour utiliser une texture, et des parametres de filtrage,...
Definition: uniforms.cpp:198
GLuint make_uint_texture(const int unit, const int width, const int height, const GLenum texel_type)
creation de textures pour stocker des donnees (autres qu'une couleur).
Definition: texture.cpp:161
GLuint make_depth_texture(const int unit, const int width, const int height, const GLenum texel_type)
creation de textures pour stocker des donnees (autres qu'une couleur).
Definition: texture.cpp:156
representation d'une couleur (rgba) transparente ou opaque.
Definition: color.h:14
void release()
destruction.
Definition: framebuffer.cpp:33
int height() const
renvoie la hauteur du framebuffer.
Definition: framebuffer.cpp:45
void clear_texcoord(const vec2 &value)
texcoord par defaut.
void clear_position(const Point &value)
position par defaut.
void clear_material(const unsigned value)
indice de matiere par defaut.
int width() const
renvoie la largeur du framebuffer.
Definition: framebuffer.cpp:40
void unbind(const int width, const int height)
desactive le framebuffer, selection du framebuffer par defaut associe a la fenetre.
GLuint create(const int width, const int height)
creation du framebuffer
Definition: framebuffer.cpp:13
void clear_color(const Color &value)
couleur par defaut.
void clear_depth(const float value)
profondeur par defaut.
void unbind_textures()
nettoyage, desactive les textures utilisees par les autres shaders, cf use_color_texture(),...
void bind(const GLuint program, const bool store_color, const bool store_depth, const bool store_position, const bool store_texcoord, const bool store_normal, const bool store_material)
selection du framebuffer, stocker les sorties du fragment shader. les textures sont initialisees avec...
Definition: framebuffer.cpp:51
void clear_normal(const Vector &value)
normale par defaut.
representation d'un point 3d.
Definition: vec.h:21
representation d'un vecteur 3d.
Definition: vec.h:59
vecteur generique, utilitaire.
Definition: vec.h:131