518 lines
16 KiB
C
518 lines
16 KiB
C
/********************************************************************/
|
|
/* STRIPE: converting a polygonal model to triangle strips
|
|
Francine Evans, 1996.
|
|
SUNY @ Stony Brook
|
|
Advisors: Steven Skiena and Amitabh Varshney
|
|
*/
|
|
/********************************************************************/
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
/* STRIPE: outputex.c
|
|
This file contains routines that are used for various functions in
|
|
the local algorithm.
|
|
*/
|
|
/*---------------------------------------------------------------------*/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "global.h"
|
|
#include "outputex.h"
|
|
#include "triangulatex.h"
|
|
#include "polverts.h"
|
|
#include "ties.h"
|
|
#include "partial.h"
|
|
#include "sturctsex.h"
|
|
#include "options.h"
|
|
#include "output.h"
|
|
#include "common.h"
|
|
#include "util.h"
|
|
|
|
|
|
void Output_TriEx(int id1, int id2, int id3, FILE *output, int next_face, int flag,
|
|
int where)
|
|
{
|
|
/* We will save everything into a list, rather than output at once,
|
|
as was done in the old routine. This way for future modifications
|
|
we can change the strips later on if we want to.
|
|
*/
|
|
|
|
int swap,temp1,temp2,temp3;
|
|
static int total=0;
|
|
static int tri=0;
|
|
static int strips = 0;
|
|
static int cost = 0;
|
|
|
|
if (flag == -20)
|
|
{
|
|
cost = cost + where+total+tri+strips+strips;
|
|
printf("We will need to send %d vertices to the renderer\n",cost);
|
|
total = 0;
|
|
tri = 0;
|
|
strips = 0;
|
|
return ;
|
|
}
|
|
|
|
|
|
if (flag == -10)
|
|
/* We are finished, now is time to output the triangle list
|
|
*/
|
|
{
|
|
fprintf(output,"\nt ");
|
|
tri = tri + Finished(&swap,output,FALSE);
|
|
total = total + swap;
|
|
strips++;
|
|
/*printf("There are %d swaps %d tri %d strips\n",total,tri,strips);*/
|
|
}
|
|
|
|
else
|
|
{
|
|
Last_Edge(&temp1,&temp2,&temp3,0);
|
|
Add_Id_Strips(id1,where);
|
|
Add_Id_Strips(id2,where);
|
|
Add_Id_Strips(id3,where);
|
|
Last_Edge(&id1,&id2,&id3,1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void Extend_BackwardsEx(int face_id, FILE *output, FILE *strip, int *ties,
|
|
int tie, int triangulate,
|
|
int swaps,int *next_id)
|
|
{
|
|
/* We just made a strip, now we are going to see if we can extend
|
|
backwards from the starting face, which had 2 or more adjacencies
|
|
to start with.
|
|
*/
|
|
int bucket,next_face,num,x,y,z,c,d=1,max,f;
|
|
ListHead *pListFace;
|
|
PF_FACES face;
|
|
P_ADJACENCIES temp;
|
|
|
|
/* Get the first triangle that we have saved the the strip data
|
|
structure, so we can see if there are any polygons adjacent
|
|
to this edge or a neighboring one
|
|
*/
|
|
First_Edge(&x,&y,&z);
|
|
|
|
pListFace = PolFaces[face_id];
|
|
face = (PF_FACES) PeekList(pListFace,LISTHEAD,0);
|
|
|
|
num = face->nPolSize;
|
|
|
|
/* Go through the edges to see if there is an adjacency
|
|
with a vertex in common to the first triangle that was
|
|
outputted in the strip. (maybe edge was deleted....)
|
|
*/
|
|
for (c=0; c<num ; c++)
|
|
{
|
|
|
|
if ( (c != (num-1)) &&
|
|
(( (*(face->pPolygon+c) == x) && (*(face->pPolygon+c+1) == y)) ||
|
|
(*(face->pPolygon+c) == y) && (*(face->pPolygon+c+1) == x)))
|
|
{
|
|
/* Input edge is still there see if there is an adjacency */
|
|
next_face = Find_Face(face_id, x, y, &bucket);
|
|
if (next_face == -1)
|
|
/* Could not find a face adjacent to the edge */
|
|
break;
|
|
pListFace = array[bucket];
|
|
max = NumOnList(pListFace);
|
|
for (f=0;;f++)
|
|
{
|
|
temp = (P_ADJACENCIES) PeekList(pListFace,LISTHEAD,f);
|
|
if (temp->face_id == next_face)
|
|
{
|
|
Last_Edge(&z,&y,&x,1);
|
|
Polygon_OutputEx(temp,temp->face_id,bucket,pListFace,
|
|
output,strip,ties,tie,triangulate,swaps,next_id,0);
|
|
return;
|
|
}
|
|
|
|
if (temp == NULL)
|
|
{
|
|
printf("Error in the new buckets%d %d %d\n",bucket,max,0);
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
}
|
|
else if ( (c == (num -1)) &&
|
|
( ((*(face->pPolygon) == x) && (*(face->pPolygon+num-1) == y)) ||
|
|
(*(face->pPolygon) == y) && (*(face->pPolygon+num-1) == x)))
|
|
{
|
|
next_face = Find_Face(face_id,x,y,&bucket);
|
|
if (next_face == -1)
|
|
/* Could not find a face adjacent to the edge */
|
|
break;
|
|
pListFace = array[bucket];
|
|
max = NumOnList(pListFace);
|
|
for (f=0;;f++)
|
|
{
|
|
temp = (P_ADJACENCIES) PeekList(pListFace,LISTHEAD,f);
|
|
if (temp->face_id == next_face)
|
|
{
|
|
Last_Edge(&z,&y,&x,1);
|
|
Polygon_OutputEx(temp,temp->face_id,bucket,pListFace,
|
|
output,strip,ties,tie,triangulate,swaps,next_id,0);
|
|
return;
|
|
}
|
|
|
|
if (temp == NULL)
|
|
{
|
|
printf("Error in the new buckets%d %d %d\n",bucket,max,0);
|
|
exit(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void Polygon_OutputEx(P_ADJACENCIES temp,int face_id,int bucket,
|
|
ListHead *pListHead, FILE *output, FILE *strips,
|
|
int *ties, int tie,
|
|
int triangulate, int swaps,
|
|
int *next_id, int where)
|
|
{
|
|
ListHead *pListFace;
|
|
PF_FACES face;
|
|
P_ADJACENCIES pfNode;
|
|
static BOOL begin = TRUE;
|
|
int old_face,next_face_id,next_bucket,e1,e2,e3,other1,other2,other3;
|
|
P_ADJACENCIES lpListInfo;
|
|
|
|
/* We have a polygon to output, the id is face id, and the number
|
|
of adjacent polygons to it is bucket.
|
|
*/
|
|
|
|
Last_Edge(&e1,&e2,&e3,0);
|
|
|
|
/* Get the polygon with id face_id */
|
|
pListFace = PolFaces[face_id];
|
|
face = (PF_FACES) PeekList(pListFace,LISTHEAD,0);
|
|
|
|
if (face->nPolSize == 3)
|
|
{
|
|
/* It is already a triangle */
|
|
if (bucket == 0)
|
|
{
|
|
/* It is not adjacent to anything so we do not have to
|
|
worry about the order of the sides or updating adjacencies
|
|
*/
|
|
|
|
Last_Edge(&e1,&e2,&e3,0);
|
|
next_face_id = Different(*(face->pPolygon),*(face->pPolygon+1),*(face->pPolygon+2),
|
|
e1,e2,e3,&other1,&other2);
|
|
/* No input edge, at the start */
|
|
if ((e2 ==0) && (e3 == 0))
|
|
{
|
|
e2 = other1;
|
|
e3 = other2;
|
|
}
|
|
|
|
Output_TriEx(e2,e3,next_face_id,strips,-1,begin,where);
|
|
RemoveList(pListHead,(PLISTINFO) temp);
|
|
/* We will be at the beginning of the next strip. */
|
|
begin = TRUE;
|
|
}
|
|
/* It is a triangle with adjacencies. This means that we
|
|
have to:
|
|
1. Update the adjacencies in the list, because we are
|
|
using this polygon and it will be deleted.
|
|
2. Get the next polygon.
|
|
*/
|
|
else
|
|
{
|
|
/* Return the face_id of the next polygon we will be using,
|
|
while updating the adjacency list by decrementing the
|
|
adjacencies of everything adjacent to the current triangle.
|
|
*/
|
|
|
|
next_face_id = Update_AdjacenciesEx(face_id, &next_bucket, &e1,&e2,ties);
|
|
old_face = next_face_id;
|
|
|
|
/* Break the tie, if there was one */
|
|
if (tie != FIRST)
|
|
old_face = Get_Next_Face(tie,face_id,triangulate);
|
|
|
|
if (next_face_id == -1)
|
|
{
|
|
Polygon_OutputEx(temp,face_id,0,pListHead,output,strips,ties,tie,
|
|
triangulate,swaps,next_id,where);
|
|
return;
|
|
}
|
|
|
|
|
|
/* We are using a different face */
|
|
if ((tie != FIRST) && (old_face != next_face_id) && (swaps == ON))
|
|
{
|
|
next_face_id = old_face;
|
|
/* Get the new output edge, since e1 and e2 are for the
|
|
original next face that we got.
|
|
*/
|
|
e3 = Get_EdgeEx(&e1,&e2,face->pPolygon,next_face_id,face->nPolSize,0,0);
|
|
}
|
|
|
|
/* Find the other vertex to transmit in the triangle */
|
|
e3 = Return_Other(face->pPolygon,e1,e2);
|
|
Last_Edge(&other1,&other2,&other3,0);
|
|
|
|
if ((other1 != 0) && (other2 != 0))
|
|
{
|
|
/* See which vertex in the output edge is not in the input edge */
|
|
if ((e1 != other2) && (e1 != other3))
|
|
e3 = e1;
|
|
else if ((e2 != other2) && (e2 != other3))
|
|
e3 = e2;
|
|
/* can happen with > 2 polys on an edge but won't form a good strip so stop
|
|
the strip here
|
|
*/
|
|
else
|
|
{
|
|
Polygon_OutputEx(temp,face_id,0,pListHead,output,strips,ties,tie,
|
|
triangulate,swaps,next_id,where);
|
|
return;
|
|
}
|
|
|
|
/* See which vertex of the input edge is not in the output edge */
|
|
if ((other2 != e1) && (other2 != e2))
|
|
{
|
|
other1 = other2;
|
|
other2 = other3;
|
|
}
|
|
else if ((other3 != e1) && (other3 != e2))
|
|
other1 = other3;
|
|
else
|
|
{
|
|
/* Degenerate triangle just return*/
|
|
Output_TriEx(other1,other2,e3,strips,next_face_id,begin,where);
|
|
RemoveList(pListHead,(PLISTINFO) temp);
|
|
begin = FALSE;
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
/* There was not an input edge, we are the first triangle in a strip */
|
|
else
|
|
{
|
|
/* Find the correct order to transmit the triangle, what is
|
|
the output edge that we want ?
|
|
*/
|
|
other1 = e3;
|
|
e3 = e2;
|
|
other2 = e1;
|
|
}
|
|
|
|
/* At this point the adjacencies have been updated and we
|
|
have the next polygon id
|
|
*/
|
|
Output_TriEx(other1,other2,e3,strips,next_face_id,begin,where);
|
|
RemoveList(pListHead,(PLISTINFO) temp);
|
|
begin = FALSE;
|
|
|
|
if (Done(next_face_id,59,&next_bucket) == NULL)
|
|
return;
|
|
|
|
pListHead = array[next_bucket];
|
|
pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
|
|
if ( pfNode )
|
|
pfNode->face_id = next_face_id;
|
|
lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
|
|
(int (*)(void *,void *)) (Compare)));
|
|
if (lpListInfo == NULL)
|
|
{
|
|
printf("There is an error finding the next polygon3 %d\n",next_face_id);
|
|
exit(0);
|
|
}
|
|
Polygon_OutputEx(lpListInfo,next_face_id,next_bucket,
|
|
pListHead, output, strips,ties,tie,triangulate,swaps,next_id,where);
|
|
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
/* It is not a triangle, we have to triangulate it .
|
|
Since it is not adjacent to anything we can triangulate it
|
|
blindly
|
|
*/
|
|
if (bucket == 0)
|
|
{
|
|
/* Check to see if there is not an input edge */
|
|
Last_Edge(&other1,&other2,&other3,0);
|
|
if ((other1 == 0) && (other2 ==0))
|
|
Blind_TriangulateEx(face->nPolSize,face->pPolygon, strips,
|
|
output,TRUE,where);
|
|
else
|
|
Blind_TriangulateEx(face->nPolSize,face->pPolygon,strips,
|
|
output,FALSE,where);
|
|
|
|
RemoveList(pListHead,(PLISTINFO) temp);
|
|
/* We will be at the beginning of the next strip. */
|
|
begin = TRUE;
|
|
}
|
|
|
|
/* If we have specified PARTIAL triangulation then
|
|
we will go to special routines that will break the
|
|
polygon and update the data structure. Else everything
|
|
below will simply triangulate the whole polygon
|
|
*/
|
|
else if (triangulate == PARTIAL)
|
|
{
|
|
|
|
/* Return the face_id of the next polygon we will be using,
|
|
*/
|
|
next_face_id = Min_Face_AdjEx(face_id,&next_bucket,ties);
|
|
|
|
|
|
/* Don't do it partially, because we can go inside and get
|
|
less adjacencies, for a quad we can do the whole thing.
|
|
*/
|
|
if ((face_id == next_face_id) && (face->nPolSize == 4) && (swaps == ON))
|
|
{
|
|
next_face_id = Update_AdjacenciesEx(face_id, &next_bucket, &e1,&e2,ties);
|
|
if (next_face_id == -1)
|
|
{
|
|
/* There is no sequential face to go to, end the strip */
|
|
Polygon_OutputEx(temp,face_id,0,pListHead,output,strips,ties,tie,
|
|
triangulate,swaps,next_id,where);
|
|
return;
|
|
}
|
|
|
|
/* Break the tie, if there was one */
|
|
if (tie != FIRST)
|
|
next_face_id = Get_Next_Face(tie,face_id,triangulate);
|
|
Non_Blind_TriangulateEx(face->nPolSize,face->pPolygon, strips,
|
|
output,next_face_id,face_id,where);
|
|
RemoveList(pListHead,(PLISTINFO) temp);
|
|
}
|
|
|
|
/* Was not a quad but we still do not want to do it partially for
|
|
now, since we want to only do one triangle at a time
|
|
*/
|
|
else if ((face_id == next_face_id) && (swaps == ON))
|
|
Inside_Polygon(face->nPolSize,face->pPolygon,strips,output,
|
|
next_face_id,face_id,next_id,pListHead,temp,where);
|
|
|
|
else
|
|
{
|
|
if ((tie != FIRST) && (swaps == ON))
|
|
next_face_id = Get_Next_Face(tie,face_id,triangulate);
|
|
Partial_Triangulate(face->nPolSize,face->pPolygon,strips,
|
|
output,next_face_id,face_id,next_id,pListHead,temp,where);
|
|
/* Check the next bucket again ,maybe it changed
|
|
We calculated one less, but that might not be the case
|
|
*/
|
|
}
|
|
|
|
if (Done(next_face_id,59,&next_bucket) == NULL)
|
|
{
|
|
/* Check to see if there is not an input edge */
|
|
Last_Edge(&other1,&other2,&other3,0);
|
|
if ((other1 == 0) && (other2 ==0))
|
|
Blind_TriangulateEx(face->nPolSize,face->pPolygon, strips,
|
|
output,TRUE,where);
|
|
else
|
|
Blind_TriangulateEx(face->nPolSize,face->pPolygon,strips,
|
|
output,FALSE,where);
|
|
|
|
if (Done(face_id,59,&bucket) != NULL)
|
|
{
|
|
pListHead = array[bucket];
|
|
pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
|
|
if ( pfNode )
|
|
pfNode->face_id = face_id;
|
|
lpListInfo = (P_ADJACENCIES) (SearchList(array[bucket], pfNode,
|
|
(int (*)(void *,void *)) (Compare)));
|
|
RemoveList(pListHead,(PLISTINFO)lpListInfo);
|
|
}
|
|
begin = TRUE;
|
|
return;
|
|
}
|
|
|
|
begin = FALSE;
|
|
pListHead = array[next_bucket];
|
|
pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
|
|
if ( pfNode )
|
|
pfNode->face_id = next_face_id;
|
|
lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
|
|
(int (*)(void *,void *)) (Compare)));
|
|
if (lpListInfo == NULL)
|
|
{
|
|
printf("There is an error finding the next polygon1 %d %d\n",next_face_id,next_bucket);
|
|
exit(0);
|
|
}
|
|
Polygon_OutputEx(lpListInfo,next_face_id,next_bucket,
|
|
pListHead, output, strips,ties,tie,triangulate,swaps,next_id,where);
|
|
}
|
|
|
|
|
|
else
|
|
{
|
|
/* WHOLE triangulation */
|
|
/* It is not a triangle and has adjacencies.
|
|
This means that we have to:
|
|
1. TriangulateEx this polygon, not blindly because
|
|
we have an edge that we want to come out on, that
|
|
is the edge that is adjacent to a polygon with the
|
|
least number of adjacencies. Also we must come in
|
|
on the last seen edge.
|
|
2. Update the adjacencies in the list, because we are
|
|
using this polygon .
|
|
3. Get the next polygon.
|
|
*/
|
|
/* Return the face_id of the next polygon we will be using,
|
|
while updating the adjacency list by decrementing the
|
|
adjacencies of everything adjacent to the current polygon.
|
|
*/
|
|
|
|
next_face_id = Update_AdjacenciesEx(face_id, &next_bucket, &e1,&e2,ties);
|
|
|
|
if (Done(next_face_id,59,&next_bucket) == NULL)
|
|
{
|
|
Polygon_OutputEx(temp,face_id,0,pListHead,output,strips,ties,tie,
|
|
triangulate,swaps,next_id,where);
|
|
/* Because maybe there was more than 2 polygons on the edge */
|
|
return;
|
|
}
|
|
|
|
/* Break the tie, if there was one */
|
|
else if (tie != FIRST)
|
|
next_face_id = Get_Next_Face(tie,face_id,triangulate);
|
|
|
|
Non_Blind_TriangulateEx(face->nPolSize,face->pPolygon, strips,
|
|
output,next_face_id,face_id,where);
|
|
RemoveList(pListHead,(PLISTINFO) temp);
|
|
begin = FALSE;
|
|
pListHead = array[next_bucket];
|
|
pfNode = (P_ADJACENCIES) malloc(sizeof(ADJACENCIES) );
|
|
if ( pfNode )
|
|
pfNode->face_id = next_face_id;
|
|
lpListInfo = (P_ADJACENCIES) (SearchList(array[next_bucket], pfNode,
|
|
(int (*)(void *,void *)) (Compare)));
|
|
if (lpListInfo == NULL)
|
|
{
|
|
printf("There is an error finding the next polygon2 %d %d\n",next_face_id,next_bucket);
|
|
exit(0);
|
|
}
|
|
Polygon_OutputEx(lpListInfo,next_face_id,next_bucket,
|
|
pListHead, output, strips,ties,tie,triangulate,swaps,next_id,where);
|
|
}
|
|
|
|
}
|
|
Last_Edge(&e1,&e2,&e3,0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|