gKit2 light
mesh.cpp
1 
2 #include <cstdio>
3 #include <cassert>
4 #include <string>
5 #include <algorithm>
6 
7 #include "vec.h"
8 #include "mesh.h"
9 
10 #include "program.h"
11 #include "uniforms.h"
12 
13 #include "window.h"
14 
15 
16 int Mesh::create( const GLenum primitives )
17 {
18  m_primitives= primitives;
19  return 0;
20 }
21 
22 Mesh::Mesh( const GLenum primitives, const std::vector<vec3>& positions ) :
23  m_positions(), m_texcoords(), m_normals(), m_colors(), m_indices(),
24  m_color(White()), m_primitives(GL_POINTS), m_vao(0), m_buffer(0), m_index_buffer(0), m_vertex_buffer_size(0), m_index_buffer_size(0), m_update_buffers(false)
25 {
26  m_primitives= primitives;
27  m_positions= positions;
28  m_update_buffers= true;
29 }
30 
31 Mesh::Mesh( const GLenum primitives, const std::vector<vec3>& positions, const std::vector<unsigned>& indices ) :
32  m_positions(), m_texcoords(), m_normals(), m_colors(), m_indices(),
33  m_color(White()), m_primitives(GL_POINTS), m_vao(0), m_buffer(0), m_index_buffer(0), m_vertex_buffer_size(0), m_index_buffer_size(0), m_update_buffers(false)
34 {
35  m_primitives= primitives;
36  m_positions= positions;
37  m_indices= indices;
38  m_update_buffers= true;
39 }
40 
41 Mesh::Mesh( const GLenum primitives, const std::vector<vec3>& positions,
42  const std::vector<vec2>& texcoords,
43  const std::vector<vec3>& normals,
44  const std::vector<vec4>& colors,
45  const std::vector<unsigned>& indices ) :
46  m_positions(), m_texcoords(), m_normals(), m_colors(), m_indices(),
47  m_color(White()), m_primitives(GL_POINTS), m_vao(0), m_buffer(0), m_index_buffer(0), m_vertex_buffer_size(0), m_index_buffer_size(0), m_update_buffers(false)
48 {
49  m_primitives= primitives;
50  m_positions= positions;
51  m_indices= indices;
52  m_update_buffers= true;
53 
54  // n'initialise les autres attributs que s'ils sont definis
55  if(texcoords.size() > 0 && texcoords.size() == positions.size())
56  m_texcoords= texcoords;
57  if(normals.size() > 0 && normals.size() == positions.size())
58  m_normals= normals;
59  if(colors.size() > 0 && colors.size() == positions.size())
60  m_colors= colors;
61 }
62 
63 
65 {
66  printf("mesh release %d\n", m_vao);
67 
68  glDeleteVertexArrays(1, &m_vao);
69  glDeleteBuffers(1, &m_buffer);
70  glDeleteBuffers(1, &m_index_buffer);
71 }
72 
73 // definit les attributs du prochain sommet
74 Mesh& Mesh::default_color( const Color& color )
75 {
76  m_color= color;
77  return *this;
78 }
79 
80 Mesh& Mesh::color( const vec4& color )
81 {
82  if(m_colors.size() <= m_positions.size())
83  m_colors.push_back(color);
84  else
85  m_colors.back()= color;
86  m_update_buffers= true;
87  return *this;
88 }
89 
90 Mesh& Mesh::normal( const vec3& normal )
91 {
92  if(m_normals.size() <= m_positions.size())
93  m_normals.push_back(normal);
94  else
95  m_normals.back()= normal;
96  m_update_buffers= true;
97  return *this;
98 }
99 
100 Mesh& Mesh::texcoord( const vec2& uv )
101 {
102  if(m_texcoords.size() <= m_positions.size())
103  m_texcoords.push_back(uv);
104  else
105  m_texcoords.back()= uv;
106  m_update_buffers= true;
107  return *this;
108 }
109 
110 // insere un nouveau sommet
111 unsigned int Mesh::vertex( const vec3& position )
112 {
113  m_update_buffers= true;
114  m_positions.push_back(position);
115 
116  // copie les autres attributs du sommet, uniquement s'ils sont definis
117  if(m_texcoords.size() > 0 && m_texcoords.size() != m_positions.size())
118  m_texcoords.push_back(m_texcoords.back());
119  if(m_normals.size() > 0 && m_normals.size() != m_positions.size())
120  m_normals.push_back(m_normals.back());
121  if(m_colors.size() > 0 && m_colors.size() != m_positions.size())
122  m_colors.push_back(m_colors.back());
123 
124  // copie la matiere courante, uniquement si elle est definie
125  if(m_triangle_materials.size() > 0 && int(m_triangle_materials.size()) < triangle_count())
126  m_triangle_materials.push_back(m_triangle_materials.back());
127 
128  unsigned int index= m_positions.size() -1;
129  // construction de l'index buffer pour les strip
130  switch(m_primitives)
131  {
132  case GL_LINE_STRIP:
133  case GL_LINE_LOOP:
134  case GL_TRIANGLE_STRIP:
135  case GL_TRIANGLE_FAN:
136  m_indices.push_back(index);
137  break;
138  default:
139  break;
140  }
141 
142  // renvoie l'indice du sommet
143  return index;
144 }
145 
146 // update attributes
147 Mesh& Mesh::color( const unsigned int id, const vec4& c )
148 {
149  assert(id < m_colors.size());
150  m_update_buffers= true;
151  m_colors[id]= c;
152  return *this;
153 }
154 
155 Mesh& Mesh::normal( const unsigned int id, const vec3& n )
156 {
157  assert(id < m_normals.size());
158  m_update_buffers= true;
159  m_normals[id]= n;
160  return *this;
161 }
162 
163 Mesh& Mesh::texcoord( const unsigned int id, const vec2& uv )
164 {
165  assert(id < m_texcoords.size());
166  m_update_buffers= true;
167  m_texcoords[id]= uv;
168  return *this;
169 }
170 
171 void Mesh::vertex( const unsigned int id, const vec3& p )
172 {
173  assert(id < m_positions.size());
174  m_update_buffers= true;
175  m_positions[id]= p;
176 }
177 
178 void Mesh::clear( )
179 {
180  m_update_buffers= true;
181 
182  m_positions.clear();
183  m_texcoords.clear();
184  m_normals.clear();
185  m_colors.clear();
186  m_indices.clear();
187  //~ m_materials.clear();
188  m_triangle_materials.clear();
189 }
190 
191 //
192 Mesh& Mesh::triangle( const unsigned int a, const unsigned int b, const unsigned int c )
193 {
194  assert(a < m_positions.size());
195  assert(b < m_positions.size());
196  assert(c < m_positions.size());
197  m_update_buffers= true;
198  m_indices.push_back(a);
199  m_indices.push_back(b);
200  m_indices.push_back(c);
201 
202  // copie la matiere courante, uniquement si elle est definie
203  if(m_triangle_materials.size() > 0 && int(m_triangle_materials.size()) < triangle_count())
204  m_triangle_materials.push_back(m_triangle_materials.back());
205 
206  m_update_buffers= true;
207  return *this;
208 }
209 
210 Mesh& Mesh::triangle_last( const int a, const int b, const int c )
211 {
212  assert(a < 0);
213  assert(b < 0);
214  assert(c < 0);
215  m_update_buffers= true;
216  m_indices.push_back(int(m_positions.size()) + a);
217  m_indices.push_back(int(m_positions.size()) + b);
218  m_indices.push_back(int(m_positions.size()) + c);
219 
220  // copie la matiere courante, uniquement si elle est definie
221  if(m_triangle_materials.size() > 0 && int(m_triangle_materials.size()) < triangle_count())
222  m_triangle_materials.push_back(m_triangle_materials.back());
223 
224  m_update_buffers= true;
225  return *this;
226 }
227 
229 {
230  m_update_buffers= true;
231  m_indices.push_back(~0u); // ~0u plus grand entier non signe representable, ou UINT_MAX...
232 #if 1
233  glPrimitiveRestartIndex(~0u);
234  glEnable(GL_PRIMITIVE_RESTART);
235 #else
236  glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); // n'existe pas sur mac ?!
237 #endif
238  return *this;
239 }
240 
241 Mesh& Mesh::index( const int a )
242 {
243  if(a < 0)
244  m_indices.push_back(int(m_positions.size()) + a);
245  else if(a < int(m_positions.size()))
246  m_indices.push_back(a);
247  else
248  {
249  printf("[error] Mesh::index(): invalid index...\n");
250  return *this; // erreur
251  }
252 
253  // copie la matiere courante, uniquement si elle est definie
254  if(m_triangle_materials.size() > 0 && int(m_triangle_materials.size()) < triangle_count())
255  m_triangle_materials.push_back(m_triangle_materials.back());
256 
257  m_update_buffers= true;
258  return *this;
259 }
260 
261 
263 {
264  return m_materials;
265 }
266 
267 const Materials& Mesh::materials( ) const
268 {
269  return m_materials;
270 }
271 
272 void Mesh::materials( const Materials& materials )
273 {
274  m_materials= materials;
275 }
276 
277 Mesh& Mesh::material( const unsigned int id )
278 {
279  if(int(m_triangle_materials.size()) <= triangle_count())
280  m_triangle_materials.push_back(id);
281  else
282  m_triangle_materials.back()= id;
283  m_update_buffers= true;
284  return *this;
285 }
286 
287 const std::vector<unsigned int>& Mesh::material_indices( ) const
288 {
289  return m_triangle_materials;
290 }
291 
292 int Mesh::triangle_material_index( const unsigned int id ) const
293 {
294  assert((size_t) id < m_triangle_materials.size());
295  return m_triangle_materials[id];
296 }
297 
298 const Material &Mesh::triangle_material( const unsigned int id ) const
299 {
300  assert((size_t) id < m_triangle_materials.size());
301  return m_materials.material(m_triangle_materials[id]);
302 }
303 
304 
305 std::vector<TriangleGroup> Mesh::groups( )
306 {
307  return groups(m_triangle_materials);
308 }
309 
310 std::vector<TriangleGroup> Mesh::groups( const std::vector<unsigned int>& triangle_properties )
311 {
312  if(m_primitives != GL_TRIANGLES)
313  return {};
314 
315  // pas le bon nombre d'infos, renvoyer un seul groupe
316  if(int(triangle_properties.size()) != triangle_count())
317  {
318  if(m_indices.size())
319  return { {0, 0, int(m_indices.size())} };
320  else
321  return { {0, 0, int(m_positions.size())} };
322  }
323 
324  // trie les triangles
325  std::vector<int> remap(triangle_count());
326  for(unsigned i= 0; i < remap.size(); i++)
327  remap[i]= i;
328 
329  struct triangle_sort
330  {
331  const std::vector<unsigned int>& properties;
332 
333  triangle_sort( const std::vector<unsigned int>& _properties ) : properties(_properties) {}
334 
335  bool operator() ( const int& a, const int& b ) const
336  {
337  return properties[a] < properties[b];
338  }
339  };
340 
341  std::stable_sort(remap.begin(), remap.end(), triangle_sort(triangle_properties));
342 
343  // re-organise les triangles, et construit les groupes
344  std::vector<TriangleGroup> groups;
345  if(m_indices.size())
346  {
347  int first= 0;
348  int property_id= triangle_properties[remap[0]];
349 
350  // re-organise l'index buffer...
351  std::vector<unsigned int> indices;
352  std::vector<unsigned int> material_indices;
353  for(unsigned i= 0; i < remap.size(); i++)
354  {
355  int id= triangle_properties[remap[i]];
356  if(id != property_id)
357  {
358  groups.push_back( {property_id, first, int(3*i) - first} );
359  first= 3*i;
360  property_id= id;
361  }
362 
363  indices.push_back(m_indices[3*remap[i]]);
364  indices.push_back(m_indices[3*remap[i]+1]);
365  indices.push_back(m_indices[3*remap[i]+2]);
366 
367  material_indices.push_back(m_triangle_materials[remap[i]]);
368  }
369 
370  // dernier groupe
371  groups.push_back( {property_id, first, int(3 * remap.size()) - first} );
372 
373  std::swap(m_indices, indices);
374  std::swap(m_triangle_materials, material_indices);
375  }
376  else
377  {
378  int first= 0;
379  int property_id= triangle_properties[remap[0]];
380 
381  // re-organise les attributs !!
382  std::vector<vec3> positions;
383  std::vector<vec2> texcoords;
384  std::vector<vec3> normals;
385  std::vector<vec4> colors;
386  std::vector<unsigned int> material_indices;
387  for(unsigned i= 0; i < remap.size(); i++)
388  {
389  int id= triangle_properties[remap[i]];
390  if(id != property_id)
391  {
392  groups.push_back( {property_id, first, int(3*i) - first} );
393  first= 3*i;
394  property_id= id;
395  }
396 
397  positions.push_back(m_positions[3*remap[i]]);
398  positions.push_back(m_positions[3*remap[i]+1]);
399  positions.push_back(m_positions[3*remap[i]+2]);
400  if(has_texcoord())
401  {
402  texcoords.push_back(m_texcoords[3*remap[i]]);
403  texcoords.push_back(m_texcoords[3*remap[i]+1]);
404  texcoords.push_back(m_texcoords[3*remap[i]+2]);
405  }
406  if(has_normal())
407  {
408  normals.push_back(m_normals[3*remap[i]]);
409  normals.push_back(m_normals[3*remap[i]+1]);
410  normals.push_back(m_normals[3*remap[i]+2]);
411  }
412  if(has_color())
413  {
414  colors.push_back(m_colors[3*remap[i]]);
415  colors.push_back(m_colors[3*remap[i]+1]);
416  colors.push_back(m_colors[3*remap[i]+2]);
417  }
418 
419  material_indices.push_back(m_triangle_materials[remap[i]]);
420  }
421 
422  // dernier groupe
423  groups.push_back( {property_id, first, int(3 * remap.size()) - first} );
424 
425  std::swap(m_positions, positions);
426  std::swap(m_texcoords, texcoords);
427  std::swap(m_normals, normals);
428  std::swap(m_colors, colors);
429  std::swap(m_triangle_materials, material_indices);
430  }
431 
432  return groups;
433 }
434 
436 {
437  if(m_primitives != GL_TRIANGLES)
438  return 0;
439 
440  if(m_indices.size() > 0)
441  return int(m_indices.size() / 3);
442  else
443  return int(m_positions.size() / 3);
444 }
445 
446 TriangleData Mesh::triangle( const unsigned int id ) const
447 {
448  unsigned int a, b, c;
449  if(m_indices.size() > 0)
450  {
451  assert((size_t) id*3+2 < m_indices.size());
452  a= m_indices[id*3];
453  b= m_indices[id*3 +1];
454  c= m_indices[id*3 +2];
455  }
456  else
457  {
458  assert((size_t) id*3+2 < m_positions.size());
459  a= id*3;
460  b= id*3 +1;
461  c= id*3 +2;
462  }
463 
465  triangle.a= m_positions[a];
466  triangle.b= m_positions[b];
467  triangle.c= m_positions[c];
468 
469  if(m_normals.size() == m_positions.size())
470  {
471  triangle.na= m_normals[a];
472  triangle.nb= m_normals[b];
473  triangle.nc= m_normals[c];
474  }
475  else
476  {
477  // calculer la normale geometrique
478  Vector ab= Point(m_positions[b]) - Point(m_positions[a]);
479  Vector ac= Point(m_positions[c]) - Point(m_positions[a]);
480  Vector n= normalize(cross(ab, ac));
481  triangle.na= vec3(n);
482  triangle.nb= vec3(n);
483  triangle.nc= vec3(n);
484  }
485 
486  if(m_texcoords.size() == m_positions.size())
487  {
488  triangle.ta= m_texcoords[a];
489  triangle.tb= m_texcoords[b];
490  triangle.tc= m_texcoords[c];
491  }
492  else
493  {
494  // coordonnees barycentriques des sommets, convention p(u, v)= w*a + u*b + v*c, avec w= 1 - u -v
495  triangle.ta= vec2(0, 0); // w= 1
496  triangle.tb= vec2(1, 0); // w= 0
497  triangle.tc= vec2(0, 1); // w= 0
498  }
499 
500  return triangle;
501 }
502 
503 void Mesh::bounds( Point& pmin, Point& pmax ) const
504 {
505  if(m_positions.size() < 1)
506  return;
507 
508  pmin= Point(m_positions[0]);
509  pmax= pmin;
510 
511  for(unsigned i= 1; i < m_positions.size(); i++)
512  {
513  vec3 p= m_positions[i];
514  pmin= Point( std::min(pmin.x, p.x), std::min(pmin.y, p.y), std::min(pmin.z, p.z) );
515  pmax= Point( std::max(pmax.x, p.x), std::max(pmax.y, p.y), std::max(pmax.z, p.z) );
516  }
517 }
518 
519 
520 
521 
522 
525 {
526 public:
528  void copy( GLenum target, const size_t offset, const size_t length, const void *data )
529  {
530  if(m_buffer == 0)
531  glGenBuffers(1, &m_buffer);
532 
533  assert(m_buffer);
534  glBindBuffer(GL_COPY_READ_BUFFER, m_buffer);
535  if(length > m_size)
536  {
537  m_size= (length / (16*1024*1024) + 1) * (16*1024*1024); // alloue par bloc de 16Mo
538  assert(m_size >= length);
539 
540  // alloue un buffer intermediaire dynamique...
541  glBufferData(GL_COPY_READ_BUFFER, m_size, nullptr, GL_DYNAMIC_DRAW);
542  printf("[UpdateBuffer] allocate %dMo staging buffer...\n", int(m_size / 1024 / 1024));
543  }
544 
545  // place les donnees dans le buffer intermediaire
546  glBufferSubData(GL_COPY_READ_BUFFER, 0, length, data);
547  // copie les donnees dans le vertex buffer statique
548  glCopyBufferSubData(GL_COPY_READ_BUFFER, target, 0, offset, length);
549  }
550 
553  {
554  release();
555  }
556 
558  void release( )
559  {
560  glDeleteBuffers(1, &m_buffer);
561  m_buffer= 0;
562  m_size= 0;
563  }
564 
567  {
568  static UpdateBuffer buffer;
569  return buffer;
570  }
571 
572 protected:
574  UpdateBuffer( ) : m_buffer(0), m_size(0) {}
575 
576  GLuint m_buffer;
577  size_t m_size;
578 };
579 
580 
581 GLuint Mesh::create_buffers( const bool use_texcoord, const bool use_normal, const bool use_color, const bool use_material_index )
582 {
583  if(m_positions.size() == 0)
584  return 0;
585 
586 #if 1
587  if(use_texcoord && !has_texcoord())
588  printf("[oops] mesh: no texcoord array...\n");
589  if(use_normal && !has_normal())
590  printf("[oops] mesh: no normal array...\n");
591  if(use_color && !has_color())
592  printf("[oops] mesh: no color array...\n");
593  if(use_material_index && !has_material_index())
594  printf("[oops] mesh: no material index array...\n");
595 #endif
596 
597  if(m_vao)
598  // c'est deja fait...
599  return m_vao;
600 
601  // configuration du format de sommet
602  glGenVertexArrays(1, &m_vao);
603  glBindVertexArray(m_vao);
604 
605  // determine la taille du buffer pour stocker tous les attributs et les indices
606  m_vertex_buffer_size= vertex_buffer_size();
607  if(use_texcoord && has_texcoord())
608  m_vertex_buffer_size+= texcoord_buffer_size();
609  if(use_normal && has_normal())
610  m_vertex_buffer_size+= normal_buffer_size();
611  if(use_color && has_color())
612  m_vertex_buffer_size+= color_buffer_size();
613  if(use_material_index && has_material_index())
614  m_vertex_buffer_size+= m_positions.size() * sizeof(unsigned char);
615 
616  // alloue le buffer
617  glGenBuffers(1, &m_buffer);
618  glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
619  glBufferData(GL_ARRAY_BUFFER, m_vertex_buffer_size, nullptr, GL_STATIC_DRAW);
620 
621  // index buffer
622  m_index_buffer_size= index_buffer_size();
623  if(m_index_buffer_size)
624  {
625  glGenBuffers(1, &m_index_buffer);
626  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
627  glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer_size, index_buffer(), GL_STATIC_DRAW);
628  }
629 
630  // transfere les donnees dans les buffers
631  update_buffers(use_texcoord, use_normal, use_color, use_material_index);
632 
633  return m_vao;
634 }
635 
636 int Mesh::update_buffers( const bool use_texcoord, const bool use_normal, const bool use_color, const bool use_material_index )
637 {
638  assert(m_vao > 0);
639  assert(m_buffer > 0);
640  if(!m_update_buffers)
641  return 0;
642 
643  // alloue un buffer de copie, necessaire pour transferer plus de 256Mo... cf tuto_stream.cpp / transfert de donnees gpu
645 
646  glBindVertexArray(m_vao);
647  glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
648 
649  // determine la taille du buffer pour stocker tous les attributs et les indices
650  size_t size= vertex_buffer_size();
651  if(use_texcoord && has_texcoord())
652  size+= texcoord_buffer_size();
653  if(use_normal && has_normal())
654  size+= normal_buffer_size();
655  if(use_color && has_color())
656  size+= color_buffer_size();
657  if(use_material_index && has_material_index())
658  size+= m_positions.size() * sizeof(unsigned char);
659 
660  if(size != m_vertex_buffer_size)
661  {
662  m_vertex_buffer_size= size;
663  glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_STATIC_DRAW);
664  }
665 
666  // transferer les attributs et configurer le format de sommet (vao)
667  size_t offset= 0;
668  size= vertex_buffer_size();
669  //~ glBufferSubData(GL_ARRAY_BUFFER, offset, size, vertex_buffer()); // copie les donnees dans le vertex buffer
670  update.copy(GL_ARRAY_BUFFER, offset, size, vertex_buffer()); // copie les donnees dans le vertex buffer
671 
672  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (const void *) offset);
673  glEnableVertexAttribArray(0);
674 
675  if(use_texcoord && has_texcoord())
676  {
677  offset= offset + size;
678  size= texcoord_buffer_size();
679  //~ glBufferSubData(GL_ARRAY_BUFFER, offset, size, texcoord_buffer()); // copie les donnees dans le vertex buffer
680  update.copy(GL_ARRAY_BUFFER, offset, size, texcoord_buffer()); // copie les donnees dans le vertex buffer
681 
682  glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (const void *) offset);
683  glEnableVertexAttribArray(1);
684  }
685 
686  if(use_normal && has_normal())
687  {
688  offset= offset + size;
689  size= normal_buffer_size();
690  //~ glBufferSubData(GL_ARRAY_BUFFER, offset, size, normal_buffer()); // copie les donnees dans le vertex buffer
691  update.copy(GL_ARRAY_BUFFER, offset, size, normal_buffer()); // copie les donnees dans le vertex buffer
692 
693  glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (const void *) offset);
694  glEnableVertexAttribArray(2);
695  }
696 
697  if(use_color && has_color())
698  {
699  offset= offset + size;
700  size= color_buffer_size();
701  //~ glBufferSubData(GL_ARRAY_BUFFER, offset, size, color_buffer()); // copie les donnees dans le vertex buffer
702  update.copy(GL_ARRAY_BUFFER, offset, size, color_buffer()); // copie les donnees dans le vertex buffer
703 
704  glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 0, (const void *) offset);
705  glEnableVertexAttribArray(3);
706  }
707 
708  if(use_material_index && has_material_index())
709  {
710  assert(int(m_triangle_materials.size()) == triangle_count());
711 
712  offset= offset + size;
713  size= m_positions.size() * sizeof(unsigned char);
714 
715  // prepare un indice de matiere par sommet / 3 indices par triangle
716  std::vector<unsigned char> buffer(m_positions.size());
717  if(m_indices.size())
718  {
721  for(int triangle_id= 0; triangle_id < int(m_triangle_materials.size()); triangle_id++)
722  {
723  int material_id= m_triangle_materials[triangle_id];
724  assert(triangle_id*3+2 < int(m_indices.size()));
725  unsigned a= m_indices[triangle_id*3];
726  unsigned b= m_indices[triangle_id*3 +1];
727  unsigned c= m_indices[triangle_id*3 +2];
728 
729  buffer[a]= material_id;
730  buffer[b]= material_id;
731  buffer[c]= material_id;
732  }
733  }
734  else
735  {
736  for(int triangle_id= 0; triangle_id < int(m_triangle_materials.size()); triangle_id++)
737  {
738  int material_id= m_triangle_materials[triangle_id];
739  assert(triangle_id*3+2 < int(m_positions.size()));
740  unsigned a= triangle_id*3;
741  unsigned b= triangle_id*3 +1;
742  unsigned c= triangle_id*3 +2;
743 
744  buffer[a]= material_id;
745  buffer[b]= material_id;
746  buffer[c]= material_id;
747  }
748  }
749 
750  //~ glBufferSubData(GL_ARRAY_BUFFER, offset, size, buffer.data()); // copie les donnees dans le vertex buffer
751  update.copy(GL_ARRAY_BUFFER, offset, size, buffer.data()); // copie les donnees dans le vertex buffer
752 
753  glVertexAttribIPointer(4, 1, GL_UNSIGNED_BYTE, 0, (const void *) offset);
754  glEnableVertexAttribArray(4);
755  }
756 
757  // index buffer
758  size= index_buffer_size();
759  if(size != m_index_buffer_size)
760  {
761  m_index_buffer_size= index_buffer_size();
762  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
763  glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_buffer_size(), index_buffer(), GL_STATIC_DRAW);
764  }
765 
766  m_update_buffers= false;
767  return 1;
768 }
769 
770 void Mesh::draw( const GLuint program, const bool use_position, const bool use_texcoord, const bool use_normal, const bool use_color, const bool use_material_index )
771 {
772  if(m_indices.size())
773  draw(0, int(m_indices.size()), program, use_position, use_texcoord, use_normal, use_color, use_material_index);
774  else
775  draw(0, int(m_positions.size()), program, use_position, use_texcoord, use_normal, use_color, use_material_index);
776 }
777 
778 void Mesh::draw( const int first, const int n, const GLuint program, const bool use_position, const bool use_texcoord, const bool use_normal, const bool use_color, const bool use_material_index )
779 {
780  if(program == 0)
781  {
782  printf("[oops] no program... can't draw !!\n");
783  return;
784  }
785 
786  // transfere toutes les donnees disponibles (et correctement definies)
787  // le meme mesh peut etre dessine avec plusieurs shaders utilisant des attributs differents...
788  if(m_vao == 0)
789  create_buffers(has_texcoord(), has_normal(), has_color(), has_material_index());
790  assert(m_vao != 0);
791 
792  if(m_update_buffers)
793  update_buffers(has_texcoord(), has_normal(), has_color(), has_material_index());
794 
795  glBindVertexArray(m_vao);
796 
797  #ifndef GK_RELEASE
798  {
799  char label[2048]= { 0 };
800  #ifdef GL_VERSION_4_3
801  {
802  char tmp[1024];
803  glGetObjectLabel(GL_PROGRAM, program, sizeof(tmp), nullptr, tmp);
804  sprintf(label, "program( %u '%s' )", program, tmp);
805  }
806  #else
807  sprintf(label, "program( %u )", program);
808  #endif
809 
810  // verifie que le program est selectionne
811  GLuint current;
812  glGetIntegerv(GL_CURRENT_PROGRAM, (GLint *) &current);
813  if(current != program)
814  printf("[oops] %s: not active... undefined draw !!\n", label);
815 
816  // verifie que les attributs necessaires a l'execution du shader sont presents dans le mesh...
817  // etape 1 : recuperer le nombre d'attributs
818  GLint n= 0;
819  glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n);
820 
821  // etape 2 : recuperer les infos de chaque attribut
822  char name[1024];
823  for(int index= 0; index < n; index++)
824  {
825  GLint glsl_size;
826  GLenum glsl_type;
827  glGetActiveAttrib(program, index, sizeof(name), nullptr, &glsl_size, &glsl_type, name);
828 
829  GLint location= glGetAttribLocation(program, name);
830  if(location == 0) // attribut position necessaire a l'execution du shader
831  {
832  if(!use_position || !has_position())
833  printf("[oops] position attribute '%s' in %s: no data... undefined draw !!\n", name, label);
834  if(glsl_size != 1 || glsl_type != GL_FLOAT_VEC3)
835  printf("[oops] position attribute '%s' is not declared as a vec3 in %s... undefined draw !!\n", name, label);
836  }
837  else if(location == 1) // attribut texcoord necessaire
838  {
839  if(!use_texcoord || !has_texcoord())
840  printf("[oops] texcoord attribute '%s' in %s: no data... undefined draw !!\n", name, label);
841  if(glsl_size != 1 || glsl_type != GL_FLOAT_VEC2)
842  printf("[oops] texcoord attribute '%s' is not declared as a vec2 in %s... undefined draw !!\n", name, label);
843  }
844  else if(location == 2) // attribut normal necessaire
845  {
846  if(!use_normal || !has_normal())
847  printf("[oops] normal attribute '%s' in %s: no data... undefined draw !!\n", name, label);
848  if(glsl_size != 1 || glsl_type != GL_FLOAT_VEC3)
849  printf("[oops] attribute '%s' is not declared as a vec3 in %s... undefined draw !!\n", name, label);
850  }
851  else if(location == 3) // attribut color necessaire
852  {
853  if(!use_color || !has_color())
854  printf("[oops] color attribute '%s' in %s: no data... undefined draw !!\n", name, label);
855  if(glsl_size != 1 || glsl_type != GL_FLOAT_VEC4)
856  printf("[oops] attribute '%s' is not declared as a vec4 in %s... undefined draw !!\n", name, label);
857  }
858  else if(location == 4) // attribut material_index necessaire
859  {
860  if(!use_material_index || !has_material_index())
861  printf("[oops] material_index attribute '%s' in %s: no data... undefined draw !!\n", name, label);
862  if(glsl_size != 1 || glsl_type != GL_UNSIGNED_INT)
863  printf("[oops] attribute '%s' is not declared as a uint in %s... undefined draw !!\n", name, label);
864  }
865  }
866  }
867  #endif
868 
869  if(m_indices.size() > 0)
870  glDrawElements(m_primitives, n, GL_UNSIGNED_INT, (void *) (first * sizeof(unsigned)));
871  else
872  glDrawArrays(m_primitives, first, n);
873 }
representation d'un objet / maillage.
Definition: mesh.h:112
std::size_t texcoord_buffer_size() const
renvoie la taille (en octets) du texcoord buffer.
Definition: mesh.h:308
const float * color_buffer() const
renvoie l'adresse de la couleur du premier sommet. par convention, la couleur est un vec4,...
Definition: mesh.h:311
unsigned int vertex(const vec3 &p)
insere un sommet de position p, et ses attributs (s'ils sont definis par color(), texcoord(),...
Definition: mesh.cpp:111
Mesh & texcoord(const vec2 &uv)
definit les coordonnees de texture du prochain sommet.
Definition: mesh.cpp:100
Mesh()
constructeur par defaut.
Definition: mesh.h:117
const float * vertex_buffer() const
renvoie l'adresse de la position du premier sommet. permet de construire les vertex buffers openGL....
Definition: mesh.h:296
GLuint create_buffers(const bool use_texcoord, const bool use_normal, const bool use_color, const bool use_material_index)
construit les buffers et le vertex array object necessaires pour dessiner l'objet avec openGL....
Definition: mesh.cpp:581
const std::vector< unsigned int > & material_indices() const
renvoie les indices des matieres des triangles.
Definition: mesh.cpp:287
Mesh & material(const unsigned int id)
definit la matiere du prochain triangle. id est l'indice d'une matiere ajoutee dans materials(),...
Definition: mesh.cpp:277
Mesh & restart_strip()
demarre un nouveau strip. a utiliser avec un objet composes de GL_TRIANGLE_STRIP, doit aussi fonction...
Definition: mesh.cpp:228
std::vector< TriangleGroup > groups()
renvoie les groupes de triangles de meme matiere. re-organise les triangles. permet d'afficher l'obje...
Definition: mesh.cpp:305
void bounds(Point &pmin, Point &pmax) const
renvoie min et max les coordonnees des extremites des positions des sommets de l'objet (boite engloba...
Definition: mesh.cpp:503
Color default_color() const
renvoie la couleur par defaut du mesh, utilisee si les sommets n'ont pas de couleur associee.
Definition: mesh.h:284
void draw(const GLuint program, const bool use_position, const bool use_texcoord, const bool use_normal, const bool use_color, const bool use_material_index)
dessine l'objet avec un shader program.
Definition: mesh.cpp:770
std::size_t index_buffer_size() const
renvoie la taille (en octets) de l'index buffer.
Definition: mesh.h:318
int create(const GLenum primitives)
construit les objets openGL.
Definition: mesh.cpp:16
void clear()
vide la description.
Definition: mesh.cpp:178
Mesh & triangle(const unsigned int a, const unsigned int b, const unsigned int c)
Definition: mesh.cpp:192
Mesh & normal(const vec3 &n)
definit la normale du prochain sommet.
Definition: mesh.cpp:90
int triangle_count() const
renvoie le nombre de triangles.
Definition: mesh.cpp:435
std::size_t vertex_buffer_size() const
renvoie la longueur (en octets) du vertex buffer.
Definition: mesh.h:298
const Material & triangle_material(const unsigned int id) const
renvoie la matiere d'un triangle.
Definition: mesh.cpp:298
int triangle_material_index(const unsigned int id) const
renvoie l'indice de la matiere d'un triangle.
Definition: mesh.cpp:292
const float * texcoord_buffer() const
renvoie l'adresse des coordonnees de textures du premier sommet. par convention, c'est un vec2,...
Definition: mesh.h:306
const void * index_buffer() const
renvoie l'adresse du premier indice du premier triangle. par convention c'est un uint,...
Definition: mesh.h:316
Mesh & index(const int a)
Definition: mesh.cpp:241
GLenum primitives() const
renvoie le type de primitives.
Definition: mesh.h:336
void release()
detruit les objets openGL.
Definition: mesh.cpp:64
Mesh & color(const vec4 &c)
definit la couleur du prochain sommet.
Definition: mesh.cpp:80
Mesh & triangle_last(const int a, const int b, const int c)
Definition: mesh.cpp:210
bool has_position() const
verifie que les attributs sont decrits de maniere coherente.
Definition: mesh.h:328
const Materials & materials() const
renvoie la description des matieres.
Definition: mesh.cpp:267
std::size_t normal_buffer_size() const
renvoie la longueur (en octets) du normal buffer.
Definition: mesh.h:303
std::size_t color_buffer_size() const
renvoie la taille (en octets) du color buffer.
Definition: mesh.h:313
const float * normal_buffer() const
renvoie l'adresse de la normale du premier sommet. par convention, la normale est un vec3,...
Definition: mesh.h:301
buffer unique de copie / mise a jour des vertex buffers statiques. singleton. tous les meshs utilisen...
Definition: mesh.cpp:525
void release()
detruit le buffer.
Definition: mesh.cpp:558
static UpdateBuffer & manager()
acces au singleton.
Definition: mesh.cpp:566
void copy(GLenum target, const size_t offset, const size_t length, const void *data)
transfere les donnees dans un buffer statique.
Definition: mesh.cpp:528
~UpdateBuffer()
detruit le buffer.
Definition: mesh.cpp:552
UpdateBuffer()
constructeur prive. singleton.
Definition: mesh.cpp:574
void label(Widgets &w, const char *format,...)
cree un texte. meme fonctionnement que printf().
Definition: widgets.cpp:142
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
Color White()
utilitaire. renvoie une couleur blanche.
Definition: color.cpp:52
Point max(const Point &a, const Point &b)
renvoie la plus grande composante de chaque point. x, y, z= max(a.x, b.x), max(a.y,...
Definition: vec.cpp:35
Point min(const Point &a, const Point &b)
renvoie la plus petite composante de chaque point. x, y, z= min(a.x, b.x), min(a.y,...
Definition: vec.cpp:30
Vector normalize(const Vector &v)
renvoie un vecteur unitaire / longueur == 1.
Definition: vec.cpp:123
float length(const Vector &v)
renvoie la longueur d'un vecteur.
Definition: vec.cpp:142
Vector cross(const Vector &u, const Vector &v)
renvoie le produit vectoriel de 2 vecteurs.
Definition: vec.cpp:129
void normals(MeshData &data)
(re-) calcule les normales des sommets. utiliser avant les reindexations, cf indices() et vertices().
Definition: mesh_data.cpp:307
representation d'une couleur (rgba) transparente ou opaque.
Definition: color.h:14
const Material & material(const int id) const
renvoie la ieme matiere.
Definition: materials.h:102
representation d'un point 3d.
Definition: vec.h:21
representation d'un triangle.
Definition: mesh.h:95
representation d'un vecteur 3d.
Definition: vec.h:59
vecteur generique, utilitaire.
Definition: vec.h:131
vecteur generique, utilitaire.
Definition: vec.h:146
vecteur generique 4d, ou 3d homogene, utilitaire.
Definition: vec.h:168