1
0
Fork 0
terragear/detect.c

184 lines
6.6 KiB
C
Raw Normal View History

2000-02-09 19:51:45 +00:00
#include "plugin.h"
// Triangle-stripdetection made simple. By Joost Bloemen, Copyright Vimana BV
// If you can improve the algorithm, be sure to let me know you can reach me
// at research@3dtop.com
struct BMF_SURFACE{
USHORT p0, p1, p2;
};
struct Hit{
USHORT hits;
USHORT t[3];
UCHAR mask[3];
BMF_SURFACE p[3];
BOOL Stripped;
}* HitList;
// INPUT:
//ilist is the list with indices of the original triangles, will be broken down to
// only the triangles that can 't be stripped, at the end.
//length is the number of triangles in ilist.
// OUTPUT:
//nr-strips is the number of strips we detected, they have a minimum of two triangles
//strips_length contains an array[nr_strips] of strip-lengths, strip1, strip2 strip3 etc...
//nr_indices is the total number of vertice-indices we have in the array "stripindex":
//stripindex is a long list of strip1-indices, strip2-indices, strip3-indices etc...
//return-value is the new number of seperate triangles in ilist.
USHORT DetectStrips(BMF_SURFACE * ilist, USHORT length,
USHORT * nr_strips, USHORT * strip_length,
USHORT * nr_indices, USHORT * stripindex)
{
USHORT lastp0,lastp1,lastp2;
USHORT n,nr,trynr;
USHORT p0,p1,p2;
USHORT i,k,next,p;
UCHAR mask;
BMF_SURFACE * temp, * tempEnd;
struct Hit * tempHitList;
// First part makes a hitlist per triangle, how many sides(hits) a triangle has shared,
// the indexes of the hits, up to 3 masks that define wich points the triangles each share
// and the points of each shared triangle.
HitList=(struct Hit *)GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT,length*sizeof(struct Hit));
tempHitList=HitList;
for(n=0;n<length;n++,tempHitList++)
{
p0=ilist[n].p0;
p1=ilist[n].p1;
p2=ilist[n].p2;
temp=ilist;
tempEnd=ilist+length;
while(temp<tempEnd)
{USHORT p;
// The following piece of code accounts for 99% of the time when converting large models
nr=2; // count-down, we only want the ones with two points the same
mask=0;
if ((p=temp->p0)==p0){mask|=0x11;nr--;}
else {if (p==p1){mask|=0x12;nr--;}
else {if (p==p2){mask|=0x14;nr--;}}
}
if ((p=temp->p1)==p0){mask|=0x21;nr--;}
else {if (p==p1){mask|=0x22;nr--;}
else {if (p==p2){mask|=0x24;nr--;}}
}
if ((p=temp->p2)==p0){mask|=0x41;nr--;}
else {if (p==p1){mask|=0x42;nr--;}
else {if (p==p2){mask|=0x44;nr--;}}
}
// That's it
if(!nr) //this doesn't happen very often
{USHORT nrs=tempHitList->hits;
//Rotate and save points so that p0 and p1 point to points that are the same.
// to check later, if we can make a strip of this
switch (mask>>4){
case 5:
tempHitList->p[nrs].p1=temp->p0;
tempHitList->p[nrs].p0=temp->p2;
tempHitList->p[nrs].p2=temp->p1;
break;
case 6:
tempHitList->p[nrs].p0=temp->p1;
tempHitList->p[nrs].p1=temp->p2;
tempHitList->p[nrs].p2=temp->p0;
break;
case 3:
tempHitList->p[nrs].p0=temp->p0;
tempHitList->p[nrs].p1=temp->p1;
tempHitList->p[nrs].p2=temp->p2;
break;
}
tempHitList->t[nrs]=temp-ilist; // (temp-ilist) is actually the triangle-number
tempHitList->mask[nrs]=mask; // mask is for later
if(++tempHitList->hits==3)temp=tempEnd; // break while-loop if we have 3 hits
}
temp++;
}
}
// Next:
// Start with trying to make a strip of all triangles with 1 hit as a starting point,
// then 2 , finally 3.
// That's all.
for(trynr=1;trynr<=3;trynr++)
{
for(p=0;p<length;p++)
{
if(HitList[p].hits==trynr&&!HitList[p].Stripped)
{
n=p; // n is first triangle of possible strip
i=0; // i is triangle-counter of this possible strip
k=10; // found a matching triangle
while(k>=10) // while found a triangle
{for (k=0;k<trynr;k++) // try all possible triangles
{next=HitList[n].t[k]; // possible triangle
if(!HitList[next].Stripped) // not included yet ?
{if(!i) // if testing with first triangle, it must be rotated so that
// points that are the same as next triangle are p1 and p2
{switch (HitList[n].mask[k]&0x0f){
case 6:
lastp0=ilist[p].p0; // lastp0-p2 is first triangle of strip
lastp1=ilist[p].p1; // is a local triangle that defines the last
lastp2=ilist[p].p2; // triangle added to the strip
break;
case 3:
lastp1=ilist[p].p0;
lastp2=ilist[p].p1;
lastp0=ilist[p].p2;
break;
case 5:
lastp0=ilist[p].p1;
lastp1=ilist[p].p2;
lastp2=ilist[p].p0;
break;
}
stripindex[*nr_indices]=lastp0; //save
stripindex[(*nr_indices)+1]=lastp1;
stripindex[(*nr_indices)+2]=lastp2;
}
if(i&1) // odd or even, makes a difference, see OpenGL
{if (HitList[n].p[k].p0==lastp0&&HitList[n].p[k].p1==lastp2) //new one fits ?
{lastp0=HitList[n].p[k].p0; // update last triangle used
lastp1=HitList[n].p[k].p1;
lastp2=HitList[n].p[k].p2;
HitList[next].Stripped=TRUE; //this one is done
stripindex[(*nr_indices)++]=lastp2; //save, p2 defines this triangle
n=next; //use this one as next source
k=10; // break for-loop with k, found one
i++;
} }
else
{if (HitList[n].p[k].p0==lastp2&&HitList[n].p[k].p1==lastp1) //new one fits ?
{lastp0=HitList[n].p[k].p0; // update last triangle used
lastp1=HitList[n].p[k].p1;
lastp2=HitList[n].p[k].p2;
HitList[next].Stripped=TRUE; //this one is done
if(!i++)
{
(*nr_indices)+=3; //first triangle had 3 indices and keep it
HitList[n].Stripped=TRUE; //and is done also
}
stripindex[(*nr_indices)++]=lastp2; // save, p2 defines this triangle
n=next; //use this one as next source
k=10; // break for-loop with k, found one
} } } } }
i++; //actual number of triangles in strip is one more
if(i>1)strip_length[(*nr_strips)++]=i+2; //actual strip-length (in indices) is traingles +2
} } }
// Done.
// Now keep all triangles that aren't stripped in original triangle-list and return
// remaining number of triangles in original triangle-list.
i=0;
for(p=0;p<length;p++)
{if(!HitList[p].Stripped)
{
ilist[i++]=ilist[p];
}
}
GlobalFree(HitList);
return(i);
}