example.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. #include <igl/readOBJ.h>
  2. #include <igl/writeOBJ.h>
  3. #include <igl/writeOFF.h>
  4. #include <igl/readWRL.h>
  5. #include <igl/report_gl_error.h>
  6. #include <igl/polygon_mesh_to_triangle_mesh.h>
  7. #include <igl/readOFF.h>
  8. #include <igl/readMESH.h>
  9. #include <igl/draw_mesh.h>
  10. #include <igl/draw_floor.h>
  11. #include <igl/pathinfo.h>
  12. #include <igl/list_to_matrix.h>
  13. #include <igl/quat_to_mat.h>
  14. #include <igl/per_face_normals.h>
  15. #include <igl/material_colors.h>
  16. #include <igl/trackball.h>
  17. #include <igl/snap_to_canonical_view_quat.h>
  18. #include <igl/REDRUM.h>
  19. #include <igl/Camera.h>
  20. #include <igl/ReAntTweakBar.h>
  21. #include <igl/get_seconds.h>
  22. #include <igl/jet.h>
  23. #include <igl/randperm.h>
  24. #include <igl/normalize_row_lengths.h>
  25. #include <igl/boost/components.h>
  26. #include <igl/boost/bfs_orient.h>
  27. #include <igl/orient_outward.h>
  28. #include <igl/embree/reorient_facets_raycast.h>
  29. #include <igl/unique_simplices.h>
  30. #include <igl/C_STR.h>
  31. #include <igl/write_triangle_mesh.h>
  32. #include <igl/two_axis_valuator_fixed_up.h>
  33. #include <igl/snap_to_fixed_up.h>
  34. #include <Eigen/Core>
  35. #include <Eigen/Geometry>
  36. #ifdef __APPLE__
  37. #include <GLUT/glut.h>
  38. #else
  39. #include <GL/glut.h>
  40. #endif
  41. #ifndef GLUT_WHEEL_UP
  42. #define GLUT_WHEEL_UP 3
  43. #endif
  44. #ifndef GLUT_WHEEL_DOWN
  45. #define GLUT_WHEEL_DOWN 4
  46. #endif
  47. #ifndef GLUT_WHEEL_RIGHT
  48. #define GLUT_WHEEL_RIGHT 5
  49. #endif
  50. #ifndef GLUT_WHEEL_LEFT
  51. #define GLUT_WHEEL_LEFT 6
  52. #endif
  53. #ifndef GLUT_ACTIVE_COMMAND
  54. #define GLUT_ACTIVE_COMMAND 8
  55. #endif
  56. #include <ctime>
  57. #include <string>
  58. #include <vector>
  59. #include <stack>
  60. #include <iostream>
  61. int cc_selected = -1;
  62. Eigen::MatrixXd V;
  63. Eigen::VectorXd Vmid,Vmin,Vmax;
  64. double bbd = 1.0;
  65. Eigen::MatrixXi F;
  66. Eigen::VectorXi CC;
  67. struct State
  68. {
  69. igl::Camera camera;
  70. Eigen::MatrixXd N;
  71. Eigen::MatrixXd C;
  72. } s;
  73. std::string out_filename;
  74. // See README for descriptions
  75. enum RotationType
  76. {
  77. ROTATION_TYPE_IGL_TRACKBALL = 0,
  78. ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1,
  79. NUM_ROTATION_TYPES = 2,
  80. } rotation_type;
  81. enum CenterType
  82. {
  83. CENTER_TYPE_ORBIT = 0,
  84. CENTER_TYPE_FPS = 1,
  85. NUM_CENTER_TYPES = 2,
  86. } center_type = CENTER_TYPE_ORBIT;
  87. enum OrientMethod
  88. {
  89. ORIENT_METHOD_OUTWARD = 0,
  90. ORIENT_METHOD_AO = 1,
  91. NUM_ORIENT_METHODS = 2,
  92. } orient_method = ORIENT_METHOD_AO;
  93. std::stack<State> undo_stack;
  94. std::stack<State> redo_stack;
  95. bool wireframe_visible = false;
  96. bool fill_visible = true;
  97. bool is_rotating = false;
  98. int down_x,down_y;
  99. igl::Camera down_camera;
  100. bool is_animating = false;
  101. double animation_start_time = 0;
  102. double ANIMATION_DURATION = 0.5;
  103. Eigen::Quaterniond animation_from_quat;
  104. Eigen::Quaterniond animation_to_quat;
  105. int width,height;
  106. Eigen::Vector4f light_pos(-0.1,-0.1,0.9,0);
  107. #define REBAR_NAME "temp.rbr"
  108. igl::ReTwBar rebar;
  109. // Forward
  110. void init_patches();
  111. void init_relative();
  112. void push_undo()
  113. {
  114. undo_stack.push(s);
  115. // Clear
  116. redo_stack = std::stack<State>();
  117. }
  118. void TW_CALL set_orient_method(const void * value, void * clientData)
  119. {
  120. const OrientMethod old_orient_method = orient_method;
  121. orient_method = *(const OrientMethod *)value;
  122. if(orient_method != old_orient_method)
  123. {
  124. init_patches();
  125. init_relative();
  126. }
  127. }
  128. void TW_CALL get_orient_method(void * value, void *clientData)
  129. {
  130. OrientMethod * om = (OrientMethod *)(value);
  131. *om = orient_method;
  132. }
  133. void TW_CALL set_rotation_type(const void * value, void * clientData)
  134. {
  135. using namespace Eigen;
  136. using namespace std;
  137. using namespace igl;
  138. const RotationType old_rotation_type = rotation_type;
  139. rotation_type = *(const RotationType *)(value);
  140. if(rotation_type == ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP &&
  141. old_rotation_type != ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP)
  142. {
  143. push_undo();
  144. animation_from_quat = s.camera.m_rotation_conj;
  145. snap_to_fixed_up(animation_from_quat,animation_to_quat);
  146. // start animation
  147. animation_start_time = get_seconds();
  148. is_animating = true;
  149. }
  150. }
  151. void TW_CALL get_rotation_type(void * value, void *clientData)
  152. {
  153. RotationType * rt = (RotationType *)(value);
  154. *rt = rotation_type;
  155. }
  156. void reshape(int width, int height)
  157. {
  158. ::width = width;
  159. ::height = height;
  160. glViewport(0,0,width,height);
  161. // Send the new window size to AntTweakBar
  162. TwWindowSize(width, height);
  163. s.camera.m_aspect = (double)width/(double)height;
  164. }
  165. void push_scene()
  166. {
  167. using namespace igl;
  168. using namespace std;
  169. glMatrixMode(GL_PROJECTION);
  170. glPushMatrix();
  171. glLoadIdentity();
  172. auto & camera = s.camera;
  173. glMultMatrixd(camera.projection().data());
  174. glMatrixMode(GL_MODELVIEW);
  175. glPushMatrix();
  176. glLoadIdentity();
  177. gluLookAt(
  178. camera.eye()(0), camera.eye()(1), camera.eye()(2),
  179. camera.at()(0), camera.at()(1), camera.at()(2),
  180. camera.up()(0), camera.up()(1), camera.up()(2));
  181. }
  182. void push_object()
  183. {
  184. using namespace igl;
  185. glPushMatrix();
  186. glScaled(2./bbd,2./bbd,2./bbd);
  187. glTranslated(-Vmid(0),-Vmid(1),-Vmid(2));
  188. }
  189. void pop_object()
  190. {
  191. glPopMatrix();
  192. }
  193. void pop_scene()
  194. {
  195. glMatrixMode(GL_PROJECTION);
  196. glPopMatrix();
  197. glMatrixMode(GL_MODELVIEW);
  198. glPopMatrix();
  199. }
  200. // Set up double-sided lights
  201. void lights()
  202. {
  203. using namespace std;
  204. using namespace Eigen;
  205. glEnable(GL_LIGHTING);
  206. //glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
  207. glEnable(GL_LIGHT0);
  208. float WHITE[4] = {1,1,1,1.};
  209. float GREY[4] = {0.4,0.4,0.4,1.};
  210. float BLACK[4] = {0.,0.,0.,1.};
  211. float NEAR_BLACK[4] = {0.1,0.1,0.1,1.};
  212. Vector4f pos = light_pos;
  213. glLightfv(GL_LIGHT0,GL_AMBIENT,BLACK);
  214. glLightfv(GL_LIGHT0,GL_DIFFUSE,WHITE);
  215. glLightfv(GL_LIGHT0,GL_SPECULAR,BLACK);
  216. glLightfv(GL_LIGHT0,GL_POSITION,pos.data());
  217. //glEnable(GL_LIGHT1);
  218. //pos(0) *= -1;
  219. //pos(1) *= -1;
  220. //pos(2) *= -1;
  221. //glLightfv(GL_LIGHT1,GL_AMBIENT,BLACK);
  222. //glLightfv(GL_LIGHT1,GL_DIFFUSE,NEAR_BLACK);
  223. //glLightfv(GL_LIGHT1,GL_SPECULAR,BLACK);
  224. //glLightfv(GL_LIGHT1,GL_POSITION,pos.data());
  225. }
  226. void display()
  227. {
  228. using namespace igl;
  229. using namespace std;
  230. using namespace Eigen;
  231. glClearColor(1,1,1,0);
  232. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  233. if(is_animating)
  234. {
  235. double t = (get_seconds() - animation_start_time)/ANIMATION_DURATION;
  236. if(t > 1)
  237. {
  238. t = 1;
  239. is_animating = false;
  240. }
  241. Quaterniond q = animation_from_quat.slerp(t,animation_to_quat).normalized();
  242. auto & camera = s.camera;
  243. switch(center_type)
  244. {
  245. default:
  246. case CENTER_TYPE_ORBIT:
  247. camera.orbit(q.conjugate());
  248. break;
  249. case CENTER_TYPE_FPS:
  250. camera.turn_eye(q.conjugate());
  251. break;
  252. }
  253. }
  254. glEnable(GL_DEPTH_TEST);
  255. glEnable(GL_NORMALIZE);
  256. lights();
  257. push_scene();
  258. push_object();
  259. // Set material properties
  260. glEnable(GL_COLOR_MATERIAL);
  261. glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
  262. if(wireframe_visible)
  263. {
  264. glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
  265. if(fill_visible)
  266. {
  267. glColor3f(0,0,0);
  268. draw_mesh(V,F,s.N);
  269. }else
  270. {
  271. draw_mesh(V,F,s.N,s.C);
  272. }
  273. // visualize selected patch
  274. glLineWidth(10);
  275. glBegin(GL_TRIANGLES);
  276. glColor3d(0, 0, 0);
  277. // loop over faces
  278. for(int i = 0; i<F.rows();i++)
  279. {
  280. if (CC(i) != cc_selected) continue;
  281. // loop over corners of triangle
  282. for(int j = 0;j<3;j++)
  283. {
  284. glVertex3d(V(F(i,j),0),V(F(i,j),1),V(F(i,j),2));
  285. }
  286. }
  287. glEnd();
  288. glLineWidth(1);
  289. glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
  290. glBegin(GL_TRIANGLES);
  291. glColor3d(1, 0, 0);
  292. // loop over faces
  293. for(int i = 0; i<F.rows();i++)
  294. {
  295. if (CC(i) != cc_selected) continue;
  296. // loop over corners of triangle
  297. glNormal3d(s.N(i,0),s.N(i,1),s.N(i,2));
  298. for(int j = 0;j<3;j++)
  299. {
  300. glVertex3d(V(F(i,j),0),V(F(i,j),1),V(F(i,j),2));
  301. }
  302. }
  303. glEnd();
  304. }
  305. glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
  306. if(fill_visible)
  307. {
  308. glEnable(GL_POLYGON_OFFSET_FILL); // Avoid Stitching!
  309. glPolygonOffset(1.0, 0);
  310. draw_mesh(V,F,s.N,s.C);
  311. }
  312. pop_object();
  313. // Draw a nice floor
  314. glPushMatrix();
  315. const double floor_offset =
  316. -2./bbd*(V.col(1).maxCoeff()-Vmid(1));
  317. glTranslated(0,floor_offset,0);
  318. const float GREY[4] = {0.5,0.5,0.6,1.0};
  319. const float DARK_GREY[4] = {0.2,0.2,0.3,1.0};
  320. draw_floor(GREY,DARK_GREY);
  321. glPopMatrix();
  322. pop_scene();
  323. report_gl_error();
  324. TwDraw();
  325. glutSwapBuffers();
  326. glutPostRedisplay();
  327. }
  328. void mouse_wheel(int wheel, int direction, int mouse_x, int mouse_y)
  329. {
  330. using namespace std;
  331. using namespace igl;
  332. using namespace Eigen;
  333. GLint viewport[4];
  334. glGetIntegerv(GL_VIEWPORT,viewport);
  335. if(wheel == 0 && TwMouseMotion(mouse_x, viewport[3] - mouse_y))
  336. {
  337. static double mouse_scroll_y = 0;
  338. const double delta_y = 0.125*direction;
  339. mouse_scroll_y += delta_y;
  340. TwMouseWheel(mouse_scroll_y);
  341. return;
  342. }
  343. push_undo();
  344. auto & camera = s.camera;
  345. switch(center_type)
  346. {
  347. case CENTER_TYPE_ORBIT:
  348. if(wheel==0)
  349. {
  350. // factor of zoom change
  351. double s = (1.-0.01*direction);
  352. //// FOV zoom: just widen angle. This is hardly ever appropriate.
  353. //camera.m_angle *= s;
  354. //camera.m_angle = min(max(camera.m_angle,1),89);
  355. camera.push_away(s);
  356. }else
  357. {
  358. // Dolly zoom:
  359. camera.dolly_zoom((double)direction*1.0);
  360. }
  361. break;
  362. default:
  363. case CENTER_TYPE_FPS:
  364. // Move `eye` and `at`
  365. camera.dolly((wheel==0?Vector3d(0,0,1):Vector3d(-1,0,0))*0.1*direction);
  366. break;
  367. }
  368. }
  369. void mouse(int glutButton, int glutState, int mouse_x, int mouse_y)
  370. {
  371. using namespace std;
  372. using namespace Eigen;
  373. using namespace igl;
  374. bool tw_using = TwEventMouseButtonGLUT(glutButton,glutState,mouse_x,mouse_y);
  375. switch(glutButton)
  376. {
  377. case GLUT_RIGHT_BUTTON:
  378. case GLUT_LEFT_BUTTON:
  379. {
  380. switch(glutState)
  381. {
  382. case 1:
  383. // up
  384. glutSetCursor(GLUT_CURSOR_INHERIT);
  385. is_rotating = false;
  386. break;
  387. case 0:
  388. if(!tw_using)
  389. {
  390. push_undo();
  391. glutSetCursor(GLUT_CURSOR_CYCLE);
  392. // collect information for trackball
  393. is_rotating = true;
  394. down_camera = s.camera;
  395. down_x = mouse_x;
  396. down_y = mouse_y;
  397. }
  398. break;
  399. }
  400. break;
  401. // Scroll down
  402. case GLUT_WHEEL_DOWN:
  403. {
  404. mouse_wheel(0,-1,mouse_x,mouse_y);
  405. break;
  406. }
  407. // Scroll up
  408. case GLUT_WHEEL_UP:
  409. {
  410. mouse_wheel(0,1,mouse_x,mouse_y);
  411. break;
  412. }
  413. // Scroll left
  414. case GLUT_WHEEL_LEFT:
  415. {
  416. mouse_wheel(1,-1,mouse_x,mouse_y);
  417. break;
  418. }
  419. // Scroll right
  420. case GLUT_WHEEL_RIGHT:
  421. {
  422. mouse_wheel(1,1,mouse_x,mouse_y);
  423. break;
  424. }
  425. }
  426. }
  427. }
  428. void mouse_drag(int mouse_x, int mouse_y)
  429. {
  430. using namespace igl;
  431. using namespace std;
  432. using namespace Eigen;
  433. bool tw_using = TwMouseMotion(mouse_x,mouse_y);
  434. if(is_rotating)
  435. {
  436. glutSetCursor(GLUT_CURSOR_CYCLE);
  437. Quaterniond q;
  438. auto & camera = s.camera;
  439. switch(rotation_type)
  440. {
  441. case ROTATION_TYPE_IGL_TRACKBALL:
  442. {
  443. // Rotate according to trackball
  444. igl::trackball<double>(
  445. width,
  446. height,
  447. 2.0,
  448. down_camera.m_rotation_conj.coeffs().data(),
  449. down_x,
  450. down_y,
  451. mouse_x,
  452. mouse_y,
  453. q.coeffs().data());
  454. break;
  455. }
  456. case ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP:
  457. {
  458. // Rotate according to two axis valuator with fixed up vector
  459. two_axis_valuator_fixed_up(
  460. width, height,
  461. 2.0,
  462. down_camera.m_rotation_conj,
  463. down_x, down_y, mouse_x, mouse_y,
  464. q);
  465. break;
  466. }
  467. default:
  468. break;
  469. }
  470. switch(center_type)
  471. {
  472. default:
  473. case CENTER_TYPE_ORBIT:
  474. camera.orbit(q.conjugate());
  475. break;
  476. case CENTER_TYPE_FPS:
  477. camera.turn_eye(q.conjugate());
  478. break;
  479. }
  480. }
  481. }
  482. void init_relative()
  483. {
  484. using namespace Eigen;
  485. using namespace igl;
  486. per_face_normals(V,F,s.N);
  487. normalize_row_lengths(s.N,s.N);
  488. Vmax = V.colwise().maxCoeff();
  489. Vmin = V.colwise().minCoeff();
  490. Vmid = 0.5*(Vmax + Vmin);
  491. bbd = (Vmax-Vmin).norm();
  492. }
  493. void randomly_color(
  494. const Eigen::VectorXi & CC,
  495. Eigen::MatrixXd & C)
  496. {
  497. using namespace Eigen;
  498. using namespace igl;
  499. using namespace std;
  500. VectorXi I;
  501. srand ( unsigned ( time(0) ) );
  502. double num_cc = (double)CC.maxCoeff()+1.0;
  503. randperm(num_cc,I);
  504. C.resize(CC.rows(),3);
  505. for(int f = 0;f<CC.rows();f++)
  506. {
  507. jet(
  508. (double)I(CC(f))/num_cc,
  509. C(f,0),
  510. C(f,1),
  511. C(f,2));
  512. }
  513. }
  514. void TW_CALL randomize_colors(void * /*clientData*/)
  515. {
  516. push_undo();
  517. randomly_color(CC,s.C);
  518. }
  519. void init_patches()
  520. {
  521. using namespace Eigen;
  522. using namespace igl;
  523. using namespace std;
  524. {
  525. VectorXi VCC;
  526. components(F,VCC);
  527. cout<<"There are "<<VCC.maxCoeff()+1<<" connected components of vertices."<<endl;
  528. }
  529. bfs_orient(F,F,CC);
  530. VectorXi I;
  531. switch(orient_method)
  532. {
  533. case ORIENT_METHOD_AO:
  534. {
  535. cout<<"orient_outward_ao()"<<endl;
  536. reorient_facets_raycast(V,F,F,I);
  537. break;
  538. }
  539. case ORIENT_METHOD_OUTWARD:
  540. default:
  541. cout<<"orient_outward()"<<endl;
  542. orient_outward(V,F,CC,F,I);
  543. break;
  544. }
  545. double num_cc = (double)CC.maxCoeff()+1.0;
  546. cout<<"There are "<<num_cc<<" 'manifold/orientable' patches of faces."<<endl;
  547. }
  548. void undo()
  549. {
  550. using namespace std;
  551. if(!undo_stack.empty())
  552. {
  553. redo_stack.push(s);
  554. s = undo_stack.top();
  555. undo_stack.pop();
  556. }
  557. }
  558. void redo()
  559. {
  560. using namespace std;
  561. if(!redo_stack.empty())
  562. {
  563. undo_stack.push(s);
  564. s = redo_stack.top();
  565. redo_stack.pop();
  566. }
  567. }
  568. bool save(const std::string & out_filename)
  569. {
  570. using namespace std;
  571. using namespace igl;
  572. if(write_triangle_mesh(out_filename,V,F))
  573. {
  574. cout<<GREENGIN("Saved mesh to `"<<out_filename<<"` successfully.")<<endl;
  575. return true;
  576. }else
  577. {
  578. cout<<REDRUM("Failed to save mesh to `"<<out_filename<<"`.")<<endl;
  579. return false;
  580. }
  581. }
  582. void TW_CALL saveCB(void * /*clientData*/)
  583. {
  584. save(out_filename);
  585. }
  586. void key(unsigned char key, int mouse_x, int mouse_y)
  587. {
  588. using namespace std;
  589. using namespace Eigen;
  590. using namespace igl;
  591. int mod = glutGetModifiers();
  592. switch(key)
  593. {
  594. // ESC
  595. case char(27):
  596. rebar.save(REBAR_NAME);
  597. // ^C
  598. case char(3):
  599. exit(0);
  600. case 'I':
  601. case 'i':
  602. {
  603. push_undo();
  604. s.N *= -1.0;
  605. F = F.rowwise().reverse().eval();
  606. break;
  607. }
  608. case 'z':
  609. case 'Z':
  610. if(mod & GLUT_ACTIVE_COMMAND)
  611. {
  612. if(mod & GLUT_ACTIVE_SHIFT)
  613. {
  614. redo();
  615. }else
  616. {
  617. undo();
  618. }
  619. }else
  620. {
  621. push_undo();
  622. Quaterniond q;
  623. snap_to_canonical_view_quat(s.camera.m_rotation_conj,1.0,q);
  624. switch(center_type)
  625. {
  626. default:
  627. case CENTER_TYPE_ORBIT:
  628. s.camera.orbit(q.conjugate());
  629. break;
  630. case CENTER_TYPE_FPS:
  631. s.camera.turn_eye(q.conjugate());
  632. break;
  633. }
  634. }
  635. break;
  636. case 'u':
  637. mouse_wheel(0, 1,mouse_x,mouse_y);
  638. break;
  639. case 'j':
  640. mouse_wheel(0,-1,mouse_x,mouse_y);
  641. break;
  642. case 'n':
  643. cc_selected = (cc_selected + 1) % (CC.maxCoeff() + 2);
  644. cout << "selected cc: " << cc_selected << endl;
  645. glutPostRedisplay();
  646. break;
  647. default:
  648. if(!TwEventKeyboardGLUT(key,mouse_x,mouse_y))
  649. {
  650. cout<<"Unknown key command: "<<key<<" "<<int(key)<<endl;
  651. }
  652. }
  653. }
  654. int main(int argc, char * argv[])
  655. {
  656. using namespace std;
  657. using namespace Eigen;
  658. using namespace igl;
  659. string filename = "../shared/truck.obj";
  660. switch(argc)
  661. {
  662. case 3:
  663. out_filename = argv[2];
  664. case 2:
  665. // Read and prepare mesh
  666. filename = argv[1];
  667. break;
  668. default:
  669. cerr<<"Usage:"<<endl<<" ./example input.obj (output.obj)"<<endl;
  670. cout<<endl<<"Opening default mesh..."<<endl;
  671. break;
  672. }
  673. // print key commands
  674. cout<<"[Click] and [drag] Rotate model using trackball."<<endl;
  675. cout<<"[Z,z] Snap rotation to canonical view."<<endl;
  676. cout<<"[Command+Z] Undo."<<endl;
  677. cout<<"[Shift+Command+Z] Redo."<<endl;
  678. cout<<"[^C,ESC] Exit."<<endl;
  679. // dirname, basename, extension and filename
  680. string d,b,ext,f;
  681. pathinfo(filename,d,b,ext,f);
  682. // Convert extension to lower case
  683. transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
  684. vector<vector<double > > vV,vN,vTC;
  685. vector<vector<int > > vF,vFTC,vFN;
  686. if(ext == "obj")
  687. {
  688. // Convert extension to lower case
  689. if(!igl::readOBJ(filename,vV,vTC,vN,vF,vFTC,vFN))
  690. {
  691. return 1;
  692. }
  693. }else if(ext == "off")
  694. {
  695. // Convert extension to lower case
  696. if(!igl::readOFF(filename,vV,vF,vN))
  697. {
  698. return 1;
  699. }
  700. }else if(ext == "wrl")
  701. {
  702. // Convert extension to lower case
  703. if(!igl::readWRL(filename,vV,vF))
  704. {
  705. return 1;
  706. }
  707. //}else
  708. //{
  709. // // Convert extension to lower case
  710. // MatrixXi T;
  711. // if(!igl::readMESH(filename,V,T,F))
  712. // {
  713. // return 1;
  714. // }
  715. // //if(F.size() > T.size() || F.size() == 0)
  716. // {
  717. // boundary_facets(T,F);
  718. // }
  719. }
  720. if(vV.size() > 0)
  721. {
  722. if(!list_to_matrix(vV,V))
  723. {
  724. return 1;
  725. }
  726. polygon_mesh_to_triangle_mesh(vF,F);
  727. }
  728. MatrixXi F_unique;
  729. unique_simplices(F, F_unique);
  730. F = F_unique;
  731. init_patches();
  732. init_relative();
  733. randomly_color(CC,s.C);
  734. // Init glut
  735. glutInit(&argc,argv);
  736. if( !TwInit(TW_OPENGL, NULL) )
  737. {
  738. // A fatal error occured
  739. fprintf(stderr, "AntTweakBar initialization failed: %s\n", TwGetLastError());
  740. return 1;
  741. }
  742. // Create a tweak bar
  743. rebar.TwNewBar("bar");
  744. TwDefine("bar label='Patches' size='200 550' text=light alpha='200' color='68 68 68'");
  745. rebar.TwAddVarRW("camera_rotation", TW_TYPE_QUAT4D,
  746. s.camera.m_rotation_conj.coeffs().data(), "open readonly=true");
  747. TwType RotationTypeTW = ReTwDefineEnumFromString("RotationType",
  748. "igl_trackball,two-axis-valuator-fixed-up");
  749. rebar.TwAddVarCB( "rotation_type", RotationTypeTW,
  750. set_rotation_type,get_rotation_type,NULL,"keyIncr=] keyDecr=[");
  751. TwType CenterTypeTW = ReTwDefineEnumFromString("CenterType","orbit,fps");
  752. rebar.TwAddVarRW("center_type", CenterTypeTW,&center_type,
  753. "keyIncr={ keyDecr=}");
  754. TwType OrientMethodTW = ReTwDefineEnumFromString("OrientMethod",
  755. "outward,ambient-occlusion");
  756. rebar.TwAddVarCB( "orient_method", OrientMethodTW,
  757. set_orient_method,get_orient_method,NULL,"keyIncr=< keyDecr=>");
  758. rebar.TwAddVarRW("wireframe_visible",TW_TYPE_BOOLCPP,&wireframe_visible,"key=l");
  759. rebar.TwAddVarRW("fill_visible",TW_TYPE_BOOLCPP,&fill_visible,"key=f");
  760. rebar.TwAddButton("randomize_colors",randomize_colors,NULL,"key=c");
  761. if(out_filename != "")
  762. {
  763. rebar.TwAddButton("save",
  764. saveCB,NULL,
  765. C_STR("label='Save to `"<<out_filename<<"`' "<<
  766. "key=s"));
  767. }
  768. rebar.load(REBAR_NAME);
  769. animation_from_quat = Quaterniond(1,0,0,0);
  770. s.camera.m_rotation_conj = animation_from_quat;
  771. animation_start_time = get_seconds();
  772. // Init antweakbar
  773. #ifdef __APPLE__
  774. glutInitDisplayString( "rgba depth double samples>=8");
  775. #else
  776. glutInitDisplayString( "rgba depth double "); // samples>=8 somehow not supported on Kenshi's machines...?
  777. #endif
  778. glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)/2.0,glutGet(GLUT_SCREEN_HEIGHT)/2.0);
  779. glutCreateWindow("patches");
  780. glutDisplayFunc(display);
  781. glutReshapeFunc(reshape);
  782. glutKeyboardFunc(key);
  783. glutMouseFunc(mouse);
  784. glutMotionFunc(mouse_drag);
  785. glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT);
  786. glutMainLoop();
  787. return 0;
  788. }