State.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  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. #include "State.h"
  9. #include "bind_vertex_attrib_array.h"
  10. #include "../ViewerData.h"
  11. #include "create_shader_program.h"
  12. #include "destroy_shader_program.h"
  13. IGL_INLINE void igl::opengl::State::init_buffers()
  14. {
  15. // Mesh: Vertex Array Object & Buffer objects
  16. glGenVertexArrays(1, &vao_mesh);
  17. glBindVertexArray(vao_mesh);
  18. glGenBuffers(1, &vbo_V);
  19. glGenBuffers(1, &vbo_V_normals);
  20. glGenBuffers(1, &vbo_V_ambient);
  21. glGenBuffers(1, &vbo_V_diffuse);
  22. glGenBuffers(1, &vbo_V_specular);
  23. glGenBuffers(1, &vbo_V_uv);
  24. glGenBuffers(1, &vbo_F);
  25. glGenTextures(1, &vbo_tex);
  26. // Line overlay
  27. glGenVertexArrays(1, &vao_overlay_lines);
  28. glBindVertexArray(vao_overlay_lines);
  29. glGenBuffers(1, &vbo_lines_F);
  30. glGenBuffers(1, &vbo_lines_V);
  31. glGenBuffers(1, &vbo_lines_V_colors);
  32. // Point overlay
  33. glGenVertexArrays(1, &vao_overlay_points);
  34. glBindVertexArray(vao_overlay_points);
  35. glGenBuffers(1, &vbo_points_F);
  36. glGenBuffers(1, &vbo_points_V);
  37. glGenBuffers(1, &vbo_points_V_colors);
  38. dirty = ViewerData::DIRTY_ALL;
  39. }
  40. IGL_INLINE void igl::opengl::State::free_buffers()
  41. {
  42. glDeleteVertexArrays(1, &vao_mesh);
  43. glDeleteVertexArrays(1, &vao_overlay_lines);
  44. glDeleteVertexArrays(1, &vao_overlay_points);
  45. glDeleteBuffers(1, &vbo_V);
  46. glDeleteBuffers(1, &vbo_V_normals);
  47. glDeleteBuffers(1, &vbo_V_ambient);
  48. glDeleteBuffers(1, &vbo_V_diffuse);
  49. glDeleteBuffers(1, &vbo_V_specular);
  50. glDeleteBuffers(1, &vbo_V_uv);
  51. glDeleteBuffers(1, &vbo_F);
  52. glDeleteBuffers(1, &vbo_lines_F);
  53. glDeleteBuffers(1, &vbo_lines_V);
  54. glDeleteBuffers(1, &vbo_lines_V_colors);
  55. glDeleteBuffers(1, &vbo_points_F);
  56. glDeleteBuffers(1, &vbo_points_V);
  57. glDeleteBuffers(1, &vbo_points_V_colors);
  58. glDeleteTextures(1, &vbo_tex);
  59. }
  60. IGL_INLINE void igl::opengl::State::set_data(
  61. const igl::ViewerData &data,
  62. bool invert_normals)
  63. {
  64. bool per_corner_uv = (data.F_uv.rows() == data.F.rows());
  65. bool per_corner_normals = (data.F_normals.rows() == 3 * data.F.rows());
  66. dirty |= data.dirty;
  67. // Input:
  68. // X #F by dim quantity
  69. // Output:
  70. // X_vbo #F*3 by dim scattering per corner
  71. const auto per_face = [&data](
  72. const Eigen::MatrixXd & X,
  73. RowMatrixXf & X_vbo)
  74. {
  75. X_vbo.resize(data.F.rows()*3,3);
  76. for (unsigned i=0; i<data.F.rows();++i)
  77. for (unsigned j=0;j<3;++j)
  78. X_vbo.row(i*3+j) = X.row(i).cast<float>().head(3);
  79. };
  80. // Input:
  81. // X #V by dim quantity
  82. // Output:
  83. // X_vbo #F*3 by dim scattering per corner
  84. const auto per_corner = [&data](
  85. const Eigen::MatrixXd & X,
  86. RowMatrixXf & X_vbo)
  87. {
  88. X_vbo.resize(data.F.rows()*3,3);
  89. for (unsigned i=0; i<data.F.rows();++i)
  90. for (unsigned j=0;j<3;++j)
  91. X_vbo.row(i*3+j) = X.row(data.F(i,j)).cast<float>();
  92. };
  93. if (!data.face_based)
  94. {
  95. if (!(per_corner_uv || per_corner_normals))
  96. {
  97. // Vertex positions
  98. if (dirty & ViewerData::DIRTY_POSITION)
  99. V_vbo = data.V.cast<float>();
  100. // Vertex normals
  101. if (dirty & ViewerData::DIRTY_NORMAL)
  102. {
  103. V_normals_vbo = data.V_normals.cast<float>();
  104. if (invert_normals)
  105. V_normals_vbo = -V_normals_vbo;
  106. }
  107. // Per-vertex material settings
  108. if (dirty & ViewerData::DIRTY_AMBIENT)
  109. V_ambient_vbo = data.V_material_ambient.cast<float>();
  110. if (dirty & ViewerData::DIRTY_DIFFUSE)
  111. V_diffuse_vbo = data.V_material_diffuse.cast<float>();
  112. if (dirty & ViewerData::DIRTY_SPECULAR)
  113. V_specular_vbo = data.V_material_specular.cast<float>();
  114. // Face indices
  115. if (dirty & ViewerData::DIRTY_FACE)
  116. F_vbo = data.F.cast<unsigned>();
  117. // Texture coordinates
  118. if (dirty & ViewerData::DIRTY_UV)
  119. V_uv_vbo = data.V_uv.cast<float>();
  120. }
  121. else
  122. {
  123. // Per vertex properties with per corner UVs
  124. if (dirty & ViewerData::DIRTY_POSITION)
  125. {
  126. per_corner(data.V,V_vbo);
  127. }
  128. if (dirty & ViewerData::DIRTY_AMBIENT)
  129. {
  130. V_ambient_vbo.resize(4,data.F.rows()*3);
  131. for (unsigned i=0; i<data.F.rows();++i)
  132. for (unsigned j=0;j<3;++j)
  133. V_ambient_vbo.col (i*3+j) = data.V_material_ambient.row(data.F(i,j)).transpose().cast<float>();
  134. }
  135. if (dirty & ViewerData::DIRTY_DIFFUSE)
  136. {
  137. V_diffuse_vbo.resize(4,data.F.rows()*3);
  138. for (unsigned i=0; i<data.F.rows();++i)
  139. for (unsigned j=0;j<3;++j)
  140. V_diffuse_vbo.col (i*3+j) = data.V_material_diffuse.row(data.F(i,j)).transpose().cast<float>();
  141. }
  142. if (dirty & ViewerData::DIRTY_SPECULAR)
  143. {
  144. V_specular_vbo.resize(4,data.F.rows()*3);
  145. for (unsigned i=0; i<data.F.rows();++i)
  146. for (unsigned j=0;j<3;++j)
  147. V_specular_vbo.col(i*3+j) = data.V_material_specular.row(data.F(i,j)).transpose().cast<float>();
  148. }
  149. if (dirty & ViewerData::DIRTY_NORMAL)
  150. {
  151. V_normals_vbo.resize(3,data.F.rows()*3);
  152. for (unsigned i=0; i<data.F.rows();++i)
  153. for (unsigned j=0;j<3;++j)
  154. V_normals_vbo.col (i*3+j) =
  155. per_corner_normals ?
  156. data.F_normals.row(i*3+j).transpose().cast<float>() :
  157. data.V_normals.row(data.F(i,j)).transpose().cast<float>();
  158. if (invert_normals)
  159. V_normals_vbo = -V_normals_vbo;
  160. }
  161. if (dirty & ViewerData::DIRTY_FACE)
  162. {
  163. F_vbo.resize(data.F.rows(),3);
  164. for (unsigned i=0; i<data.F.rows();++i)
  165. F_vbo.row(i) << i*3+0, i*3+1, i*3+2;
  166. }
  167. if (dirty & ViewerData::DIRTY_UV)
  168. {
  169. V_uv_vbo.resize(data.F.rows()*3,2);
  170. for (unsigned i=0; i<data.F.rows();++i)
  171. for (unsigned j=0;j<3;++j)
  172. V_uv_vbo.row(i*3+j) =
  173. data.V_uv.row(per_corner_uv ?
  174. data.F_uv(i,j) : data.F(i,j)).cast<float>();
  175. }
  176. }
  177. }
  178. else
  179. {
  180. if (dirty & ViewerData::DIRTY_POSITION)
  181. {
  182. per_corner(data.V,V_vbo);
  183. }
  184. if (dirty & ViewerData::DIRTY_AMBIENT)
  185. {
  186. per_face(data.F_material_ambient,V_ambient_vbo);
  187. }
  188. if (dirty & ViewerData::DIRTY_DIFFUSE)
  189. {
  190. per_face(data.F_material_diffuse,V_diffuse_vbo);
  191. }
  192. if (dirty & ViewerData::DIRTY_SPECULAR)
  193. {
  194. per_face(data.F_material_specular,V_specular_vbo);
  195. }
  196. if (dirty & ViewerData::DIRTY_NORMAL)
  197. {
  198. V_normals_vbo.resize(data.F.rows()*3,3);
  199. for (unsigned i=0; i<data.F.rows();++i)
  200. for (unsigned j=0;j<3;++j)
  201. V_normals_vbo.row(i*3+j) =
  202. per_corner_normals ?
  203. data.F_normals.row(i*3+j).cast<float>() :
  204. data.F_normals.row(i).cast<float>();
  205. if (invert_normals)
  206. V_normals_vbo = -V_normals_vbo;
  207. }
  208. if (dirty & ViewerData::DIRTY_FACE)
  209. {
  210. F_vbo.resize(data.F.rows(),3);
  211. for (unsigned i=0; i<data.F.rows();++i)
  212. F_vbo.row(i) << i*3+0, i*3+1, i*3+2;
  213. }
  214. if (dirty & ViewerData::DIRTY_UV)
  215. {
  216. V_uv_vbo.resize(data.F.rows()*3,2);
  217. for (unsigned i=0; i<data.F.rows();++i)
  218. for (unsigned j=0;j<3;++j)
  219. V_uv_vbo.row(i*3+j) = data.V_uv.row(per_corner_uv ? data.F_uv(i,j) : data.F(i,j)).cast<float>();
  220. }
  221. }
  222. if (dirty & ViewerData::DIRTY_TEXTURE)
  223. {
  224. tex_u = data.texture_R.rows();
  225. tex_v = data.texture_R.cols();
  226. tex.resize(data.texture_R.size()*4);
  227. for (unsigned i=0;i<data.texture_R.size();++i)
  228. {
  229. tex(i*4+0) = data.texture_R(i);
  230. tex(i*4+1) = data.texture_G(i);
  231. tex(i*4+2) = data.texture_B(i);
  232. tex(i*4+3) = data.texture_A(i);
  233. }
  234. }
  235. if (dirty & ViewerData::DIRTY_OVERLAY_LINES)
  236. {
  237. lines_V_vbo.resize(data.lines.rows()*2,3);
  238. lines_V_colors_vbo.resize(data.lines.rows()*2,3);
  239. lines_F_vbo.resize(data.lines.rows()*2,1);
  240. for (unsigned i=0; i<data.lines.rows();++i)
  241. {
  242. lines_V_vbo.row(2*i+0) = data.lines.block<1, 3>(i, 0).cast<float>();
  243. lines_V_vbo.row(2*i+1) = data.lines.block<1, 3>(i, 3).cast<float>();
  244. lines_V_colors_vbo.row(2*i+0) = data.lines.block<1, 3>(i, 6).cast<float>();
  245. lines_V_colors_vbo.row(2*i+1) = data.lines.block<1, 3>(i, 6).cast<float>();
  246. lines_F_vbo(2*i+0) = 2*i+0;
  247. lines_F_vbo(2*i+1) = 2*i+1;
  248. }
  249. }
  250. if (dirty & ViewerData::DIRTY_OVERLAY_POINTS)
  251. {
  252. points_V_vbo.resize(data.points.rows(),3);
  253. points_V_colors_vbo.resize(data.points.rows(),3);
  254. points_F_vbo.resize(data.points.rows(),1);
  255. for (unsigned i=0; i<data.points.rows();++i)
  256. {
  257. points_V_vbo.row(i) = data.points.block<1, 3>(i, 0).cast<float>();
  258. points_V_colors_vbo.row(i) = data.points.block<1, 3>(i, 3).cast<float>();
  259. points_F_vbo(i) = i;
  260. }
  261. }
  262. }
  263. IGL_INLINE void igl::opengl::State::bind_mesh()
  264. {
  265. glBindVertexArray(vao_mesh);
  266. glUseProgram(shader_mesh);
  267. bind_vertex_attrib_array(shader_mesh,"position", vbo_V, V_vbo, dirty & ViewerData::DIRTY_POSITION);
  268. bind_vertex_attrib_array(shader_mesh,"normal", vbo_V_normals, V_normals_vbo, dirty & ViewerData::DIRTY_NORMAL);
  269. bind_vertex_attrib_array(shader_mesh,"Ka", vbo_V_ambient, V_ambient_vbo, dirty & ViewerData::DIRTY_AMBIENT);
  270. bind_vertex_attrib_array(shader_mesh,"Kd", vbo_V_diffuse, V_diffuse_vbo, dirty & ViewerData::DIRTY_DIFFUSE);
  271. bind_vertex_attrib_array(shader_mesh,"Ks", vbo_V_specular, V_specular_vbo, dirty & ViewerData::DIRTY_SPECULAR);
  272. bind_vertex_attrib_array(shader_mesh,"texcoord", vbo_V_uv, V_uv_vbo, dirty & ViewerData::DIRTY_UV);
  273. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_F);
  274. if (dirty & ViewerData::DIRTY_FACE)
  275. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*F_vbo.size(), F_vbo.data(), GL_DYNAMIC_DRAW);
  276. glActiveTexture(GL_TEXTURE0);
  277. glBindTexture(GL_TEXTURE_2D, vbo_tex);
  278. if (dirty & ViewerData::DIRTY_TEXTURE)
  279. {
  280. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  281. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  282. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  283. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  284. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  285. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_u, tex_v, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.data());
  286. }
  287. glUniform1i(glGetUniformLocation(shader_mesh,"tex"), 0);
  288. dirty &= ~ViewerData::DIRTY_MESH;
  289. }
  290. IGL_INLINE void igl::opengl::State::bind_overlay_lines()
  291. {
  292. bool is_dirty = dirty & ViewerData::DIRTY_OVERLAY_LINES;
  293. glBindVertexArray(vao_overlay_lines);
  294. glUseProgram(shader_overlay_lines);
  295. bind_vertex_attrib_array(shader_overlay_lines,"position", vbo_lines_V, lines_V_vbo, is_dirty);
  296. bind_vertex_attrib_array(shader_overlay_lines,"color", vbo_lines_V_colors, lines_V_colors_vbo, is_dirty);
  297. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_lines_F);
  298. if (is_dirty)
  299. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*lines_F_vbo.size(), lines_F_vbo.data(), GL_DYNAMIC_DRAW);
  300. dirty &= ~ViewerData::DIRTY_OVERLAY_LINES;
  301. }
  302. IGL_INLINE void igl::opengl::State::bind_overlay_points()
  303. {
  304. bool is_dirty = dirty & ViewerData::DIRTY_OVERLAY_POINTS;
  305. glBindVertexArray(vao_overlay_points);
  306. glUseProgram(shader_overlay_points);
  307. bind_vertex_attrib_array(shader_overlay_points,"position", vbo_points_V, points_V_vbo, is_dirty);
  308. bind_vertex_attrib_array(shader_overlay_points,"color", vbo_points_V_colors, points_V_colors_vbo, is_dirty);
  309. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_points_F);
  310. if (is_dirty)
  311. glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*points_F_vbo.size(), points_F_vbo.data(), GL_DYNAMIC_DRAW);
  312. dirty &= ~ViewerData::DIRTY_OVERLAY_POINTS;
  313. }
  314. IGL_INLINE void igl::opengl::State::draw_mesh(bool solid)
  315. {
  316. glPolygonMode(GL_FRONT_AND_BACK, solid ? GL_FILL : GL_LINE);
  317. /* Avoid Z-buffer fighting between filled triangles & wireframe lines */
  318. if (solid)
  319. {
  320. glEnable(GL_POLYGON_OFFSET_FILL);
  321. glPolygonOffset(1.0, 1.0);
  322. }
  323. glDrawElements(GL_TRIANGLES, 3*F_vbo.rows(), GL_UNSIGNED_INT, 0);
  324. glDisable(GL_POLYGON_OFFSET_FILL);
  325. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  326. }
  327. IGL_INLINE void igl::opengl::State::draw_overlay_lines()
  328. {
  329. glDrawElements(GL_LINES, lines_F_vbo.rows(), GL_UNSIGNED_INT, 0);
  330. }
  331. IGL_INLINE void igl::opengl::State::draw_overlay_points()
  332. {
  333. glDrawElements(GL_POINTS, points_F_vbo.rows(), GL_UNSIGNED_INT, 0);
  334. }
  335. IGL_INLINE void igl::opengl::State::init()
  336. {
  337. if(is_initialized)
  338. {
  339. return;
  340. }
  341. is_initialized = true;
  342. std::string mesh_vertex_shader_string =
  343. "#version 150\n"
  344. "uniform mat4 model;"
  345. "uniform mat4 view;"
  346. "uniform mat4 proj;"
  347. "in vec3 position;"
  348. "in vec3 normal;"
  349. "out vec3 position_eye;"
  350. "out vec3 normal_eye;"
  351. "in vec4 Ka;"
  352. "in vec4 Kd;"
  353. "in vec4 Ks;"
  354. "in vec2 texcoord;"
  355. "out vec2 texcoordi;"
  356. "out vec4 Kai;"
  357. "out vec4 Kdi;"
  358. "out vec4 Ksi;"
  359. "void main()"
  360. "{"
  361. " position_eye = vec3 (view * model * vec4 (position, 1.0));"
  362. " normal_eye = vec3 (view * model * vec4 (normal, 0.0));"
  363. " normal_eye = normalize(normal_eye);"
  364. " gl_Position = proj * vec4 (position_eye, 1.0);" //proj * view * model * vec4(position, 1.0);"
  365. " Kai = Ka;"
  366. " Kdi = Kd;"
  367. " Ksi = Ks;"
  368. " texcoordi = texcoord;"
  369. "}";
  370. std::string mesh_fragment_shader_string =
  371. "#version 150\n"
  372. "uniform mat4 model;"
  373. "uniform mat4 view;"
  374. "uniform mat4 proj;"
  375. "uniform vec4 fixed_color;"
  376. "in vec3 position_eye;"
  377. "in vec3 normal_eye;"
  378. "uniform vec3 light_position_world;"
  379. "vec3 Ls = vec3 (1, 1, 1);"
  380. "vec3 Ld = vec3 (1, 1, 1);"
  381. "vec3 La = vec3 (1, 1, 1);"
  382. "in vec4 Ksi;"
  383. "in vec4 Kdi;"
  384. "in vec4 Kai;"
  385. "in vec2 texcoordi;"
  386. "uniform sampler2D tex;"
  387. "uniform float specular_exponent;"
  388. "uniform float lighting_factor;"
  389. "uniform float texture_factor;"
  390. "out vec4 outColor;"
  391. "void main()"
  392. "{"
  393. "vec3 Ia = La * vec3(Kai);" // ambient intensity
  394. "vec3 light_position_eye = vec3 (view * vec4 (light_position_world, 1.0));"
  395. "vec3 vector_to_light_eye = light_position_eye - position_eye;"
  396. "vec3 direction_to_light_eye = normalize (vector_to_light_eye);"
  397. "float dot_prod = dot (direction_to_light_eye, normal_eye);"
  398. "float clamped_dot_prod = max (dot_prod, 0.0);"
  399. "vec3 Id = Ld * vec3(Kdi) * clamped_dot_prod;" // Diffuse intensity
  400. "vec3 reflection_eye = reflect (-direction_to_light_eye, normal_eye);"
  401. "vec3 surface_to_viewer_eye = normalize (-position_eye);"
  402. "float dot_prod_specular = dot (reflection_eye, surface_to_viewer_eye);"
  403. "dot_prod_specular = float(abs(dot_prod)==dot_prod) * max (dot_prod_specular, 0.0);"
  404. "float specular_factor = pow (dot_prod_specular, specular_exponent);"
  405. "vec3 Is = Ls * vec3(Ksi) * specular_factor;" // specular intensity
  406. "vec4 color = vec4(lighting_factor * (Is + Id) + Ia + (1.0-lighting_factor) * vec3(Kdi),(Kai.a+Ksi.a+Kdi.a)/3);"
  407. "outColor = mix(vec4(1,1,1,1), texture(tex, texcoordi), texture_factor) * color;"
  408. "if (fixed_color != vec4(0.0)) outColor = fixed_color;"
  409. "}";
  410. std::string overlay_vertex_shader_string =
  411. "#version 150\n"
  412. "uniform mat4 model;"
  413. "uniform mat4 view;"
  414. "uniform mat4 proj;"
  415. "in vec3 position;"
  416. "in vec3 color;"
  417. "out vec3 color_frag;"
  418. "void main()"
  419. "{"
  420. " gl_Position = proj * view * model * vec4 (position, 1.0);"
  421. " color_frag = color;"
  422. "}";
  423. std::string overlay_fragment_shader_string =
  424. "#version 150\n"
  425. "in vec3 color_frag;"
  426. "out vec4 outColor;"
  427. "void main()"
  428. "{"
  429. " outColor = vec4(color_frag, 1.0);"
  430. "}";
  431. std::string overlay_point_fragment_shader_string =
  432. "#version 150\n"
  433. "in vec3 color_frag;"
  434. "out vec4 outColor;"
  435. "void main()"
  436. "{"
  437. " if (length(gl_PointCoord - vec2(0.5)) > 0.5)"
  438. " discard;"
  439. " outColor = vec4(color_frag, 1.0);"
  440. "}";
  441. init_buffers();
  442. create_shader_program(
  443. mesh_vertex_shader_string,
  444. mesh_fragment_shader_string,
  445. {},
  446. shader_mesh);
  447. create_shader_program(
  448. overlay_vertex_shader_string,
  449. overlay_fragment_shader_string,
  450. {},
  451. shader_overlay_lines);
  452. create_shader_program(
  453. overlay_vertex_shader_string,
  454. overlay_point_fragment_shader_string,
  455. {},
  456. shader_overlay_points);
  457. }
  458. IGL_INLINE void igl::opengl::State::free()
  459. {
  460. const auto free = [](GLuint & id)
  461. {
  462. if(id)
  463. {
  464. destroy_shader_program(id);
  465. id = 0;
  466. }
  467. };
  468. free(shader_mesh);
  469. free(shader_overlay_lines);
  470. free(shader_overlay_points);
  471. free_buffers();
  472. }