📄 mesh.c
字号:
/*
** 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.
**
** $Date: 2006-03-11 18:07:02 -0600 (Sat, 11 Mar 2006) $ $Revision: 1.1 $
** $Header: /cygdrive/c/RCVS/CVS/ReactOS/reactos/lib/glu32/libtess/mesh.c,v 1.1 2004/02/02 16:39:15 navaraf Exp $
*/
#include "gluos.h"
#include <stddef.h>
#include <assert.h>
#include "mesh.h"
#include "memalloc.h"
#define TRUE 1
#define FALSE 0
static GLUvertex *allocVertex()
{
return (GLUvertex *)memAlloc( sizeof( GLUvertex ));
}
static GLUface *allocFace()
{
return (GLUface *)memAlloc( sizeof( GLUface ));
}
/************************ Utility Routines ************************/
/* Allocate and free half-edges in pairs for efficiency.
* The *only* place that should use this fact is allocation/free.
*/
typedef struct { GLUhalfEdge e, eSym; } EdgePair;
/* MakeEdge creates a new pair of half-edges which form their own loop.
* No vertex or face structures are allocated, but these must be assigned
* before the current edge operation is completed.
*/
static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext )
{
GLUhalfEdge *e;
GLUhalfEdge *eSym;
GLUhalfEdge *ePrev;
EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair ));
if (pair == NULL) return NULL;
e = &pair->e;
eSym = &pair->eSym;
/* Make sure eNext points to the first edge of the edge pair */
if( eNext->Sym < eNext ) { eNext = eNext->Sym; }
/* Insert in circular doubly-linked list before eNext.
* Note that the prev pointer is stored in Sym->next.
*/
ePrev = eNext->Sym->next;
eSym->next = ePrev;
ePrev->Sym->next = e;
e->next = eNext;
eNext->Sym->next = eSym;
e->Sym = eSym;
e->Onext = e;
e->Lnext = eSym;
e->Org = NULL;
e->Lface = NULL;
e->winding = 0;
e->activeRegion = NULL;
eSym->Sym = e;
eSym->Onext = eSym;
eSym->Lnext = e;
eSym->Org = NULL;
eSym->Lface = NULL;
eSym->winding = 0;
eSym->activeRegion = NULL;
return e;
}
/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
* CS348a notes (see mesh.h). Basically it modifies the mesh so that
* a->Onext and b->Onext are exchanged. This can have various effects
* depending on whether a and b belong to different face or vertex rings.
* For more explanation see __gl_meshSplice() below.
*/
static void Splice( GLUhalfEdge *a, GLUhalfEdge *b )
{
GLUhalfEdge *aOnext = a->Onext;
GLUhalfEdge *bOnext = b->Onext;
aOnext->Sym->Lnext = b;
bOnext->Sym->Lnext = a;
a->Onext = bOnext;
b->Onext = aOnext;
}
/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
* origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
* a place to insert the new vertex in the global vertex list. We insert
* the new vertex *before* vNext so that algorithms which walk the vertex
* list will not see the newly created vertices.
*/
static void MakeVertex( GLUvertex *newVertex,
GLUhalfEdge *eOrig, GLUvertex *vNext )
{
GLUhalfEdge *e;
GLUvertex *vPrev;
GLUvertex *vNew = newVertex;
assert(vNew != NULL);
/* insert in circular doubly-linked list before vNext */
vPrev = vNext->prev;
vNew->prev = vPrev;
vPrev->next = vNew;
vNew->next = vNext;
vNext->prev = vNew;
vNew->anEdge = eOrig;
vNew->data = NULL;
/* leave coords, s, t undefined */
/* fix other edges on this vertex loop */
e = eOrig;
do {
e->Org = vNew;
e = e->Onext;
} while( e != eOrig );
}
/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
* face of all edges in the face loop to which eOrig belongs. "fNext" gives
* a place to insert the new face in the global face list. We insert
* the new face *before* fNext so that algorithms which walk the face
* list will not see the newly created faces.
*/
static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext )
{
GLUhalfEdge *e;
GLUface *fPrev;
GLUface *fNew = newFace;
assert(fNew != NULL);
/* insert in circular doubly-linked list before fNext */
fPrev = fNext->prev;
fNew->prev = fPrev;
fPrev->next = fNew;
fNew->next = fNext;
fNext->prev = fNew;
fNew->anEdge = eOrig;
fNew->data = NULL;
fNew->trail = NULL;
fNew->marked = FALSE;
/* The new face is marked "inside" if the old one was. This is a
* convenience for the common case where a face has been split in two.
*/
fNew->inside = fNext->inside;
/* fix other edges on this face loop */
e = eOrig;
do {
e->Lface = fNew;
e = e->Lnext;
} while( e != eOrig );
}
/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
* and removes from the global edge list.
*/
static void KillEdge( GLUhalfEdge *eDel )
{
GLUhalfEdge *ePrev, *eNext;
/* Half-edges are allocated in pairs, see EdgePair above */
if( eDel->Sym < eDel ) { eDel = eDel->Sym; }
/* delete from circular doubly-linked list */
eNext = eDel->next;
ePrev = eDel->Sym->next;
eNext->Sym->next = ePrev;
ePrev->Sym->next = eNext;
memFree( eDel );
}
/* KillVertex( vDel ) destroys a vertex and removes it from the global
* vertex list. It updates the vertex loop to point to a given new vertex.
*/
static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg )
{
GLUhalfEdge *e, *eStart = vDel->anEdge;
GLUvertex *vPrev, *vNext;
/* change the origin of all affected edges */
e = eStart;
do {
e->Org = newOrg;
e = e->Onext;
} while( e != eStart );
/* delete from circular doubly-linked list */
vPrev = vDel->prev;
vNext = vDel->next;
vNext->prev = vPrev;
vPrev->next = vNext;
memFree( vDel );
}
/* KillFace( fDel ) destroys a face and removes it from the global face
* list. It updates the face loop to point to a given new face.
*/
static void KillFace( GLUface *fDel, GLUface *newLface )
{
GLUhalfEdge *e, *eStart = fDel->anEdge;
GLUface *fPrev, *fNext;
/* change the left face of all affected edges */
e = eStart;
do {
e->Lface = newLface;
e = e->Lnext;
} while( e != eStart );
/* delete from circular doubly-linked list */
fPrev = fDel->prev;
fNext = fDel->next;
fNext->prev = fPrev;
fPrev->next = fNext;
memFree( fDel );
}
/****************** Basic Edge Operations **********************/
/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
* The loop consists of the two new half-edges.
*/
GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh )
{
GLUvertex *newVertex1= allocVertex();
GLUvertex *newVertex2= allocVertex();
GLUface *newFace= allocFace();
GLUhalfEdge *e;
/* if any one is null then all get freed */
if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) {
if (newVertex1 != NULL) memFree(newVertex1);
if (newVertex2 != NULL) memFree(newVertex2);
if (newFace != NULL) memFree(newFace);
return NULL;
}
e = MakeEdge( &mesh->eHead );
if (e == NULL) return NULL;
MakeVertex( newVertex1, e, &mesh->vHead );
MakeVertex( newVertex2, e->Sym, &mesh->vHead );
MakeFace( newFace, e, &mesh->fHead );
return e;
}
/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
* mesh connectivity and topology. It changes the mesh so that
* eOrg->Onext <- OLD( eDst->Onext )
* eDst->Onext <- OLD( eOrg->Onext )
* where OLD(...) means the value before the meshSplice operation.
*
* This can have two effects on the vertex structure:
* - if eOrg->Org != eDst->Org, the two vertices are merged together
* - if eOrg->Org == eDst->Org, the origin is split into two vertices
* In both cases, eDst->Org is changed and eOrg->Org is untouched.
*
* Similarly (and independently) for the face structure,
* - if eOrg->Lface == eDst->Lface, one loop is split into two
* - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
* In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
*
* Some special cases:
* If eDst == eOrg, the operation has no effect.
* If eDst == eOrg->Lnext, the new face will have a single edge.
* If eDst == eOrg->Lprev, the old face will have a single edge.
* If eDst == eOrg->Onext, the new vertex will have a single edge.
* If eDst == eOrg->Oprev, the old vertex will have a single edge.
*/
int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
{
int joiningLoops = FALSE;
int joiningVertices = FALSE;
if( eOrg == eDst ) return 1;
if( eDst->Org != eOrg->Org ) {
/* We are merging two disjoint vertices -- destroy eDst->Org */
joiningVertices = TRUE;
KillVertex( eDst->Org, eOrg->Org );
}
if( eDst->Lface != eOrg->Lface ) {
/* We are connecting two disjoint loops -- destroy eDst->Lface */
joiningLoops = TRUE;
KillFace( eDst->Lface, eOrg->Lface );
}
/* Change the edge structure */
Splice( eDst, eOrg );
if( ! joiningVertices ) {
GLUvertex *newVertex= allocVertex();
if (newVertex == NULL) return 0;
/* We split one vertex into two -- the new vertex is eDst->Org.
* Make sure the old vertex points to a valid half-edge.
*/
MakeVertex( newVertex, eDst, eOrg->Org );
eOrg->Org->anEdge = eOrg;
}
if( ! joiningLoops ) {
GLUface *newFace= allocFace();
if (newFace == NULL) return 0;
/* We split one loop into two -- the new loop is eDst->Lface.
* Make sure the old face points to a valid half-edge.
*/
MakeFace( newFace, eDst, eOrg->Lface );
eOrg->Lface->anEdge = eOrg;
}
return 1;
}
/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
* if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
* eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
* the newly created loop will contain eDel->Dst. If the deletion of eDel
* would create isolated vertices, those are deleted as well.
*
* This function could be implemented as two calls to __gl_meshSplice
* plus a few calls to memFree, but this would allocate and delete
* unnecessary vertices and faces.
*/
int __gl_meshDelete( GLUhalfEdge *eDel )
{
GLUhalfEdge *eDelSym = eDel->Sym;
int joiningLoops = FALSE;
/* First step: disconnect the origin vertex eDel->Org. We make all
* changes to get a consistent mesh in this "intermediate" state.
*/
if( eDel->Lface != eDel->Rface ) {
/* We are joining two loops into one -- remove the left face */
joiningLoops = TRUE;
KillFace( eDel->Lface, eDel->Rface );
}
if( eDel->Onext == eDel ) {
KillVertex( eDel->Org, NULL );
} else {
/* Make sure that eDel->Org and eDel->Rface point to valid half-edges */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -