/* * Copyright (c) 1986, 1987, 1988, 1989 by Sun Microsystems, Inc. * Permission to use, copy, modify, and distribute this software for any * purpose and without fee is hereby granted, provided that the above * copyright notice appear in all copies and that both that copyright * notice and this permission notice are retained, and that the name * of Sun Microsystems, Inc., not be used in advertising or publicity * pertaining to this software without specific, written prior permission. * Sun Microsystems, Inc., makes no representations about the suitability * of this software or the interface defined in this software for any * purpose. It is provided "as is" without express or implied warranty. */ #ifndef lint static char sccsid[] = "@(#)clipvertex.c 1.1 94/10/31 Copyr 1983 Sun Micro"; #endif /* * Copyright (c) 1983 by Sun Microsystems, Inc. */ /* Polygon clipper for 3-D polygons. Uses Sutherland Hodgeman algorithm in 'Reentrant Polygon Clipping', CACM 17:1, January 1974. Two function calls are included clipvertex( p) must be called for each vertex of a polygon and clipend() is called to terminate the polygon. Output vertices are written to the global array 'vtxlist'. */ /*------------globals---------------------*/ #define TRUE 1 #define FALSE 0 #define LEFT 0 #define RIGHT 1 #define BOTTOM 2 #define TOP 3 #define NEAR 4 #define FAR 5 #define VTXSIZE 7 static int procvtx(), polclos(), outvtx(), polout(); typedef struct { /* vertex, NDC coordinates */ int x,y,z,w; int dx,dy,dz,dw; /* unit normal at vertex 20b.10b */ } vtxtype; extern vtxtype _core_vtxlist[]; /***** OUTPUT VERTEX LIST *****/ extern short _core_vtxcount; static struct clipplane { struct clipplane *nextplane; /* ptr to data for next clip plane */ int (*procvtx)(); /* vertex processing routine */ int (*polclos)(); /* close-polygon-entry routine */ short firstvtx; /* TRUE if this is 1st vertex */ short planeno; /* clip plane number for this plane */ short nout; /* no. vtxs output by this stage */ vtxtype f, /* 1st vertex of polygon */ s, /* saved previous vtx of current pol */ i; /* intersect of edge with clip plane */ } planes[6] = { /* 6 clipping planes */ &planes[1], procvtx, polclos, TRUE, LEFT, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, &planes[2], procvtx, polclos, TRUE, RIGHT, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, &planes[3], procvtx, polclos, TRUE, BOTTOM, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, &planes[4], procvtx, polclos, TRUE, TOP, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, &planes[5], procvtx, polclos, TRUE, NEAR, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, &planes[0], outvtx, polout, TRUE, FAR, 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, }; /*------------------------------------------- printplanes() { int i; for (i=0; i<6; i++) { fprintf(stderr, " %d %d %d\n", planes[i].firstvtx, planes[i].planeno, planes[i].nout); fprintf(stderr, " %d %d %d %d\n", planes[i].f.x,planes[i].f.y, planes[i].f.z,planes[i].f.w); fprintf(stderr, " %d %d %d %d\n", planes[i].s.x,planes[i].s.y, planes[i].s.z,planes[i].s.w); fprintf(stderr, " %d %d %d %d\n", planes[i].i.x,planes[i].i.y, planes[i].i.z,planes[i].i.w); } } ---------------------------------------------*/ /*------------------------------------*/ clipvertex( p) vtxtype *p; { /* hand this routine each vertex */ procvtx( p, &planes[0]); } /*------------------------------------*/ clipend() /* this routine terminates polygon */ { polclos( &planes[0]); } /*------------------------------------*/ static procvtx( p, plane) vtxtype *p; struct clipplane *plane; { if (plane->firstvtx) { plane->f = *p; /* f is first vertex of polygon */ plane->s = *p; /* s is previous 'saved' vertex */ } else { if (linecross( plane, p)) { /* if line sp crosses plane */ plane->s = *p; /* compute intersect vtx i */ (*(plane->procvtx))( &plane->i, plane->nextplane); } else plane->s = *p; } if ( visible( plane)) { /* if s on visible side of plane */ (*(plane->procvtx))( &plane->s, plane->nextplane); plane->nout++; } plane->firstvtx = FALSE; } /*-----------------------------------------*/ static polclos( pl) register struct clipplane *pl; { if (pl->nout ) { if (linecross( pl, &pl->f)) { /* handle last edge */ (*(pl->procvtx))( &pl->i, pl->nextplane); } } pl->firstvtx = TRUE; pl->nout = 0; (*(pl->polclos))( pl->nextplane); } /*--------------------------------------------*/ static outvtx( p, pl) vtxtype *p; struct clipplane *pl; { /* output routine from last stage of clipper */ pl->nout++; _core_vtxlist[_core_vtxcount++] = *p; } /*--------------------------------------------*/ static polout( pl) struct clipplane *pl; { if (pl->nout ) { /* later may want to notify about end of polygon */ } pl->nout = 0; } /*----------------------------------------*/ static linecross( pl, p) struct clipplane *pl; vtxtype *p; { int svis, pvis, diff, i; int *ptri, *ptrs, *ptrp; switch( pl->planeno) { case LEFT: svis = pl->s.x + pl->s.w; /* x-(-w) */ pvis = p->x + p->w; break; case RIGHT: svis = pl->s.w - pl->s.x; /* -(x-w) */ pvis = p->w - p->x; break; case BOTTOM: svis = pl->s.y + pl->s.w; /* y-(-w) */ pvis = p->y + p->w; break; case TOP: svis = pl->s.w - pl->s.y; /* -(y-w) */ pvis = p->w - p->y; break; case NEAR: svis = pl->s.z; /* (z-0) */ pvis = p->z; break; case FAR: svis = pl->s.w - pl->s.z; /* -(z-w) */ pvis = p->w - p->z; break; } if ((svis ^ pvis) & 0x80000000) { /* if opposite signs then on */ diff = svis - pvis; /* opposite sides of plane */ ptri = &pl->i.x; ptrs = &pl->s.x; ptrp = &p->x; for (i=0; iplaneno) { case LEFT: svis = pl->s.x + pl->s.w; /* x-(-w) */ break; case RIGHT: svis = pl->s.w - pl->s.x; /* -(x-w) */ break; case BOTTOM: svis = pl->s.y + pl->s.w; /* y-(-w) */ break; case TOP: svis = pl->s.w - pl->s.y; /* -(y-w) */ break; case NEAR: svis = pl->s.z; /* (z-0) */ break; case FAR: svis = pl->s.w - pl->s.z; /* -(z-w) */ break; } if (svis >= 0) return( TRUE); else return( FALSE); }