/********************************************************************/ /* STRIPE: converting a polygonal model to triangle strips Francine Evans, 1996. SUNY @ Stony Brook Advisors: Steven Skiena and Amitabh Varshney */ /********************************************************************/ /*---------------------------------------------------------------------*/ /* STRIPE: newpolve.c This routine contains the bulk of the code that will find the patches of quads in the data model */ /*---------------------------------------------------------------------*/ #include #include "polverts.h" #include "extend.h" #include "output.h" #include "triangulate.h" #include "common.h" #include "util.h" #include "global.h" #include "init.h" #include "add.h" ListHead **PolVerts; ListHead **PolFaces; ListHead **PolEdges; int length; BOOL resetting = FALSE; int ids[STRIP_MAX]; int added_quad = 0; BOOL reversed = FALSE; int patch = 0; extern int *vn; extern int *vt; int Calculate_Walks(int lastvert,int y, PF_FACES temp2) { /* Find the length of the walk */ int previous_edge1, previous_edge2; register int nextvert,numverts,counter,walk=0; BOOL flag; F_EDGES *node; ListHead *pListHead; static int seen = 0; /* Find the edge that we are currently on */ if (y != 3) { previous_edge1 = *(temp2->pPolygon +y); previous_edge2 = *(temp2->pPolygon + y + 1); } else { previous_edge1 = *(temp2->pPolygon +y); previous_edge2 = *(temp2->pPolygon); } temp2->seen = seen; counter = y; /*Find the adjacent face to this edge */ node = *(temp2->VertandId+y); if (node->edge[2] != lastvert) nextvert = node->edge[2]; else nextvert = node->edge[1]; /* Keep walking in this direction until we cannot do so */ while ((nextvert != lastvert) && (nextvert != -1)) { walk++; pListHead = PolFaces[nextvert]; temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0); numverts = temp2->nPolSize; if ((numverts != 4) || (temp2->seen == seen)) { walk--; nextvert = -1; } else { temp2->seen = seen; /* Find edge that is not adjacent to the previous one */ counter = 0; flag = TRUE; while ((counter < 3) && (flag)) { if ( ((*(temp2->pPolygon+counter) == previous_edge1) || (*(temp2->pPolygon+counter+1) == previous_edge2)) || ((*(temp2->pPolygon+counter) == previous_edge2) || (*(temp2->pPolygon+counter+1) == previous_edge1)) ) counter++; else flag = FALSE; } /* Get the IDs of the next edge */ if (counter < 3) { previous_edge1 = *(temp2->pPolygon + counter); previous_edge2 = *(temp2->pPolygon + counter + 1); } else { previous_edge1 = *(temp2->pPolygon + counter); previous_edge2 = *(temp2->pPolygon); } node = *(temp2->VertandId + counter); if (node->edge[1] == nextvert) nextvert = node->edge[2]; else nextvert = node->edge[1]; } } seen++; return walk; } BOOL Check_Right(int last_seen,PF_FACES temp2,int y,int face_id) { /* Check when we last saw the face to the right of the current one. We want to have seen it just before we started this strip */ F_EDGES *node; ListHead *pListHead; register int nextvert,oldy; PF_FACES t; oldy = y; if (y != 3) y = y+1; else y = 0; node = *(temp2->VertandId + y); if (face_id == node->edge[1]) nextvert = node->edge[2]; else nextvert = node->edge[1]; if (nextvert == -1) return FALSE; pListHead = PolFaces[nextvert]; t = (PF_FACES) PeekList(pListHead,LISTHEAD,0); if (t->seen != (last_seen - 1)) { /* maybe because of the numbering, we are not on the right orientation, so we have to check the opposite one to be sure */ if (oldy != 0) y = oldy-1; else y = 3; node = *(temp2->VertandId + y); if (face_id == node->edge[1]) nextvert = node->edge[2]; else nextvert = node->edge[1]; if (nextvert == -1) return FALSE; pListHead = PolFaces[nextvert]; t = (PF_FACES) PeekList(pListHead,LISTHEAD,0); if (t->seen != (last_seen - 1)) return FALSE; } return TRUE; } int Update_and_Test(PF_FACES temp2,int y,BOOL first,int distance,int lastvert, int val) { static int last_seen = 17; int previous_edge1, previous_edge2; register int original_distance,nextvert,numverts,counter; BOOL flag; F_EDGES *node; ListHead *pListHead; original_distance = distance; /* Find the edge that we are currently on */ if (y != 3) { previous_edge1 = *(temp2->pPolygon +y); previous_edge2 = *(temp2->pPolygon + y + 1); } else { previous_edge1 = *(temp2->pPolygon +y); previous_edge2 = *(temp2->pPolygon); } temp2->seen = val; temp2->seen2 = val; node = *(temp2->VertandId+y); if (lastvert != node->edge[2]) nextvert = node->edge[2]; else nextvert = node->edge[1]; /* Keep walking in this direction until we cannot do so or we go to distance */ while ((distance > 0) && (nextvert != lastvert) && (nextvert != -1)) { distance--; pListHead = PolFaces[nextvert]; temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0); temp2->seen = val; if (temp2->seen2 == val) { last_seen++; return (original_distance - distance); } temp2->seen2 = val; numverts = temp2->nPolSize; if (numverts != 4) nextvert = -1; else if ((!first) && (!(Check_Right(last_seen,temp2,y,nextvert)))) { last_seen++; return (original_distance - distance); } else { /* Find edge that is not adjacent to the previous one */ counter = 0; flag = TRUE; while ((counter < 3) && (flag)) { if ( ((*(temp2->pPolygon+counter) == previous_edge1) || (*(temp2->pPolygon+counter+1) == previous_edge2)) || ((*(temp2->pPolygon+counter) == previous_edge2) || (*(temp2->pPolygon+counter+1) == previous_edge1)) ) counter++; else flag = FALSE; } /* Get the IDs of the next edge */ if (counter < 3) { previous_edge1 = *(temp2->pPolygon + counter); previous_edge2 = *(temp2->pPolygon + counter + 1); } else { previous_edge1 = *(temp2->pPolygon + counter); previous_edge2 = *(temp2->pPolygon); } if ( ((*(temp2->walked+counter) == -1) && (*(temp2->walked+counter+2) == -1))) { printf("There is an error in the walks!\n"); printf("1Code %d %d \n",*(temp2->walked+counter),*(temp2->walked+counter+2)); exit(0); } else { if ((*(temp2->walked+counter) == -1) && (*(temp2->walked+counter-2) == -1)) { printf("There is an error in the walks!\n"); printf("2Code %d %d \n",*(temp2->walked+counter),*(temp2->walked+counter-2)); exit(0); } } node = *(temp2->VertandId + counter); y = counter; if (node->edge[1] == nextvert) nextvert = node->edge[2]; else nextvert = node->edge[1]; } } last_seen++; if (distance != 0) { if (((nextvert == -1) || (nextvert == lastvert)) && (distance != 1)) return (original_distance - distance); } return original_distance; } int Test_Adj(PF_FACES temp2,int x,int north,int distance,int lastvert, int value) { /* if first time, then just update the last seen field */ if (x==1) return(Update_and_Test(temp2,north,TRUE,distance,lastvert,value)); /* else we have to check if we are adjacent to the last strip */ else return(Update_and_Test(temp2,north,FALSE,distance,lastvert,value)); } void Get_Band_Walk(PF_FACES temp2,int face_id,int *dir1,int *dir2, int orientation,int cutoff_length) { int previous_edge1, previous_edge2; F_EDGES *node; ListHead *pListHead; register int walk = 0, nextvert,numverts,counter; BOOL flag; /* Get the largest band that will include this face, starting from orientation. Save the values of the largest band (either north and south together, or east and west together) in the direction variables. */ /* Find the edge that we are currently on */ if (orientation != 3) { previous_edge1 = *(temp2->pPolygon + orientation); previous_edge2 = *(temp2->pPolygon + orientation + 1); } else { previous_edge1 = *(temp2->pPolygon + orientation ); previous_edge2 = *(temp2->pPolygon); } if (orientation == 0) { if (*dir1 > *(temp2->walked + 1)) *dir1 = *(temp2->walked + 1); if (*dir2 > *(temp2->walked + 3)) *dir2 = *(temp2->walked + 3); } else if (orientation == 3) { if (*dir1 > *(temp2->walked + orientation - 3)) *dir1 = *(temp2->walked + orientation - 3) ; if (*dir2 > *(temp2->walked + orientation -1 )) *dir2 = *(temp2->walked + orientation - 1); } else { if (*dir1 > *(temp2->walked + orientation - 1)) *dir1 = *(temp2->walked + orientation -1) ; if (*dir2 > *(temp2->walked+ orientation + 1)) *dir2 = *(temp2->walked + orientation + 1); } /* if we know already that we can't extend the band from this face, we do not need to do the walk */ if ((*dir1 != 0) && (*dir2 != 0)) { /* Find the adjacent face to this edge */ node = *(temp2->VertandId+orientation); if (face_id == node->edge[1]) nextvert = node->edge[2]; else nextvert = node->edge[1]; } else nextvert = -1; /* leave w/o walking */ /* Keep walking in this direction until we cannot do so */ while ((nextvert != face_id) && (nextvert != -1)) { walk++; pListHead = PolFaces[nextvert]; temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0); numverts = temp2->nPolSize; if ((numverts != 4) || (walk > cutoff_length)) nextvert = -1; else { /* Find edge that is not adjacent to the previous one */ counter = 0; flag = TRUE; while ((counter < 3) && (flag)) { if ( ((*(temp2->pPolygon+counter) == previous_edge1) || (*(temp2->pPolygon+counter+1) == previous_edge2)) || ((*(temp2->pPolygon+counter) == previous_edge2) || (*(temp2->pPolygon+counter+1) == previous_edge1)) ) counter++; else flag = FALSE; } /* Get the IDs of the next edge */ if (counter < 3) { previous_edge1 = *(temp2->pPolygon + counter); previous_edge2 = *(temp2->pPolygon + counter + 1); } else { previous_edge1 = *(temp2->pPolygon + counter); previous_edge2 = *(temp2->pPolygon); } /* find out how far we can extend in the 2 directions along this new face in the walk */ if (counter == 0) { if (*dir1 > *(temp2->walked + 1)) *dir1 = *(temp2->walked + 1); if (*dir2 > *(temp2->walked + 3)) *dir2 = *(temp2->walked + 3); } else if (counter == 3) { if (*dir1 > *(temp2->walked + counter - 3)) *dir1 = *(temp2->walked + counter - 3) ; if (*dir2 > *(temp2->walked + counter -1 )) *dir2 = *(temp2->walked + counter -1); } else { if (*dir1 > *(temp2->walked + counter - 1)) *dir1 = *(temp2->walked + counter -1) ; if (*dir2 > *(temp2->walked + counter + 1)) *dir2 = *(temp2->walked + counter + 1); } /* if we know already that we can't extend the band from this face, we do not need to do the walk */ if ((*dir1 == 0) || (*dir2 == 0)) nextvert = -1; if (nextvert != -1) { node = *(temp2->VertandId + counter); if (node->edge[1] == nextvert) nextvert = node->edge[2]; else nextvert = node->edge[1]; } } } } int Find_Max(PF_FACES temp2,int lastvert,int north,int left, int *lastminup,int *lastminleft) { int temp,walk,counter,minup,x,band_value; int previous_edge1, previous_edge2; F_EDGES *node; ListHead *pListHead; BOOL flag; static int last_seen = 0; register int smallest_so_far,nextvert,max=-1; *lastminup = MAX_BAND; *lastminleft = 1; if (left == 3) { previous_edge1 = *(temp2->pPolygon + left); previous_edge2 = *(temp2->pPolygon); } else { previous_edge1 = *(temp2->pPolygon + left + 1); previous_edge2 = *(temp2->pPolygon + left); } temp2->seen = last_seen; walk = *(temp2->walked + left); for (x=1;x<=(walk+1); x++) { /* test to see if we have a true band that is, are they adjacent to each other */ minup = *(temp2->walked + north) + 1; /* if we are at the very first face, then we do not have to check the adjacent faces going up and our north distance is the distance of this face's north direction. */ if (x == 1) { *lastminup = minup; minup = Test_Adj(temp2,x,north,*lastminup,lastvert,last_seen); *lastminup = minup; smallest_so_far = minup; } /* find the largest band that we can have */ if (minup < (*lastminup)) { /* see if we really can go up all the way temp should by less than our equal to minup if it is less, then one of the faces was not adjacent to those next to it and the band height will be smaller */ temp = Test_Adj(temp2,x,north,minup,lastvert,last_seen); if (temp > minup) { printf("There is an error in the test adj\n"); exit(0); } minup = temp; band_value = x * minup; if (minup < smallest_so_far) { if (band_value > max) { smallest_so_far = minup; *lastminup = minup; *lastminleft = x; max = band_value; } else smallest_so_far = minup; } else { band_value = x * smallest_so_far; if (band_value > max) { *lastminup = smallest_so_far; *lastminleft = x; max = band_value; } } } else { if (x != 1) { temp = Test_Adj(temp2,x,north,smallest_so_far,lastvert,last_seen); if (temp > smallest_so_far) { printf("There is an error in the test adj\n"); exit(0); } smallest_so_far = temp; } band_value = x * smallest_so_far; if (band_value > max) { *lastminup = smallest_so_far; *lastminleft = x; max = band_value; } } if ( x != (walk + 1)) { node = *(temp2->VertandId+left); if (lastvert == node->edge[1]) nextvert = node->edge[2]; else nextvert = node->edge[1]; lastvert = nextvert; if (nextvert == -1) return max; pListHead = PolFaces[nextvert]; temp2 = (PF_FACES) PeekList(pListHead, LISTHEAD, 0); /* if we have visited this face before, then there is an error */ if (((*(temp2->walked) == -1) && (*(temp2->walked+1) == -1) && (*(temp2->walked+2) == -1) && (*(temp2->walked+3) == -1)) || (temp2->nPolSize !=4) || (temp2->seen == last_seen)) { if (lastvert == node->edge[1]) nextvert = node->edge[2]; else nextvert = node->edge[1]; if (nextvert == -1) return max; lastvert = nextvert; /* Last attempt to get the face ... */ pListHead = PolFaces[nextvert]; temp2 = (PF_FACES) PeekList(pListHead, LISTHEAD, 0); if (((*(temp2->walked) == -1) && (*(temp2->walked+1) == -1) && (*(temp2->walked+2) == -1) && (*(temp2->walked+3) == -1)) || (temp2->nPolSize !=4) || (temp2->seen == last_seen)) return max; /* The polygon was not saved with the edge, not enough room. We will get the walk when we come to that polygon later. */ } /*else {*/ counter = 0; flag = TRUE; temp2->seen = last_seen; while ((counter < 3) && (flag)) { if ( ((*(temp2->pPolygon+counter) == previous_edge1) || (*(temp2->pPolygon+counter+1) == previous_edge2)) || ((*(temp2->pPolygon+counter) == previous_edge2) || (*(temp2->pPolygon+counter+1) == previous_edge1)) ) counter++; else flag = FALSE; } /*}*/ /* Get the IDs of the next edge */ left = counter; north = left+1; if (left ==3) north = 0; if (counter < 3) { previous_edge1 = *(temp2->pPolygon + counter + 1); previous_edge2 = *(temp2->pPolygon + counter); } else { previous_edge1 = *(temp2->pPolygon + counter); previous_edge2 = *(temp2->pPolygon); } } } last_seen++; return max; } void Mark_Face(PF_FACES temp2, int color1, int color2, int color3, FILE *output_file, BOOL end, int *edge1, int *edge2, int *face_id, int norms, int texture) { static int last_quad[4]; int x,y,z=0; int saved[2]; static int output1, output2,last_id; BOOL cptexture = FALSE; /* Are we done with the patch? If so return the last edge that we will come out on, and that will be the edge that we will start to extend upon. */ if (end) { *edge1 = output1; *edge2 = output2; *face_id = last_id; return; } cptexture = texture; last_id = *face_id; *(temp2->walked) = -1; *(temp2->walked+1) = -1; *(temp2->walked+2) = -1; *(temp2->walked+3) = -1; added_quad++; temp2->nPolSize = 1; if (patch == 0) { /* At the first quad in the strip -- save it */ last_quad[0] = *(temp2->pPolygon); last_quad[1] = *(temp2->pPolygon+1); last_quad[2] = *(temp2->pPolygon+2); last_quad[3] = *(temp2->pPolygon+3); patch++; } else { /* Now we have a triangle to output, find the edge in common */ for (x=0; x < 4 ;x++) { for (y=0; y< 4; y++) { if (last_quad[x] == *(temp2->pPolygon+y)) { saved[z++] = last_quad[x]; if (z > 2) { /* This means that there was a non convex or an overlapping polygon */ z--; break; } } } } if (z != 2) { printf("Z is not 2 %d \n",patch); printf("4 %d %d %d %d %d %d %d\n",*(temp2->pPolygon), *(temp2->pPolygon+1),*(temp2->pPolygon+2),*(temp2->pPolygon+3), color1,color2,color3); printf("%d %d %d %d\n",last_quad[0],last_quad[1],last_quad[2],last_quad[3]); exit(1); } if (patch == 1) { /* First one to output, there was no output edge */ patch++; x = Adjacent(saved[0],saved[1],last_quad,4); y = Adjacent(saved[1],saved[0],last_quad,4); /* Data might be mixed and we do not have textures for some of the vertices */ if ((texture) && ( ((vt[x]) == 0) || ((vt[y])==0) || ((vt[saved[1]])==0))) cptexture = FALSE; if ((!norms) && (!cptexture)) { fprintf(output_file,"\nt %d %d %d ",x+1,y+1,saved[1]+1); fprintf(output_file,"%d ",saved[0]+1); } else if ((norms) && (!cptexture)) { fprintf(output_file,"\nt %d//%d %d//%d %d//%d ",x+1,vn[x] +1, y+1,vn[y] +1, saved[1]+1,vn[saved[1]]+1); fprintf(output_file,"%d//%d ",saved[0]+1,vn[saved[0]]+1); } else if ((cptexture) && (!norms)) { fprintf(output_file,"\nt %d/%d %d/%d %d/%d ",x+1,vt[x] +1, y+1,vt[y] +1, saved[1]+1,vt[saved[1]]+1); fprintf(output_file,"%d//%d ",saved[0]+1,vt[saved[0]]+1); } else { fprintf(output_file,"\nt %d/%d/%d %d/%d/%d %d/%d/%d ",x+1,vt[x]+1,vn[x] +1, y+1,vt[y]+1,vn[y] +1, saved[1]+1,vt[saved[1]]+1,vn[saved[1]]+1); fprintf(output_file,"%d/%d/%d ",saved[0]+1,vt[saved[0]]+1,vn[saved[0]]+1); } x = Adjacent(saved[0],saved[1],temp2->pPolygon,4); y = Adjacent(saved[1],saved[0],temp2->pPolygon,4); /* Data might be mixed and we do not have textures for some of the vertices */ if ((texture) && ( (vt[x] == 0) || (vt[y]==0))) { if (cptexture) fprintf(output_file,"\nq "); cptexture = FALSE; } if ((!norms) && (!cptexture)) { fprintf(output_file,"%d ",x+1); fprintf(output_file,"%d ",y+1); } else if ((norms) && (!cptexture)) { fprintf(output_file,"%d//%d ",x+1,vn[x]+1); fprintf(output_file,"%d//%d ",y+1,vn[y]+1); } else if ((cptexture) && (!norms)) { fprintf(output_file,"%d/%d ",x+1,vt[x]+1); fprintf(output_file,"%d/%d ",y+1,vt[y]+1); } else { fprintf(output_file,"%d/%d/%d ",x+1,vt[x]+1,vn[x]+1); fprintf(output_file,"%d/%d/%d ",y+1,vt[y]+1,vn[y]+1); } output1 = x; output2 = y; } else { x = Adjacent(output2,output1,temp2->pPolygon,4); y = Adjacent(output1,output2,temp2->pPolygon,4); /* Data might be mixed and we do not have textures for some of the vertices */ if ((texture) && ( ((vt[x]) == 0) || ((vt[y])==0) )) texture = FALSE; if ((!norms) && (!texture)) { fprintf(output_file,"\nq %d ",x+1); fprintf(output_file,"%d ",y+1); } else if ((norms) && (!texture)) { fprintf(output_file,"\nq %d//%d ",x+1,vn[x]+1); fprintf(output_file,"%d//%d ",y+1,vn[y]+1); } else if ((texture) && (!norms)) { fprintf(output_file,"\nq %d/%d ",x+1,vt[x]+1); fprintf(output_file,"%d/%d ",y+1,vt[y]+1); } else { fprintf(output_file,"\nq %d/%d/%d ",x+1,vt[x]+1,vn[x]+1); fprintf(output_file,"%d/%d/%d ",y+1,vt[y]+1,vn[y]+1); } output1 = x; output2 = y; } last_quad[0] = *(temp2->pPolygon); last_quad[1] = *(temp2->pPolygon+1); last_quad[2] = *(temp2->pPolygon+2); last_quad[3] = *(temp2->pPolygon+3); } } void Fast_Reset(int x) { register int y,numverts; register int front_walk, back_walk; ListHead *pListHead; PF_FACES temp = NULL; pListHead = PolFaces[x]; temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0); numverts = temp->nPolSize; front_walk = 0; back_walk = 0; resetting = TRUE; /* we are doing this only for quads */ if (numverts == 4) { /* for each face not seen yet, do North and South together and East and West together */ for (y=0;y<2;y++) { /* Check if the opposite sides were seen already */ /* Find walk for the first edge */ front_walk = Calculate_Walks(x,y,temp); /* Find walk in the opposite direction */ back_walk = Calculate_Walks(x,y+2,temp); /* Now put into the data structure the numbers that we have found */ Assign_Walk(x,temp,front_walk,y,back_walk); Assign_Walk(x,temp,back_walk,y+2,front_walk); } } resetting = FALSE; } void Reset_Max(PF_FACES temp2,int face_id,int north,int last_north, int orientation, int last_left,FILE *output_file,int color1,int color2,int color3, BOOL start) { int previous_edge1,previous_edge2; F_EDGES *node; ListHead *pListHead; int f,t,nextvert,counter; BOOL flag; /* Reset walks on faces, since we just found a patch */ if (orientation !=3) { previous_edge1 = *(temp2->pPolygon + orientation+1); previous_edge2 = *(temp2->pPolygon + orientation ); } else { previous_edge1 = *(temp2->pPolygon + orientation ); previous_edge2 = *(temp2->pPolygon); } /* only if we are going left, otherwise there will be -1 there */ /*Find the adjacent face to this edge */ for (t = 0; t <=3 ; t++) { node = *(temp2->VertandId+t); if (face_id == node->edge[1]) f = node->edge[2]; else f = node->edge[1]; if (f != -1) Fast_Reset(f); } node = *(temp2->VertandId+orientation); if (face_id == node->edge[1]) nextvert = node->edge[2]; else nextvert = node->edge[1]; while ((last_left--) > 1) { if (start) Reset_Max(temp2,face_id,orientation,last_left,north,last_north,output_file,color1,color2,color3,FALSE); face_id = nextvert; pListHead = PolFaces[nextvert]; temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0); if ((temp2->nPolSize != 4) && (temp2->nPolSize != 1)) { /* There is more than 2 polygons on the edge, and we could have gotten the wrong one */ if (nextvert != node->edge[1]) nextvert = node->edge[1]; else nextvert = node->edge[2]; pListHead = PolFaces[nextvert]; temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0); node = *(temp2->VertandId+orientation); } if (!start) { for (t = 0; t <=3 ; t++) { node = *(temp2->VertandId+t); if (face_id == node->edge[1]) f = node->edge[2]; else f = node->edge[1]; if (f != -1) Fast_Reset(f); } } counter = 0; flag = TRUE; while ((counter < 3) && (flag)) { if ( ((*(temp2->pPolygon+counter) == previous_edge1) || (*(temp2->pPolygon+counter+1) == previous_edge2)) || ((*(temp2->pPolygon+counter) == previous_edge2) || (*(temp2->pPolygon+counter+1) == previous_edge1)) ) counter++; else flag = FALSE; } /* Get the IDs of the next edge */ if (counter < 3) { previous_edge1 = *(temp2->pPolygon + counter+1); previous_edge2 = *(temp2->pPolygon + counter); } else { previous_edge1 = *(temp2->pPolygon + counter); previous_edge2 = *(temp2->pPolygon); } orientation = counter; node = *(temp2->VertandId + counter); if (node->edge[1] == nextvert) nextvert = node->edge[2]; else nextvert = node->edge[1]; if (!reversed) { if (counter != 3) north = counter +1; else north = 0; } else { if (counter != 0) north = counter -1; else north = 3; } } if (start) Reset_Max(temp2,face_id,orientation,last_left,north,last_north,output_file,color1,color2,color3,FALSE); else if (nextvert != -1) Fast_Reset(nextvert); } int Peel_Max(PF_FACES temp2,int face_id,int north,int last_north, int orientation, int last_left,FILE *output_file,int color1,int color2,int color3, BOOL start, int *swaps_added, int norms, int texture) { int end1,end2,last_id,s=0,walk = 0; int previous_edge1,previous_edge2; static int last_seen = 1000; F_EDGES *node; ListHead *pListHead; int nextvert,numverts,counter,dummy,tris=0; BOOL flag; /* Peel the patch from the model. We will try and extend off the end of each strip in the patch. We will return the number of triangles completed by this extension only, and the number of swaps in the extension only. */ patch = 0; if (orientation !=3) { previous_edge1 = *(temp2->pPolygon + orientation+1); previous_edge2 = *(temp2->pPolygon + orientation ); } else { previous_edge1 = *(temp2->pPolygon + orientation ); previous_edge2 = *(temp2->pPolygon); } walk = *(temp2->walked + orientation); /* only if we are going left, otherwise there will be -1 there */ if ((start) && ((walk+1) < last_left)) { printf("There is an error in the left %d %d\n",walk,last_left); exit(0); } /* Find the adjacent face to this edge */ node = *(temp2->VertandId+orientation); if (face_id == node->edge[1]) nextvert = node->edge[2]; else nextvert = node->edge[1]; temp2->seen = last_seen; while ((last_left--) > 1) { if (start) tris += Peel_Max(temp2,face_id,orientation,last_left,north,last_north,output_file, color1,color2,color3,FALSE,swaps_added,norms,texture); else Mark_Face(temp2,color1,color2,color3,output_file,FALSE,&dummy,&dummy,&face_id,norms,texture); pListHead = PolFaces[nextvert]; temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0); numverts = temp2->nPolSize; if ((numverts != 4) || (temp2->seen == last_seen) || (nextvert == -1)) { /* There is more than 2 polygons on the edge, and we could have gotten the wrong one */ if (nextvert != node->edge[1]) nextvert = node->edge[1]; else nextvert = node->edge[2]; pListHead = PolFaces[nextvert]; temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0); numverts = temp2->nPolSize; if ((numverts != 4) || (temp2->seen == last_seen) ) { printf("Peel 2 %d\n",numverts); exit(1); } } face_id = nextvert; temp2->seen = last_seen; counter = 0; flag = TRUE; while ((counter < 3) && (flag)) { if ( ((*(temp2->pPolygon+counter) == previous_edge1) || (*(temp2->pPolygon+counter+1) == previous_edge2)) || ((*(temp2->pPolygon+counter) == previous_edge2) || (*(temp2->pPolygon+counter+1) == previous_edge1)) ) counter++; else flag = FALSE; } /* Get the IDs of the next edge */ if (counter < 3) { previous_edge1 = *(temp2->pPolygon + counter+1); previous_edge2 = *(temp2->pPolygon + counter); } else { previous_edge1 = *(temp2->pPolygon + counter); previous_edge2 = *(temp2->pPolygon); } orientation = counter; node = *(temp2->VertandId + counter); if (node->edge[1] == nextvert) nextvert = node->edge[2]; else nextvert = node->edge[1]; if (!reversed) { if (counter != 3) north = counter +1; else north = 0; } else { if (counter != 0) north = counter -1; else north = 3; } } if (start) tris += Peel_Max(temp2,face_id,orientation,last_left,north,last_north,output_file, color1,color2,color3,FALSE,swaps_added,norms,texture); else Mark_Face(temp2,color1,color2,color3,output_file,FALSE,&dummy,&dummy,&face_id,norms,texture);/* do the last face */ last_seen++; /* Get the edge that we came out on the last strip of the patch */ Mark_Face(NULL,0,0,0,output_file,TRUE,&end1,&end2,&last_id,norms,texture); tris += Extend_Face(last_id,end1,end2,&s,output_file,color1,color2,color3,vn,norms,vt,texture); *swaps_added = *swaps_added + s; return tris; } void Find_Bands(int numfaces, FILE *output_file, int *swaps, int *bands, int *cost, int *tri, int norms, int *vert_norms, int texture, int *vert_texture) { register int x,y,max1,max2,numverts,face_id,flag,maximum = 25; ListHead *pListHead; PF_FACES temp = NULL; int color1 = 0, color2 = 100, color3 = 255; int larger,smaller; int north_length1,last_north,left_length1,last_left,north_length2,left_length2; int total_tri = 0, total_swaps = 0,last_id; int end1, end2,s=0; register int cutoff = 20; /* Code that will find the patches. "Cutoff" will be the cutoff of the area of the patches that we will be allowing. After we reach this cutoff length, then we will run the local algorithm on the remaining faces. */ /* For each faces that is left find the largest possible band that we can have with the remaining faces. Note that we will only be finding patches consisting of quads. */ vn = vert_norms; vt = vert_texture; y=1; *bands = 0; while ((maximum >= cutoff)) { y++; maximum = -1; for (x=0; xnPolSize; /* we are doing this only for quads */ if (numverts == 4) { /* We want a face that is has not been used yet, since we know that that face must be part of a band. Then we will find the largest band that the face may be contained in */ /* Doing the north and the left */ if ((*(temp->walked) != -1) && (*(temp->walked+3) != -1)) max1 = Find_Max(temp,x,0,3,&north_length1,&left_length1); if ((*(temp->walked+1) != -1) && (*(temp->walked+2) != -1)) max2 = Find_Max(temp,x,2,1,&north_length2,&left_length2); if ((max1 != (north_length1 * left_length1)) || (max2 != (north_length2 * left_length2))) { printf("Max1 %d, %d %d Max2 %d, %d %d\n",max1,north_length1,left_length1,max2,north_length2,left_length2); exit(0); } if ((max1 > max2) && (max1 > maximum)) { maximum = max1; face_id = x; flag = 1; last_north = north_length1; last_left = left_length1; /* so we know we saved max1 */ } else if ((max2 > maximum) ) { maximum = max2; face_id = x; flag = 2; last_north = north_length2; last_left = left_length2; /* so we know we saved max2 */ } } } if ((maximum < cutoff) && (*bands == 0)) return; pListHead = PolFaces[face_id]; temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0); /* There are no patches that we found in this pass */ if (maximum == -1) break; printf("The maximum is face %d area %d: lengths %d %d\n",face_id,maximum,last_north,last_left); if (maximum == 16) printf("Fran"); if (last_north > last_left) { larger = last_north; smaller = last_left; } else { larger = last_left; smaller = last_north; } length = larger; if (flag == 1) { if (last_north > last_left) /* go north sequentially */ { total_tri += Peel_Max(temp,face_id,0,last_north,3,last_left,output_file,color1,color2,color3,TRUE,&s,norms,texture); Reset_Max(temp,face_id,0,last_north,3,last_left,output_file,color1,color2,color3,TRUE); total_swaps += s; } else { reversed = TRUE; total_tri += Peel_Max(temp,face_id,3,last_left,0,last_north,output_file,color1,color2,color3,TRUE,&s,norms,texture); Reset_Max(temp,face_id,3,last_left,0,last_north,output_file,color1,color2,color3,TRUE); reversed = FALSE; total_swaps += s; } /* Get the edge that we came out on the last strip of the patch */ Mark_Face(NULL,0,0,0,NULL,TRUE,&end1,&end2,&last_id,norms,texture); total_tri += Extend_Face(last_id,end1,end2,&s,output_file,color1,color2,color3,vn,norms,vt,texture); total_swaps += s; } else { if (last_north > last_left) { total_tri += Peel_Max(temp,face_id,2,last_north,1,last_left,output_file,color1,color2,color3,TRUE,&s,norms,texture); Reset_Max(temp,face_id,2,last_north,1,last_left,output_file,color1,color2,color3,TRUE); total_swaps += s; } else { reversed = TRUE; total_tri += Peel_Max(temp,face_id,1,last_left,2,last_north,output_file,color1,color2,color3,TRUE,&s,norms,texture); Reset_Max(temp,face_id,1,last_left,2,last_north,output_file,color1,color2,color3,TRUE); reversed = FALSE; total_swaps += s; } /* Get the edge that we came out on on the patch */ Mark_Face(NULL,0,0,0,NULL,TRUE,&end1,&end2,&last_id,norms,texture); total_tri += Extend_Face(last_id,end1,end2,&s,output_file,color1,color2,color3,vn,norms,vt,texture); total_swaps += s; } /* Now compute the cost of transmitting this band, is equal to going across the larger portion sequentially, and swapping 3 times per other dimension */ total_tri += (maximum * 2); *bands = *bands + smaller; } printf("We transmitted %d triangles,using %d swaps and %d strips\n",total_tri,total_swaps, *bands); printf("COST %d\n",total_tri + total_swaps + *bands + *bands); *cost = total_tri + total_swaps + *bands + *bands; *tri = total_tri; added_quad = added_quad * 4; *swaps = total_swaps; } void Save_Rest(int *numfaces) { /* Put the polygons that are left into a data structure so that we can run the stripping code on it. */ register int x,y=0,numverts; ListHead *pListHead; PF_FACES temp=NULL; for (x=0; x<*numfaces; x++) { /* for each face, get the face */ pListHead = PolFaces[x]; temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0); numverts = temp->nPolSize; /* If we did not do the face before add it to data structure with new face id number */ if (numverts != 1) { CopyFace(temp->pPolygon,numverts,y+1,temp->pNorms); y++; } /* Used it, so remove it */ else RemoveList(pListHead,(PLISTINFO) temp); } *numfaces = y; } void Assign_Walk(int lastvert,PF_FACES temp2, int front_walk,int y, int back_walk) { /* Go back and do the walk again, but this time save the lengths inside the data structure. y was the starting edge number for the front_walk length back_walk is the length of the walk along the opposite edge */ int previous_edge1, previous_edge2; register int walk = 0,nextvert,numverts,counter; BOOL flag; F_EDGES *node; ListHead *pListHead; static int seen = 0; static BOOL first = TRUE; BOOL wrap = FALSE, set = FALSE; /* In the "Fast_Reset" resetting will be true */ if ((resetting) && (first)) { seen = 0; first = FALSE; } seen++; /* Had a band who could be a cycle */ if (front_walk == back_walk) wrap = TRUE; /* Find the edge that we are currently on */ if (y != 3) { previous_edge1 = *(temp2->pPolygon +y); previous_edge2 = *(temp2->pPolygon + y + 1); } else { previous_edge1 = *(temp2->pPolygon +y); previous_edge2 = *(temp2->pPolygon); } /* Assign the lengths */ if (y < 2) { *(temp2->walked+y) = front_walk--; *(temp2->walked+y+2) = back_walk++; } else { *(temp2->walked+y) = front_walk--; *(temp2->walked+y-2) = back_walk++; } /*Find the adjacent face to this edge */ node = *(temp2->VertandId+y); if (node->edge[2] != lastvert) nextvert = node->edge[2]; else nextvert = node->edge[1]; temp2->seen3 = seen; /* Keep walking in this direction until we cannot do so */ while ((nextvert != lastvert) && (nextvert != -1) && (front_walk >= 0)) { walk++; pListHead = PolFaces[nextvert]; temp2 = (PF_FACES) PeekList(pListHead,LISTHEAD,0); numverts = temp2->nPolSize; if ((numverts != 4)) { nextvert = -1; /* Don't include this face in the walk */ walk--; } else { /* Find edge that is not adjacent to the previous one */ counter = 0; flag = TRUE; while ((counter < 3) && (flag)) { if ( ((*(temp2->pPolygon+counter) == previous_edge1) || (*(temp2->pPolygon+counter+1) == previous_edge2)) || ((*(temp2->pPolygon+counter) == previous_edge2) || (*(temp2->pPolygon+counter+1) == previous_edge1)) ) counter++; else flag = FALSE; } /* Get the IDs of the next edge */ if (counter < 3) { previous_edge1 = *(temp2->pPolygon + counter); previous_edge2 = *(temp2->pPolygon + counter + 1); } else { previous_edge1 = *(temp2->pPolygon + counter); previous_edge2 = *(temp2->pPolygon); } /* Put in the walk lengths */ if (counter < 2) { if (((*(temp2->walked + counter) >= 0) || (*(temp2->walked +counter + 2) >= 0))) { if ((resetting == FALSE) && ((temp2->seen3) != (seen-1))) { /* If there are more than 2 polygons adjacent to an edge then we can be trying to assign more than once. We will save the smaller one */ temp2->seen3 = seen; if ( (*(temp2->walked+counter) <= front_walk) && (*(temp2->walked+counter+2) <= back_walk) ) return; if (*(temp2->walked+counter) > front_walk) *(temp2->walked+counter) = front_walk--; else front_walk--; if (*(temp2->walked+counter+2) > back_walk) *(temp2->walked+counter+2) = back_walk++; else back_walk++; } else if (resetting == FALSE) { /* if there was a cycle then all lengths are the same */ walk--; back_walk--; front_walk++; temp2->seen3 = seen; *(temp2->walked+counter) = front_walk--; *(temp2->walked+counter+2) = back_walk++; } else if (((temp2->seen3 == (seen-1)) && (wrap) && (walk == 1)) || (set)) { /* if there was a cycle then all lengths are the same */ set = TRUE; walk--; back_walk--; front_walk++; temp2->seen3 = seen; *(temp2->walked+counter) = front_walk--; *(temp2->walked+counter+2) = back_walk++; } else { temp2->seen3 = seen; *(temp2->walked+counter) = front_walk--; *(temp2->walked+counter+2) = back_walk++; } } /* if was > 0 */ else { temp2->seen3 = seen; *(temp2->walked+counter) = front_walk--; *(temp2->walked+counter+2) = back_walk++; } } else { if (((*(temp2->walked + counter) >= 0 ) || (*(temp2->walked +counter - 2) >= 0)) ) { if ((temp2->seen3 != (seen-1)) && (resetting == FALSE)) { /* If there are more than 2 polygons adjacent to an edge then we can be trying to assign more than once. We will save the smaller one */ temp2->seen3 = seen; if ( (*(temp2->walked+counter) <= front_walk) && (*(temp2->walked+counter-2) <= back_walk) ) return; if (*(temp2->walked+counter) > front_walk) *(temp2->walked+counter) = front_walk--; else front_walk--; if (*(temp2->walked+counter-2) > back_walk) *(temp2->walked+counter-2) = back_walk++; else back_walk++; } else if (resetting == FALSE) { walk--; back_walk--; front_walk++; temp2->seen3 = seen; *(temp2->walked+counter) = front_walk--; *(temp2->walked+counter-2) = back_walk++; } else if (((temp2->seen3 == (seen-1)) && (walk == 1) && (wrap)) || (set)) { /* if there was a cycle then all lengths are the same */ set = TRUE; walk--; back_walk--; front_walk++; temp2->seen3 = seen; *(temp2->walked+counter) = front_walk--; *(temp2->walked+counter-2) = back_walk++; } else { temp2->seen3 = seen; *(temp2->walked+counter) = front_walk--; *(temp2->walked+counter-2) = back_walk++; } } else { temp2->seen3 = seen; *(temp2->walked+counter) = front_walk--; *(temp2->walked+counter-2) = back_walk++; } } if (nextvert != -1) { node = *(temp2->VertandId + counter); if (node->edge[1] == nextvert) nextvert = node->edge[2]; else nextvert = node->edge[1]; } } } if ((EVEN(seen)) ) seen+=2; } void Save_Walks(int numfaces) { int x,y,numverts; int front_walk, back_walk; ListHead *pListHead; PF_FACES temp = NULL; for (x=0; xnPolSize; front_walk = 0; back_walk = 0; /* we are finding patches only for quads */ if (numverts == 4) { /* for each face not seen yet, do North and South together and East and West together */ for (y=0;y<2;y++) { /* Check if the opposite sides were seen already from another starting face, if they were then there is no need to do the walk again */ if ( ((*(temp->walked+y) == -1) && (*(temp->walked+y+2) == -1) )) { /* Find walk for the first edge */ front_walk = Calculate_Walks(x,y,temp); /* Find walk in the opposite direction */ back_walk = Calculate_Walks(x,y+2,temp); /* Now put into the data structure the numbers that we have found */ Assign_Walk(x,temp,front_walk,y,back_walk); Assign_Walk(x,temp,back_walk,y+2,front_walk); } } } } }