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