/********************************************************************/ /* STRIPE: converting a polygonal model to triangle strips Francine Evans, 1996. SUNY @ Stony Brook Advisors: Steven Skiena and Amitabh Varshney */ /********************************************************************/ /*---------------------------------------------------------------------*/ /* STRIPE: bands.c This file contains the main procedure code that will read in the object and then call the routines that produce the triangle strips. */ /*---------------------------------------------------------------------*/ #include #include #include #include #include "global.h" #include "polverts.h" #include "triangulate.h" #include "ties.h" #include "outputex.h" #include "options.h" #include "local.h" #include "init.h" #include "free.h" #include "add.h" #define MAX1 60 /* TIMING for Windows */ #ifdef WIN32 #include #include /* TIMING for UNIX */ #else #include #include #include #include struct timeval tm; struct timezone tz; double et; #define START gettimeofday(&tm,&tz);\ et = (tm.tv_sec)+ (0.000001* (tm.tv_usec)); #define STOP gettimeofday(&tm,&tz);\ et = (tm.tv_sec)+(0.000001*(tm.tv_usec)) - et; #endif void get_time() { /* For timing */ #ifdef WIN32 struct _timeb timebuffer; char *timeline; #else long timer; #endif #ifdef WIN32 _ftime( &timebuffer ); timeline = ctime( & ( timebuffer.time ) ); printf( "The time is %.19s.%hu %s", timeline, timebuffer.millitm, &timeline[20] ); #else printf("Time for last frame = %lf seconds\n", et); #endif } /* ** Here the main program begins. It will start by loading in a .obj file then it will convert the polygonal model into triangle strips. ** */ void main (int argc,char *argv[]) { char *fname,*all,buff[255], *ptr, *ptr2; FILE *file, *bands; int face_id=0, vert_count, loop, num=0,num2; float center[3]; int temp[MAX1],vertex,strips, swaps,tempi,cost,triangles; int f,t,tr,g; char *file_open; int num_vert = 0, num_faces = 0, num_nvert = 0, num_edges = 0, num_texture = 0, num_tris = 0; double fra = 0.0; BOOL texture, normal, normal_and_texture,quads = FALSE; /* Options variables */ float norm_difference; /* Structures for the object */ struct vert_struct *vertices = NULL, *nvertices = NULL, *pvertices = NULL, *pnvertices = NULL; get_time(); START /* File that will contain the triangle strip data */ bands = fopen("bands.d","w"); /* Scan the file once to find out the number of vertices, vertice normals, and faces so we can set up some memory structures */ /* Interpret the options specified */ norm_difference = get_options(argc,argv,&f,&t,&tr,&g); if (f == BINARY) file_open = "rb"; else file_open = "r"; fname = argv[argc-1]; printf ("File: %s\n",fname); /*printf ("Scanning...%s ",file_open);*/ /* File can be in binary for faster reading */ if (file = fopen (fname,file_open)) { while (!feof (file)) { /* Read a line */ if (f == BINARY) fread (buff,sizeof(char) * 255,1, file); else fgets (buff, sizeof(char) * 255, file); num++; /* At a vertex */ if (*buff == 'v') { /* At a normal */ if (*(buff+1)=='n') num_nvert++; else if (*(buff+1)=='t') num_texture++; /* At a regular vertex */ else num_vert++; } /* At a face */ else if (*buff == 'f') { num_faces++; strtok(buff, " "); tempi = 0; while (strtok(NULL, " ") != NULL) tempi++; num_tris += tempi - 2; } } fclose (file); } else { printf("Error in the file name\n"); exit(1); } /* Allocate structures for the information */ Start_Face_Struct(num_faces); vertices = (struct vert_struct *) malloc (sizeof (struct vert_struct) * num_vert); if (num_nvert > 0) { nvertices = (struct vert_struct *) malloc (sizeof (struct vert_struct) * num_nvert); vert_norms = (int *) malloc (sizeof (int) * num_vert); /* Initialize entries to zero, in case there are 2 hits to the same vertex we will know it - used for determining the normal difference */ init_vert_norms(num_vert); } else nvertices = NULL; if (num_texture > 0) { vert_texture = (int *) malloc (sizeof(int) * num_vert); init_vert_texture(num_vert); } /* Set up the temporary 'p' pointers */ pvertices = vertices; pnvertices = nvertices; /* Load the object into memory */ /*printf (" Loading...");*/ fprintf(bands,"#%s: a triangle strip representation created by STRIPE.\n#This is a .objf file\n#by Francine Evans\n",fname); /* File will be put in a list for faster execution if file is in binary */ if (file = fopen(fname,file_open)) { if (f == BINARY) { all = (char *) malloc (sizeof(char) * 255 * num); fread(all,sizeof(char) * 255 * num, 1, file); ptr = all; } else ptr = (char *) malloc (sizeof(char) * 255 * num); } while (num > 0) { num--; if (f == ASCII) fgets (ptr, sizeof(char) * 255, file); else ptr = ptr + 255; /* Load in vertices/normals */ if (*ptr == 'v') { if (*(ptr+1)=='n') { sscanf (ptr+3,"%lf%lf%lf", &(pnvertices->x), &(pnvertices->y), &(pnvertices->z)); fprintf(bands,"vn %lf %lf %lf\n", pnvertices->x,pnvertices->y,pnvertices->z); ++pnvertices; } else if (*(ptr+1)=='t') { sscanf (ptr+3,"%f%f%f",¢er[0],¢er[1],¢er[2]); fprintf(bands,"vt %f %f %f\n",center[0],center[1],center[2]); } else { sscanf (ptr+2,"%lf%lf%lf", &(pvertices->x), &(pvertices->y), &(pvertices->z)); fprintf(bands,"v %lf %lf %lf\n", pvertices->x,pvertices->y,pvertices->z); ++pvertices; } } else if (*ptr == 'f') { /* Read in faces */ num2 = 0; face_id++; ptr2 = ptr+1; normal = FALSE; texture = FALSE, normal_and_texture = FALSE; while (*ptr2) { if (*ptr2 >='0' && *ptr2 <='9') { num2++; ++ptr2; while (*ptr2 && (*ptr2!=' ' && *ptr2!='/')) ptr2++; /* There are normals in this line */ if (*ptr2 == '/') { if (*(ptr2+1) == '/') normal = TRUE; else texture = TRUE; } else if (*ptr2 == ' ') { if ((num2 == 3) && (texture)) normal_and_texture = TRUE; } } else ++ptr2; } ptr2 = ptr+1; /* loop on the number of numbers in this line of face data */ vert_count = 0; for (loop=0;loop'9') { if (*ptr2 == '-') break; ptr2++; } vertex = atoi(ptr2)-1; if (vertex < 0) { vertex = num_vert + vertex; *ptr2 = ' '; ptr2++; } /* If there are either normals or textures with the vertices in this file, the data alternates so we must read it this way */ if ( (normal) && (!normal_and_texture)) { if (loop%2) { add_norm_id(vertex,vert_count); /* Test here to see if we added a new vertex, since the vertex has more than one normal and the 2 normals are greater than the threshold specified */ if (norm_array(vertex,0,norm_difference,nvertices,num_vert)) { /* Add a new vertex and change the id of the vertex that we just read to the id of the new vertex that we just added */ /* Put it in the output file, note the added vertices will be after the normals and separated from the rest of the vertices. Will not affect our viewer */ fprintf(bands,"v %lf %lf %lf\n", (vertices + temp[vert_count - 1])->x, (vertices + temp[vert_count - 1])->y, (vertices + temp[vert_count - 1])->z); num_vert++; temp[vert_count - 1] = num_vert - 1; if (!(add_vert_id(num_vert - 1,vert_count))) vert_count--; } } /* the vertex */ else { temp[vert_count] = vertex ; vert_count++; if (!(add_vert_id(vertex,vert_count))) vert_count--; norm_array(vertex,1,norm_difference,nvertices,num_vert); } } /* Else there are vertices and textures with the data */ else if (normal_and_texture) { if( !((loop+1)%3)) { add_norm_id(vertex,vert_count); /* Test here to see if we added a new vertex, since the vertex has more than one normal and the 2 normals are greater than the threshold specified */ if (norm_array(vertex,0,norm_difference,nvertices,num_vert)) { /* Add a new vertex and change the id of the vertex that we just read to the id of the new vertex that we just added */ /* Put it in the output file, note the added vertices will be after the normals and separated from the rest of the vertices. Will not affect our viewer */ fprintf(bands,"v %lf %lf %lf\n", (vertices + temp[vert_count - 1])->x, (vertices + temp[vert_count - 1])->y, (vertices + temp[vert_count - 1])->z); num_vert++; temp[vert_count - 1] = num_vert - 1; if (!(add_vert_id(num_vert - 1,vert_count))) vert_count--; } } /* the vertex */ else if ((loop == 0) || (*(ptr2-1) == ' ')) { temp[vert_count] = vertex ; vert_count++; if (vert_count == 4) quads = TRUE; if (!(add_vert_id(vertex,vert_count))) vert_count--; add_texture(vertex,TRUE); norm_array(vertex,1,norm_difference,nvertices,num_vert); } else /* The texture */ add_texture(vertex,FALSE); } else if ( texture ) { /* the vertex */ if (!(loop%2)) { temp[vert_count] = vertex ; vert_count++; if (vert_count == 4) quads = TRUE; add_texture(vertex,TRUE); if (!(add_vert_id(vertex,vert_count))) vert_count--; norm_array(vertex,1,norm_difference,nvertices,num_vert); } else /* texture */ add_texture(vertex,FALSE); } else { /*** no nvertices ***/ temp[vert_count] = vertex ; vert_count++; if (vert_count == 4) quads = TRUE; if (!(add_vert_id(vertex,vert_count))) vert_count--; } while (*ptr2>='0' && *ptr2<='9') ptr2++; } /* Done with the polygon */ num_edges += vert_count; /* add it to face structure */ if (vert_count >= 3) AddNewFace(ids,vert_count,face_id,norms); else face_id--; if (vert_count == 4) quads = TRUE; } else if ((g == TRUE) && (face_id > 0) && ((*ptr == 'g') || (*ptr == 's') || (*ptr == 'm') || (*ptr == 'o'))) { /* The user specified that the strips will be contained in each group from the data file, so we just finished a group and will find the triangle strips in it. */ Start_Edge_Struct(num_vert); Find_Adjacencies(face_id); if (quads) { Init_Table_SGI(); Build_SGI_Table(num_vert,face_id); /* Code for lengths of walks in each direction */ Save_Walks(face_id,TRUE); /* Code for finding the bands */ Find_Bands(face_id,bands,&swaps,&strips,&cost,&triangles,num_nvert,vert_norms,num_texture,vert_texture); /* Remove the faces that we did so that we can run the strip code on the rest of the faces that are left */ if (cost != 0) { printf("Total %d triangles with %d cost\n",triangles,cost); Save_Rest(&face_id); printf("We saved %d .... now doing the local algorithm\n",face_id); fprintf(bands,"\n#local\n"); End_Edge_Struct(num_vert); Start_Edge_Struct(num_vert); Find_Adjacencies(face_id); } } SGI_Strip(num_vert,face_id,bands,t,tr); /* Get the total cost */ Output_TriEx(-1,-2,-3,NULL,-1,-20,cost); End_Face_Struct(num_faces); End_Edge_Struct(num_vert); cost = 0; face_id = 0; quads = FALSE; Start_Face_Struct(num_faces-face_id); num_faces = num_faces - face_id; Free_Strips(); } } /* Done reading in all the information into data structures */ num_faces = face_id; fclose (file); /*printf(" Done.\n\n");*/ free(vertices); free(nvertices); /*printf ("Vertices: %d\nNormals: %d\nFaces: %d\n",num_vert,num_nvert,num_faces);*/ Start_Edge_Struct(num_vert); Find_Adjacencies(num_faces); /* Initialize it */ Init_Table_SGI(); /* Build it */ Build_SGI_Table(num_vert,num_faces); InitStripTable(); if (quads) { /* Code for lengths of walks in each direction */ Save_Walks(num_faces,TRUE); /* Code for finding the bands */ Find_Bands(num_faces,bands,&swaps,&strips,&cost,&triangles,num_nvert,vert_norms,num_texture,vert_texture); /*printf("Total %d triangles with %d cost\n",triangles,cost);*/ /* Remove the faces that we did so that we can run the strip code on the rest of the faces that are left */ Save_Rest(&num_faces); /*printf("We saved %d .... now doing the local algorithm\n",num_faces);*/ fprintf(bands,"\n#local\n"); End_Edge_Struct(num_vert); Start_Edge_Struct(num_vert); Find_Adjacencies(num_faces); } SGI_Strip(num_vert,num_faces,bands,t,tr); /* Get the total cost */ Output_TriEx(-1,-2,-3,NULL,-1,-20,cost); End_Face_Struct(num_faces); End_Edge_Struct(num_vert); fclose(bands); STOP get_time(); }