sweep.c

来自「mesa-6.5-minigui源码」· C语言 代码 · 共 1,363 行 · 第 1/4 页

C
1,363
字号
/*** License Applicability. Except to the extent portions of this file are** made subject to an alternative license as permitted in the SGI Free** Software License B, Version 1.1 (the "License"), the contents of this** file are subject only to the provisions of the License. You may not use** this file except in compliance with the License. You may obtain a copy** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:**** http://oss.sgi.com/projects/FreeB**** Note that, as provided in the License, the Software is distributed on an** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.**** Original Code. The Original Code is: OpenGL Sample Implementation,** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.** Copyright in any portions created by third parties is as indicated** elsewhere herein. All Rights Reserved.**** Additional Notice Provisions: The application programming interfaces** established by SGI in conjunction with the Original Code are The** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X** Window System(R) (Version 1.3), released October 19, 1998. This software** was created using the OpenGL(R) version 1.2.1 Sample Implementation** published by SGI, but has not been independently verified as being** compliant with the OpenGL(R) version 1.2.1 Specification.***//*** Author: Eric Veach, July 1994.***/#include "gluos.h"#include <assert.h>#include <stddef.h>#include <setjmp.h>		/* longjmp */#include <limits.h>		/* LONG_MAX */#include "mesh.h"#include "geom.h"#include "tess.h"#include "dict.h"#include "priorityq.h"#include "memalloc.h"#include "sweep.h"#define TRUE 1#define FALSE 0#ifdef FOR_TRITE_TEST_PROGRAMextern void DebugEvent( GLUtesselator *tess );#else#define DebugEvent( tess )#endif/* * Invariants for the Edge Dictionary. * - each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2) *   at any valid location of the sweep event * - if EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2 *   share a common endpoint * - for each e, e->Dst has been processed, but not e->Org * - each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org) *   where "event" is the current sweep line event. * - no edge e has zero length * * Invariants for the Mesh (the processed portion). * - the portion of the mesh left of the sweep line is a planar graph, *   ie. there is *some* way to embed it in the plane * - no processed edge has zero length * - no two processed vertices have identical coordinates * - each "inside" region is monotone, ie. can be broken into two chains *   of monotonically increasing vertices according to VertLeq(v1,v2) *   - a non-invariant: these chains may intersect (very slightly) * * Invariants for the Sweep. * - if none of the edges incident to the event vertex have an activeRegion *   (ie. none of these edges are in the edge dictionary), then the vertex *   has only right-going edges. * - if an edge is marked "fixUpperEdge" (it is a temporary edge introduced *   by ConnectRightVertex), then it is the only right-going edge from *   its associated vertex.  (This says that these edges exist only *   when it is necessary.) */#undef	MAX#undef	MIN#define MAX(x,y)	((x) >= (y) ? (x) : (y))#define MIN(x,y)	((x) <= (y) ? (x) : (y))/* When we merge two edges into one, we need to compute the combined * winding of the new edge. */#define AddWinding(eDst,eSrc)	(eDst->winding += eSrc->winding, \                                 eDst->Sym->winding += eSrc->Sym->winding)static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent );static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp );static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp );static int EdgeLeq( GLUtesselator *tess, ActiveRegion *reg1,		    ActiveRegion *reg2 )/* * Both edges must be directed from right to left (this is the canonical * direction for the upper edge of each region). * * The strategy is to evaluate a "t" value for each edge at the * current sweep line position, given by tess->event.  The calculations * are designed to be very stable, but of course they are not perfect. * * Special case: if both edge destinations are at the sweep event, * we sort the edges by slope (they would otherwise compare equally). */{  GLUvertex *event = tess->event;  GLUhalfEdge *e1, *e2;  GLdouble t1, t2;  e1 = reg1->eUp;  e2 = reg2->eUp;  if( e1->Dst == event ) {    if( e2->Dst == event ) {      /* Two edges right of the sweep line which meet at the sweep event.       * Sort them by slope.       */      if( VertLeq( e1->Org, e2->Org )) {	return EdgeSign( e2->Dst, e1->Org, e2->Org ) <= 0;      }      return EdgeSign( e1->Dst, e2->Org, e1->Org ) >= 0;    }    return EdgeSign( e2->Dst, event, e2->Org ) <= 0;  }  if( e2->Dst == event ) {    return EdgeSign( e1->Dst, event, e1->Org ) >= 0;  }  /* General case - compute signed distance *from* e1, e2 to event */  t1 = EdgeEval( e1->Dst, event, e1->Org );  t2 = EdgeEval( e2->Dst, event, e2->Org );  return (t1 >= t2);}static void DeleteRegion( GLUtesselator *tess, ActiveRegion *reg ){  if( reg->fixUpperEdge ) {    /* It was created with zero winding number, so it better be     * deleted with zero winding number (ie. it better not get merged     * with a real edge).     */    assert( reg->eUp->winding == 0 );  }  reg->eUp->activeRegion = NULL;  dictDelete( tess->dict, reg->nodeUp ); /* __gl_dictListDelete */  memFree( reg );}static int FixUpperEdge( ActiveRegion *reg, GLUhalfEdge *newEdge )/* * Replace an upper edge which needs fixing (see ConnectRightVertex). */{  assert( reg->fixUpperEdge );  if ( !__gl_meshDelete( reg->eUp ) ) return 0;  reg->fixUpperEdge = FALSE;  reg->eUp = newEdge;  newEdge->activeRegion = reg;  return 1;}static ActiveRegion *TopLeftRegion( ActiveRegion *reg ){  GLUvertex *org = reg->eUp->Org;  GLUhalfEdge *e;  /* Find the region above the uppermost edge with the same origin */  do {    reg = RegionAbove( reg );  } while( reg->eUp->Org == org );  /* If the edge above was a temporary edge introduced by ConnectRightVertex,   * now is the time to fix it.   */  if( reg->fixUpperEdge ) {    e = __gl_meshConnect( RegionBelow(reg)->eUp->Sym, reg->eUp->Lnext );    if (e == NULL) return NULL;    if ( !FixUpperEdge( reg, e ) ) return NULL;    reg = RegionAbove( reg );  }  return reg;}static ActiveRegion *TopRightRegion( ActiveRegion *reg ){  GLUvertex *dst = reg->eUp->Dst;  /* Find the region above the uppermost edge with the same destination */  do {    reg = RegionAbove( reg );  } while( reg->eUp->Dst == dst );  return reg;}static ActiveRegion *AddRegionBelow( GLUtesselator *tess,				     ActiveRegion *regAbove,				     GLUhalfEdge *eNewUp )/* * Add a new active region to the sweep line, *somewhere* below "regAbove" * (according to where the new edge belongs in the sweep-line dictionary). * The upper edge of the new region will be "eNewUp". * Winding number and "inside" flag are not updated. */{  ActiveRegion *regNew = (ActiveRegion *)memAlloc( sizeof( ActiveRegion ));  if (regNew == NULL) longjmp(tess->env,1);  regNew->eUp = eNewUp;  /* __gl_dictListInsertBefore */  regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew );  if (regNew->nodeUp == NULL) longjmp(tess->env,1);  regNew->fixUpperEdge = FALSE;  regNew->sentinel = FALSE;  regNew->dirty = FALSE;  eNewUp->activeRegion = regNew;  return regNew;}static GLboolean IsWindingInside( GLUtesselator *tess, int n ){  switch( tess->windingRule ) {  case GLU_TESS_WINDING_ODD:    return (n & 1);  case GLU_TESS_WINDING_NONZERO:    return (n != 0);  case GLU_TESS_WINDING_POSITIVE:    return (n > 0);  case GLU_TESS_WINDING_NEGATIVE:    return (n < 0);  case GLU_TESS_WINDING_ABS_GEQ_TWO:    return (n >= 2) || (n <= -2);  }  /*LINTED*/  assert( FALSE );  /*NOTREACHED*/  return GL_FALSE;  /* avoid compiler complaints */}static void ComputeWinding( GLUtesselator *tess, ActiveRegion *reg ){  reg->windingNumber = RegionAbove(reg)->windingNumber + reg->eUp->winding;  reg->inside = IsWindingInside( tess, reg->windingNumber );}static void FinishRegion( GLUtesselator *tess, ActiveRegion *reg )/* * Delete a region from the sweep line.  This happens when the upper * and lower chains of a region meet (at a vertex on the sweep line). * The "inside" flag is copied to the appropriate mesh face (we could * not do this before -- since the structure of the mesh is always * changing, this face may not have even existed until now). */{  GLUhalfEdge *e = reg->eUp;  GLUface *f = e->Lface;  f->inside = reg->inside;  f->anEdge = e;   /* optimization for __gl_meshTessellateMonoRegion() */  DeleteRegion( tess, reg );}static GLUhalfEdge *FinishLeftRegions( GLUtesselator *tess,	       ActiveRegion *regFirst, ActiveRegion *regLast )/* * We are given a vertex with one or more left-going edges.  All affected * edges should be in the edge dictionary.  Starting at regFirst->eUp, * we walk down deleting all regions where both edges have the same * origin vOrg.  At the same time we copy the "inside" flag from the * active region to the face, since at this point each face will belong * to at most one region (this was not necessarily true until this point * in the sweep).  The walk stops at the region above regLast; if regLast * is NULL we walk as far as possible.	At the same time we relink the * mesh if necessary, so that the ordering of edges around vOrg is the * same as in the dictionary. */{  ActiveRegion *reg, *regPrev;  GLUhalfEdge *e, *ePrev;  regPrev = regFirst;  ePrev = regFirst->eUp;  while( regPrev != regLast ) {    regPrev->fixUpperEdge = FALSE;	/* placement was OK */    reg = RegionBelow( regPrev );    e = reg->eUp;    if( e->Org != ePrev->Org ) {      if( ! reg->fixUpperEdge ) {	/* Remove the last left-going edge.  Even though there are no further	 * edges in the dictionary with this origin, there may be further	 * such edges in the mesh (if we are adding left edges to a vertex	 * that has already been processed).  Thus it is important to call	 * FinishRegion rather than just DeleteRegion.	 */	FinishRegion( tess, regPrev );	break;      }      /* If the edge below was a temporary edge introduced by       * ConnectRightVertex, now is the time to fix it.       */      e = __gl_meshConnect( ePrev->Lprev, e->Sym );      if (e == NULL) longjmp(tess->env,1);      if ( !FixUpperEdge( reg, e ) ) longjmp(tess->env,1);    }    /* Relink edges so that ePrev->Onext == e */    if( ePrev->Onext != e ) {      if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);      if ( !__gl_meshSplice( ePrev, e ) ) longjmp(tess->env,1);    }    FinishRegion( tess, regPrev );	/* may change reg->eUp */    ePrev = reg->eUp;    regPrev = reg;  }  return ePrev;}static void AddRightEdges( GLUtesselator *tess, ActiveRegion *regUp,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?