1 // This file is part of libigl, a simple c++ geometry processing library.
2 //
3 // Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public License
6 // v. 2.0. If a copy of the MPL was not distributed with this file, You can
7 // obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #include "MeshGL.h"
10 #include "bind_vertex_attrib_array.h"
11 #include "create_shader_program.h"
12 #include "destroy_shader_program.h"
13 #include <iostream>
14 
init_buffers()15 IGL_INLINE void igl::opengl::MeshGL::init_buffers()
16 {
17   // Mesh: Vertex Array Object & Buffer objects
18   glGenVertexArrays(1, &vao_mesh);
19   glBindVertexArray(vao_mesh);
20   glGenBuffers(1, &vbo_V);
21   glGenBuffers(1, &vbo_V_normals);
22   glGenBuffers(1, &vbo_V_ambient);
23   glGenBuffers(1, &vbo_V_diffuse);
24   glGenBuffers(1, &vbo_V_specular);
25   glGenBuffers(1, &vbo_V_uv);
26   glGenBuffers(1, &vbo_F);
27   glGenTextures(1, &vbo_tex);
28 
29   // Line overlay
30   glGenVertexArrays(1, &vao_overlay_lines);
31   glBindVertexArray(vao_overlay_lines);
32   glGenBuffers(1, &vbo_lines_F);
33   glGenBuffers(1, &vbo_lines_V);
34   glGenBuffers(1, &vbo_lines_V_colors);
35 
36   // Point overlay
37   glGenVertexArrays(1, &vao_overlay_points);
38   glBindVertexArray(vao_overlay_points);
39   glGenBuffers(1, &vbo_points_F);
40   glGenBuffers(1, &vbo_points_V);
41   glGenBuffers(1, &vbo_points_V_colors);
42 
43   dirty = MeshGL::DIRTY_ALL;
44 }
45 
free_buffers()46 IGL_INLINE void igl::opengl::MeshGL::free_buffers()
47 {
48   if (is_initialized)
49   {
50     glDeleteVertexArrays(1, &vao_mesh);
51     glDeleteVertexArrays(1, &vao_overlay_lines);
52     glDeleteVertexArrays(1, &vao_overlay_points);
53 
54     glDeleteBuffers(1, &vbo_V);
55     glDeleteBuffers(1, &vbo_V_normals);
56     glDeleteBuffers(1, &vbo_V_ambient);
57     glDeleteBuffers(1, &vbo_V_diffuse);
58     glDeleteBuffers(1, &vbo_V_specular);
59     glDeleteBuffers(1, &vbo_V_uv);
60     glDeleteBuffers(1, &vbo_F);
61     glDeleteBuffers(1, &vbo_lines_F);
62     glDeleteBuffers(1, &vbo_lines_V);
63     glDeleteBuffers(1, &vbo_lines_V_colors);
64     glDeleteBuffers(1, &vbo_points_F);
65     glDeleteBuffers(1, &vbo_points_V);
66     glDeleteBuffers(1, &vbo_points_V_colors);
67 
68     glDeleteTextures(1, &vbo_tex);
69   }
70 }
71 
bind_mesh()72 IGL_INLINE void igl::opengl::MeshGL::bind_mesh()
73 {
74   glBindVertexArray(vao_mesh);
75   glUseProgram(shader_mesh);
76   bind_vertex_attrib_array(shader_mesh,"position", vbo_V, V_vbo, dirty & MeshGL::DIRTY_POSITION);
77   bind_vertex_attrib_array(shader_mesh,"normal", vbo_V_normals, V_normals_vbo, dirty & MeshGL::DIRTY_NORMAL);
78   bind_vertex_attrib_array(shader_mesh,"Ka", vbo_V_ambient, V_ambient_vbo, dirty & MeshGL::DIRTY_AMBIENT);
79   bind_vertex_attrib_array(shader_mesh,"Kd", vbo_V_diffuse, V_diffuse_vbo, dirty & MeshGL::DIRTY_DIFFUSE);
80   bind_vertex_attrib_array(shader_mesh,"Ks", vbo_V_specular, V_specular_vbo, dirty & MeshGL::DIRTY_SPECULAR);
81   bind_vertex_attrib_array(shader_mesh,"texcoord", vbo_V_uv, V_uv_vbo, dirty & MeshGL::DIRTY_UV);
82 
83   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_F);
84   if (dirty & MeshGL::DIRTY_FACE)
85     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*F_vbo.size(), F_vbo.data(), GL_DYNAMIC_DRAW);
86 
87   glActiveTexture(GL_TEXTURE0);
88   glBindTexture(GL_TEXTURE_2D, vbo_tex);
89   if (dirty & MeshGL::DIRTY_TEXTURE)
90   {
91     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
92     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
93     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
94     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
95     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
96     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_u, tex_v, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.data());
97   }
98   glUniform1i(glGetUniformLocation(shader_mesh,"tex"), 0);
99   dirty &= ~MeshGL::DIRTY_MESH;
100 }
101 
bind_overlay_lines()102 IGL_INLINE void igl::opengl::MeshGL::bind_overlay_lines()
103 {
104   bool is_dirty = dirty & MeshGL::DIRTY_OVERLAY_LINES;
105 
106   glBindVertexArray(vao_overlay_lines);
107   glUseProgram(shader_overlay_lines);
108  bind_vertex_attrib_array(shader_overlay_lines,"position", vbo_lines_V, lines_V_vbo, is_dirty);
109  bind_vertex_attrib_array(shader_overlay_lines,"color", vbo_lines_V_colors, lines_V_colors_vbo, is_dirty);
110 
111   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_lines_F);
112   if (is_dirty)
113     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*lines_F_vbo.size(), lines_F_vbo.data(), GL_DYNAMIC_DRAW);
114 
115   dirty &= ~MeshGL::DIRTY_OVERLAY_LINES;
116 }
117 
bind_overlay_points()118 IGL_INLINE void igl::opengl::MeshGL::bind_overlay_points()
119 {
120   bool is_dirty = dirty & MeshGL::DIRTY_OVERLAY_POINTS;
121 
122   glBindVertexArray(vao_overlay_points);
123   glUseProgram(shader_overlay_points);
124  bind_vertex_attrib_array(shader_overlay_points,"position", vbo_points_V, points_V_vbo, is_dirty);
125  bind_vertex_attrib_array(shader_overlay_points,"color", vbo_points_V_colors, points_V_colors_vbo, is_dirty);
126 
127   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_points_F);
128   if (is_dirty)
129     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*points_F_vbo.size(), points_F_vbo.data(), GL_DYNAMIC_DRAW);
130 
131   dirty &= ~MeshGL::DIRTY_OVERLAY_POINTS;
132 }
133 
draw_mesh(bool solid)134 IGL_INLINE void igl::opengl::MeshGL::draw_mesh(bool solid)
135 {
136   glPolygonMode(GL_FRONT_AND_BACK, solid ? GL_FILL : GL_LINE);
137 
138   /* Avoid Z-buffer fighting between filled triangles & wireframe lines */
139   if (solid)
140   {
141     glEnable(GL_POLYGON_OFFSET_FILL);
142     glPolygonOffset(1.0, 1.0);
143   }
144   glDrawElements(GL_TRIANGLES, 3*F_vbo.rows(), GL_UNSIGNED_INT, 0);
145 
146   glDisable(GL_POLYGON_OFFSET_FILL);
147   glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
148 }
149 
draw_overlay_lines()150 IGL_INLINE void igl::opengl::MeshGL::draw_overlay_lines()
151 {
152   glDrawElements(GL_LINES, lines_F_vbo.rows(), GL_UNSIGNED_INT, 0);
153 }
154 
draw_overlay_points()155 IGL_INLINE void igl::opengl::MeshGL::draw_overlay_points()
156 {
157   glDrawElements(GL_POINTS, points_F_vbo.rows(), GL_UNSIGNED_INT, 0);
158 }
159 
init()160 IGL_INLINE void igl::opengl::MeshGL::init()
161 {
162   if(is_initialized)
163   {
164     return;
165   }
166   is_initialized = true;
167   std::string mesh_vertex_shader_string =
168 R"(#version 150
169   uniform mat4 view;
170   uniform mat4 proj;
171   uniform mat4 normal_matrix;
172   in vec3 position;
173   in vec3 normal;
174   out vec3 position_eye;
175   out vec3 normal_eye;
176   in vec4 Ka;
177   in vec4 Kd;
178   in vec4 Ks;
179   in vec2 texcoord;
180   out vec2 texcoordi;
181   out vec4 Kai;
182   out vec4 Kdi;
183   out vec4 Ksi;
184 
185   void main()
186   {
187     position_eye = vec3 (view * vec4 (position, 1.0));
188     normal_eye = vec3 (normal_matrix * vec4 (normal, 0.0));
189     normal_eye = normalize(normal_eye);
190     gl_Position = proj * vec4 (position_eye, 1.0); //proj * view * vec4(position, 1.0);"
191     Kai = Ka;
192     Kdi = Kd;
193     Ksi = Ks;
194     texcoordi = texcoord;
195   }
196 )";
197 
198   std::string mesh_fragment_shader_string =
199 R"(#version 150
200   uniform mat4 view;
201   uniform mat4 proj;
202   uniform vec4 fixed_color;
203   in vec3 position_eye;
204   in vec3 normal_eye;
205   uniform vec3 light_position_eye;
206   vec3 Ls = vec3 (1, 1, 1);
207   vec3 Ld = vec3 (1, 1, 1);
208   vec3 La = vec3 (1, 1, 1);
209   in vec4 Ksi;
210   in vec4 Kdi;
211   in vec4 Kai;
212   in vec2 texcoordi;
213   uniform sampler2D tex;
214   uniform float specular_exponent;
215   uniform float lighting_factor;
216   uniform float texture_factor;
217   out vec4 outColor;
218   void main()
219   {
220     vec3 Ia = La * vec3(Kai);    // ambient intensity
221 
222     vec3 vector_to_light_eye = light_position_eye - position_eye;
223     vec3 direction_to_light_eye = normalize (vector_to_light_eye);
224     float dot_prod = dot (direction_to_light_eye, normalize(normal_eye));
225     float clamped_dot_prod = max (dot_prod, 0.0);
226     vec3 Id = Ld * vec3(Kdi) * clamped_dot_prod;    // Diffuse intensity
227 
228     vec3 reflection_eye = reflect (-direction_to_light_eye, normalize(normal_eye));
229     vec3 surface_to_viewer_eye = normalize (-position_eye);
230     float dot_prod_specular = dot (reflection_eye, surface_to_viewer_eye);
231     dot_prod_specular = float(abs(dot_prod)==dot_prod) * max (dot_prod_specular, 0.0);
232     float specular_factor = pow (dot_prod_specular, specular_exponent);
233     vec3 Is = Ls * vec3(Ksi) * specular_factor;    // specular intensity
234     vec4 color = vec4(lighting_factor * (Is + Id) + Ia + (1.0-lighting_factor) * vec3(Kdi),(Kai.a+Ksi.a+Kdi.a)/3);
235     outColor = mix(vec4(1,1,1,1), texture(tex, texcoordi), texture_factor) * color;
236     if (fixed_color != vec4(0.0)) outColor = fixed_color;
237   }
238 )";
239 
240   std::string overlay_vertex_shader_string =
241 R"(#version 150
242   uniform mat4 view;
243   uniform mat4 proj;
244   in vec3 position;
245   in vec3 color;
246   out vec3 color_frag;
247 
248   void main()
249   {
250     gl_Position = proj * view * vec4 (position, 1.0);
251     color_frag = color;
252   }
253 )";
254 
255   std::string overlay_fragment_shader_string =
256 R"(#version 150
257   in vec3 color_frag;
258   out vec4 outColor;
259   void main()
260   {
261     outColor = vec4(color_frag, 1.0);
262   }
263 )";
264 
265   std::string overlay_point_fragment_shader_string =
266 R"(#version 150
267   in vec3 color_frag;
268   out vec4 outColor;
269   void main()
270   {
271     if (length(gl_PointCoord - vec2(0.5)) > 0.5)
272       discard;
273     outColor = vec4(color_frag, 1.0);
274   }
275 )";
276 
277   init_buffers();
278   create_shader_program(
279     mesh_vertex_shader_string,
280     mesh_fragment_shader_string,
281     {},
282     shader_mesh);
283   create_shader_program(
284     overlay_vertex_shader_string,
285     overlay_fragment_shader_string,
286     {},
287     shader_overlay_lines);
288   create_shader_program(
289     overlay_vertex_shader_string,
290     overlay_point_fragment_shader_string,
291     {},
292     shader_overlay_points);
293 }
294 
free()295 IGL_INLINE void igl::opengl::MeshGL::free()
296 {
297   const auto free = [](GLuint & id)
298   {
299     if(id)
300     {
301       destroy_shader_program(id);
302       id = 0;
303     }
304   };
305 
306   if (is_initialized)
307   {
308     free(shader_mesh);
309     free(shader_overlay_lines);
310     free(shader_overlay_points);
311     free_buffers();
312   }
313 }
314