⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sweep.c

📁 Mesa is an open-source implementation of the OpenGL specification - a system for rendering interacti
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice including the dates of first publication and * either this permission notice or a reference to * http://oss.sgi.com/projects/FreeB/ * shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Except as contained in this notice, the name of Silicon Graphics, Inc. * shall not be used in advertising or otherwise to promote the sale, use or * other dealings in this Software without prior written authorization from * Silicon Graphics, Inc. *//*** 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,       GLUhalfEdge *eFirst, GLUhalfEdge *eLast, GLUhalfEdge *eTopLeft,       GLboolean cleanUp )/* * Purpose: insert right-going edges into the edge dictionary, and update

⌨️ 快捷键说明

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