#include #include #include #include #include #include #include #include #include #include using namespace std; //data strucutre to store 3d points typedef struct { float x; float y; float z; } Vector3; //data structure to store triangle - note that v1, v2, and v3 are indexes into the vertex array typedef struct { int v1; int v2; int v3; Vector3 normal; Vector3 color; } Tri; //all the triangles in the mesh vector Triangles; //all the vertices in the mesh vector Vertices; //for computing the center point and extent of the model Vector3 center; float max_x, max_y, max_z, min_x, min_y, min_z; float max_extent; //variables for virtual trackball int track; int startx, starty, endx, endy; float angle; Vector3 axis; int display_mode; int view_mode; GLfloat objectM[4][4] = { {1.0, 0.0, 0.0, 0.0}, {0.0, 1.0, 0.0, 0.0}, {0.0, 0.0, 1.0, 0.0}, {0.0, 0.0, 0.0, 1.0} }; GLfloat *trackballM = (GLfloat *)objectM; ///globals for reshape int GW; int GH; //forward declarations of functions void readLine(char* str); void readStream(istream& is); void drawTri(Tri); void drawObjects(); void display(); void TrackBall(); //open the file for reading void ReadFile(char* filename) { printf("Reading coordinates from %s\n", filename); ifstream in_f(filename); if (!in_f) { printf("Could not open file %s\n", filename); //exit(-1); } else { readStream(in_f); } } //process the input stream from the file void readStream(istream& is) { char str[256]; for (;is;) { is >> ws; is.get(str,sizeof(str)); if (!is) break; is.ignore(9999,'\n'); readLine(str); } } //process each line of input save vertices and faces appropriately void readLine(char* str) { int indx = 0, vi; float x, y, z; float r, g, b; int mat; if (str[0]=='#') return; if (str[0]=='V' && !strncmp(str,"Vertex ",7)) { static Vector3 v; assert(sscanf(str,"Vertex %d %g %g %g",&vi,&x,&y,&z)==4); v.x = x; v.y = y; v.z = z; Vertices.push_back(v); //cout << "made a vertex " << v.x << " " << v.y << " " << v.z << endl; //house keeping to display in center of the scene center.x += v.x; center.y += v.y; center.z += v.z; if (v.x > max_x) max_x = v.x; if (v.x < min_x) min_x = v.x; if (v.y > max_y) max_y = v.y; if (v.y < min_y) min_y = v.y; if (v.z > max_z) max_z = v.z; if (v.z < min_z) min_z = v.z; } else if (str[0]=='F' && !strncmp(str,"Face ",5)) { Tri t; char* s=str+4; int fi=-1; for (int t_i = 0;;t_i++) { while (*s && isspace(*s)) s++; //if we reach the end of the line break out of the loop if (!*s) break; //save the position of the current character char* beg=s; //advance to next space while (*s && isdigit(*s)) s++; //covert the character to an integer int j=atoi(beg); //the first number we encounter will be the face index, don't store it if (fi<0) { fi=j; continue; } //otherwise process the digit we've grabbed in j as a vertex index //the first number will be the face id the following are vertex ids if (t_i == 1) t.v1 = j; else if (t_i == 2) t.v2 = j; else if (t_i == 3) t.v3 = j; //if there is more data to process break out if (*s =='{') break; } //initialization - replace with real calculation t.normal.x = 0; t.normal.y = 1.0; t.normal.z = 0; //possibly process colors if the mesh has colors if (*s && *s =='{'){ char *s1 = s+1; cout << "trying to parse color " << !strncmp(s1,"rgb",3) << endl; //if we're reading off a color if (!strncmp(s1,"rgb=",4)) { //grab the values of the string assert(sscanf(s1,"rgb=(%g %g %g) matid=%d",&r,&g,&b,&mat)==4); t.color.x = r; t.color.x = g; t.color.x = b; cout << "set color to: " << r << " " << g << " " << b << endl; } } Triangles.push_back(t); //cout << "made a tri " << t.v1 << " " << t.v2 << " " << t.v3 << endl; } } //testing routine for parser - left in just as informative code about accessing data void printFirstThree() { printf("first vertex: %f %f %f \n", Vertices[0].x, Vertices[0].y, Vertices[0].z); printf("first face: %d %d %d \n", Triangles[0].v1, Triangles[0].v2, Triangles[0].v3); printf("second vertex: %f %f %f \n", Vertices[1].x, Vertices[1].y, Vertices[1]); printf("second face: %d %d %d \n", Triangles[1].v1, Triangles[1].v2, Triangles[1].v3); printf("third vertex: %f %f %f \n", Vertices[2].x, Vertices[2].y, Vertices[2].z); printf("third face: %d %d %d \n", Triangles[2].v1, Triangles[2].v2, Triangles[2].v3); } //drawing routine to draw triangles as wireframe void drawTria(Tri t) { if(display_mode == 0) { glBegin(GL_LINE_LOOP); glColor3f(0.0, 0.0, 0.5); //note that the vertices are indexed starting at 0, but the triangles //index them starting from 1, so we must offset by -1!!! glVertex3f(Vertices[t.v1 - 1].x, Vertices[t.v1 - 1].y, Vertices[t.v1 - 1].z); glVertex3f(Vertices[t.v2 - 1].x, Vertices[t.v2 - 1].y, Vertices[t.v2 - 1].z); glVertex3f(Vertices[t.v3 - 1].x, Vertices[t.v3 - 1].y, Vertices[t.v3 - 1].z); glEnd(); } } void drawSphere() { glColor3f(1.0, 0.0, 0.0); glutWireSphere(0.35, 10, 10); } //debugging routine which just draws the vertices of the mesh void DrawAllVerts() { glColor3f(1.0, 0.0, 1.0); glBegin(GL_POINTS); for (int k=0; k < Vertices.size(); k++) { glVertex3f(Vertices[k].x, Vertices[k].y, Vertices[k].z); //cout << "drawing " << Vertices[k].x << endl; } glEnd(); } void reshape(int w, int h) { GW = w; GH = h; glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (view_mode == 0) glOrtho( -2.0*(float)w/h, 2.0*(float)w/h, -2.0, 2.0, 1.0, 15.0); //else... fill in glMatrixMode(GL_MODELVIEW); glViewport(0, 0, w, h); glutPostRedisplay(); } void drawObjects() { //transforms for the mesh glPushMatrix(); //leave these transformations in as they center and scale each mesh correctly //scale object to window glScalef(1.0/(float)max_extent, 1.0/(float)max_extent, 1.0/(float)max_extent); //translate the object to the orgin glTranslatef(-(center.x), -(center.y), -(center.z)); //draw the wireframe mesh for(int j = 0; j < Triangles.size(); j++) { //Add transforms, if needed here... drawTria(Triangles[j]); } glPopMatrix(); //transforms for the sphere glPushMatrix(); //draw the glut sphere behind the mesh glTranslatef(1.25, 0.0, -2.0); drawSphere(); glPopMatrix(); } void display() { float numV = Vertices.size(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); //set up the camera gluLookAt(0, 0, 3.0, 0, 0, 0, 0, 1, 0); drawObjects(); glPopMatrix(); glutSwapBuffers(); } float p2w_x(int p_x) { float x_i = ( (float)p_x - ((GW-1.0)/2.0) )*2.0/GW; return(((float)GW/(float)GH)*x_i); } float p2w_y(int p_y) { return( ( (float)p_y - ((GH-1.0)/2.0) )*2.0/GH); } //mouse event function void mouse(int button, int state, int x, int y) { if (button == GLUT_LEFT_BUTTON) { if (state == GLUT_DOWN) { /* if the left button is clicked */ printf("mouse clicked at %d %d\n", x, GH-y-1); startx = x; starty = GH-y-1; } else if (state == GLUT_UP) { track = 0; } } } //mouse move function void mouseMove(int x, int y) { endx = x; endy = GH-y-1; track = 1; //...TrackBall(); glutPostRedisplay(); } void keyboard(unsigned char key, int x, int y) { switch(key) { case 'v': view_mode = !view_mode; //..additional code pulled out break; default: break; } } int main( int argc, char** argv ) { //set up my window glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(300, 300); glutInitWindowPosition(100, 100); glutCreateWindow("Mesh display"); glClearColor(1.0, 1.0, 1.0, 1.0); //register glut callback functions glutDisplayFunc( display ); glutReshapeFunc( reshape ); glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutMotionFunc(mouseMove); //enable z-buffer glEnable(GL_DEPTH_TEST); //set-up viewing glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-2.0, 2.0, -2.0, 2.0, 1.0, 15.0); glMatrixMode(GL_MODELVIEW); glViewport(0, 0, 300, 300); //image to pixel //initialization max_x = max_y = max_z = -999999; min_x = min_y = min_z = 99999; center.x = 0; center.y = 0; center.z = 0; display_mode = 0; max_extent = 1.0; view_mode = 0; //make sure a file to read is specified if (argc > 1) { cout << "file " << argv[1] << endl; //read-in the mesh file specified ReadFile(argv[1]); if (Vertices.size() > 4) printFirstThree(); //once the file is parsed find out the maximum extent to center and scale mesh max_extent = max_x - min_x; if (max_y - min_y > max_extent) max_extent = max_y - min_y; //cout << "max_extent " << max_extent << " max_x " << max_x << " min_x " << min_x << endl; //cout << "max_y " << max_y << " min_y " << min_y << " max_z " << max_z << " min_z " << min_z << endl; center.x = center.x/Vertices.size(); center.y = center.y/Vertices.size(); center.z = center.z/Vertices.size(); //cout << "center " << center.x << " " << center.y << " " << center.z << endl; //cout << "scale by " << 1.0/(float)max_extent << endl; } else { cout << "format is: meshparcer filename" << endl; } glutMainLoop(); }