example.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  1. #include <igl/C_STR.h>
  2. #include <igl/Camera.h>
  3. #include <igl/REDRUM.h>
  4. #include <igl/components.h>
  5. #include <igl/opengl/create_shader_program.h>
  6. #include <igl/opengl2/draw_floor.h>
  7. #include <igl/get_seconds.h>
  8. #include <igl/hsv_to_rgb.h>
  9. #include <igl/opengl/init_render_to_texture.h>
  10. #include <igl/jet.h>
  11. #include <igl/per_face_normals.h>
  12. #include <igl/randperm.h>
  13. #include <igl/read_triangle_mesh.h>
  14. #include <igl/opengl/report_gl_error.h>
  15. #include <igl/rgb_to_hsv.h>
  16. #include <igl/snap_to_canonical_view_quat.h>
  17. #include <igl/snap_to_fixed_up.h>
  18. #include <igl/trackball.h>
  19. #include <igl/two_axis_valuator_fixed_up.h>
  20. #include <igl/write_triangle_mesh.h>
  21. #include <igl/anttweakbar/ReAntTweakBar.h>
  22. #include <Eigen/Core>
  23. #include <Eigen/Geometry>
  24. #ifdef __APPLE__
  25. #include <GLUT/glut.h>
  26. #else
  27. #include <GL/glut.h>
  28. #endif
  29. #ifndef GLUT_WHEEL_UP
  30. #define GLUT_WHEEL_UP 3
  31. #endif
  32. #ifndef GLUT_WHEEL_DOWN
  33. #define GLUT_WHEEL_DOWN 4
  34. #endif
  35. #ifndef GLUT_WHEEL_RIGHT
  36. #define GLUT_WHEEL_RIGHT 5
  37. #endif
  38. #ifndef GLUT_WHEEL_LEFT
  39. #define GLUT_WHEEL_LEFT 6
  40. #endif
  41. #ifndef GLUT_ACTIVE_COMMAND
  42. #define GLUT_ACTIVE_COMMAND 8
  43. #endif
  44. #include <ctime>
  45. #include <string>
  46. #include <vector>
  47. #include <stack>
  48. #include <iostream>
  49. int cc_hover = -1;
  50. Eigen::MatrixXd V;
  51. Eigen::VectorXd Vmid,Vmin,Vmax;
  52. double bbd = 1.0;
  53. Eigen::MatrixXi F;
  54. Eigen::VectorXi CC;
  55. Eigen::MatrixXd N;
  56. struct State
  57. {
  58. igl::Camera camera;
  59. Eigen::VectorXf I;
  60. Eigen::Matrix<GLubyte,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> selected;
  61. GLuint mask_id;
  62. } s;
  63. std::string out_filename;
  64. GLuint pick_tex = 0;
  65. GLuint pick_fbo = 0;
  66. GLuint pick_dfbo = 0;
  67. // See README for descriptions
  68. enum RotationType
  69. {
  70. ROTATION_TYPE_IGL_TRACKBALL = 0,
  71. ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1,
  72. NUM_ROTATION_TYPES = 2,
  73. } rotation_type;
  74. enum CenterType
  75. {
  76. CENTER_TYPE_ORBIT = 0,
  77. CENTER_TYPE_FPS = 1,
  78. NUM_CENTER_TYPES = 2,
  79. } center_type = CENTER_TYPE_ORBIT;
  80. std::stack<State> undo_stack;
  81. std::stack<State> redo_stack;
  82. bool wireframe_visible = false;
  83. bool fill_visible = true;
  84. bool is_rotating = false;
  85. int down_x,down_y;
  86. igl::Camera down_camera;
  87. bool is_animating = false;
  88. double animation_start_time = 0;
  89. double ANIMATION_DURATION = 0.5;
  90. Eigen::Quaterniond animation_from_quat;
  91. Eigen::Quaterniond animation_to_quat;
  92. int width,height;
  93. Eigen::Vector4f light_pos(-0.1,-0.1,0.9,0);
  94. #define REBAR_NAME "temp.rbr"
  95. igl::anttweakbar::ReTwBar rebar;
  96. // Forward
  97. void init_components();
  98. void init_relative();
  99. void push_undo()
  100. {
  101. undo_stack.push(s);
  102. // Clear
  103. redo_stack = std::stack<State>();
  104. }
  105. void TW_CALL set_rotation_type(const void * value, void * clientData)
  106. {
  107. using namespace Eigen;
  108. using namespace std;
  109. using namespace igl;
  110. const RotationType old_rotation_type = rotation_type;
  111. rotation_type = *(const RotationType *)(value);
  112. if(rotation_type == ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP &&
  113. old_rotation_type != ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP)
  114. {
  115. animation_from_quat = s.camera.m_rotation_conj;
  116. snap_to_fixed_up(animation_from_quat,animation_to_quat);
  117. // start animation
  118. animation_start_time = get_seconds();
  119. is_animating = true;
  120. }
  121. }
  122. void TW_CALL get_rotation_type(void * value, void *clientData)
  123. {
  124. RotationType * rt = (RotationType *)(value);
  125. *rt = rotation_type;
  126. }
  127. void reshape(int width, int height)
  128. {
  129. ::width = width;
  130. ::height = height;
  131. glViewport(0,0,width,height);
  132. // Send the new window size to AntTweakBar
  133. TwWindowSize(width, height);
  134. s.camera.m_aspect = (double)width/(double)height;
  135. igl::opengl::init_render_to_texture(width,height, pick_tex, pick_fbo, pick_dfbo);
  136. igl::opengl::report_gl_error("init_render_to_texture: ");
  137. glutPostRedisplay();
  138. }
  139. void push_scene()
  140. {
  141. using namespace igl;
  142. using namespace std;
  143. glMatrixMode(GL_PROJECTION);
  144. glPushMatrix();
  145. glLoadIdentity();
  146. auto & camera = s.camera;
  147. glMultMatrixd(camera.projection().data());
  148. glMatrixMode(GL_MODELVIEW);
  149. glPushMatrix();
  150. glLoadIdentity();
  151. gluLookAt(
  152. camera.eye()(0), camera.eye()(1), camera.eye()(2),
  153. camera.at()(0), camera.at()(1), camera.at()(2),
  154. camera.up()(0), camera.up()(1), camera.up()(2));
  155. glScaled(2./bbd,2./bbd,2./bbd);
  156. glTranslated(-Vmid(0),-Vmid(1),-Vmid(2));
  157. }
  158. void pop_scene()
  159. {
  160. glMatrixMode(GL_PROJECTION);
  161. glPopMatrix();
  162. glMatrixMode(GL_MODELVIEW);
  163. glPopMatrix();
  164. }
  165. void draw_mesh(
  166. const Eigen::MatrixXd & V,
  167. const Eigen::MatrixXi & F,
  168. const Eigen::MatrixXd & N,
  169. const Eigen::VectorXf & S,
  170. const GLuint & S_loc)
  171. {
  172. using namespace Eigen;
  173. using namespace std;
  174. static Matrix<float,Dynamic,3,RowMajor> VR,NR;
  175. static Matrix<int,Dynamic,3,RowMajor> FR;
  176. static Matrix<float,Dynamic,1,ColMajor> SR;
  177. static GLuint ibo,vbo,sbo,nbo;
  178. static bool scene_dirty = true;
  179. if(scene_dirty)
  180. {
  181. VR.resize(F.rows()*3,3);
  182. NR.resize(F.rows()*3,3);
  183. SR.resize(F.rows()*3,1);
  184. FR.resize(F.rows(),3);
  185. for(int f = 0;f<F.rows();f++)
  186. {
  187. for(int c = 0;c<3;c++)
  188. {
  189. VR.row(3*f+c) = V.row(F(f,c)).cast<float>();
  190. SR(3*f+c) = S(F(f,c));
  191. NR.row(3*f+c) = N.row(f).cast<float>();
  192. FR(f,c) = 3*f+c;
  193. }
  194. }
  195. glGenBuffers(1,&ibo);
  196. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,ibo);
  197. glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(GLuint)*FR.size(),FR.data(),GL_STATIC_DRAW);
  198. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
  199. glGenBuffers(1,&vbo);
  200. glGenBuffers(1,&nbo);
  201. glGenBuffers(1,&sbo);
  202. glBindBuffer(GL_ARRAY_BUFFER,vbo);
  203. glBufferData(GL_ARRAY_BUFFER,sizeof(float)*VR.size(),VR.data(),GL_STATIC_DRAW);
  204. glBindBuffer(GL_ARRAY_BUFFER,nbo);
  205. glBufferData(GL_ARRAY_BUFFER,sizeof(float)*NR.size(),NR.data(),GL_STATIC_DRAW);
  206. glBindBuffer(GL_ARRAY_BUFFER,sbo);
  207. glBufferData(GL_ARRAY_BUFFER,sizeof(float)*SR.size(),SR.data(),GL_STATIC_DRAW);
  208. igl::opengl::report_gl_error("glBindBuffer: ");
  209. scene_dirty = false;
  210. }
  211. glEnableClientState(GL_VERTEX_ARRAY);
  212. glBindBuffer(GL_ARRAY_BUFFER,vbo);
  213. glVertexPointer(3,GL_FLOAT,0,0);
  214. glEnableClientState(GL_NORMAL_ARRAY);
  215. glBindBuffer(GL_ARRAY_BUFFER,nbo);
  216. glNormalPointer(GL_FLOAT,0,0);
  217. glBindBuffer(GL_ARRAY_BUFFER,sbo);
  218. glVertexAttribPointer(S_loc, 1, GL_FLOAT, GL_FALSE, 0, 0);
  219. glEnableVertexAttribArray(S_loc);
  220. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,ibo);
  221. glDrawElements(GL_TRIANGLES,FR.size(),GL_UNSIGNED_INT,0);
  222. glBindBuffer(GL_ARRAY_BUFFER,0);
  223. }
  224. // Set up double-sided lights
  225. void lights()
  226. {
  227. using namespace std;
  228. using namespace Eigen;
  229. glEnable(GL_LIGHTING);
  230. glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
  231. glEnable(GL_LIGHT0);
  232. float WHITE[4] = {1,1,1,1.};
  233. float BLACK[4] = {0.,0.,0.,1.};
  234. Vector4f pos = light_pos;
  235. glLightfv(GL_LIGHT0,GL_AMBIENT,BLACK);
  236. glLightfv(GL_LIGHT0,GL_DIFFUSE,WHITE);
  237. glLightfv(GL_LIGHT0,GL_SPECULAR,BLACK);
  238. glLightfv(GL_LIGHT0,GL_POSITION,pos.data());
  239. //glEnable(GL_LIGHT1);
  240. //pos(0) *= -1;
  241. //pos(1) *= -1;
  242. //pos(2) *= -1;
  243. //glLightfv(GL_LIGHT1,GL_AMBIENT,BLACK);
  244. //glLightfv(GL_LIGHT1,GL_DIFFUSE,NEAR_BLACK);
  245. //glLightfv(GL_LIGHT1,GL_SPECULAR,BLACK);
  246. //glLightfv(GL_LIGHT1,GL_POSITION,pos.data());
  247. }
  248. template <int Rows, int Cols>
  249. GLuint generate_1d_texture(
  250. const Eigen::Matrix<GLubyte,Rows,Cols,Eigen::RowMajor> & colors)
  251. {
  252. assert(colors.cols() == 3 && "Seems colors.cols() must be 3");
  253. GLuint tex_id = 0;
  254. glGenTextures(1,&tex_id);
  255. glBindTexture(GL_TEXTURE_1D,tex_id);
  256. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  257. glTexImage1D(GL_TEXTURE_1D, 0, colors.cols(),colors.rows(),
  258. 0,GL_RGB, GL_UNSIGNED_BYTE,
  259. colors.data());
  260. igl::opengl::report_gl_error("glTexImage1D: ");
  261. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  262. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  263. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  264. igl::opengl::report_gl_error("texture: ");
  265. return tex_id;
  266. }
  267. GLuint color_shader(const size_t max_ids, GLuint & scalar_loc, GLuint & tex_id)
  268. {
  269. std::string vertex_shader = R"(
  270. #version 120
  271. attribute float scalar_in;
  272. varying float scalar_out;
  273. void main()
  274. {
  275. scalar_out = scalar_in;
  276. gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
  277. }
  278. )";
  279. std::string fragment_shader = R"(
  280. #version 120
  281. varying float scalar_out;
  282. uniform float cmin;
  283. uniform float cmax;
  284. uniform sampler1D color_map;
  285. void main()
  286. {
  287. float scalar_normalized = max(min((scalar_out-cmin)/(cmax-cmin),1.0),0.0);
  288. gl_FragColor = texture1D(color_map,scalar_normalized);
  289. }
  290. )";
  291. Eigen::Matrix<GLubyte,Eigen::Dynamic,3,Eigen::RowMajor> colors(max_ids,3);
  292. for(size_t id = 0;id<max_ids;id++)
  293. {
  294. size_t index = id;
  295. size_t re = (index)%(256*256);
  296. colors(id,0) = (index-re)/(256*256);
  297. index = re;
  298. re = index%(256);
  299. colors(id,1) = (index-re)/(256);
  300. colors(id,2) = re;
  301. }
  302. tex_id = generate_1d_texture(colors);
  303. return igl::opengl::create_shader_program(
  304. vertex_shader.c_str(),
  305. fragment_shader.c_str(),
  306. {{"scalar_in",scalar_loc}}
  307. );
  308. }
  309. void display()
  310. {
  311. using namespace igl;
  312. using namespace std;
  313. using namespace Eigen;
  314. glClearColor(0.8,0.8,0.8,0);
  315. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  316. if(is_animating)
  317. {
  318. double t = (get_seconds() - animation_start_time)/ANIMATION_DURATION;
  319. if(t > 1)
  320. {
  321. t = 1;
  322. is_animating = false;
  323. }
  324. Quaterniond q = animation_from_quat.slerp(t,animation_to_quat).normalized();
  325. auto & camera = s.camera;
  326. switch(center_type)
  327. {
  328. default:
  329. case CENTER_TYPE_ORBIT:
  330. camera.orbit(q.conjugate());
  331. break;
  332. case CENTER_TYPE_FPS:
  333. camera.turn_eye(q.conjugate());
  334. break;
  335. }
  336. }
  337. glEnable(GL_DEPTH_TEST);
  338. glEnable(GL_NORMALIZE);
  339. lights();
  340. push_scene();
  341. const auto & color_components_shader = [](
  342. const GLuint scalar_loc,
  343. GLuint & tex_id)->GLuint
  344. {
  345. std::string vertex_shader = R"(
  346. #version 120
  347. attribute float scalar_in;
  348. varying vec3 normal;
  349. varying float scalar_out;
  350. void main()
  351. {
  352. gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
  353. normal = normalize(gl_NormalMatrix * gl_Normal);
  354. scalar_out = scalar_in;
  355. }
  356. )";
  357. std::string fragment_shader = R"(
  358. #version 120
  359. varying vec3 normal;
  360. varying float scalar_out;
  361. uniform float cmin;
  362. uniform float cmax;
  363. uniform float cc_hover;
  364. uniform sampler1D color_map;
  365. uniform sampler1D selected_mask;
  366. void main()
  367. {
  368. float scalar_normalized = max(min((scalar_out-cmin)/(cmax-cmin),1.0),0.0);
  369. vec4 texture_color = texture1D(color_map,scalar_normalized);
  370. bool is_selected = texture1D(selected_mask,scalar_normalized).x > 0.5;
  371. const vec4 selected_color = vec4(1,0.2,0.2,1);
  372. if(scalar_out==cc_hover)
  373. {
  374. texture_color = 0.5*(texture_color + selected_color);
  375. }
  376. if(is_selected)
  377. {
  378. texture_color = selected_color;
  379. }
  380. const float num_lights = 1.0;
  381. vec4 diffuse = (1.0/num_lights)*(gl_LightSource[0].diffuse);
  382. vec4 ambient = vec4(0,0,0,0);
  383. ambient += (1.0/num_lights)*(gl_FrontMaterial.ambient * gl_LightSource[0].ambient);
  384. ambient += (1.0/num_lights)*(gl_LightModel.ambient * gl_FrontMaterial.ambient);
  385. vec4 color = ambient;
  386. // Phong
  387. vec3 lightDir = normalize(vec3(gl_LightSource[0].position));
  388. vec3 halfVector = gl_LightSource[0].halfVector.xyz;
  389. vec3 n = normalize(normal);
  390. float NdotL = max(abs(dot(n.xyz,lightDir)), 0.0);
  391. vec4 specular = vec4(0.0,0.0,0.0,0.0);
  392. if (NdotL > 0.0) {
  393. color += diffuse * NdotL;
  394. vec3 halfV = normalize(halfVector);
  395. float NdotHV = max(abs(dot(n,halfV)),0.0);
  396. specular += gl_FrontMaterial.specular * gl_LightSource[0].specular * pow(NdotHV, gl_FrontMaterial.shininess);
  397. }
  398. gl_FragColor = color * texture_color + specular;
  399. }
  400. )";
  401. typedef Matrix<GLubyte,64,3,RowMajor> Matrix64_3_R_ubyte;
  402. typedef Matrix<float,64,3,RowMajor> Matrix64_3_R_float;
  403. Matrix64_3_R_ubyte colors;
  404. {
  405. Matrix64_3_R_float rgb = (Matrix64_3_R_ubyte()<<
  406. 255, 0, 0,
  407. 255, 24, 0,
  408. 255, 48, 0,
  409. 255, 72, 0,
  410. 255, 96, 0,
  411. 255, 120, 0,
  412. 255, 143, 0,
  413. 255, 167, 0,
  414. 255, 191, 0,
  415. 255, 215, 0,
  416. 255, 239, 0,
  417. 247, 255, 0,
  418. 223, 255, 0,
  419. 199, 255, 0,
  420. 175, 255, 0,
  421. 151, 255, 0,
  422. 128, 255, 0,
  423. 104, 255, 0,
  424. 80, 255, 0,
  425. 56, 255, 0,
  426. 32, 255, 0,
  427. 8, 255, 0,
  428. 0, 255, 16,
  429. 0, 255, 40,
  430. 0, 255, 64,
  431. 0, 255, 88,
  432. 0, 255, 112,
  433. 0, 255, 135,
  434. 0, 255, 159,
  435. 0, 255, 183,
  436. 0, 255, 207,
  437. 0, 255, 231,
  438. 0, 255, 255,
  439. 0, 231, 255,
  440. 0, 207, 255,
  441. 0, 183, 255,
  442. 0, 159, 255,
  443. 0, 135, 255,
  444. 0, 112, 255,
  445. 0, 88, 255,
  446. 0, 64, 255,
  447. 0, 40, 255,
  448. 0, 16, 255,
  449. 8, 0, 255,
  450. 32, 0, 255,
  451. 56, 0, 255,
  452. 80, 0, 255,
  453. 104, 0, 255,
  454. 128, 0, 255,
  455. 151, 0, 255,
  456. 175, 0, 255,
  457. 199, 0, 255,
  458. 223, 0, 255,
  459. 247, 0, 255,
  460. 255, 0, 239,
  461. 255, 0, 215,
  462. 255, 0, 191,
  463. 255, 0, 167,
  464. 255, 0, 143,
  465. 255, 0, 120,
  466. 255, 0, 96,
  467. 255, 0, 72,
  468. 255, 0, 48,
  469. 255, 0, 24).finished().cast<float>()/255.f;
  470. Matrix64_3_R_float H;
  471. rgb_to_hsv(rgb,H);
  472. H.col(1) *= 0.1;
  473. H.col(2) = (H.col(2).array() + 0.1*(1.-H.col(2).array())).eval();
  474. hsv_to_rgb(H,rgb);
  475. colors = (rgb*255.).cast<GLubyte>();
  476. }
  477. tex_id = generate_1d_texture(colors);
  478. GLuint prog_id = igl::opengl::create_shader_program(
  479. vertex_shader.c_str(),
  480. fragment_shader.c_str(),
  481. {{"scalar_in",scalar_loc}}
  482. );
  483. igl::opengl::report_gl_error("create_shader_program: ");
  484. return prog_id;
  485. };
  486. static GLuint scalar_loc = 1;
  487. static GLuint tex_id = 0;
  488. static GLuint color_components_prog =
  489. color_components_shader(scalar_loc,tex_id);
  490. // Set material properties
  491. glEnable(GL_COLOR_MATERIAL);
  492. glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
  493. glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,(const GLfloat[]){1,1,1,1});
  494. if(wireframe_visible)
  495. {
  496. glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
  497. if(fill_visible)
  498. {
  499. glColor3f(0,0,0);
  500. glUseProgram(0);
  501. draw_mesh(V,F,N,s.I,scalar_loc);
  502. }else
  503. {
  504. glUseProgram(color_components_prog);
  505. igl::opengl::report_gl_error("UseProgram: ");
  506. draw_mesh(V,F,N,s.I,scalar_loc);
  507. }
  508. }
  509. glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
  510. glPushAttrib(GL_ALL_ATTRIB_BITS);
  511. glUseProgram(color_components_prog);
  512. igl::opengl::report_gl_error("use: ");
  513. glUniform1f(glGetUniformLocation(color_components_prog,"cmin"),s.I.minCoeff());
  514. glUniform1f(glGetUniformLocation(color_components_prog,"cmax"),s.I.maxCoeff());
  515. //glUniform1f(glGetUniformLocation(color_components_prog,"cc_selected"),cc_selected);
  516. glUniform1f(glGetUniformLocation(color_components_prog,"cc_hover"),cc_hover);
  517. glActiveTexture(GL_TEXTURE0);
  518. glBindTexture(GL_TEXTURE_1D, tex_id);
  519. glUniform1i(glGetUniformLocation(color_components_prog,"color_map"),0);
  520. glActiveTexture(GL_TEXTURE1);
  521. glBindTexture(GL_TEXTURE_1D, s.mask_id);
  522. glUniform1i(glGetUniformLocation(color_components_prog,"selected_mask"),1);
  523. igl::opengl::report_gl_error("unif: ");
  524. if(fill_visible)
  525. {
  526. glEnable(GL_POLYGON_OFFSET_FILL); // Avoid Stitching!
  527. glPolygonOffset(1.0, 0);
  528. }
  529. draw_mesh(V,F,N,s.I,scalar_loc);
  530. glPopAttrib();
  531. glUseProgram(0);
  532. // Draw a nice floor
  533. glPushMatrix();
  534. const double floor_offset =
  535. -2./bbd*(V.col(1).maxCoeff()-Vmid(1));
  536. glTranslated(0,floor_offset,0);
  537. const float GREY[4] = {0.5,0.5,0.6,1.0};
  538. const float DARK_GREY[4] = {0.2,0.2,0.3,1.0};
  539. igl::opengl2::draw_floor(GREY,DARK_GREY);
  540. glPopMatrix();
  541. pop_scene();
  542. TwDraw();
  543. glutSwapBuffers();
  544. if(is_animating)
  545. {
  546. glutPostRedisplay();
  547. }
  548. }
  549. void mouse_wheel(int wheel, int direction, int mouse_x, int mouse_y)
  550. {
  551. using namespace std;
  552. using namespace igl;
  553. using namespace Eigen;
  554. GLint viewport[4];
  555. glGetIntegerv(GL_VIEWPORT,viewport);
  556. if(wheel == 0 && TwMouseMotion(mouse_x, viewport[3] - mouse_y))
  557. {
  558. static double mouse_scroll_y = 0;
  559. const double delta_y = 0.125*direction;
  560. mouse_scroll_y += delta_y;
  561. TwMouseWheel(mouse_scroll_y);
  562. return;
  563. }
  564. auto & camera = s.camera;
  565. switch(center_type)
  566. {
  567. case CENTER_TYPE_ORBIT:
  568. if(wheel==0)
  569. {
  570. // factor of zoom change
  571. double s = (1.-0.01*direction);
  572. //// FOV zoom: just widen angle. This is hardly ever appropriate.
  573. //camera.m_angle *= s;
  574. //camera.m_angle = min(max(camera.m_angle,1),89);
  575. camera.push_away(s);
  576. }else
  577. {
  578. // Dolly zoom:
  579. camera.dolly_zoom((double)direction*1.0);
  580. }
  581. break;
  582. default:
  583. case CENTER_TYPE_FPS:
  584. // Move `eye` and `at`
  585. camera.dolly((wheel==0?Vector3d(0,0,1):Vector3d(-1,0,0))*0.1*direction);
  586. break;
  587. }
  588. glutPostRedisplay();
  589. }
  590. bool pick(const int x, const int y, int & cc_selected)
  591. {
  592. using namespace Eigen;
  593. using namespace igl;
  594. using namespace std;
  595. static GLuint scalar_loc = 1;
  596. static GLuint tex_id = 0;
  597. static const size_t max_ids = s.I.maxCoeff()+1;
  598. static GLuint color_shader_prog = color_shader(max_ids,scalar_loc,tex_id);
  599. const int pick_s = 0;
  600. const int pick_w = pick_s;
  601. GLint old_vp[4];
  602. glGetIntegerv(GL_VIEWPORT,old_vp);
  603. const double pick_ratio = double(pick_w)/double(old_vp[2]);
  604. // ceil, cause might otherwise round down to 0
  605. const int pick_h = ceil(double(old_vp[3])*pick_ratio);
  606. glViewport(
  607. x-pick_w,
  608. old_vp[3]-y-pick_h,2*pick_w+1,2*pick_h+1);
  609. glMatrixMode(GL_PROJECTION);
  610. Matrix4d proj;
  611. glGetDoublev(GL_PROJECTION_MATRIX,proj.data());
  612. glPushMatrix();
  613. glLoadIdentity();
  614. gluPickMatrix(
  615. x,
  616. old_vp[3]-y,
  617. pick_w*2+1,
  618. pick_h*2+1,
  619. old_vp);
  620. glMultMatrixd(proj.data());
  621. glMatrixMode(GL_MODELVIEW);
  622. // Activate color shader
  623. glUseProgram(color_shader_prog);
  624. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,pick_fbo);
  625. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,pick_dfbo);
  626. // Clear screen
  627. glClearColor(0,0,0,0);
  628. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  629. glPushAttrib(GL_ALL_ATTRIB_BITS);
  630. glEnable(GL_TEXTURE_1D);
  631. glBindTexture(GL_TEXTURE_1D, tex_id);
  632. glUniform1f(glGetUniformLocation(color_shader_prog,"cmin"),s.I.minCoeff());
  633. glUniform1f(glGetUniformLocation(color_shader_prog,"cmax"),s.I.maxCoeff());
  634. draw_mesh(V,F,N,s.I,scalar_loc);
  635. glPopAttrib();
  636. glMatrixMode(GL_PROJECTION);
  637. glPopMatrix();
  638. glMatrixMode(GL_MODELVIEW);
  639. glViewport(old_vp[0],old_vp[1],old_vp[2],old_vp[3]);
  640. Matrix<GLubyte,1,4> pixel;
  641. glReadPixels(x,old_vp[3]-y,1,1,GL_RGBA,GL_UNSIGNED_BYTE,pixel.data());
  642. glUseProgram(0);
  643. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
  644. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,0);
  645. if(pixel(3) == 0)
  646. {
  647. cc_selected = -1;
  648. return false;
  649. }
  650. cc_selected = pixel(0)*256*256+pixel(1)*256+pixel(2);
  651. return true;
  652. }
  653. void regenerate_mask()
  654. {
  655. if(glIsTexture(s.mask_id))
  656. {
  657. glDeleteTextures(1,&s.mask_id);
  658. }
  659. s.mask_id = generate_1d_texture(s.selected);
  660. }
  661. void mouse(int glutButton, int glutState, int mouse_x, int mouse_y)
  662. {
  663. using namespace std;
  664. using namespace Eigen;
  665. using namespace igl;
  666. bool tw_using = TwEventMouseButtonGLUT(glutButton,glutState,mouse_x,mouse_y);
  667. int mod = glutGetModifiers();
  668. switch(glutButton)
  669. {
  670. case GLUT_RIGHT_BUTTON:
  671. {
  672. switch(glutState)
  673. {
  674. case 1:
  675. // up
  676. glutSetCursor(GLUT_CURSOR_INHERIT);
  677. is_rotating = false;
  678. break;
  679. case 0:
  680. glutSetCursor(GLUT_CURSOR_CYCLE);
  681. // collect information for trackball
  682. is_rotating = true;
  683. down_camera = s.camera;
  684. down_x = mouse_x;
  685. down_y = mouse_y;
  686. break;
  687. }
  688. break;
  689. }
  690. case GLUT_LEFT_BUTTON:
  691. {
  692. switch(glutState)
  693. {
  694. case 1:
  695. // up
  696. glutSetCursor(GLUT_CURSOR_INHERIT);
  697. is_rotating = false;
  698. break;
  699. case 0:
  700. if(!tw_using)
  701. {
  702. push_scene();
  703. int cc_selected=-1;
  704. if(pick(mouse_x,mouse_y,cc_selected))
  705. {
  706. push_undo();
  707. if(!(mod & GLUT_ACTIVE_SHIFT))
  708. {
  709. s.selected.setConstant(0);
  710. }
  711. s.selected(cc_selected,0) = 255;
  712. regenerate_mask();
  713. }else
  714. {
  715. glutSetCursor(GLUT_CURSOR_CYCLE);
  716. // collect information for trackball
  717. is_rotating = true;
  718. down_camera = s.camera;
  719. down_x = mouse_x;
  720. down_y = mouse_y;
  721. }
  722. pop_scene();
  723. }
  724. break;
  725. }
  726. break;
  727. }
  728. // Scroll down
  729. case GLUT_WHEEL_DOWN:
  730. {
  731. mouse_wheel(0,-1,mouse_x,mouse_y);
  732. break;
  733. }
  734. // Scroll up
  735. case GLUT_WHEEL_UP:
  736. {
  737. mouse_wheel(0,1,mouse_x,mouse_y);
  738. break;
  739. }
  740. // Scroll left
  741. case GLUT_WHEEL_LEFT:
  742. {
  743. mouse_wheel(1,-1,mouse_x,mouse_y);
  744. break;
  745. }
  746. // Scroll right
  747. case GLUT_WHEEL_RIGHT:
  748. {
  749. mouse_wheel(1,1,mouse_x,mouse_y);
  750. break;
  751. }
  752. }
  753. glutPostRedisplay();
  754. }
  755. void mouse_move(int mouse_x, int mouse_y)
  756. {
  757. using namespace igl;
  758. using namespace std;
  759. using namespace Eigen;
  760. bool tw_using = TwMouseMotion(mouse_x,mouse_y);
  761. push_scene();
  762. pick(mouse_x,mouse_y,cc_hover);
  763. pop_scene();
  764. glutPostRedisplay();
  765. }
  766. void mouse_drag(int mouse_x, int mouse_y)
  767. {
  768. using namespace igl;
  769. using namespace std;
  770. using namespace Eigen;
  771. bool tw_using = TwMouseMotion(mouse_x,mouse_y);
  772. if(is_rotating)
  773. {
  774. glutSetCursor(GLUT_CURSOR_CYCLE);
  775. Quaterniond q;
  776. auto & camera = s.camera;
  777. switch(rotation_type)
  778. {
  779. case ROTATION_TYPE_IGL_TRACKBALL:
  780. {
  781. // Rotate according to trackball
  782. igl::trackball<double>(
  783. width,
  784. height,
  785. 2.0,
  786. down_camera.m_rotation_conj.coeffs().data(),
  787. down_x,
  788. down_y,
  789. mouse_x,
  790. mouse_y,
  791. q.coeffs().data());
  792. break;
  793. }
  794. case ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP:
  795. {
  796. // Rotate according to two axis valuator with fixed up vector
  797. two_axis_valuator_fixed_up(
  798. width, height,
  799. 2.0,
  800. down_camera.m_rotation_conj,
  801. down_x, down_y, mouse_x, mouse_y,
  802. q);
  803. break;
  804. }
  805. default:
  806. break;
  807. }
  808. switch(center_type)
  809. {
  810. default:
  811. case CENTER_TYPE_ORBIT:
  812. camera.orbit(q.conjugate());
  813. break;
  814. case CENTER_TYPE_FPS:
  815. camera.turn_eye(q.conjugate());
  816. break;
  817. }
  818. }
  819. glutPostRedisplay();
  820. }
  821. void init_relative()
  822. {
  823. using namespace Eigen;
  824. using namespace igl;
  825. per_face_normals(V,F,N);
  826. Vmax = V.colwise().maxCoeff();
  827. Vmin = V.colwise().minCoeff();
  828. Vmid = 0.5*(Vmax + Vmin);
  829. bbd = (Vmax-Vmin).norm();
  830. }
  831. void init_components()
  832. {
  833. using namespace Eigen;
  834. using namespace igl;
  835. using namespace std;
  836. components(F,CC);
  837. s.I = CC.cast<float>();
  838. s.selected = Matrix<GLubyte,Dynamic,Dynamic>::Zero(s.I.maxCoeff()+1,3);
  839. cout<<"s.selected: "<<s.selected.rows()<<endl;
  840. regenerate_mask();
  841. }
  842. void undo()
  843. {
  844. using namespace std;
  845. if(!undo_stack.empty())
  846. {
  847. redo_stack.push(s);
  848. s = undo_stack.top();
  849. undo_stack.pop();
  850. }
  851. regenerate_mask();
  852. }
  853. void redo()
  854. {
  855. using namespace std;
  856. if(!redo_stack.empty())
  857. {
  858. undo_stack.push(s);
  859. s = redo_stack.top();
  860. redo_stack.pop();
  861. }
  862. regenerate_mask();
  863. }
  864. bool save(const std::string & out_filename)
  865. {
  866. using namespace std;
  867. using namespace igl;
  868. if(write_triangle_mesh(out_filename,V,F))
  869. {
  870. cout<<GREENGIN("Saved mesh to `"<<out_filename<<"` successfully.")<<endl;
  871. return true;
  872. }else
  873. {
  874. cout<<REDRUM("Failed to save mesh to `"<<out_filename<<"`.")<<endl;
  875. return false;
  876. }
  877. }
  878. void TW_CALL saveCB(void * /*clientData*/)
  879. {
  880. save(out_filename);
  881. }
  882. void key(unsigned char key, int mouse_x, int mouse_y)
  883. {
  884. using namespace std;
  885. using namespace Eigen;
  886. using namespace igl;
  887. int mod = glutGetModifiers();
  888. switch(key)
  889. {
  890. // ESC
  891. case char(27):
  892. rebar.save(REBAR_NAME);
  893. // ^C
  894. case char(3):
  895. exit(0);
  896. case 'z':
  897. case 'Z':
  898. if(mod & GLUT_ACTIVE_COMMAND)
  899. {
  900. if(mod & GLUT_ACTIVE_SHIFT)
  901. {
  902. redo();
  903. }else
  904. {
  905. undo();
  906. }
  907. }else
  908. {
  909. Quaterniond q;
  910. snap_to_canonical_view_quat(s.camera.m_rotation_conj,1.0,q);
  911. switch(center_type)
  912. {
  913. default:
  914. case CENTER_TYPE_ORBIT:
  915. s.camera.orbit(q.conjugate());
  916. break;
  917. case CENTER_TYPE_FPS:
  918. s.camera.turn_eye(q.conjugate());
  919. break;
  920. }
  921. }
  922. break;
  923. case 'u':
  924. mouse_wheel(0, 1,mouse_x,mouse_y);
  925. break;
  926. case 'j':
  927. mouse_wheel(0,-1,mouse_x,mouse_y);
  928. break;
  929. default:
  930. if(!TwEventKeyboardGLUT(key,mouse_x,mouse_y))
  931. {
  932. cout<<"Unknown key command: "<<key<<" "<<int(key)<<endl;
  933. }
  934. }
  935. glutPostRedisplay();
  936. }
  937. int main(int argc, char * argv[])
  938. {
  939. using namespace std;
  940. using namespace Eigen;
  941. using namespace igl;
  942. string filename = "../shared/truck.obj";
  943. switch(argc)
  944. {
  945. case 3:
  946. out_filename = argv[2];
  947. case 2:
  948. // Read and prepare mesh
  949. filename = argv[1];
  950. break;
  951. default:
  952. cerr<<"Usage:"<<endl<<" ./example input.obj (output.obj)"<<endl;
  953. cout<<endl<<"Opening default mesh..."<<endl;
  954. break;
  955. }
  956. // print key commands
  957. cout<<"[Click] and [drag] Rotate model using trackball."<<endl;
  958. cout<<"[Z,z] Snap rotation to canonical view."<<endl;
  959. cout<<"[Command+Z] Undo."<<endl;
  960. cout<<"[Shift+Command+Z] Redo."<<endl;
  961. cout<<"[^C,ESC] Exit."<<endl;
  962. read_triangle_mesh(filename,V,F);
  963. // Init glut
  964. glutInit(&argc,argv);
  965. if( !TwInit(TW_OPENGL, NULL) )
  966. {
  967. // A fatal error occured
  968. fprintf(stderr, "AntTweakBar initialization failed: %s\n", TwGetLastError());
  969. return 1;
  970. }
  971. // Create a tweak bar
  972. rebar.TwNewBar("bar");
  973. TwDefine("bar label='Components' size='200 550' text=light alpha='200' color='68 68 68'");
  974. rebar.TwAddVarRW("camera_rotation", TW_TYPE_QUAT4D,
  975. s.camera.m_rotation_conj.coeffs().data(), "open readonly=true");
  976. TwType RotationTypeTW = igl::anttweakbar::ReTwDefineEnumFromString("RotationType",
  977. "igl_trackball,two-axis-valuator-fixed-up");
  978. rebar.TwAddVarCB( "rotation_type", RotationTypeTW,
  979. set_rotation_type,get_rotation_type,NULL,"keyIncr=] keyDecr=[");
  980. TwType CenterTypeTW = igl::anttweakbar::ReTwDefineEnumFromString("CenterType","orbit,fps");
  981. rebar.TwAddVarRW("center_type", CenterTypeTW,&center_type,
  982. "keyIncr={ keyDecr=}");
  983. rebar.TwAddVarRW("wireframe_visible",TW_TYPE_BOOLCPP,&wireframe_visible,"key=l");
  984. rebar.TwAddVarRW("fill_visible",TW_TYPE_BOOLCPP,&fill_visible,"key=f");
  985. if(out_filename != "")
  986. {
  987. rebar.TwAddButton("save",
  988. saveCB,NULL,
  989. C_STR("label='Save to `"<<out_filename<<"`' "<<
  990. "key=s"));
  991. }
  992. rebar.load(REBAR_NAME);
  993. animation_from_quat = Quaterniond(1,0,0,0);
  994. s.camera.m_rotation_conj = animation_from_quat;
  995. animation_start_time = get_seconds();
  996. glutInitDisplayString( "rgba depth double samples>=8");
  997. glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)/2.0,glutGet(GLUT_SCREEN_HEIGHT)/2.0);
  998. glutCreateWindow("components");
  999. glutDisplayFunc(display);
  1000. glutReshapeFunc(reshape);
  1001. glutKeyboardFunc(key);
  1002. glutMouseFunc(mouse);
  1003. glutMotionFunc(mouse_drag);
  1004. glutPassiveMotionFunc(mouse_move);
  1005. init_components();
  1006. init_relative();
  1007. regenerate_mask();
  1008. std::cout<<"OpenGL version: "<<glGetString(GL_VERSION)<<std::endl;
  1009. glutMainLoop();
  1010. return 0;
  1011. }