/********************************************************************/ /* STRIPE: converting a polygonal model to triangle strips Francine Evans, 1996. SUNY @ Stony Brook Advisors: Steven Skiena and Amitabh Varshney */ /********************************************************************/ /*---------------------------------------------------------------------*/ /* STRIPE: add.c This file contains the procedure code that will add information to our data structures. */ /*---------------------------------------------------------------------*/ #include #include #include #include #include "global.h" #include "queue.h" #include "polverts.h" #include "triangulate.h" #include "ties.h" #include "outputex.h" #include "options.h" #include "local.h" BOOL new_vertex(double difference, int id1,int id2, struct vert_struct *n) { /* Is the difference between id1 and id2 (2 normal vertices that mapped to the same vertex) greater than the threshold that was specified? */ struct vert_struct *pn1,*pn2; double dot_product; double distance1, distance2,distance; double rad; char arg1[100]; char arg2[100]; pn1 = n + id1; pn2 = n + id2; dot_product = ((pn1->x) * (pn2->x)) + ((pn1->y) * (pn2->y)) + ((pn1->z) * (pn2->z)); /* Get the absolute value */ if (dot_product < 0) dot_product = dot_product * -1; distance1 = sqrt( (pn1->x * pn1->x) + (pn1->y * pn1->y) + (pn1->z * pn1->z) ); distance2 = sqrt( (pn2->x * pn2->x) + (pn2->y * pn2->y) + (pn2->z * pn2->z) ); distance = distance1 * distance2; rad = acos((double)dot_product/(double)distance); /* convert to degrees */ rad = (180 * rad)/PI; if ( rad <= difference) return FALSE; /* double checking because of imprecision with floating point acos function */ sprintf( arg1,"%.5f", rad ); sprintf( arg2,"%.5f", difference ); if ( strcmp( arg1, arg2 ) <=0 ) return( FALSE ); if ( rad <= difference) return FALSE; else return TRUE; } BOOL Check_VN(int vertex,int normal, struct vert_added *added) { /* Check to see if we already added this vertex and normal */ register int x,n; n = (added+vertex)->num; for (x = 0; x < n; x++) { if (*((added+vertex)->normal+x) == normal) return TRUE; } return FALSE; } BOOL norm_array(int id, int vertex, double normal_difference, struct vert_struct *n, int num_vert) { static int last; static struct vert_added *added; register int x; static BOOL first = TRUE; if (first) { /* This is the first time that we are in here, so we will allocate a structure that will save the vertices that we added, so that we do not add the same thing twice */ first = FALSE; added = (struct vert_added *) malloc (sizeof (struct vert_added ) * num_vert); /* The number of vertices added for each vertex must be initialized to zero */ for (x = 0; x < num_vert; x++) (added+x)->num = 0; } if (vertex) /* Set the pointer to the vertex, we will be calling again with the normal to fill it with */ last = id; else { /* Fill the pointer with the id of the normal */ if (*(vert_norms + last) == 0) *(vert_norms + last) = id; else if ((*(vert_norms + last) != id) && ((int)normal_difference != 360)) { /* difference is big enough, we need to create a new vertex */ if (new_vertex(normal_difference,id,*(vert_norms + last),n)) { /* First check to see if we added this vertex and normal already */ if (Check_VN(last,id,added)) return FALSE; /* OK, create the new vertex, and have its id = the number of vertices and its normal what we have here */ vert_norms = realloc(vert_norms, sizeof(int) * (num_vert + 1)); if (!vert_norms) { printf("Allocation error - aborting\n"); exit(1); } *(vert_norms + num_vert) = id; /* We created a new vertex, now put it in our added structure so we do not add the same thing twice */ (added+last)->num = (added+last)->num + 1; if ((added+last)->num == 1) { /* First time */ (added+last)->normal = (int *) malloc (sizeof (int ) * 1); *((added+last)->normal) = id; } else { /* Not the first time, reallocate space */ (added+last)->normal = realloc((added+last)->normal,sizeof(int) * (added+last)->num); *((added+last)->normal+((added+last)->num-1)) = id; } return TRUE; } } } return FALSE; } void add_texture(int id,BOOL vertex) { /* Save the texture with its vertex for future use when outputting */ static int last; if (vertex) last = id; else *(vert_texture+last) = id; } int add_vert_id(int id, int index_count) { register int x; /* Test if degenerate, if so do not add degenerate vertex */ for (x = 1; x < index_count ; x++) { if (ids[x] == id) return 0; } ids[index_count] = id; return 1; } void add_norm_id(int id, int index_count) { norms[index_count] = id; } void AddNewFace(int ids[STRIP_MAX], int vert_count, int face_id, int norms[STRIP_MAX]) { PF_FACES pfNode; int *pTempInt; int *pnorms; F_EDGES **pTempVertptr; int *pTempmarked, *pTempwalked; register int y,count = 0; /* Add a new face into our face data structure */ pfNode = (PF_FACES) malloc(sizeof(F_FACES) ); if ( pfNode ) { pfNode->pPolygon = (int*) malloc(sizeof(int) * (vert_count) ); pfNode->pNorms = (int*) malloc(sizeof(int) * (vert_count) ); pfNode->VertandId = (F_EDGES**)malloc(sizeof(F_EDGES*) * (vert_count)); pfNode->marked = (int*)malloc(sizeof(int) * (vert_count)); pfNode->walked = (int*)malloc(sizeof(int) * (vert_count)); } pTempInt =pfNode->pPolygon; pnorms = pfNode->pNorms; pTempmarked = pfNode->marked; pTempwalked = pfNode->walked; pTempVertptr = pfNode->VertandId; pfNode->nPolSize = vert_count; pfNode->seen = -1; pfNode->seen2 = -1; for (y=1;y<=vert_count;y++) { *(pTempInt + count) = ids[y]; *(pnorms + count) = norms[y]; *(pTempmarked + count) = FALSE; *(pTempwalked + count) = -1; *(pTempVertptr+count) = NULL; count++; } AddHead(PolFaces[face_id-1],(PLISTINFO) pfNode); } void CopyFace(int ids[STRIP_MAX], int vert_count, int face_id, int norms[STRIP_MAX]) { PF_FACES pfNode; int *pTempInt; int *pnorms; F_EDGES **pTempVertptr; int *pTempmarked, *pTempwalked; register int y,count = 0; /* Copy a face node into a new node, used after the global algorithm is run, so that we can save whatever is left into a new structure */ pfNode = (PF_FACES) malloc(sizeof(F_FACES) ); if ( pfNode ) { pfNode->pPolygon = (int*) malloc(sizeof(int) * (vert_count) ); pfNode->pNorms = (int*) malloc(sizeof(int) * (vert_count) ); pfNode->VertandId = (F_EDGES**)malloc(sizeof(F_EDGES*) * (vert_count)); pfNode->marked = (int*)malloc(sizeof(int) * (vert_count)); pfNode->walked = (int*)malloc(sizeof(int) * (vert_count)); } pTempInt =pfNode->pPolygon; pnorms = pfNode->pNorms; pTempmarked = pfNode->marked; pTempwalked = pfNode->walked; pTempVertptr = pfNode->VertandId; pfNode->nPolSize = vert_count; pfNode->seen = -1; pfNode->seen2 = -1; for (y=0;y v2) { t = v1; v1 = v2; v2 = t; } pListHead = PolEdges[v1]; temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count); if (temp == NULL) { printf("Have the wrong edge \n:"); exit(1); } while (flag) { if (v2 == temp->edge[0]) return; else temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,++count); } } void Add_AdjEdge(int v1,int v2,int fnum,int index1 ) { PF_EDGES temp = NULL; PF_FACES temp2 = NULL; PF_EDGES pfNode; ListHead *pListHead; ListHead *pListFace; BOOL flag = TRUE; register int count = 0; register int t,v3 = -1; if (v1 > v2) { t = v1; v1 = v2; v2 = t; } pListFace = PolFaces[fnum]; temp2 = (PF_FACES) PeekList(pListFace,LISTHEAD,0); pListHead = PolEdges[v1]; temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count); if (temp == NULL) flag = FALSE; count++; while (flag) { if (v2 == temp->edge[0]) { /* If greater than 2 polygons adjacent to an edge, then we will only save the first 2 that we found. We will have a small performance hit, but this does not happen often. */ if (temp->edge[2] == -1) temp->edge[2] = fnum; else v3 = temp->edge[2]; flag = FALSE; } else { temp = (PF_EDGES) PeekList(pListHead,LISTHEAD,count); count++; if (temp == NULL) flag = FALSE; } } /* Did not find it */ if (temp == NULL) { pfNode = (PF_EDGES) malloc(sizeof(F_EDGES) ); if ( pfNode ) { pfNode->edge[0] = v2; pfNode->edge[1] = fnum; pfNode->edge[2] = v3; AddTail( PolEdges[v1], (PLISTINFO) pfNode ); } else { printf("Out of memory!\n"); exit(1); } *(temp2->VertandId+index1) = pfNode; } else *(temp2->VertandId+index1) = temp; }