// http://www.songho.ca/opengl/gl_vbo.html#create IGL_INLINE void igl::opengl::create_index_vbo( const Eigen::MatrixXi & F, GLuint & F_vbo_id) { // Generate Buffers glGenBuffers(1,&F_vbo_id); // Bind Buffers glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,F_vbo_id); // Copy data to buffers // We expect a matrix with each vertex position on a row, we then want to // pass this data to OpenGL reading across rows (row-major) if(F.Options & Eigen::RowMajor) { glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*F.size(), F.data(), GL_STATIC_DRAW); }else { // Create temporary copy of transpose Eigen::MatrixXi FT = F.transpose(); // If its column major then we need to temporarily store a transpose glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*F.size(), FT.data(), GL_STATIC_DRAW); } // bind with 0, so, switch back to normal pointer operation glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); }
void BuildNJTree::configure(Eigen::MatrixXi& IDs, int numOccupiedNodes) { numJoints = (IDs.size()+2)/2; graph = Graph(numJoints); name = get(vertex_name, graph); newNodesIndex = numJoints + numOccupiedNodes; int i = 0; VertexIterator vi, vend; for (tie(vi, vend) = vertices(graph); vi != vend; ++vi, ++i) { name[*vi] = IDs(i); } }
void parse_rhs( const int nrhs, const mxArray *prhs[], Eigen::MatrixXd & V, Eigen::MatrixXi & F, Eigen::MatrixXd & P, Eigen::MatrixXd & N, int & num_samples) { using namespace std; if(nrhs < 5) { mexErrMsgTxt("nrhs < 5"); } const int dim = mxGetN(prhs[0]); if(dim != 3) { mexErrMsgTxt("Mesh vertex list must be #V by 3 list of vertex positions"); } if(dim != (int)mxGetN(prhs[1])) { mexErrMsgTxt("Mesh facet size must be 3"); } if(mxGetN(prhs[2]) != dim) { mexErrMsgTxt("Point list must be #P by 3 list of origin locations"); } if(mxGetN(prhs[3]) != dim) { mexErrMsgTxt("Normal list must be #P by 3 list of origin normals"); } if(mxGetN(prhs[4]) != 1 || mxGetM(prhs[4]) != 1) { mexErrMsgTxt("Number of samples must be scalar."); } V.resize(mxGetM(prhs[0]),mxGetN(prhs[0])); copy(mxGetPr(prhs[0]),mxGetPr(prhs[0])+V.size(),V.data()); F.resize(mxGetM(prhs[1]),mxGetN(prhs[1])); copy(mxGetPr(prhs[1]),mxGetPr(prhs[1])+F.size(),F.data()); F.array() -= 1; P.resize(mxGetM(prhs[2]),mxGetN(prhs[2])); copy(mxGetPr(prhs[2]),mxGetPr(prhs[2])+P.size(),P.data()); N.resize(mxGetM(prhs[3]),mxGetN(prhs[3])); copy(mxGetPr(prhs[3]),mxGetPr(prhs[3])+N.size(),N.data()); if(*mxGetPr(prhs[4]) != (int)*mxGetPr(prhs[4])) { mexErrMsgTxt("Number of samples should be non negative integer."); } num_samples = (int) *mxGetPr(prhs[4]); }
IGL_INLINE void igl::adjacency_matrix( const Eigen::MatrixXi & F, Eigen::SparseMatrix<T>& A) { using namespace std; using namespace Eigen; typedef Triplet<T> IJV; vector<IJV > ijv; ijv.reserve(F.size()*2); // Loop over faces for(int i = 0;i<F.rows();i++) { // Loop over this face for(int j = 0;j<F.cols();j++) { // Get indices of edge: s --> d int s = F(i,j); int d = F(i,(j+1)%F.cols()); ijv.push_back(IJV(s,d,1)); ijv.push_back(IJV(d,s,1)); } } const int n = F.maxCoeff()+1; A.resize(n,n); switch(F.cols()) { case 3: A.reserve(6*(F.maxCoeff()+1)); break; case 4: A.reserve(26*(F.maxCoeff()+1)); break; } A.setFromTriplets(ijv.begin(),ijv.end()); // Force all non-zeros to be one // Iterate over outside for(int k=0; k<A.outerSize(); ++k) { // Iterate over inside for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it) { assert(it.value() != 0); A.coeffRef(it.row(),it.col()) = 1; } } }
// Read a surface mesh from a {.obj|.off|.mesh} files // Inputs: // mesh_filename path to {.obj|.off|.mesh} file // Outputs: // V #V by 3 list of mesh vertex positions // F #F by 3 list of triangle indices // Returns true only if successfuly able to read file bool load_mesh_from_file( const std::string mesh_filename, Eigen::MatrixXd & V, Eigen::MatrixXi & F) { using namespace std; using namespace igl; using namespace Eigen; string dirname, basename, extension, filename; pathinfo(mesh_filename,dirname,basename,extension,filename); transform(extension.begin(), extension.end(), extension.begin(), ::tolower); bool success = false; if(extension == "obj") { success = readOBJ(mesh_filename,V,F); }else if(extension == "off") { success = readOFF(mesh_filename,V,F); }else if(extension == "mesh") { // Unused Tets read from .mesh file MatrixXi Tets; success = readMESH(mesh_filename,V,Tets,F); // We're not going to use any input tets. Only the surface if(Tets.size() > 0 && F.size() == 0) { // If Tets read, but no faces then use surface of tet volume }else { // Rearrange vertices so that faces come first VectorXi IM; faces_first(V,F,IM); // Dont' bother reordering Tets, but this is how one would: //Tets = // Tets.unaryExpr(bind1st(mem_fun( static_cast<VectorXi::Scalar& // (VectorXi::*)(VectorXi::Index)>(&VectorXi::operator())), // &IM)).eval(); // Don't throw away any interior vertices, since user may want weights // there } }else { cerr<<"Error: Unknown shape file format extension: ."<<extension<<endl; return false; } return success; }
IGL_INLINE void igl::triangle_fan( const Eigen::MatrixXi & E, Eigen::MatrixXi & cap) { using namespace std; using namespace Eigen; // Handle lame base case if(E.size() == 0) { cap.resize(0,E.cols()+1); return; } // "Triangulate" aka "close" the E trivially with facets // Note: in 2D we need to know if E endpoints are incoming or // outgoing (left or right). Thus this will not work. assert(E.cols() == 2); // Arbitrary starting vertex //int s = E(int(((double)rand() / RAND_MAX)*E.rows()),0); int s = E(rand()%E.rows(),0); vector<vector<int> > lcap; for(int i = 0;i<E.rows();i++) { // Skip edges incident on s (they would be zero-area) if(E(i,0) == s || E(i,1) == s) { continue; } vector<int> e(3); e[0] = s; e[1] = E(i,0); e[2] = E(i,1); lcap.push_back(e); } list_to_matrix(lcap,cap); }
IGL_INLINE void igl::draw_mesh( const Eigen::MatrixXd & V, const Eigen::MatrixXi & F, const Eigen::MatrixXd & N, const Eigen::MatrixXi & NF, const Eigen::MatrixXd & C, const Eigen::MatrixXd & TC, const Eigen::MatrixXi & TF, const Eigen::MatrixXd & W, const GLuint W_index, const Eigen::MatrixXi & WI, const GLuint WI_index) { using namespace std; using namespace Eigen; const int rF = F.rows(); const int cF = F.cols(); const int cC = C.cols(); const int rC = C.rows(); const int cW = W.cols(); const int rW = W.rows(); const int rV = V.rows(); const int rTC = TC.rows(); const int rTF = TF.rows(); const int rNF = NF.rows(); const int rN = N.rows(); if(F.size() > 0) { assert(F.maxCoeff() < V.rows()); assert(V.cols() == 3); assert(rC == rV || rC == rF || rC == rF*3 || rC==1 || C.size() == 0); assert(C.cols() == 3 || C.size() == 0); assert(N.cols() == 3 || N.size() == 0); assert(TC.cols() == 2 || TC.size() == 0); assert(cF == 3 || cF == 4); assert(TF.size() == 0 || TF.cols() == F.cols()); assert(NF.size() == 0 || NF.cols() == NF.cols()); } if(W.size()>0) { assert(W.rows() == V.rows()); assert(WI.rows() == V.rows()); assert(W.cols() == WI.cols()); } switch(F.cols()) { default: case 3: glBegin(GL_TRIANGLES); break; case 4: glBegin(GL_QUADS); break; } // loop over faces for(int i = 0; i<rF;i++) { // loop over corners of triangle for(int j = 0;j<cF;j++) { int tc = -1; if(rTF != 0) { tc = TF(i,j); } else if(rTC == 1) { tc = 0; }else if(rTC == rV) { tc = F(i,j); }else if(rTC == rF*cF) { tc = i*cF + j; }else if(rTC == rF) { tc = i; }else { assert(TC.size() == 0); } // RGB(A) Matrix<MatrixXd::Scalar,1,Dynamic> color; if(rC == 1) { color = C.row(0); }else if(rC == rV) { color = C.row(F(i,j)); }else if(rC == rF*cF) { color = C.row(i*cF+j); }else if(rC == rF) { color = C.row(i); }else { assert(C.size() == 0); } int n = -1; if(rNF != 0) { n = NF(i,j); // indexed normals } else if(rN == 1) { n = 0; // uniform normals }else if(rN == rF) { n = i; // face normals }else if(rN == rV) { n = F(i,j); // vertex normals }else if(rN == rF*cF) { n = i*cF + j; // corner normals }else { assert(N.size() == 0); } { if(rW>0 && W_index !=0 && WI_index != 0) { int weights_left = cW; while(weights_left != 0) { int pass_size = std::min(4,weights_left); int weights_already_passed = cW-weights_left; // Get attribute location of next 4 weights int pass_W_index = W_index + weights_already_passed/4; int pass_WI_index = WI_index + weights_already_passed/4; switch(pass_size) { case 1: glVertexAttrib1d( pass_W_index, W(F(i,j),0+weights_already_passed)); glVertexAttrib1d( pass_WI_index, WI(F(i,j),0+weights_already_passed)); break; case 2: glVertexAttrib2d( pass_W_index, W(F(i,j),0+weights_already_passed), W(F(i,j),1+weights_already_passed)); glVertexAttrib2d( pass_WI_index, WI(F(i,j),0+weights_already_passed), WI(F(i,j),1+weights_already_passed)); break; case 3: glVertexAttrib3d( pass_W_index, W(F(i,j),0+weights_already_passed), W(F(i,j),1+weights_already_passed), W(F(i,j),2+weights_already_passed)); glVertexAttrib3d( pass_WI_index, WI(F(i,j),0+weights_already_passed), WI(F(i,j),1+weights_already_passed), WI(F(i,j),2+weights_already_passed)); break; default: glVertexAttrib4d( pass_W_index, W(F(i,j),0+weights_already_passed), W(F(i,j),1+weights_already_passed), W(F(i,j),2+weights_already_passed), W(F(i,j),3+weights_already_passed)); glVertexAttrib4d( pass_WI_index, WI(F(i,j),0+weights_already_passed), WI(F(i,j),1+weights_already_passed), WI(F(i,j),2+weights_already_passed), WI(F(i,j),3+weights_already_passed)); break; } weights_left -= pass_size; } } if(tc != -1) { glTexCoord2d(TC(tc,0),TC(tc,1)); } if(rC>0) { switch(cC) { case 3: glColor3dv(color.data()); break; case 4: glColor4dv(color.data()); break; default: break; } } if(n != -1) { glNormal3d(N(n,0),N(n,1),N(n,2)); } glVertex3d(V(F(i,j),0),V(F(i,j),1),V(F(i,j),2)); } } } glEnd(); }
void display() { if(sorted_F.size() != F.size()) { mouse(0,1,-1,-1); } //using namespace Eigen; using namespace igl; using namespace std; glClearColor(BG[0],BG[1],BG[2],0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // All smooth points glEnable( GL_POINT_SMOOTH ); lights(); push_scene(); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glEnable(GL_NORMALIZE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //glEnable(GL_CULL_FACE); //glCullFace(GL_BACK); // Draw a nice floor push_object(); glEnable(GL_LIGHTING); glTranslated(0,V.col(1).minCoeff(),0); glScaled(2*bbd,2*bbd,2*bbd); glTranslated(0,-1000*FLOAT_EPS,0); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); igl::opengl2::draw_floor(); pop_object(); glDisable(GL_CULL_FACE); if(trackball_on) { glEnable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); }else { float front[4]; copy(GOLD_DIFFUSE,GOLD_DIFFUSE+3,front); float back[4]; //copy(FAST_GREEN_DIFFUSE,FAST_GREEN_DIFFUSE+3,back); copy(GOLD_DIFFUSE,GOLD_DIFFUSE+3,back); float amb[4]; copy(SILVER_AMBIENT,SILVER_AMBIENT+3,amb); float spec[4]; copy(SILVER_SPECULAR,SILVER_SPECULAR+3,spec); front[3] = back[3] = amb[3] = spec[3] = alpha; // Set material properties glDisable(GL_COLOR_MATERIAL); glMaterialfv(GL_FRONT, GL_AMBIENT, amb); glMaterialfv(GL_FRONT, GL_DIFFUSE, front); glMaterialfv(GL_FRONT, GL_SPECULAR, spec); glMaterialf (GL_FRONT, GL_SHININESS, 128); glMaterialfv(GL_BACK, GL_AMBIENT, amb); glMaterialfv(GL_BACK, GL_DIFFUSE, back); glMaterialfv(GL_BACK, GL_SPECULAR, spec); glMaterialf (GL_BACK, GL_SHININESS, 128); glEnable(GL_LIGHTING); } push_object(); // Draw the model igl::opengl2::draw_mesh(V,sorted_F,sorted_N,C); pop_object(); pop_scene(); igl::opengl::report_gl_error(); glutSwapBuffers(); glutPostRedisplay(); }