example.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  1. #include <igl/Viewport.h>
  2. #include <igl/report_gl_error.h>
  3. #include <igl/ReAntTweakBar.h>
  4. #include <igl/trackball.h>
  5. #include <igl/two_axis_valuator_fixed_up.h>
  6. #include <igl/PI.h>
  7. #include <igl/EPS.h>
  8. #include <igl/get_seconds.h>
  9. #include <igl/draw_floor.h>
  10. #include <Eigen/Core>
  11. #include <Eigen/Geometry>
  12. #ifdef WIN32
  13. #include <GL/glut.h>
  14. #else
  15. #include <GLUT/glut.h>
  16. #endif
  17. #include <vector>
  18. #include <stack>
  19. #include <iostream>
  20. #include <algorithm>
  21. class Camera
  22. {
  23. public:
  24. // m_zoom Zoom of camera lens {1}
  25. // m_angle Field of view angle in degrees {45}
  26. // m_aspect Aspect ratio {1}
  27. // m_near near clipping plane {1e-2}
  28. // m_far far clipping plane {100}
  29. // m_at_dist distance of looking at point {1}
  30. // m_rotation Rotation part of rigid transformation of camera {identity}.
  31. // Note that this seems to the inverse of what's stored in the old
  32. // igl::Camera class.
  33. // m_translation Translation part of rigid transformation of camera
  34. // {(0,0,1)}
  35. double m_zoom, m_angle, m_aspect, m_near, m_far, m_at_dist;
  36. Eigen::Quaterniond m_rotation;
  37. Eigen::Vector3d m_translation;
  38. Camera():
  39. m_zoom(1),m_angle(45.0),m_aspect(1),m_near(1e-2),m_far(100),m_at_dist(1),
  40. m_rotation(1,0,0,0),
  41. m_translation(0,0,1)
  42. {
  43. }
  44. // Return projection matrix that takes relative camera coordinates and
  45. // transforms it to viewport coordinates
  46. Eigen::Matrix4d projection() const
  47. {
  48. Eigen::Matrix4d P;
  49. using namespace std;
  50. using namespace igl;
  51. // http://stackoverflow.com/a/3738696/148668
  52. const double yScale = tan(PI*0.5 - 0.5*m_angle*PI/180.);
  53. // http://stackoverflow.com/a/14975139/148668
  54. const double xScale = yScale/m_aspect;
  55. P<<
  56. xScale, 0, 0, 0,
  57. 0, yScale, 0, 0,
  58. 0, 0, -(m_far+m_near)/(m_far-m_near), -1,
  59. 0, 0, -2.*m_near*m_far/(m_far-m_near), 0;
  60. return P.transpose();
  61. }
  62. // Return an Affine transformation that takes a world 3d coordinate and
  63. // transforms it into the relative camera coordinates.
  64. Eigen::Affine3d affine() const
  65. {
  66. using namespace Eigen;
  67. Affine3d t = Affine3d::Identity();
  68. t.rotate(m_rotation);
  69. t.translate(m_translation);
  70. return t;
  71. }
  72. // Returns world coordinates position of center or "eye" of camera.
  73. Eigen::Vector3d eye() const
  74. {
  75. using namespace Eigen;
  76. return affine() * Vector3d(0,0,0);
  77. }
  78. // Returns world coordinate position of a point "eye" is looking at.
  79. Eigen::Vector3d at() const
  80. {
  81. using namespace Eigen;
  82. return affine() * (Vector3d(0,0,-1)*m_at_dist);
  83. }
  84. // Returns world coordinate unit vector of "up" vector
  85. Eigen::Vector3d up() const
  86. {
  87. using namespace Eigen;
  88. Affine3d t = Affine3d::Identity();
  89. t.rotate(m_rotation);
  90. return t * Vector3d(0,1,0);
  91. }
  92. // Move dv in the relative coordinate frame of the camera (move the FPS)
  93. //
  94. // Inputs:
  95. // dv (x,y,z) displacement vector
  96. //
  97. void dolly(const Eigen::Vector3d & dv)
  98. {
  99. m_translation += dv;
  100. }
  101. // "Scale zoom": Move `eye`, but leave `at`
  102. //
  103. // Input:
  104. // s amount to scale distance to at
  105. void push_away(const double s)
  106. {
  107. using namespace Eigen;
  108. using namespace igl;
  109. #ifndef NDEBUG
  110. Vector3d old_at = at();
  111. #endif
  112. const double old_at_dist = m_at_dist;
  113. m_at_dist = old_at_dist * s;
  114. dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist));
  115. assert((old_at-at()).squaredNorm() < DOUBLE_EPS);
  116. }
  117. // Turn around eye so that rotation is now q
  118. //
  119. // Inputs:
  120. // q new rotation as quaternion
  121. void turn_eye(const Eigen::Quaterniond & q)
  122. {
  123. using namespace Eigen;
  124. using namespace igl;
  125. Vector3d old_eye = eye();
  126. // eye should be fixed
  127. //
  128. // eye_1 = R_1 * t_1 = eye_0
  129. // t_1 = R_1' * eye_0
  130. m_rotation = q;
  131. m_translation = m_rotation.conjugate() * old_eye;
  132. assert((old_eye - eye()).squaredNorm() < DOUBLE_EPS);
  133. }
  134. // Orbit around at so that rotation is now q
  135. //
  136. // Inputs:
  137. // q new rotation as quaternion
  138. void orbit(const Eigen::Quaterniond & q)
  139. {
  140. using namespace Eigen;
  141. using namespace igl;
  142. #ifndef NDEBUG
  143. Vector3d old_at = at();
  144. #endif
  145. // at should be fixed
  146. //
  147. // at_1 = R_1 * t_1 - R_1 * z = at_0
  148. // t_1 = R_1' * (at_0 + R_1 * z)
  149. m_rotation = q;
  150. m_translation =
  151. m_rotation.conjugate() *
  152. (old_at +
  153. m_rotation * Vector3d(0,0,1) * m_at_dist);
  154. assert((old_at - at()).squaredNorm() < DOUBLE_EPS);
  155. }
  156. // Aka "Hitchcock", "Vertigo", "Spielberg" or "Trombone" zoom:
  157. // simultaneously dolly while changing angle so that `at` not only stays
  158. // put in relative coordinates but also projected coordinates. That is
  159. //
  160. // Inputs:
  161. // da change in angle in degrees
  162. void dolly_zoom(const double da)
  163. {
  164. using namespace std;
  165. using namespace igl;
  166. using namespace Eigen;
  167. #ifndef NDEBUG
  168. Vector3d old_at = at();
  169. #endif
  170. const double old_angle = m_angle;
  171. m_angle += da;
  172. m_angle = min(89.,max(5.,m_angle));
  173. const double s =
  174. (2.*tan(old_angle/2./180.*M_PI)) /
  175. (2.*tan(m_angle/2./180.*M_PI)) ;
  176. const double old_at_dist = m_at_dist;
  177. m_at_dist = old_at_dist * s;
  178. dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist));
  179. assert((old_at-at()).squaredNorm() < DOUBLE_EPS);
  180. }
  181. // Return top right corner of unit plane in relative coordinates, that is
  182. // (w/2,h/2,1)
  183. Eigen::Vector3d unit_plane() const
  184. {
  185. using namespace igl;
  186. // Distance of center pixel to eye
  187. const double d = 1.0;
  188. const double a = m_aspect;
  189. const double theta = m_angle*PI/180.;
  190. const double w =
  191. 2.*sqrt(-d*d/(a*a*pow(tan(0.5*theta),2.)-1.))*a*tan(0.5*theta);
  192. const double h = w/a;
  193. return Eigen::Vector3d(w*0.5,h*0.5,-d);
  194. }
  195. // Rotate and translate so that camera is situated at "eye" looking at "at"
  196. // with "up" pointing up.
  197. //
  198. // Inputs:
  199. // eye (x,y,z) coordinates of eye position
  200. // at (x,y,z) coordinates of at position
  201. // up (x,y,z) coordinates of up vector
  202. void look_at(
  203. const Eigen::Vector3d & eye,
  204. const Eigen::Vector3d & at,
  205. const Eigen::Vector3d & up)
  206. {
  207. using namespace Eigen;
  208. using namespace std;
  209. using namespace igl;
  210. // http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml
  211. // Normalize vector from at to eye
  212. Vector3d F = eye-at;
  213. m_at_dist = F.norm();
  214. F.normalize();
  215. // Project up onto plane orthogonal to F and normalize
  216. const Vector3d proj_up = (up-(up.dot(F))*F).normalized();
  217. Quaterniond a,b;
  218. a.setFromTwoVectors(Vector3d(0,0,-1),-F);
  219. b.setFromTwoVectors(a*Vector3d(0,1,0),proj_up);
  220. m_rotation = a*b;
  221. m_translation = m_rotation.conjugate() * eye;
  222. assert( (eye-this->eye()).squaredNorm() < DOUBLE_EPS);
  223. assert((F-(this->eye()-this->at()).normalized()).squaredNorm() <
  224. DOUBLE_EPS);
  225. assert( (at-this->at()).squaredNorm() < DOUBLE_EPS);
  226. assert( (proj_up-this->up()).squaredNorm() < DOUBLE_EPS);
  227. }
  228. };
  229. enum RotationType
  230. {
  231. ROTATION_TYPE_IGL_TRACKBALL = 0,
  232. ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1,
  233. NUM_ROTATION_TYPES = 2,
  234. } rotation_type = ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP;
  235. enum CenterType
  236. {
  237. CENTER_TYPE_ORBIT = 0,
  238. CENTER_TYPE_FPS = 1,
  239. NUM_CENTER_TYPES = 2,
  240. } center_type = CENTER_TYPE_ORBIT;
  241. int width,height;
  242. #define REBAR_NAME "temp.rbr"
  243. igl::ReTwBar rebar;
  244. struct State
  245. {
  246. int viewing_camera;
  247. std::vector<Camera> cameras;
  248. std::vector<GLuint> tex_ids;
  249. std::vector<GLuint> fbo_ids;
  250. std::vector<GLuint> dfbo_ids;
  251. State():viewing_camera(0),cameras(4),
  252. tex_ids(cameras.size()),
  253. fbo_ids(cameras.size()),
  254. dfbo_ids(cameras.size())
  255. {}
  256. } s;
  257. const Eigen::Vector4d back(1,1,1,1);
  258. std::stack<State> undo_stack;
  259. bool is_rotating = false;
  260. Camera down_camera;
  261. int down_x,down_y;
  262. std::stack<State> redo_stack;
  263. void push_undo()
  264. {
  265. undo_stack.push(s);
  266. // Clear
  267. redo_stack = std::stack<State>();
  268. }
  269. void undo()
  270. {
  271. if(!undo_stack.empty())
  272. {
  273. redo_stack.push(s);
  274. s = undo_stack.top();
  275. undo_stack.pop();
  276. }
  277. }
  278. void redo()
  279. {
  280. if(!redo_stack.empty())
  281. {
  282. undo_stack.push(s);
  283. s = redo_stack.top();
  284. redo_stack.pop();
  285. }
  286. }
  287. void print(const Camera & camera)
  288. {
  289. using namespace std;
  290. cout<<
  291. "rotation: "<<camera.m_rotation.coeffs().transpose()<<endl<<
  292. "translation: "<<camera.m_translation.transpose()<<endl<<
  293. "eye: "<<camera.eye().transpose()<<endl<<
  294. "at: "<<camera.at().transpose()<<endl<<
  295. "up: "<<camera.up().transpose()<<endl<<
  296. endl;
  297. }
  298. void init_cameras()
  299. {
  300. using namespace Eigen;
  301. using namespace std;
  302. s.cameras[0].look_at(
  303. Vector3d(0,0,1),
  304. Vector3d(0,0,0),
  305. Vector3d(0,1,0));
  306. s.cameras[1].look_at(
  307. Vector3d(0,0,-1),
  308. Vector3d(0,0,0),
  309. Vector3d(0,1,0));
  310. s.cameras[2].look_at(
  311. Vector3d(-2,0,0),
  312. Vector3d(0,0,0),
  313. Vector3d(0,1,0));
  314. s.cameras[3].look_at(
  315. Vector3d(3,0,0),
  316. Vector3d(0,0,0),
  317. Vector3d(0,1,0));
  318. }
  319. bool init_render_to_texture(
  320. const int width,
  321. const int height,
  322. GLuint & tex_id,
  323. GLuint & fbo_id,
  324. GLuint & dfbo_id)
  325. {
  326. using namespace igl;
  327. using namespace std;
  328. // Set up a "render-to-texture" frame buffer and texture combo
  329. glDeleteTextures(1,&tex_id);
  330. glDeleteFramebuffersEXT(1,&fbo_id);
  331. glDeleteFramebuffersEXT(1,&dfbo_id);
  332. // http://www.opengl.org/wiki/Framebuffer_Object_Examples#Quick_example.2C_render_to_texture_.282D.29
  333. glGenTextures(1, &tex_id);
  334. glBindTexture(GL_TEXTURE_2D, tex_id);
  335. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  336. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  337. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  338. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  339. //NULL means reserve texture memory, but texels are undefined
  340. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
  341. glBindTexture(GL_TEXTURE_2D, 0);
  342. //-------------------------
  343. glGenFramebuffersEXT(1, &fbo_id);
  344. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id);
  345. //Attach 2D texture to this FBO
  346. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex_id, 0);
  347. glGenRenderbuffersEXT(1, &dfbo_id);
  348. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, dfbo_id);
  349. glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height);
  350. //-------------------------
  351. //Attach depth buffer to FBO
  352. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, dfbo_id);
  353. //-------------------------
  354. //Does the GPU support current FBO configuration?
  355. GLenum status;
  356. status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  357. switch(status)
  358. {
  359. case GL_FRAMEBUFFER_COMPLETE_EXT:
  360. break;
  361. default:
  362. return false;
  363. }
  364. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
  365. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  366. return true;
  367. }
  368. void reshape(int width, int height)
  369. {
  370. ::width = width;
  371. ::height = height;
  372. glViewport(0,0,width,height);
  373. // Send the new window size to AntTweakBar
  374. TwWindowSize(width, height);
  375. }
  376. void draw_scene(const Camera & v_camera,
  377. const bool render_to_texture,
  378. const GLuint & v_tex_id,
  379. const GLuint & v_fbo_id,
  380. const GLuint & v_dfbo_id)
  381. {
  382. using namespace igl;
  383. using namespace std;
  384. using namespace Eigen;
  385. if(render_to_texture)
  386. {
  387. // render to framebuffer
  388. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, v_fbo_id);
  389. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, v_dfbo_id);
  390. glClearColor(back(0),back(1),back(2),1);
  391. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  392. }
  393. glMatrixMode(GL_PROJECTION);
  394. glPushMatrix();
  395. glLoadIdentity();
  396. //gluPerspective(v_camera.m_angle,v_camera.m_aspect,v_camera.m_near,v_camera.m_far);
  397. glMultMatrixd(v_camera.projection().data());
  398. glMatrixMode(GL_MODELVIEW);
  399. glPushMatrix();
  400. glLoadIdentity();
  401. gluLookAt(
  402. v_camera.eye()(0), v_camera.eye()(1), v_camera.eye()(2),
  403. v_camera.at()(0), v_camera.at()(1), v_camera.at()(2),
  404. v_camera.up()(0), v_camera.up()(1), v_camera.up()(2));
  405. for(int c = 0;c<(int)s.cameras.size();c++)
  406. {
  407. auto & camera = s.cameras[c];
  408. if(&v_camera == &camera)
  409. {
  410. continue;
  411. }
  412. // draw camera
  413. glPushMatrix();
  414. glMultMatrixd(camera.affine().matrix().data());
  415. // eye
  416. glColor4f(0,0,0,1);
  417. glPointSize(10.f);
  418. glBegin(GL_POINTS);
  419. glVertex3f(0,0,0);
  420. glEnd();
  421. // frustrum
  422. const Vector3d u = camera.unit_plane();
  423. glBegin(GL_LINES);
  424. for(int x = -1;x<=1;x+=2)
  425. {
  426. for(int y = -1;y<=1;y+=2)
  427. {
  428. glVertex3f(0,0,0);
  429. glVertex3f(x*u(0),y*u(1),u(2));
  430. }
  431. }
  432. glEnd();
  433. const Vector3d n = u*(camera.m_near-FLOAT_EPS);
  434. glBegin(GL_QUADS);
  435. glVertex3f( n(0),-n(1),n(2));
  436. glVertex3f(-n(0),-n(1),n(2));
  437. glVertex3f(-n(0), n(1),n(2));
  438. glVertex3f( n(0), n(1),n(2));
  439. glEnd();
  440. for(int pass = 0;pass<2;pass++)
  441. {
  442. switch(pass)
  443. {
  444. case 1:
  445. glColor4f(1,1,1,0.5);
  446. glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
  447. //glEnable(GL_BLEND);
  448. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  449. glEnable(GL_TEXTURE_2D);
  450. glBindTexture(GL_TEXTURE_2D,s.tex_ids[c]);
  451. break;
  452. default:
  453. case 0:
  454. glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
  455. glColor4f(0,0,0,1);
  456. break;
  457. }
  458. glBegin(GL_QUADS);
  459. glTexCoord2d(1,0);
  460. glVertex3f( 0.5*u(0),-0.5*u(1),0.5*u(2));
  461. glTexCoord2d(0,0);
  462. glVertex3f(-0.5*u(0),-0.5*u(1),0.5*u(2));
  463. glTexCoord2d(0,1);
  464. glVertex3f(-0.5*u(0), 0.5*u(1),0.5*u(2));
  465. glTexCoord2d(1,1);
  466. glVertex3f( 0.5*u(0), 0.5*u(1),0.5*u(2));
  467. glEnd();
  468. switch(pass)
  469. {
  470. case 1:
  471. glBindTexture(GL_TEXTURE_2D, 0);
  472. glDisable(GL_TEXTURE_2D);
  473. glDisable(GL_BLEND);
  474. break;
  475. default:
  476. break;
  477. }
  478. }
  479. glPopMatrix();
  480. }
  481. glDisable(GL_LIGHTING);
  482. glEnable(GL_COLOR_MATERIAL);
  483. glLineWidth(3.f);
  484. glColor4f(1,0,1,1);
  485. glutWireCube(0.25);
  486. glColor4f(1,0.5,0.5,1);
  487. //glutWireSphere(0.125,20,20);
  488. {
  489. glPushMatrix();
  490. glTranslated(0,-1,0);
  491. draw_floor();
  492. glPopMatrix();
  493. }
  494. // Axes
  495. for(int d = 0;d<3;d++)
  496. {
  497. glColor4f(d==0,d==1,d==2,1);
  498. glBegin(GL_LINES);
  499. glVertex3f(0,0,0);
  500. glVertex3f(d==0,d==1,d==2);
  501. glEnd();
  502. }
  503. glMatrixMode(GL_PROJECTION);
  504. glPopMatrix();
  505. glMatrixMode(GL_MODELVIEW);
  506. glPopMatrix();
  507. report_gl_error();
  508. if(render_to_texture)
  509. {
  510. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  511. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
  512. }
  513. }
  514. void display()
  515. {
  516. using namespace igl;
  517. using namespace std;
  518. using namespace Eigen;
  519. glClearColor(back(0),back(1),back(2),0);
  520. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  521. glEnable(GL_DEPTH_TEST);
  522. // Update aspect ratios (may have changed since undo/redo)
  523. {
  524. const double aspect = (double)width/(double)height;
  525. for(int c = 0;c<(int)s.cameras.size();c++)
  526. {
  527. auto & camera = s.cameras[c];
  528. auto & tex_id = s.tex_ids[c];
  529. auto & fbo_id = s.fbo_ids[c];
  530. auto & dfbo_id = s.dfbo_ids[c];
  531. if(aspect != camera.m_aspect)
  532. {
  533. cout<<"Initializing camera #"<<c<<"..."<<endl;
  534. camera.m_aspect = aspect;
  535. bool ret = init_render_to_texture(width,height,tex_id,fbo_id,dfbo_id);
  536. assert(ret);
  537. }
  538. draw_scene(camera,true,tex_id,fbo_id,dfbo_id);
  539. }
  540. }
  541. {
  542. auto & camera = s.cameras[s.viewing_camera];
  543. draw_scene(camera,false,0,0,0);
  544. }
  545. TwDraw();
  546. glutSwapBuffers();
  547. glutPostRedisplay();
  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.cameras[s.viewing_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. }
  589. void mouse(int glutButton, int glutState, int mouse_x, int mouse_y)
  590. {
  591. using namespace std;
  592. using namespace Eigen;
  593. using namespace igl;
  594. bool tw_using = TwEventMouseButtonGLUT(glutButton,glutState,mouse_x,mouse_y);
  595. switch(glutButton)
  596. {
  597. case GLUT_RIGHT_BUTTON:
  598. case GLUT_LEFT_BUTTON:
  599. {
  600. switch(glutState)
  601. {
  602. case 1:
  603. // up
  604. glutSetCursor(GLUT_CURSOR_INHERIT);
  605. is_rotating = false;
  606. break;
  607. case 0:
  608. if(!tw_using)
  609. {
  610. push_undo();
  611. glutSetCursor(GLUT_CURSOR_CYCLE);
  612. // collect information for trackball
  613. is_rotating = true;
  614. down_camera = s.cameras[s.viewing_camera];
  615. down_x = mouse_x;
  616. down_y = mouse_y;
  617. }
  618. break;
  619. }
  620. break;
  621. // Scroll down
  622. case GLUT_WHEEL_DOWN:
  623. {
  624. mouse_wheel(0,-1,mouse_x,mouse_y);
  625. break;
  626. }
  627. // Scroll up
  628. case GLUT_WHEEL_UP:
  629. {
  630. mouse_wheel(0,1,mouse_x,mouse_y);
  631. break;
  632. }
  633. // Scroll left
  634. case GLUT_WHEEL_LEFT:
  635. {
  636. mouse_wheel(1,-1,mouse_x,mouse_y);
  637. break;
  638. }
  639. // Scroll right
  640. case GLUT_WHEEL_RIGHT:
  641. {
  642. mouse_wheel(1,1,mouse_x,mouse_y);
  643. break;
  644. }
  645. }
  646. }
  647. }
  648. void mouse_drag(int mouse_x, int mouse_y)
  649. {
  650. using namespace igl;
  651. using namespace std;
  652. using namespace Eigen;
  653. /*bool tw_using =*/ TwMouseMotion(mouse_x,mouse_y);
  654. if(is_rotating)
  655. {
  656. glutSetCursor(GLUT_CURSOR_CYCLE);
  657. auto & camera = s.cameras[s.viewing_camera];
  658. Quaterniond q;
  659. switch(rotation_type)
  660. {
  661. case ROTATION_TYPE_IGL_TRACKBALL:
  662. {
  663. // Rotate according to trackball
  664. igl::trackball(
  665. width, height,
  666. 2.0,
  667. down_camera.m_rotation.conjugate(),
  668. down_x, down_y, mouse_x, mouse_y,
  669. q);
  670. break;
  671. }
  672. case ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP:
  673. {
  674. // Rotate according to two axis valuator with fixed up vector
  675. two_axis_valuator_fixed_up(
  676. width, height,
  677. 2.0,
  678. down_camera.m_rotation.conjugate(),
  679. down_x, down_y, mouse_x, mouse_y,
  680. q);
  681. break;
  682. }
  683. default:
  684. break;
  685. }
  686. switch(center_type)
  687. {
  688. default:
  689. case CENTER_TYPE_ORBIT:
  690. camera.orbit(q.conjugate());
  691. break;
  692. case CENTER_TYPE_FPS:
  693. camera.turn_eye(q.conjugate());
  694. break;
  695. }
  696. }
  697. }
  698. void key(unsigned char key, int mouse_x, int mouse_y)
  699. {
  700. using namespace std;
  701. int mod = glutGetModifiers();
  702. switch(key)
  703. {
  704. // ESC
  705. case char(27):
  706. rebar.save(REBAR_NAME);
  707. // ^C
  708. case char(3):
  709. exit(0);
  710. case 'z':
  711. case 'Z':
  712. if(mod & GLUT_ACTIVE_COMMAND)
  713. {
  714. if(mod & GLUT_ACTIVE_SHIFT)
  715. {
  716. redo();
  717. }else
  718. {
  719. undo();
  720. }
  721. break;
  722. }
  723. default:
  724. if(!TwEventKeyboardGLUT(key,mouse_x,mouse_y))
  725. {
  726. cout<<"Unknown key command: "<<key<<" "<<int(key)<<endl;
  727. }
  728. }
  729. }
  730. void TW_CALL set_rotation(const void * value, void * clientData)
  731. {
  732. using namespace std;
  733. using namespace Eigen;
  734. const double * rt = (const double*)(value);
  735. Quaterniond conj;
  736. copy(rt,rt+4,conj.coeffs().data());
  737. auto & camera = s.cameras[s.viewing_camera];
  738. switch(center_type)
  739. {
  740. default:
  741. case CENTER_TYPE_ORBIT:
  742. camera.orbit(conj.conjugate());
  743. break;
  744. case CENTER_TYPE_FPS:
  745. camera.turn_eye(conj.conjugate());
  746. break;
  747. }
  748. }
  749. void TW_CALL get_rotation(void * value, void *clientData)
  750. {
  751. using namespace std;
  752. using namespace Eigen;
  753. const auto & camera = s.cameras[s.viewing_camera];
  754. double * rt = (double*)(value);
  755. Quaterniond conj = camera.m_rotation.conjugate();
  756. copy(conj.coeffs().data(),conj.coeffs().data()+4,rt);
  757. }
  758. int main(int argc, char * argv[])
  759. {
  760. using namespace std;
  761. using namespace Eigen;
  762. using namespace igl;
  763. // print key commands
  764. cout<<"[Command+Z] Undo."<<endl;
  765. cout<<"[Shift+Command+Z] Redo."<<endl;
  766. cout<<"[^C,ESC] Exit."<<endl;
  767. // Init glut
  768. glutInit(&argc,argv);
  769. if( !TwInit(TW_OPENGL, NULL) )
  770. {
  771. // A fatal error occured
  772. fprintf(stderr, "AntTweakBar initialization failed: %s\n", TwGetLastError());
  773. return 1;
  774. }
  775. // Create a tweak bar
  776. rebar.TwNewBar("bar");
  777. TwDefine("bar label='camera' size='200 550' text=light alpha='200' color='68 68 68'");
  778. TwType RotationTypeTW = ReTwDefineEnumFromString("RotationType","igl_trackball,two_axis_fixed_up");
  779. rebar.TwAddVarRW("rotation_type", RotationTypeTW,&rotation_type,
  780. "keyIncr=] keyDecr=[");
  781. TwType CenterTypeTW = ReTwDefineEnumFromString("CenterType","orbit,fps");
  782. rebar.TwAddVarCB("rotation", TW_TYPE_QUAT4D,set_rotation,get_rotation,NULL,"");
  783. rebar.TwAddVarRW("center_type", CenterTypeTW,&center_type,
  784. "keyIncr={ keyDecr=}");
  785. rebar.load(REBAR_NAME);
  786. init_cameras();
  787. // Init antweakbar
  788. glutInitDisplayString( "rgba depth double samples>=8");
  789. // Top right corner
  790. glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)/2.0,glutGet(GLUT_SCREEN_HEIGHT)/2.0);
  791. glutInitWindowPosition(glutGet(GLUT_SCREEN_WIDTH)/2.0,-1);
  792. glutCreateWindow("camera");
  793. glutDisplayFunc(display);
  794. glutReshapeFunc(reshape);
  795. glutKeyboardFunc(key);
  796. glutMouseFunc(mouse);
  797. glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT);
  798. glutMotionFunc(mouse_drag);
  799. glutMainLoop();
  800. return 0;
  801. }