#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __APPLE__ # include #else # include #endif #include #include #include #include struct State { igl::Camera camera; } s; enum RotationType { ROTATION_TYPE_IGL_TRACKBALL = 0, ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1, NUM_ROTATION_TYPES = 2, } rotation_type; bool is_rotating = false; int down_x,down_y; igl::Camera down_camera; bool is_animating = false; double animation_start_time = 0; double ANIMATION_DURATION = 0.5; Eigen::Quaterniond animation_from_quat; Eigen::Quaterniond animation_to_quat; // Use vector for range-based `for` std::vector undo_stack; std::vector redo_stack; void push_undo() { undo_stack.push_back(s); // Clear redo_stack = std::vector(); } void undo() { using namespace std; if(!undo_stack.empty()) { redo_stack.push_back(s); s = undo_stack.front(); undo_stack.pop_back(); } } void redo() { using namespace std; if(!redo_stack.empty()) { undo_stack.push_back(s); s = redo_stack.front(); redo_stack.pop_back(); } } void TW_CALL set_rotation_type(const void * value, void * clientData) { using namespace Eigen; using namespace std; using namespace igl; const RotationType old_rotation_type = rotation_type; rotation_type = *(const RotationType *)(value); if(rotation_type == ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP && old_rotation_type != ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP) { push_undo(); animation_from_quat = s.camera.m_rotation_conj; snap_to_fixed_up(animation_from_quat,animation_to_quat); // start animation animation_start_time = get_seconds(); is_animating = true; } } void TW_CALL get_rotation_type(void * value, void *clientData) { RotationType * rt = (RotationType *)(value); *rt = rotation_type; } // Width and height of window int width,height; // Position of light float light_pos[4] = {0.1,0.1,-0.9,0}; // Vertex positions, normals, colors and centroid Eigen::MatrixXd V,U,N,C,mid; Eigen::VectorXi S; igl::ARAPData arap_data; Eigen::MatrixXi F; int selected_col = 0; // Faces // Bounding box diagonal length double bbd; int tot_num_samples = 0; #define REBAR_NAME "temp.rbr" igl::ReTwBar rebar; // Pointer to the tweak bar bool flip_y = false; bool rotate_xy = false; int num_in_selection(const Eigen::VectorXi & S) { int count = 0; for(int v = 0;v= 0) { count++; } } return count; } bool init_arap() { using namespace igl; using namespace Eigen; using namespace std; VectorXi b(num_in_selection(S)); assert(S.rows() == V.rows()); C.resize(S.rows(),3); MatrixXd bc = MatrixXd::Zero(b.size(),S.maxCoeff()+1); // get b from S { int bi = 0; for(int v = 0;v= 0) { b(bi) = v; bc(bi,S(v)) = 1; bi++; if(S(v) == 0) { C.row(v) = RowVector3d(0.039,0.31,1); }else { C.row(v) = RowVector3d(1,0.41,0.70); } }else { C.row(v) = RowVector3d( GOLD_DIFFUSE[0], GOLD_DIFFUSE[1], GOLD_DIFFUSE[2]); } } } // Store current mesh U = V; VectorXi _S; VectorXd _D; MatrixXd W; if(!harmonic(V,F,b,bc,1,W)) { return false; } partition(W,100,arap_data.G,_S,_D); return arap_precomputation(V,F,b,arap_data); } bool update_arap() { using namespace Eigen; using namespace igl; using namespace std; MatrixXd bc(num_in_selection(S),V.cols()); // get b from S { int bi = 0; for(int v = 0;v= 0) { bc.row(bi) = V.row(v); switch(S(v)) { case 0: { //const double r = mid(0)*0.25; //bc(bi,0) += r*cos(0.5*get_seconds()*2.*PI); //bc(bi,1) -= r+r*sin(0.5*get_seconds()*2.*PI); break; } case 1: { //const double r = mid(1)*0.15; //bc(bi,1) += r+r*cos(0.15*get_seconds()*2.*PI); //bc(bi,2) -= r*sin(0.15*get_seconds()*2.*PI); //// Pull-up //bc(bi,0) += 0.42;//mid(0)*0.5; //bc(bi,1) += 0.55;//mid(0)*0.5; // Bend Vector3d t(-1,0,0); Quaterniond q(AngleAxisd(PI/1.5,Vector3d(0,1.0,0.1).normalized())); const Vector3d a = bc.row(bi); bc.row(bi) = (q*(a-t) + t) + Vector3d(1.5,0.1,0.9); break; } default: break; } bi++; } } } if(!arap_solve(bc,arap_data,U)) { cerr<<"arap_solve failed."< 1) { t = 1; is_animating = false; } const Quaterniond q = animation_from_quat.slerp(t,animation_to_quat).normalized(); s.camera.orbit(q.conjugate()); } glDisable(GL_LIGHTING); lights(); push_scene(); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glEnable(GL_NORMALIZE); push_object(); // Draw the model // Set material properties //glDisable(GL_COLOR_MATERIAL); //glMaterialfv(GL_FRONT, GL_AMBIENT, GOLD_AMBIENT); //glMaterialfv(GL_FRONT, GL_DIFFUSE, GOLD_DIFFUSE ); //glMaterialfv(GL_FRONT, GL_SPECULAR, GOLD_SPECULAR); //glMaterialf (GL_FRONT, GL_SHININESS, 128); //glMaterialfv(GL_BACK, GL_AMBIENT, SILVER_AMBIENT); //glMaterialfv(GL_BACK, GL_DIFFUSE, FAST_GREEN_DIFFUSE ); //glMaterialfv(GL_BACK, GL_SPECULAR, SILVER_SPECULAR); //glMaterialf (GL_BACK, GL_SHININESS, 128); glEnable(GL_COLOR_MATERIAL); draw_mesh(U,F,N,C); glDisable(GL_COLOR_MATERIAL); pop_object(); // Draw a nice floor glPushMatrix(); const double floor_offset = -2./bbd*(V.col(1).maxCoeff()-mid(1)); glTranslated(0,floor_offset,0); const float GREY[4] = {0.5,0.5,0.6,1.0}; const float DARK_GREY[4] = {0.2,0.2,0.3,1.0}; //draw_floor(GREY,DARK_GREY); draw_floor(); glPopMatrix(); pop_scene(); report_gl_error(); TwDraw(); glutSwapBuffers(); //if(is_animating) //{ glutPostRedisplay(); //} } void mouse_wheel(int wheel, int direction, int mouse_x, int mouse_y) { using namespace std; using namespace igl; using namespace Eigen; GLint viewport[4]; glGetIntegerv(GL_VIEWPORT,viewport); if(wheel == 0 && TwMouseMotion(mouse_x, viewport[3] - mouse_y)) { static double mouse_scroll_y = 0; const double delta_y = 0.125*direction; mouse_scroll_y += delta_y; TwMouseWheel(mouse_scroll_y); return; } push_undo(); auto & camera = s.camera; if(wheel==0) { // factor of zoom change double s = (1.-0.01*direction); //// FOV zoom: just widen angle. This is hardly ever appropriate. //camera.m_angle *= s; //camera.m_angle = min(max(camera.m_angle,1),89); camera.push_away(s); }else { // Dolly zoom: camera.dolly_zoom((double)direction*1.0); } } void mouse(int glutButton, int glutState, int mouse_x, int mouse_y) { using namespace std; using namespace Eigen; using namespace igl; bool tw_using = TwEventMouseButtonGLUT(glutButton,glutState,mouse_x,mouse_y); switch(glutButton) { case GLUT_RIGHT_BUTTON: case GLUT_LEFT_BUTTON: { switch(glutState) { case 1: // up glutSetCursor(GLUT_CURSOR_LEFT_ARROW); is_rotating = false; break; case 0: // down if(!tw_using) { glutSetCursor(GLUT_CURSOR_CYCLE); // collect information for trackball is_rotating = true; down_camera = s.camera; down_x = mouse_x; down_y = mouse_y; } break; } break; } // Scroll down case 3: { mouse_wheel(0,-1,mouse_x,mouse_y); break; } // Scroll up case 4: { mouse_wheel(0,1,mouse_x,mouse_y); break; } // Scroll left case 5: { mouse_wheel(1,-1,mouse_x,mouse_y); break; } // Scroll right case 6: { mouse_wheel(1,1,mouse_x,mouse_y); break; } } glutPostRedisplay(); } void mouse_drag(int mouse_x, int mouse_y) { using namespace igl; using namespace Eigen; if(is_rotating) { glutSetCursor(GLUT_CURSOR_CYCLE); Quaterniond q; auto & camera = s.camera; switch(rotation_type) { case ROTATION_TYPE_IGL_TRACKBALL: { // Rotate according to trackball igl::trackball( width, height, 2.0, down_camera.m_rotation_conj.coeffs().data(), down_x, down_y, mouse_x, mouse_y, q.coeffs().data()); break; } case ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP: { // Rotate according to two axis valuator with fixed up vector two_axis_valuator_fixed_up( width, height, 2.0, down_camera.m_rotation_conj, down_x, down_y, mouse_x, mouse_y, q); break; } default: break; } camera.orbit(q.conjugate()); }else { TwEventMouseMotionGLUT(mouse_x, mouse_y); } glutPostRedisplay(); } void key(unsigned char key, int mouse_x, int mouse_y) { using namespace std; switch(key) { // ESC case char(27): rebar.save(REBAR_NAME); // ^C case char(3): exit(0); default: if(!TwEventKeyboardGLUT(key,mouse_x,mouse_y)) { cout<<"Unknown key command: "< > vV,vN,vTC; vector > vF,vTF,vFN; // Convert extension to lower case if(!igl::readOBJ(filename,vV,vTC,vN,vF,vTF,vFN)) { return 1; } if(vV.size() > 0) { if(!list_to_matrix(vV,V)) { cerr<<"Bad V"<=8 "); glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)/2.0,glutGet(GLUT_SCREEN_HEIGHT)); glutCreateWindow("colored-mesh"); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(key); glutMouseFunc(mouse); glutMotionFunc(mouse_drag); glutPassiveMotionFunc( [](int x, int y) { TwEventMouseMotionGLUT(x,y); glutPostRedisplay(); }); static std::function timer_bounce; auto timer = [] (int ms) { timer_bounce(ms); }; timer_bounce = [&] (int ms) { glutTimerFunc(ms, timer, ms); glutPostRedisplay(); }; glutTimerFunc(500, timer, 500); if(!init_arap()) { cerr<<"Initializing arap failed."<