Viewer.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062
  1. #include "Viewer.h"
  2. #include <igl/get_seconds.h>
  3. #ifdef _WIN32
  4. # include <windows.h>
  5. # undef max
  6. # undef min
  7. #endif
  8. // Todo: windows equivalent for `usleep`
  9. #include <unistd.h>
  10. #ifndef __APPLE__
  11. # define GLEW_STATIC
  12. # include <GL/glew.h>
  13. #endif
  14. #ifdef __APPLE__
  15. # include <OpenGL/gl3.h>
  16. # define __gl_h_ /* Prevent inclusion of the old gl.h */
  17. #else
  18. # ifdef _WIN32
  19. # include <windows.h>
  20. # endif
  21. # include <GL/gl.h>
  22. #endif
  23. #include <Eigen/LU>
  24. #define GLFW_INCLUDE_GLU
  25. #include <GLFW/glfw3.h>
  26. #include <cmath>
  27. #include <cstdio>
  28. #include <sstream>
  29. #include <iomanip>
  30. #include <iostream>
  31. #include <fstream>
  32. #include <algorithm>
  33. #include <igl/project.h>
  34. #include <limits>
  35. #include <cassert>
  36. #ifdef ENABLE_XML_SERIALIZATION
  37. #include "igl/xml/XMLSerializer.h"
  38. #endif
  39. #include <igl/readOBJ.h>
  40. #include <igl/readOFF.h>
  41. #include <igl/adjacency_list.h>
  42. #include <igl/writeOBJ.h>
  43. #include <igl/writeOFF.h>
  44. #include <igl/massmatrix.h>
  45. #include <igl/file_dialog_open.h>
  46. #include <igl/file_dialog_save.h>
  47. #include <igl/quat_mult.h>
  48. #include <igl/axis_angle_to_quat.h>
  49. #include <igl/trackball.h>
  50. #include <igl/snap_to_canonical_view_quat.h>
  51. #include <igl/unproject.h>
  52. #include <igl/viewer/TextRenderer.h>
  53. // Internal global variables used for glfw event handling
  54. static igl::Viewer * __viewer;
  55. static double highdpi = 1;
  56. static double scroll_x = 0;
  57. static double scroll_y = 0;
  58. static void glfw_mouse_press(GLFWwindow* window, int button, int action, int modifier)
  59. {
  60. bool tw_used = TwEventMouseButtonGLFW(button, action);
  61. igl::Viewer::MouseButton mb;
  62. if (button == GLFW_MOUSE_BUTTON_1)
  63. mb = igl::Viewer::IGL_LEFT;
  64. else if (button == GLFW_MOUSE_BUTTON_2)
  65. mb = igl::Viewer::IGL_RIGHT;
  66. else //if (button == GLFW_MOUSE_BUTTON_3)
  67. mb = igl::Viewer::IGL_MIDDLE;
  68. if (action == GLFW_PRESS)
  69. {
  70. if(!tw_used)
  71. {
  72. __viewer->mouse_down(mb,modifier);
  73. }
  74. } else
  75. {
  76. // Always call mouse_up on up
  77. __viewer->mouse_up(mb,modifier);
  78. }
  79. }
  80. static void glfw_error_callback(int error, const char* description)
  81. {
  82. fputs(description, stderr);
  83. }
  84. int global_KMod = 0;
  85. int TwEventKeyGLFW3(int glfwKey, int glfwAction)
  86. {
  87. int handled = 0;
  88. // Register of modifiers state
  89. if (glfwAction==GLFW_PRESS)
  90. {
  91. switch (glfwKey)
  92. {
  93. case GLFW_KEY_LEFT_SHIFT:
  94. case GLFW_KEY_RIGHT_SHIFT:
  95. global_KMod |= TW_KMOD_SHIFT;
  96. break;
  97. case GLFW_KEY_LEFT_CONTROL:
  98. case GLFW_KEY_RIGHT_CONTROL:
  99. global_KMod |= TW_KMOD_CTRL;
  100. break;
  101. case GLFW_KEY_LEFT_ALT:
  102. case GLFW_KEY_RIGHT_ALT:
  103. global_KMod |= TW_KMOD_ALT;
  104. break;
  105. }
  106. }
  107. else
  108. {
  109. switch (glfwKey)
  110. {
  111. case GLFW_KEY_LEFT_SHIFT:
  112. case GLFW_KEY_RIGHT_SHIFT:
  113. global_KMod &= ~TW_KMOD_SHIFT;
  114. break;
  115. case GLFW_KEY_LEFT_CONTROL:
  116. case GLFW_KEY_RIGHT_CONTROL:
  117. global_KMod &= ~TW_KMOD_CTRL;
  118. break;
  119. case GLFW_KEY_LEFT_ALT:
  120. case GLFW_KEY_RIGHT_ALT:
  121. global_KMod &= ~TW_KMOD_ALT;
  122. break;
  123. }
  124. }
  125. // Process key pressed
  126. if (glfwAction==GLFW_PRESS)
  127. {
  128. int mod = global_KMod;
  129. int testkp = ((mod&TW_KMOD_CTRL) || (mod&TW_KMOD_ALT)) ? 1 : 0;
  130. if ((mod&TW_KMOD_CTRL) && glfwKey>0 && glfwKey<GLFW_KEY_ESCAPE ) // CTRL cases
  131. handled = TwKeyPressed(glfwKey, mod);
  132. else if (glfwKey>=GLFW_KEY_ESCAPE )
  133. {
  134. int k = 0;
  135. if (glfwKey>=GLFW_KEY_F1 && glfwKey<=GLFW_KEY_F15)
  136. k = TW_KEY_F1 + (glfwKey-GLFW_KEY_F1);
  137. else if (testkp && glfwKey>=GLFW_KEY_KP_0 && glfwKey<=GLFW_KEY_KP_9)
  138. k = '0' + (glfwKey-GLFW_KEY_KP_0);
  139. else
  140. {
  141. switch (glfwKey)
  142. {
  143. case GLFW_KEY_ESCAPE :
  144. k = TW_KEY_ESCAPE;
  145. break;
  146. case GLFW_KEY_UP:
  147. k = TW_KEY_UP;
  148. break;
  149. case GLFW_KEY_DOWN:
  150. k = TW_KEY_DOWN;
  151. break;
  152. case GLFW_KEY_LEFT:
  153. k = TW_KEY_LEFT;
  154. break;
  155. case GLFW_KEY_RIGHT:
  156. k = TW_KEY_RIGHT;
  157. break;
  158. case GLFW_KEY_TAB:
  159. k = TW_KEY_TAB;
  160. break;
  161. case GLFW_KEY_ENTER:
  162. k = TW_KEY_RETURN;
  163. break;
  164. case GLFW_KEY_BACKSPACE:
  165. k = TW_KEY_BACKSPACE;
  166. break;
  167. case GLFW_KEY_INSERT:
  168. k = TW_KEY_INSERT;
  169. break;
  170. case GLFW_KEY_DELETE:
  171. k = TW_KEY_DELETE;
  172. break;
  173. case GLFW_KEY_PAGE_UP:
  174. k = TW_KEY_PAGE_UP;
  175. break;
  176. case GLFW_KEY_PAGE_DOWN:
  177. k = TW_KEY_PAGE_DOWN;
  178. break;
  179. case GLFW_KEY_HOME:
  180. k = TW_KEY_HOME;
  181. break;
  182. case GLFW_KEY_END:
  183. k = TW_KEY_END;
  184. break;
  185. case GLFW_KEY_KP_ENTER:
  186. k = TW_KEY_RETURN;
  187. break;
  188. case GLFW_KEY_KP_DIVIDE:
  189. if (testkp)
  190. k = '/';
  191. break;
  192. case GLFW_KEY_KP_MULTIPLY:
  193. if (testkp)
  194. k = '*';
  195. break;
  196. case GLFW_KEY_KP_SUBTRACT:
  197. if (testkp)
  198. k = '-';
  199. break;
  200. case GLFW_KEY_KP_ADD:
  201. if (testkp)
  202. k = '+';
  203. break;
  204. case GLFW_KEY_KP_DECIMAL:
  205. if (testkp)
  206. k = '.';
  207. break;
  208. case GLFW_KEY_KP_EQUAL:
  209. if (testkp)
  210. k = '=';
  211. break;
  212. }
  213. }
  214. if (k>0)
  215. handled = TwKeyPressed(k, mod);
  216. }
  217. }
  218. return handled;
  219. }
  220. static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int modifier)
  221. {
  222. if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
  223. glfwSetWindowShouldClose(window, GL_TRUE);
  224. if (!TwEventKeyGLFW3(key,action))
  225. {
  226. if (action == GLFW_PRESS)
  227. __viewer->key_down(key, modifier);
  228. else
  229. __viewer->key_up(key, modifier);
  230. }
  231. }
  232. static void glfw_window_size(GLFWwindow* window, int width, int height)
  233. {
  234. int w = width*highdpi;
  235. int h = height*highdpi;
  236. __viewer->resize(w, h);
  237. TwWindowSize(w, h);
  238. const auto & bar = __viewer->bar;
  239. // Keep AntTweakBar on right side of screen and height == opengl height
  240. // get the current position of a bar
  241. int size[2];
  242. TwGetParam(bar, NULL, "size", TW_PARAM_INT32, 2, size);
  243. int pos[2];
  244. // Place bar on left side of opengl rect (padded by 10 pixels)
  245. pos[0] = 10;//max(10,(int)width - size[0] - 10);
  246. // place bar at top (padded by 10 pixels)
  247. pos[1] = 10;
  248. // Set height to new height of window (padded by 10 pixels on bottom)
  249. size[1] = highdpi*(height-pos[1]-10);
  250. TwSetParam(bar, NULL, "position", TW_PARAM_INT32, 2, pos);
  251. TwSetParam(bar, NULL, "size", TW_PARAM_INT32, 2,size);
  252. }
  253. static void glfw_mouse_move(GLFWwindow* window, double x, double y)
  254. {
  255. if(!TwEventMousePosGLFW(x*highdpi,y*highdpi) || __viewer->down)
  256. {
  257. // Call if TwBar hasn't used or if down
  258. __viewer->mouse_move(x*highdpi, y*highdpi);
  259. }
  260. }
  261. static void glfw_mouse_scroll(GLFWwindow* window, double x, double y)
  262. {
  263. using namespace std;
  264. scroll_x += x;
  265. scroll_y += y;
  266. if (!TwEventMouseWheelGLFW(scroll_y))
  267. __viewer->mouse_scroll(y);
  268. }
  269. static void glfw_char_callback(GLFWwindow* window, unsigned int c)
  270. {
  271. if ((c & 0xff00)==0)
  272. TwKeyPressed(c, global_KMod);
  273. }
  274. namespace igl
  275. {
  276. void Viewer::init()
  277. {
  278. // Create a tweak bar
  279. bar = TwNewBar("libIGL-Viewer");
  280. TwDefine(" libIGL-Viewer help='This is a simple 3D mesh viewer.' "); // Message added to the help bar->
  281. TwDefine(" libIGL-Viewer size='200 685'"); // change default tweak bar size
  282. TwDefine(" libIGL-Viewer color='76 76 127' "); // change default tweak bar color
  283. TwDefine(" libIGL-Viewer refresh=0.5"); // change refresh rate
  284. // ---------------------- LOADING ----------------------
  285. #ifdef ENABLE_XML_SERIALIZATION
  286. TwAddButton(bar,"Load Scene", load_scene_cb, this, "group='Workspace'");
  287. TwAddButton(bar,"Save Scene", save_scene_cb, this, "group='Workspace'");
  288. #endif
  289. #ifdef ENABLE_IO
  290. TwAddButton(bar,"Load Mesh", open_dialog_mesh, this, "group='Mesh' key=o");
  291. #endif
  292. // ---------------------- SCENE ----------------------
  293. TwAddButton(bar,"Center object", align_camera_center_cb, this,
  294. " group='Viewing Options'"
  295. " label='Center object' key=A help='Set the center of the camera to the mesh center.'");
  296. TwAddVarRW(bar, "Zoom", TW_TYPE_FLOAT, &(options.camera_zoom),
  297. " min=0.05 max=50 step=0.1 keyIncr=+ keyDecr=- help='Scale the object (1=original size).' group='Scene'");
  298. TwAddButton(bar,"SnapView", snap_to_canonical_quaternion_cb, this,
  299. " group='Scene'"
  300. " label='Snap to canonical view' key=Z "
  301. " help='Snaps view to nearest canonical view.'");
  302. TwAddVarRW(bar,"LightDir", TW_TYPE_DIR3F, options.light_position.data(),
  303. " group='Scene'"
  304. " label='Light direction' open help='Change the light direction.' ");
  305. // ---------------------- DRAW OPTIONS ----------------------
  306. TwAddVarRW(bar, "ToggleOrthographic", TW_TYPE_BOOLCPP, &(options.orthographic),
  307. " group='Viewing Options'"
  308. " label='Orthographic view' "
  309. " help='Toggles orthographic / perspective view. Default: perspective.'");
  310. TwAddVarRW(bar, "Rotation", TW_TYPE_QUAT4F, &(options.trackball_angle),
  311. " group='Viewing Options'"
  312. " label='Rotation'"
  313. " help='Rotates view.'");
  314. TwAddVarCB(bar,"Face-based Normals/Colors", TW_TYPE_BOOLCPP, set_face_based_cb, get_face_based_cb, this,
  315. " group='Draw options'"
  316. " label='Face-based' key=T help='Toggle per face shading/colors.' ");
  317. TwAddVarRW(bar,"Show texture", TW_TYPE_BOOLCPP, &(options.show_texture),
  318. " group='Draw options'");
  319. TwAddVarCB(bar,"Invert Normals", TW_TYPE_BOOLCPP, set_invert_normals_cb, get_invert_normals_cb, this,
  320. " group='Draw options'"
  321. " label='Invert normals' key=i help='Invert normal directions for inside out meshes.' ");
  322. TwAddVarRW(bar,"ShowOverlay", TW_TYPE_BOOLCPP, &(options.show_overlay),
  323. " group='Draw options'"
  324. " label='Show overlay' key=o help='Show the overlay layers.' ");
  325. TwAddVarRW(bar,"ShowOverlayDepth", TW_TYPE_BOOLCPP, &(options.show_overlay_depth),
  326. " group='Draw options'"
  327. " label='Show overlay depth test' help='Enable the depth test for overlay layer.' ");
  328. TwAddVarRW(bar,"Background color", TW_TYPE_COLOR3F,
  329. options.background_color.data(),
  330. " help='Select a background color' colormode=hls group='Draw options'");
  331. TwAddVarRW(bar, "LineColor", TW_TYPE_COLOR3F,
  332. options.line_color.data(),
  333. " label='Line color' help='Select a outline color' group='Draw options'");
  334. TwAddVarRW(bar,"Shininess",TW_TYPE_FLOAT,&options.shininess," group='Draw options'"
  335. " min=1 max=128");
  336. // ---------------------- Overlays ----------------------
  337. TwAddVarRW(bar,"Wireframe", TW_TYPE_BOOLCPP, &(options.show_lines),
  338. " group='Overlays'"
  339. " label='Wireframe' key=l help='Toggle wire frame of mesh'");
  340. TwAddVarRW(bar,"Fill", TW_TYPE_BOOLCPP, &(options.show_faces),
  341. " group='Overlays'"
  342. " label='Fill' key=t help='Display filled polygons of mesh'");
  343. TwAddVarRW(bar,"ShowVertexId", TW_TYPE_BOOLCPP, &(options.show_vertid),
  344. " group='Overlays'"
  345. " label='Show Vertex Labels' key=';' help='Toggle vertex indices'");
  346. TwAddVarRW(bar,"ShowFaceId", TW_TYPE_BOOLCPP, &(options.show_faceid),
  347. " group='Overlays'"
  348. " label='Show Faces Labels' key='CTRL+;' help='Toggle face"
  349. " indices'");
  350. options.init();
  351. init_plugins();
  352. }
  353. Viewer::Viewer()
  354. {
  355. // Temporary variables initialization
  356. down = false;
  357. hack_never_moved = true;
  358. scroll_position = 0.0f;
  359. // Per face
  360. set_face_based(false);
  361. // C-style callbacks
  362. callback_pre_draw = 0;
  363. callback_post_draw = 0;
  364. callback_mouse_down = 0;
  365. callback_mouse_up = 0;
  366. callback_mouse_move = 0;
  367. callback_mouse_scroll = 0;
  368. callback_key_down = 0;
  369. callback_key_up = 0;
  370. callback_pre_draw_data = 0;
  371. callback_post_draw = 0;
  372. callback_mouse_down = 0;
  373. callback_mouse_up = 0;
  374. callback_mouse_move = 0;
  375. callback_mouse_scroll = 0;
  376. callback_key_down = 0;
  377. callback_key_up = 0;
  378. }
  379. void Viewer::init_plugins()
  380. {
  381. // Init all plugins
  382. for (unsigned int i = 0; i<plugins.size(); ++i)
  383. plugins[i]->init(this);
  384. }
  385. Viewer::~Viewer()
  386. {
  387. }
  388. void Viewer::shutdown_plugins()
  389. {
  390. for (unsigned int i = 0; i<plugins.size(); ++i)
  391. plugins[i]->shutdown();
  392. }
  393. bool Viewer::load_mesh_from_file(const char* mesh_file_name)
  394. {
  395. std::string mesh_file_name_string = std::string(mesh_file_name);
  396. // first try to load it with a plugin
  397. for (unsigned int i = 0; i<plugins.size(); ++i)
  398. if (plugins[i]->load(mesh_file_name_string))
  399. return true;
  400. data.clear();
  401. size_t last_dot = mesh_file_name_string.rfind('.');
  402. if (last_dot == std::string::npos)
  403. {
  404. printf("Error: No file extension found in %s\n",mesh_file_name);
  405. return false;
  406. }
  407. std::string extension = mesh_file_name_string.substr(last_dot+1);
  408. if (extension == "off" || extension =="OFF")
  409. {
  410. if (!igl::readOFF(mesh_file_name_string, data.V, data.F))
  411. return false;
  412. }
  413. else if (extension == "obj" || extension =="OBJ")
  414. {
  415. Eigen::MatrixXd corner_normals;
  416. Eigen::MatrixXi fNormIndices;
  417. Eigen::MatrixXd UV_V;
  418. Eigen::MatrixXi UV_F;
  419. if (!(igl::readOBJ(mesh_file_name_string, data.V, data.F, corner_normals, fNormIndices, UV_V, UV_F)))
  420. return false;
  421. }
  422. else
  423. {
  424. // unrecognized file type
  425. printf("Error: %s is not a recognized file type.\n",extension.c_str());
  426. return false;
  427. }
  428. data.compute_normals();
  429. data.uniform_colors(Eigen::Vector3d(51.0/255.0,43.0/255.0,33.3/255.0),
  430. Eigen::Vector3d(255.0/255.0,228.0/255.0,58.0/255.0),
  431. Eigen::Vector3d(255.0/255.0,235.0/255.0,80.0/255.0));
  432. if (data.V_uv.rows() == 0)
  433. data.grid_texture();
  434. options.align_camera_center(data.V);
  435. for (unsigned int i = 0; i<plugins.size(); ++i)
  436. if (plugins[i]->post_load())
  437. return true;
  438. return true;
  439. }
  440. bool Viewer::save_mesh_to_file(const char* mesh_file_name)
  441. {
  442. std::string mesh_file_name_string(mesh_file_name);
  443. // first try to load it with a plugin
  444. for (unsigned int i = 0; i<plugins.size(); ++i)
  445. if (plugins[i]->save(mesh_file_name_string))
  446. return true;
  447. size_t last_dot = mesh_file_name_string.rfind('.');
  448. if (last_dot == std::string::npos)
  449. {
  450. // No file type determined
  451. printf("Error: No file extension found in %s\n",mesh_file_name);
  452. return false;
  453. }
  454. std::string extension = mesh_file_name_string.substr(last_dot+1);
  455. if (extension == "off" || extension =="OFF")
  456. {
  457. return igl::writeOFF(mesh_file_name_string,data.V,data.F);
  458. }
  459. else if (extension == "obj" || extension =="OBJ")
  460. {
  461. Eigen::MatrixXd corner_normals;
  462. Eigen::MatrixXi fNormIndices;
  463. Eigen::MatrixXd UV_V;
  464. Eigen::MatrixXi UV_F;
  465. return igl::writeOBJ(mesh_file_name_string, data.V,
  466. data.F, corner_normals, fNormIndices, UV_V, UV_F);
  467. }
  468. else
  469. {
  470. // unrecognized file type
  471. printf("Error: %s is not a recognized file type.\n",extension.c_str());
  472. return false;
  473. }
  474. return true;
  475. }
  476. void Viewer::clear()
  477. {
  478. data.clear();
  479. }
  480. bool Viewer::key_down(unsigned char key, int modifiers)
  481. {
  482. if (callback_key_down)
  483. if (callback_key_down(*this,key,modifiers))
  484. return true;
  485. for (unsigned int i = 0; i<plugins.size(); ++i)
  486. if (plugins[i]->key_down(key, modifiers))
  487. return true;
  488. if (key == 'S')
  489. mouse_scroll(1);
  490. if (key == 'A')
  491. mouse_scroll(-1);
  492. // Why aren't these handled view AntTweakBar?
  493. if (key == 'z') // Don't use 'Z' because that clobbers snap_to_canonical_view_quat
  494. options.trackball_angle << 0.0f, 0.0f, 0.0f, 1.0f;
  495. if (key == 'y')
  496. options.trackball_angle << -sqrt(2.0f)/2.0f, 0.0f, 0.0f, sqrt(2.0f)/2.0f;
  497. if (key == 'x')
  498. options.trackball_angle << -0.5f, -0.5f, -0.5f, 0.5f;
  499. return false;
  500. }
  501. bool Viewer::key_up(unsigned char key, int modifiers)
  502. {
  503. if (callback_key_up)
  504. if (callback_key_up(*this,key,modifiers))
  505. return true;
  506. for (unsigned int i = 0; i<plugins.size(); ++i)
  507. if (plugins[i]->key_up(key, modifiers))
  508. return true;
  509. return false;
  510. }
  511. bool Viewer::mouse_down(MouseButton button, int modifier)
  512. {
  513. if (callback_mouse_down)
  514. if (callback_mouse_down(*this,button,modifier))
  515. return true;
  516. for (unsigned int i = 0; i<plugins.size(); ++i)
  517. if (plugins[i]->mouse_down(button,modifier))
  518. return true;
  519. down = true;
  520. down_mouse_x = current_mouse_x;
  521. down_mouse_y = current_mouse_y;
  522. down_translation = options.model_translation;
  523. // Initialization code for the trackball
  524. Eigen::RowVector3d center;
  525. if (data.V.rows() == 0)
  526. center << 0,0,0;
  527. else
  528. center = data.V.colwise().sum()/data.V.rows();
  529. Eigen::Vector3f coord = igl::project(Eigen::Vector3f(center(0),center(1),center(2)), options.view * options.model, options.proj, options.viewport);
  530. down_mouse_z = coord[2];
  531. down_rotation = options.trackball_angle;
  532. mouse_mode = ROTATION;
  533. switch (button)
  534. {
  535. case IGL_LEFT:
  536. mouse_mode = ROTATION;
  537. break;
  538. case IGL_RIGHT:
  539. mouse_mode = TRANSLATE;
  540. break;
  541. default:
  542. mouse_mode = NOTHING;
  543. break;
  544. }
  545. return true;
  546. }
  547. bool Viewer::mouse_up(MouseButton button, int modifier)
  548. {
  549. down = false;
  550. if (callback_mouse_up)
  551. if (callback_mouse_up(*this,button,modifier))
  552. return true;
  553. for (unsigned int i = 0; i<plugins.size(); ++i)
  554. if (plugins[i]->mouse_up(button,modifier))
  555. return true;
  556. mouse_mode = NOTHING;
  557. return true;
  558. }
  559. bool Viewer::mouse_move(int mouse_x, int mouse_y)
  560. {
  561. if(hack_never_moved)
  562. {
  563. down_mouse_x = mouse_x;
  564. down_mouse_y = mouse_y;
  565. hack_never_moved = false;
  566. }
  567. current_mouse_x = mouse_x;
  568. current_mouse_y = mouse_y;
  569. if (callback_mouse_move)
  570. if (callback_mouse_move(*this,mouse_x,mouse_y))
  571. return true;
  572. for (unsigned int i = 0; i<plugins.size(); ++i)
  573. if (plugins[i]->mouse_move(mouse_x, mouse_y))
  574. return true;
  575. if (down)
  576. {
  577. switch (mouse_mode)
  578. {
  579. case ROTATION :
  580. {
  581. igl::trackball(options.viewport(2),
  582. options.viewport(3),
  583. 2.0f,
  584. down_rotation.data(),
  585. down_mouse_x,
  586. down_mouse_y,
  587. mouse_x,
  588. mouse_y,
  589. options.trackball_angle.data());
  590. //Eigen::Vector4f snapq = options.trackball_angle;
  591. break;
  592. }
  593. case TRANSLATE:
  594. {
  595. //translation
  596. Eigen::Vector3f pos1 = igl::unproject(Eigen::Vector3f(mouse_x, options.viewport[3] - mouse_y, down_mouse_z), options.view * options.model, options.proj, options.viewport);
  597. Eigen::Vector3f pos0 = igl::unproject(Eigen::Vector3f(down_mouse_x, options.viewport[3] - down_mouse_y, down_mouse_z), options.view * options.model, options.proj, options.viewport);
  598. Eigen::Vector3f diff = pos1 - pos0;
  599. options.model_translation = down_translation + Eigen::Vector3f(diff[0],diff[1],diff[2]);
  600. break;
  601. }
  602. case ZOOM:
  603. {
  604. //float delta = 0.001f * (mouse_x - down_mouse_x + mouse_y - down_mouse_y);
  605. float delta = 0.001f * (mouse_x - down_mouse_x + mouse_y - down_mouse_y);
  606. options.camera_zoom *= 1 + delta;
  607. down_mouse_x = mouse_x;
  608. down_mouse_y = mouse_y;
  609. break;
  610. }
  611. default:
  612. break;
  613. }
  614. }
  615. return true;
  616. }
  617. bool Viewer::mouse_scroll(float delta_y)
  618. {
  619. scroll_position += delta_y;
  620. if (callback_mouse_scroll)
  621. if (callback_mouse_scroll(*this,delta_y))
  622. return true;
  623. for (unsigned int i = 0; i<plugins.size(); ++i)
  624. if (plugins[i]->mouse_scroll(delta_y))
  625. return true;
  626. // Only zoom if there's actually a change
  627. if(delta_y != 0)
  628. {
  629. float mult = (1.0+((delta_y>0)?1.:-1.)*0.05);
  630. const float min_zoom = 0.1f;
  631. options.camera_zoom = (options.camera_zoom * mult > min_zoom ? options.camera_zoom * mult : min_zoom);
  632. }
  633. return true;
  634. }
  635. void Viewer::draw()
  636. {
  637. using namespace std;
  638. using namespace Eigen;
  639. options.clear_framebuffers();
  640. if (callback_pre_draw)
  641. if (callback_pre_draw(*this))
  642. return;
  643. for (unsigned int i = 0; i<plugins.size(); ++i)
  644. if (plugins[i]->pre_draw())
  645. return;
  646. options.draw(data,opengl);
  647. if (callback_post_draw)
  648. if (callback_post_draw(*this))
  649. return;
  650. for (unsigned int i = 0; i<plugins.size(); ++i)
  651. if (plugins[i]->post_draw())
  652. break;
  653. TwDraw();
  654. }
  655. bool Viewer::save_scene()
  656. {
  657. #ifdef ENABLE_XML_SERIALIZATION
  658. string fname = igl::file_dialog_save();
  659. if (fname.length() == 0)
  660. return false;
  661. ::igl::XMLSerializer serializer("Viewer");
  662. serializer.Add(data,"Data");
  663. serializer.Add(options,"Options");
  664. if (plugin_manager)
  665. for (unsigned int i = 0; i <plugin_manager->plugin_list.size(); ++i)
  666. serializer.Add(*(plugin_manager->plugin_list[i]),plugin_manager->plugin_list[i]->plugin_name);
  667. serializer.Save(fname.c_str(),true);
  668. #endif
  669. return true;
  670. }
  671. bool Viewer::load_scene()
  672. {
  673. #ifdef ENABLE_XML_SERIALIZATION
  674. string fname = igl::file_dialog_open();
  675. if (fname.length() == 0)
  676. return false;
  677. ::igl::XMLSerializer serializer("Viewer");
  678. serializer.Add(data,"Data");
  679. serializer.Add(options,"Options");
  680. if (plugin_manager)
  681. for (unsigned int i = 0; i <plugin_manager->plugin_list.size(); ++i)
  682. serializer.Add(*(plugin_manager->plugin_list[i]),plugin_manager->plugin_list[i]->plugin_name);
  683. serializer.Load(fname.c_str());
  684. #endif
  685. return true;
  686. }
  687. void Viewer::resize(int w, int h)
  688. {
  689. options.viewport = Eigen::Vector4f(0,0,w,h);
  690. }
  691. void TW_CALL Viewer::snap_to_canonical_quaternion_cb(void *clientData)
  692. {
  693. Eigen::Vector4f snapq = static_cast<Viewer *>(clientData)->options.trackball_angle;
  694. igl::snap_to_canonical_view_quat<float>(snapq.data(),1,static_cast<Viewer *>(clientData)->options.trackball_angle.data());
  695. }
  696. void TW_CALL Viewer::align_camera_center_cb(void *clientData)
  697. {
  698. static_cast<Viewer *>(clientData)->options.align_camera_center(static_cast<Viewer *>(clientData)->data.V);
  699. }
  700. void TW_CALL Viewer::save_scene_cb(void *clientData)
  701. {
  702. static_cast<Viewer *>(clientData)->save_scene();
  703. }
  704. void TW_CALL Viewer::load_scene_cb(void *clientData)
  705. {
  706. static_cast<Viewer *>(clientData)->load_scene();
  707. }
  708. void TW_CALL Viewer::set_invert_normals_cb(const void *param, void *clientData)
  709. {
  710. Viewer *viewer = static_cast<Viewer *>(clientData);
  711. viewer->data.dirty |= ViewerData::DIRTY_NORMAL;
  712. viewer->options.invert_normals = *((bool *) param);
  713. }
  714. void TW_CALL Viewer::get_invert_normals_cb(void *param, void *clientData)
  715. {
  716. *((bool *) param) = static_cast<Viewer *>(clientData)->options.invert_normals;
  717. }
  718. void TW_CALL Viewer::set_face_based_cb(const void *param, void *clientData)
  719. {
  720. Viewer *viewer = static_cast<Viewer *>(clientData);
  721. viewer->set_face_based(*((bool *) param));
  722. }
  723. void TW_CALL Viewer::get_face_based_cb(void *param, void *clientData)
  724. {
  725. *((bool *) param) = static_cast<Viewer *>(clientData)->data.face_based;
  726. }
  727. void TW_CALL Viewer::open_dialog_mesh(void *clientData)
  728. {
  729. std::string fname = igl::file_dialog_open();
  730. if (fname.length() == 0)
  731. return;
  732. static_cast<Viewer *>(clientData)->load_mesh_from_file(fname.c_str());
  733. }
  734. void Viewer::set_face_based(bool newvalue)
  735. {
  736. data.set_face_based(newvalue);
  737. }
  738. void Viewer::compute_normals()
  739. {
  740. data.compute_normals();
  741. }
  742. void Viewer::set_mesh(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F)
  743. {
  744. data.set_mesh(V,F);
  745. options.align_camera_center(V);
  746. }
  747. void Viewer::set_vertices(const Eigen::MatrixXd& V)
  748. {
  749. data.set_vertices(V);
  750. }
  751. void Viewer::set_normals(const Eigen::MatrixXd& N)
  752. {
  753. data.set_normals(N);
  754. }
  755. void Viewer::set_colors(const Eigen::MatrixXd &C)
  756. {
  757. data.set_colors(C);
  758. }
  759. void Viewer::set_uv(const Eigen::MatrixXd& UV)
  760. {
  761. data.set_uv(UV);
  762. }
  763. void Viewer::set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F)
  764. {
  765. data.set_uv(UV_V,UV_F);
  766. }
  767. void Viewer::set_texture(
  768. const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& R,
  769. const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& G,
  770. const Eigen::Matrix<char,Eigen::Dynamic,Eigen::Dynamic>& B)
  771. {
  772. data.set_texture(R,G,B);
  773. }
  774. void Viewer::add_points(const Eigen::MatrixXd& P, const Eigen::MatrixXd& C)
  775. {
  776. data.add_points(P,C);
  777. }
  778. void Viewer::set_edges(
  779. const Eigen::MatrixXd& P,
  780. const Eigen::MatrixXi& E,
  781. const Eigen::MatrixXd& C)
  782. {
  783. data.set_edges(P,E,C);
  784. }
  785. void Viewer::add_edges(const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C)
  786. {
  787. data.add_edges(P1,P2,C);
  788. }
  789. void Viewer::add_label(const Eigen::VectorXd& P, const std::string& str)
  790. {
  791. data.add_label(P,str);
  792. }
  793. int Viewer::launch(std::string filename)
  794. {
  795. GLFWwindow* window;
  796. glfwSetErrorCallback(glfw_error_callback);
  797. if (!glfwInit())
  798. return EXIT_FAILURE;
  799. glfwWindowHint(GLFW_SAMPLES, 16);
  800. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  801. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
  802. #ifdef __APPLE__
  803. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  804. glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
  805. #endif
  806. window = glfwCreateWindow(1280, 800, "IGL Viewer", NULL, NULL);
  807. if (!window)
  808. {
  809. glfwTerminate();
  810. return EXIT_FAILURE;
  811. }
  812. glfwMakeContextCurrent(window);
  813. #ifndef __APPLE__
  814. glewExperimental = true;
  815. GLenum err = glewInit();
  816. if (GLEW_OK != err)
  817. {
  818. /* Problem: glewInit failed, something is seriously wrong. */
  819. fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
  820. }
  821. fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
  822. #endif
  823. #ifdef DEBUG
  824. int major, minor, rev;
  825. major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
  826. minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
  827. rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);
  828. printf("OpenGL version recieved: %d.%d.%d\n", major, minor, rev);
  829. printf("Supported OpenGL is %s\n", (const char*)glGetString(GL_VERSION));
  830. printf("Supported GLSL is %s\n", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
  831. #endif
  832. glfwSetInputMode(window,GLFW_CURSOR,GLFW_CURSOR_NORMAL);
  833. // Initialize AntTweakBar
  834. TwInit(TW_OPENGL_CORE, NULL);
  835. // Initialize IGL viewer
  836. init();
  837. __viewer = this;
  838. // Register callbacks
  839. glfwSetKeyCallback(window, glfw_key_callback); glfwSetCursorPosCallback(window,glfw_mouse_move); glfwSetWindowSizeCallback(window,glfw_window_size); glfwSetMouseButtonCallback(window,glfw_mouse_press); glfwSetScrollCallback(window,glfw_mouse_scroll); glfwSetCharCallback(window, glfw_char_callback);
  840. // Handle retina displays (windows and mac)
  841. int width, height;
  842. glfwGetFramebufferSize(window, &width, &height);
  843. int width_window, height_window;
  844. glfwGetWindowSize(window, &width_window, &height_window);
  845. highdpi = width/width_window;
  846. glfw_window_size(window,width_window,height_window);
  847. opengl.init();
  848. // Load the mesh passed as input
  849. if (filename.size() > 0)
  850. load_mesh_from_file(filename.c_str());
  851. // Rendering loop
  852. while (!glfwWindowShouldClose(window))
  853. {
  854. double tic = get_seconds();
  855. draw();
  856. glfwSwapBuffers(window);
  857. if(options.is_animating)
  858. {
  859. glfwPollEvents();
  860. // In microseconds
  861. double duration = 1000000.*(get_seconds()-tic);
  862. const double min_duration = 1000000./options.animation_max_fps;
  863. if(duration<min_duration)
  864. {
  865. // TODO: windows equivalent
  866. usleep(min_duration-duration);
  867. }
  868. }
  869. else
  870. {
  871. glfwWaitEvents();
  872. }
  873. }
  874. opengl.free();
  875. options.shut();
  876. shutdown_plugins();
  877. glfwDestroyWindow(window);
  878. glfwTerminate();
  879. return EXIT_SUCCESS;
  880. }
  881. } // end namespace