gKit2 light
mesh.cpp
1 
2 #include <cstdio>
3 #include <cassert>
4 #include <string>
5 #include <algorithm>
6 
7 #include "program.h"
8 #include "uniforms.h"
9 #include "buffer.h"
10 #include "mesh.h"
11 
12 
13 int Mesh::create( const GLenum primitives )
14 {
15  m_primitives= primitives;
16  return 0;
17 }
18 
20 {
21  if(m_vao)
22  release_vertex_format(m_vao);
23 
24  // detruit tous les shaders crees...
25  for(std::unordered_map<unsigned int, GLuint>::iterator it= m_state_map.begin(); it != m_state_map.end(); ++it)
26  if(it->second > 0)
27  release_program(it->second);
28 }
29 
30 // definit les attributs du prochain sommet
31 Mesh& Mesh::default_color( const Color& color )
32 {
33  m_color= color;
34  return *this;
35 }
36 
37 Mesh& Mesh::color( const vec4& color )
38 {
39  m_colors.push_back(color);
40  return *this;
41 }
42 
43 Mesh& Mesh::normal( const vec3& normal )
44 {
45  m_normals.push_back(normal);
46  return *this;
47 }
48 
49 Mesh& Mesh::texcoord( const vec2& uv )
50 {
51  m_texcoords.push_back(uv);
52  return *this;
53 }
54 
55 // insere un nouveau sommet
56 unsigned int Mesh::vertex( const vec3& position )
57 {
58  m_positions.push_back(position);
59 
60  // copie les autres attributs du sommet, uniquement s'ils sont definis
61  if(m_texcoords.size() > 0 && m_texcoords.size() != m_positions.size())
62  m_texcoords.push_back(m_texcoords.back());
63  if(m_normals.size() > 0 && m_normals.size() != m_positions.size())
64  m_normals.push_back(m_normals.back());
65  if(m_colors.size() > 0 && m_colors.size() != m_positions.size())
66  m_colors.push_back(m_colors.back());
67 
68  unsigned int index= (unsigned int) m_positions.size() -1;
69  // construction de l'index buffer pour les strip
70  switch(m_primitives)
71  {
72  case GL_LINE_STRIP:
73  case GL_LINE_LOOP:
74  case GL_TRIANGLE_STRIP:
75  case GL_TRIANGLE_FAN:
76  m_indices.push_back(index);
77  break;
78  default:
79  break;
80  }
81 
82  // renvoie l'indice du sommet
83  return index;
84 }
85 
86 // update attributes
87 Mesh& Mesh::color( const unsigned int id, const vec4& c )
88 {
89  assert(id < m_colors.size());
90  m_update_buffers= true;
91  m_colors[id]= c;
92  return *this;
93 }
94 
95 Mesh& Mesh::normal( const unsigned int id, const vec3& n )
96 {
97  assert(id < m_normals.size());
98  m_update_buffers= true;
99  m_normals[id]= n;
100  return *this;
101 }
102 
103 Mesh& Mesh::texcoord( const unsigned int id, const vec2& uv )
104 {
105  assert(id < m_texcoords.size());
106  m_update_buffers= true;
107  m_texcoords[id]= uv;
108  return *this;
109 }
110 
111 void Mesh::vertex( const unsigned int id, const vec3& p )
112 {
113  assert(id < m_positions.size());
114  m_update_buffers= true;
115  m_positions[id]= p;
116 }
117 
118 //
119 Mesh& Mesh::triangle( const unsigned int a, const unsigned int b, const unsigned int c )
120 {
121  assert(a < m_positions.size());
122  assert(b < m_positions.size());
123  assert(c < m_positions.size());
124  m_indices.push_back(a);
125  m_indices.push_back(b);
126  m_indices.push_back(c);
127  return *this;
128 }
129 
130 Mesh& Mesh::triangle_last( const int a, const int b, const int c )
131 {
132  assert(a < 0);
133  assert(b < 0);
134  assert(c < 0);
135  m_indices.push_back((int) m_positions.size() + a);
136  m_indices.push_back((int) m_positions.size() + b);
137  m_indices.push_back((int) m_positions.size() + c);
138  return *this;
139 }
140 
142 {
143  m_indices.push_back(~0u); // ~0u plus grand entier non signe representable
144 #if 1
145  glPrimitiveRestartIndex(~0u);
146  glEnable(GL_PRIMITIVE_RESTART);
147 #else
148  glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); // n'existe pas sur mac ?!
149 #endif
150  return *this;
151 }
152 
153 void Mesh::bounds( Point& pmin, Point& pmax )
154 {
155  if(m_positions.size() < 1)
156  return;
157 
158  pmin= Point(m_positions[0]);
159  pmax= pmin;
160 
161  for(unsigned int i= 1; i < (unsigned int) m_positions.size(); i++)
162  {
163  vec3 p= m_positions[i];
164  pmin= Point( std::min(pmin.x, p.x), std::min(pmin.y, p.y), std::min(pmin.z, p.z) );
165  pmax= Point( std::max(pmax.x, p.x), std::max(pmax.y, p.y), std::max(pmax.z, p.z) );
166  }
167 }
168 
169 const void *Mesh::attribute_buffer( const unsigned int id ) const
170 {
171  assert(id < 4);
172  switch(id)
173  {
174  case 0: return vertex_buffer(); break;
175  case 1: return texcoord_buffer(); break;
176  case 2: return normal_buffer(); break;
177  case 3: return color_buffer(); break;
178  default: return nullptr;
179  }
180 }
181 
182 std::size_t Mesh::attribute_buffer_size( const unsigned int id ) const
183 {
184  assert(id < 4);
185  switch(id)
186  {
187  case 0: return vertex_buffer_size(); break;
188  case 1: return texcoord_buffer_size(); break;
189  case 2: return normal_buffer_size(); break;
190  case 3: return color_buffer_size(); break;
191  default: return 0;
192  }
193 }
194 
195 
196 GLuint Mesh::create_buffers( const bool use_texcoord, const bool use_normal, const bool use_color )
197 {
198  if(m_positions.size() == 0)
199  return 0;
200 
201  // ne creer que les buffers necessaires
202  GLuint vao= create_vertex_format();
203  make_vertex_buffer(vao, 0, 3, GL_FLOAT, vertex_buffer_size(), vertex_buffer());
204 
205  if(m_indices.size() > 0)
207 
208 #if 1
209  if(m_texcoords.size() > 0 && m_texcoords.size() < m_positions.size() && use_texcoord)
210  printf("[error] invalid texcoords array...\n");
211  if(m_normals.size() > 0 && m_normals.size() < m_positions.size() && use_normal)
212  printf("[error] invalid normals array...\n");
213  if(m_colors.size() > 0 && m_colors.size() < m_positions.size() && use_color)
214  printf("[error] invalid colors array...\n");
215 #endif
216 
217  if(m_texcoords.size() == m_positions.size() && use_texcoord)
218  make_vertex_buffer(vao, 1, 2, GL_FLOAT, texcoord_buffer_size(), texcoord_buffer());
219  if(m_normals.size() == m_positions.size() && use_normal)
220  make_vertex_buffer(vao, 2, 3, GL_FLOAT, normal_buffer_size(), normal_buffer());
221  if(m_colors.size() == m_positions.size() && use_color)
222  make_vertex_buffer(vao, 3, 4, GL_FLOAT, color_buffer_size(), color_buffer());
223 
224  m_update_buffers= false;
225  return vao;
226 }
227 
228 int Mesh::update_buffers( const bool use_texcoord, const bool use_normal, const bool use_color )
229 {
230  assert(m_vao > 0);
231  if(!m_update_buffers)
232  return 0;
233 
234  glBindVertexArray(m_vao);
236 
237  // ne modifier que les attributs des sommets, pas la topologie / structure du maillage
238  if(m_texcoords.size() == m_positions.size() && use_texcoord)
240  if(m_normals.size() == m_positions.size() && use_normal)
242  if(m_colors.size() == m_positions.size() && use_color)
244 
245  m_update_buffers= false;
246  return 1;
247 }
248 
249 
250 GLuint Mesh::create_program( const bool use_texcoord, const bool use_normal, const bool use_color, const bool use_light )
251 {
252  std::string definitions;
253 
254  if(m_texcoords.size() == m_positions.size() && use_texcoord)
255  definitions.append("#define USE_TEXCOORD\n");
256  if(m_normals.size() == m_positions.size() && use_normal)
257  definitions.append("#define USE_NORMAL\n");
258  if(m_colors.size() == m_positions.size() && use_color)
259  definitions.append("#define USE_COLOR\n");
260  if(use_light)
261  definitions.append("#define USE_LIGHT\n");
262 
263  bool use_mesh_color= (m_primitives == GL_POINTS || m_primitives == GL_LINES || m_primitives == GL_LINE_STRIP || m_primitives == GL_LINE_LOOP);
264  if(!use_mesh_color)
265  return read_program("data/shaders/mesh.glsl", definitions.c_str());
266  else
267  return read_program("data/shaders/mesh_color.glsl", definitions.c_str());
268 }
269 
270 
271 void Mesh::draw( const Transform& model, const Transform& view, const Transform& projection,
272  const bool use_light, const Point& light, const Color& light_color,
273  const bool use_texture, const GLuint texture )
274 {
275  bool use_texcoord= (m_texcoords.size() == m_positions.size() && texture > 0);
276  bool use_normal= (m_normals.size() == m_positions.size());
277  bool use_color= (m_colors.size() == m_positions.size());
278 
279  if(m_vao == 0)
280  // force la creation de tous les buffers
281  m_vao= create_buffers(true, true, true);
282  if(m_update_buffers)
283  update_buffers(true, true, true);
284 
285  unsigned int key= 0;
286  if(use_texcoord) key= key | 1;
287  if(use_normal) key= key | 2;
288  if(use_color) key= key | 4;
289  if(use_texture) key= key | 8;
290  if(use_light) key= key | 16;
291 
292  if(m_state != key)
293  // recherche un shader deja compile pour ce type de draw
294  m_program= m_state_map[key];
295 
296  if(m_program == 0)
297  {
298  // pas de shader pour ce type de draw
299  m_program= create_program(use_texcoord, use_normal, use_color, use_light);
300  program_print_errors(m_program);
301 
302  // conserver le shader
303  m_state_map[key]= m_program;
304  }
305 
306  // conserve la config du shader selectionne.
307  m_state= key;
308 
309  glBindVertexArray(m_vao);
310  glUseProgram(m_program);
311 
312  program_uniform(m_program, "mesh_color", default_color());
313 
314  Transform mv= view * model;
315  Transform mvp= projection * view * model;
316 
317  program_uniform(m_program, "mvpMatrix", mvp);
318  program_uniform(m_program, "mvMatrix", mv);
319  program_uniform(m_program, "normalMatrix", mv.normal()); // transforme les normales dans le repere camera.
320 
321  // utiliser une texture, elle ne sera visible que si le mesh a des texcoords...
322  if(texture && use_texcoord && use_texture)
323  program_use_texture(m_program, "diffuse_color", 0, texture);
324 
325  if(use_light)
326  {
327  program_uniform(m_program, "light", view(light)); // transforme la position de la source dans le repere camera, comme les normales
328  program_uniform(m_program, "light_color", light_color);
329  }
330 
331  if(m_indices.size() > 0)
332  glDrawElements(m_primitives, (GLsizei) m_indices.size(), GL_UNSIGNED_INT, 0);
333  else
334  glDrawArrays(m_primitives, 0, (GLsizei) m_positions.size());
335 }
336 
Mesh & restart_strip()
demarre un nouveau strip. a utiliser avec un objet composes de GL_TRIANGLE_STRIP, doit aussi fonction...
Definition: mesh.cpp:141
const float * normal_buffer() const
renvoie l'adresse de la normale du premier sommet. par convention, la normale est un vec3...
Definition: mesh.h:200
std::size_t index_buffer_size() const
renvoie la taille (en octets) de l'index buffer.
Definition: mesh.h:217
const float * vertex_buffer() const
renvoie l'adresse de la position du premier sommet. permet de construire les vertex buffers openGL...
Definition: mesh.h:195
void bounds(Point &pmin, Point &pmax)
renvoie min et max les coordonnees des extremites des positions des sommets de l'objet (boite engloba...
Definition: mesh.cpp:153
vecteur generique, utilitaire.
Definition: vec.h:104
bool update_vertex_buffer(const GLuint vao, const GLint attribute, const size_t data_size, const void *data)
modifie le contenu d'un vertex buffer associe au vertex format, vao.
Definition: buffer.cpp:121
Transform normal() const
renvoie la transformation a appliquer aux normales d'un objet transforme par la matrice m...
Definition: mat.cpp:97
void draw(const Transform &model, const Transform &view, const Transform &projection, const bool use_light, const Point &light, const Color &light_color, const bool use_texture, const GLuint texture)
Definition: mesh.cpp:271
vecteur generique, utilitaire.
Definition: vec.h:94
std::size_t normal_buffer_size() const
renvoie la longueur (en octets) du normal buffer.
Definition: mesh.h:202
Mesh & color(const vec4 &c)
definit la couleur du prochain sommet.
Definition: mesh.cpp:37
representation d'un objet / maillage.
Definition: mesh.h:88
void release_vertex_format(const GLuint vao)
detruit le vertex array vao et les buffers associes, crees par make_vertex_buffer() et make_index_buf...
Definition: buffer.cpp:31
representation d'une couleur (rgba) transparente ou opaque.
Definition: color.h:13
std::size_t vertex_buffer_size() const
renvoie la longueur (en octets) du vertex buffer.
Definition: mesh.h:197
Mesh & triangle(const unsigned int a, const unsigned int b, const unsigned int c)
Definition: mesh.cpp:119
GLuint create_program(const bool use_texcoord=true, const bool use_normal=true, const bool use_color=true, const bool use_light=false)
construit un shader program configure.
Definition: mesh.cpp:250
GLuint create_buffers(const bool use_texcoord=true, const bool use_normal=true, const bool use_color=true)
Definition: mesh.cpp:196
const float * texcoord_buffer() const
renvoie l'adresse des coordonnees de textures du premier sommet. par convention, c'est un vec2...
Definition: mesh.h:205
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:56
vecteur generique 4d, ou 3d homogene, utilitaire.
Definition: vec.h:121
std::size_t attribute_buffer_size(const unsigned int id) const
renvoie la taille (en octets) d'un attribut.
Definition: mesh.cpp:182
void program_uniform(const GLuint program, const char *uniform, const unsigned int v)
affecte une valeur a un uniform du shader program. uint.
Definition: uniforms.cpp:68
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 filtrages...
Definition: uniforms.cpp:118
GLuint create_vertex_format()
cree un vertex array. a detruire avec release_vertex_format( ).
Definition: buffer.cpp:23
const void * attribute_buffer(const unsigned int id) const
Definition: mesh.cpp:169
GLuint make_index_buffer(const GLuint vao, const size_t data_size, const void *data)
cree un index buffer et configure le vertex array vao. detruit par release_vertex_format( )...
Definition: buffer.cpp:86
int create(const GLenum primitives)
construit les objets openGL.
Definition: mesh.cpp:13
std::size_t color_buffer_size() const
renvoie la taille (en octets) du color buffer.
Definition: mesh.h:212
void release()
detruit les objets openGL.
Definition: mesh.cpp:19
int program_print_errors(const GLuint program)
affiche les erreurs de compilation.
Definition: program.cpp:330
const void * index_buffer() const
renvoie l'adresse du premier indice du premier triangle. par convention c'est un uint, 1, GL_UNSIGNED_INT.
Definition: mesh.h:215
GLuint read_program(const char *filename, const char *definitions)
Definition: program.cpp:150
std::size_t texcoord_buffer_size() const
renvoie la taille (en octets) du texcoord buffer.
Definition: mesh.h:207
Mesh & triangle_last(const int a, const int b, const int c)
Definition: mesh.cpp:130
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
representation d'une transformation, une matrice 4x4, organisee par ligne / row major.
Definition: mat.h:20
int release_program(const GLuint program)
detruit les shaders et le program.
Definition: program.cpp:157
representation d'un point 3d.
Definition: vec.h:19
Mesh & normal(const vec3 &n)
definit la normale du prochain sommet.
Definition: mesh.cpp:43
GLuint make_vertex_buffer(const GLuint vao, const GLint attribute, const int size, const GLenum type, const size_t data_size, const void *data)
cree un vertex buffer et configure le vertex array vao. detruit par release_vertex_format( )...
Definition: buffer.cpp:59
Mesh & texcoord(const vec2 &uv)
definit les coordonnees de texture du prochain sommet.
Definition: mesh.cpp:49
const float * color_buffer() const
renvoie l'adresse de la couleur du premier sommet. par convention, la couleur est un vec4...
Definition: mesh.h:210
Color default_color() const
renvoie la couleur par defaut du mesh, utilisee si les sommets n'ont pas de couleur associee...
Definition: mesh.h:105