1660 lines
53 KiB
C
1660 lines
53 KiB
C
|
/********************************************************************/
|
||
|
/* 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 <stdlib.h>
|
||
|
#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; x<numfaces; x++)
|
||
|
{
|
||
|
/* Used to produce the triangle strips */
|
||
|
|
||
|
/* for each face, get the face */
|
||
|
pListHead = PolFaces[x];
|
||
|
temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
|
||
|
numverts = temp->nPolSize;
|
||
|
|
||
|
/* 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; x<numfaces; x++)
|
||
|
{
|
||
|
/* for each face, get the face */
|
||
|
pListHead = PolFaces[x];
|
||
|
temp = (PF_FACES) PeekList(pListHead,LISTHEAD,0);
|
||
|
numverts = temp->nPolSize;
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|