/************************************************************************** * * * Copyright (C) 1989, Silicon Graphics, Inc. * * * * These coded instructions, statements, and computer programs contain * * unpublished proprietary information of Silicon Graphics, Inc., and * * are protected by Federal copyright law. They may not be disclosed * * to third parties or copied or duplicated in any form, in whole or * * in part, without the prior written consent of Silicon Graphics, Inc. * * * **************************************************************************/ /* msort.c */ /* Tom Davis - 1988 Derrick Burns - 1989 */ #include #include #include #ifndef NT #include #include #else #include "winmem.h" #endif #include "monotone.h" #include "msort.h" /* code to do a merge sort where we assume that the initial data tends * to make long runs, either up or down. */ #define INITSORT 50 /*--------------------------------------------------------------------------- * init_sort - initialize merge sort data structures *--------------------------------------------------------------------------- */ void __gl_init_sort( GLUtriangulatorObj *tobj, long n ) { if( n == 0 ) return; if( tobj->minit ) { if( n > tobj->size ) { free( tobj->ptrlist ); free( tobj->limits ); free( tobj->dirs ); tobj->size = n * 2; tobj->ptrlist = (void **) malloc((unsigned int)tobj->size*sizeof(void *) ); tobj->limits = (long *) malloc((unsigned int)(tobj->size+1)*sizeof(long) ); tobj->dirs = (enum updown *) malloc((unsigned int)tobj->size*sizeof(enum updown) ); } } else { tobj->size = n; tobj->ptrlist = (void **) malloc((unsigned int)tobj->size*sizeof(void *) ); tobj->limits = (long *) malloc((unsigned int)(tobj->size+1)*sizeof(long) ); tobj->dirs = (enum updown *) malloc((unsigned int)tobj->size*sizeof(enum updown) ); tobj->minit = 1; } } /*--------------------------------------------------------------------------- * clear_sort - free merge sort data structures *--------------------------------------------------------------------------- */ void __gl_clear_sort( GLUtriangulatorObj *tobj ) { if( tobj->minit ) { free( tobj->ptrlist ); free( tobj->limits ); free( tobj->dirs ); tobj->minit = 0; } } /*--------------------------------------------------------------------------- * msort - perform a merge sort on the data *--------------------------------------------------------------------------- */ void __gl_msort( GLUtriangulatorObj *tobj, void **curptrlist, long count, long width, SortFunc comp ) { long i; long p1s, p1e, p2s, p2e, d1, d2; long q; int result; void *tmp; void **temp; void **newptrlist, **saveptrlist; void **c1s, **c1e, **c2s, **c2e, **np; /* XXX ** if comp() returns 0, then vertices are coincident. That is illegal, ** call error. */ if( count <= 1) return; if( count == 2) { result = comp( &curptrlist[0], &curptrlist[1] ); if( result < 0 ) { tmp = curptrlist[0]; curptrlist[0] = curptrlist[1]; curptrlist[1] = tmp; } else if (result == 0) { __gl_in_error( tobj, 6 ); } return; } __gl_init_sort( tobj, count ); saveptrlist = curptrlist; newptrlist = tobj->ptrlist; tobj->limitcount = 0; tobj->limits[0] = 0; i=0; while( 1 ) { do { i++; if( i == count ) break; result = comp(&curptrlist[i-1], &curptrlist[i]); if (result == 0) { __gl_in_error( tobj, 6 ); } } while( result > 0 ); tobj->dirs[tobj->limitcount] = down; tobj->limits[++tobj->limitcount] = i; if( i == count ) break; do { i++; if( i == count ) break; result = comp(&curptrlist[i-1], &curptrlist[i]); if (result == 0) { __gl_in_error( tobj, 6 ); } } while( result <= 0 ); tobj->dirs[tobj->limitcount] = up; tobj->limits[++tobj->limitcount] = i; if( i == count ) break; } q = tobj->newlimitcount = 0; for (i = 0; i < tobj->limitcount-1; i += 2) { if (tobj->dirs[i] == up) { p1s = tobj->limits[i]; p1e = tobj->limits[i+1]; d1 = 1; } else { p1s = tobj->limits[i+1]-1; p1e = tobj->limits[i]-1; d1 = -1; } if (tobj->dirs[i+1] == up) { p2s = tobj->limits[i+1]; p2e = tobj->limits[i+2]; d2 = 1; } else { p2s = tobj->limits[i+2]-1; p2e = tobj->limits[i+1]-1; d2 = -1; } while ((p1s != p1e) && (p2s != p2e)) { result = comp(&curptrlist[p1s], &curptrlist[p2s]); if (result == 0) { __gl_in_error( tobj, 6 ); } if (result > 0) { newptrlist[q++] = curptrlist[p2s]; p2s += d2; if (p2s == p2e) do { newptrlist[q++] = curptrlist[p1s]; p1s += d1; } while (p1s != p1e); } else { newptrlist[q++] = curptrlist[p1s]; p1s += d1; if (p1s == p1e) do { newptrlist[q++] = curptrlist[p2s]; p2s += d2; } while (p2s != p2e); } } tobj->limits[++tobj->newlimitcount] = q; } if (tobj->limitcount & 1) { if (tobj->dirs[tobj->limitcount-1] == up) { p1s = tobj->limits[tobj->limitcount-1]; p1e = tobj->limits[tobj->limitcount]; d1 = 1; } else { p1s = tobj->limits[tobj->limitcount] - 1; p1e = tobj->limits[tobj->limitcount-1] - 1; d1 = -1; } do { newptrlist[q++] = curptrlist[p1s]; p1s += d1; } while (p1s != p1e); tobj->limits[++tobj->newlimitcount] = q; } tobj->limitcount = tobj->newlimitcount; // The x86 compiler does not deal with this swap properly (though it does // it fine in the while loop below). Luckily, at this point saveptrlist // has the data we want, so do the assignment to newptrlist using it instead. // // Meanwhile, lets keep the old code around so we can verify the compiler // fix when it rolls out. //!!!XXX -- compiler bug #ifdef COMPILER_FIXED temp = curptrlist; curptrlist = newptrlist; newptrlist = temp; #else curptrlist = newptrlist; newptrlist = saveptrlist; #endif while (tobj->limitcount > 1) { np = newptrlist; q = tobj->newlimitcount = 0; for (i = 0; i < tobj->limitcount-1; i += 2) { c1s = curptrlist + tobj->limits[i]; c1e = curptrlist + tobj->limits[i+1]; c2s = curptrlist + tobj->limits[i+1]; c2e = curptrlist + tobj->limits[i+2]; while ((c1s != c1e) && (c2s != c2e)) { result = comp(c1s, c2s); if (result == 0) { __gl_in_error( tobj, 6 ); } if (result > 0) { *np++ = *c2s++; if (c2s == c2e) do { *np++ = *c1s++; } while (c1s != c1e); } else { *np++ = *c1s++; if (c1s == c1e) do { *np++ = *c2s++; } while (c2s != c2e); } } tobj->limits[++tobj->newlimitcount] = np - newptrlist; } if( tobj->limitcount & 1 ) { p1s = tobj->limits[tobj->limitcount-1]; p1e = tobj->limits[tobj->limitcount]; do { *np++ = curptrlist[p1s++]; } while (p1s != p1e); tobj->limits[++tobj->newlimitcount] = np - newptrlist; } tobj->limitcount = tobj->newlimitcount; temp = curptrlist; curptrlist = newptrlist; newptrlist = temp; } if (curptrlist != saveptrlist) for (i = 0; i < count; i++) saveptrlist[i] = curptrlist[i]; }