internal static FaceCount MaximumFan(Mogre.Utils.GluTesselator.GLUhalfEdge eOrig) { /* eOrig.Lface is the face we want to render. We want to find the size * of a maximal fan around eOrig.Org. To do this we just walk around * the origin vertex as far as possible in both directions. */ FaceCount newFace = new FaceCount(0, null, renderFan); Mogre.Utils.GluTesselator.GLUface trail = null; Mogre.Utils.GluTesselator.GLUhalfEdge e; for (e = eOrig; !Marked(e.Lface); e = e.Onext) { trail = AddToTrail(e.Lface, trail); ++newFace.size; } for (e = eOrig; !Marked(e.Sym.Lface); e = e.Sym.Lnext) { trail = AddToTrail(e.Sym.Lface, trail); ++newFace.size; } newFace.eStart = e; /*LINTED*/ FreeTrail(trail); return(newFace); }
/* 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. */ internal static void MakeFace(Mogre.Utils.GluTesselator.GLUface newFace, Mogre.Utils.GluTesselator.GLUhalfEdge eOrig, Mogre.Utils.GluTesselator.GLUface fNext) { Mogre.Utils.GluTesselator.GLUhalfEdge e; Mogre.Utils.GluTesselator.GLUface fPrev; Mogre.Utils.GluTesselator.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); }
/* __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. */ internal static bool __gl_meshDelete(Mogre.Utils.GluTesselator.GLUhalfEdge eDel) { Mogre.Utils.GluTesselator.GLUhalfEdge eDelSym = eDel.Sym; bool 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.Sym.Lface) { /* We are joining two loops into one -- remove the left face */ joiningLoops = true; KillFace(eDel.Lface, eDel.Sym.Lface); } if (eDel.Onext == eDel) { KillVertex(eDel.Org, null); } else { /* Make sure that eDel.Org and eDel.Sym.Lface point to valid half-edges */ eDel.Sym.Lface.anEdge = eDel.Sym.Lnext; eDel.Org.anEdge = eDel.Onext; Splice(eDel, eDel.Sym.Lnext); if (!joiningLoops) { Mogre.Utils.GluTesselator.GLUface newFace = new Mogre.Utils.GluTesselator.GLUface(); /* We are splitting one loop into two -- create a new loop for eDel. */ MakeFace(newFace, eDel, eDel.Lface); } } /* Claim: the mesh is now in a consistent state, except that eDel.Org * may have been deleted. Now we disconnect eDel.Dst. */ if (eDelSym.Onext == eDelSym) { KillVertex(eDelSym.Org, null); KillFace(eDelSym.Lface, null); } else { /* Make sure that eDel.Dst and eDel.Lface point to valid half-edges */ eDel.Lface.anEdge = eDelSym.Sym.Lnext; eDelSym.Org.anEdge = eDelSym.Onext; Splice(eDelSym, eDelSym.Sym.Lnext); } /* Any isolated vertices or faces have already been freed. */ KillEdge(eDel); return(true); }
/* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency. */ public static void __gl_meshCheckMesh(Mogre.Utils.GluTesselator.GLUmesh mesh) { Mogre.Utils.GluTesselator.GLUface fHead = mesh.fHead; Mogre.Utils.GluTesselator.GLUvertex vHead = mesh.vHead; Mogre.Utils.GluTesselator.GLUhalfEdge eHead = mesh.eHead; Mogre.Utils.GluTesselator.GLUface f, fPrev; Mogre.Utils.GluTesselator.GLUvertex v, vPrev; Mogre.Utils.GluTesselator.GLUhalfEdge e, ePrev; fPrev = fHead; for (fPrev = fHead; (f = fPrev.next) != fHead; fPrev = f) { //assert(f.prev == fPrev); e = f.anEdge; do { //assert(e.Sym != e); //assert(e.Sym.Sym == e); //assert(e.Lnext.Onext.Sym == e); //assert(e.Onext.Sym.Lnext == e); //assert(e.Lface == f); e = e.Lnext; }while (e != f.anEdge); } //assert(f.prev == fPrev && f.anEdge == null && f.data == null); vPrev = vHead; for (vPrev = vHead; (v = vPrev.next) != vHead; vPrev = v) { //assert(v.prev == vPrev); e = v.anEdge; do { //assert(e.Sym != e); //assert(e.Sym.Sym == e); //assert(e.Lnext.Onext.Sym == e); //assert(e.Onext.Sym.Lnext == e); //assert(e.Org == v); e = e.Onext; }while (e != v.anEdge); } //assert(v.prev == vPrev && v.anEdge == null && v.data == null); ePrev = eHead; for (ePrev = eHead; (e = ePrev.next) != eHead; ePrev = e) { //assert(e.Sym.next == ePrev.Sym); //assert(e.Sym != e); //assert(e.Sym.Sym == e); //assert(e.Org != null); //assert(e.Sym.Org != null); //assert(e.Lnext.Onext.Sym == e); //assert(e.Onext.Sym.Lnext == e); } //assert(e.Sym.next == ePrev.Sym && e.Sym == mesh.eHeadSym && e.Sym.Sym == e && e.Org == null && e.Sym.Org == null && e.Lface == null && e.Sym.Lface == null); }
/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh. */ internal static void __gl_meshDeleteMeshZap(Mogre.Utils.GluTesselator.GLUmesh mesh) { Mogre.Utils.GluTesselator.GLUface fHead = mesh.fHead; while (fHead.next != fHead) { __gl_meshZapFace(fHead.next); } //assert(mesh.vHead.next == mesh.vHead); }
internal static void RenderMaximumFaceGroup(GLUtessellatorImpl tess, Mogre.Utils.GluTesselator.GLUface fOrig) { /* We want to find the largest triangle fan or strip of unmarked faces * which includes the given face fOrig. There are 3 possible fans * passing through fOrig (one centered at each vertex), and 3 possible * strips (one for each CCW permutation of the vertices). Our strategy * is to try all of these, and take the primitive which uses the most * triangles (a greedy approach). */ Mogre.Utils.GluTesselator.GLUhalfEdge e = fOrig.anEdge; FaceCount max = new FaceCount(); FaceCount newFace = new FaceCount(); max.size = 1; max.eStart = e; max.render = renderTriangle; if (!tess.flagBoundary) { newFace = MaximumFan(e); if (newFace.size > max.size) { max = newFace; } newFace = MaximumFan(e.Lnext); if (newFace.size > max.size) { max = newFace; } newFace = MaximumFan(e.Onext.Sym); if (newFace.size > max.size) { max = newFace; } newFace = MaximumStrip(e); if (newFace.size > max.size) { max = newFace; } newFace = MaximumStrip(e.Lnext); if (newFace.size > max.size) { max = newFace; } newFace = MaximumStrip(e.Onext.Sym); if (newFace.size > max.size) { max = newFace; } } max.render.render(tess, max.eStart, max.size); }
/* __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. */ public static bool __gl_meshSplice(Mogre.Utils.GluTesselator.GLUhalfEdge eOrg, Mogre.Utils.GluTesselator.GLUhalfEdge eDst) { bool joiningLoops = false; bool joiningVertices = false; if (eOrg == eDst) { return(true); } 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) { Mogre.Utils.GluTesselator.GLUvertex newVertex = new Mogre.Utils.GluTesselator.GLUvertex(); /* 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) { Mogre.Utils.GluTesselator.GLUface newFace = new Mogre.Utils.GluTesselator.GLUface(); /* 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(true); }
/// <summary>***************** Other Operations *********************</summary> /* __gl_meshZapFace( fZap ) destroys a face and removes it from the * global face list. All edges of fZap will have a null pointer as their * left face. Any edges which also have a null pointer as their right face * are deleted entirely (along with any isolated vertices this produces). * An entire mesh can be deleted by zapping its faces, one at a time, * in any order. Zapped faces cannot be used in further mesh operations! */ internal static void __gl_meshZapFace(Mogre.Utils.GluTesselator.GLUface fZap) { Mogre.Utils.GluTesselator.GLUhalfEdge eStart = fZap.anEdge; Mogre.Utils.GluTesselator.GLUhalfEdge e, eNext, eSym; Mogre.Utils.GluTesselator.GLUface fPrev, fNext; /* walk around face, deleting edges whose right face is also null */ eNext = eStart.Lnext; do { e = eNext; eNext = e.Lnext; e.Lface = null; if (e.Sym.Lface == null) { /* delete the edge -- see __gl_MeshDelete above */ if (e.Onext == e) { KillVertex(e.Org, null); } else { /* Make sure that e.Org points to a valid half-edge */ e.Org.anEdge = e.Onext; Splice(e, e.Sym.Lnext); } eSym = e.Sym; if (eSym.Onext == eSym) { KillVertex(eSym.Org, null); } else { /* Make sure that eSym.Org points to a valid half-edge */ eSym.Org.anEdge = eSym.Onext; Splice(eSym, eSym.Sym.Lnext); } KillEdge(e); } }while (e != eStart); /* delete from circular doubly-linked list */ fPrev = fZap.prev; fNext = fZap.next; fNext.prev = fPrev; fPrev.next = fNext; }
private static void FreeTrail(Mogre.Utils.GluTesselator.GLUface t) { if (true) { while (t != null) { t.marked = false; t = t.trail; } } else { /* absorb trailing semicolon */ } }
/// <summary>*************** Basic Edge Operations *********************</summary> /* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face). * The loop consists of the two new half-edges. */ public static Mogre.Utils.GluTesselator.GLUhalfEdge __gl_meshMakeEdge(Mogre.Utils.GluTesselator.GLUmesh mesh) { Mogre.Utils.GluTesselator.GLUvertex newVertex1 = new Mogre.Utils.GluTesselator.GLUvertex(); Mogre.Utils.GluTesselator.GLUvertex newVertex2 = new Mogre.Utils.GluTesselator.GLUvertex(); Mogre.Utils.GluTesselator.GLUface newFace = new Mogre.Utils.GluTesselator.GLUface(); Mogre.Utils.GluTesselator.GLUhalfEdge e; 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); }
/* 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. */ internal static void KillFace(Mogre.Utils.GluTesselator.GLUface fDel, Mogre.Utils.GluTesselator.GLUface newLface) { Mogre.Utils.GluTesselator.GLUhalfEdge e, eStart = fDel.anEdge; Mogre.Utils.GluTesselator.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; }
/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg.Sym.Org * to eDst.Org, and returns the corresponding half-edge eNew. * If eOrg.Lface == eDst.Lface, this splits one loop into two, * and the newly created loop is eNew.Lface. Otherwise, two disjoint * loops are merged into one, and the loop eDst.Lface is destroyed. * * If (eOrg == eDst), the new face will have only two edges. * If (eOrg.Lnext == eDst), the old face is reduced to a single edge. * If (eOrg.Lnext.Lnext == eDst), the old face is reduced to two edges. */ internal static Mogre.Utils.GluTesselator.GLUhalfEdge __gl_meshConnect(Mogre.Utils.GluTesselator.GLUhalfEdge eOrg, Mogre.Utils.GluTesselator.GLUhalfEdge eDst) { Mogre.Utils.GluTesselator.GLUhalfEdge eNewSym; bool joiningLoops = false; Mogre.Utils.GluTesselator.GLUhalfEdge eNew = MakeEdge(eOrg); eNewSym = eNew.Sym; if (eDst.Lface != eOrg.Lface) { /* We are connecting two disjoint loops -- destroy eDst.Lface */ joiningLoops = true; KillFace(eDst.Lface, eOrg.Lface); } /* Connect the new edge appropriately */ Splice(eNew, eOrg.Lnext); Splice(eNewSym, eDst); /* Set the vertex and face information */ eNew.Org = eOrg.Sym.Org; eNewSym.Org = eDst.Org; eNew.Lface = eNewSym.Lface = eOrg.Lface; /* Make sure the old face points to a valid half-edge */ eOrg.Lface.anEdge = eNewSym; if (!joiningLoops) { Mogre.Utils.GluTesselator.GLUface newFace = new Mogre.Utils.GluTesselator.GLUface(); /* We split one loop into two -- the new loop is eNew.Lface */ MakeFace(newFace, eNew, eOrg.Lface); } return(eNew); }
internal static void CheckOrientation(GLUtessellatorImpl tess) { double area; Mogre.Utils.GluTesselator.GLUface f, fHead = tess.mesh.fHead; Mogre.Utils.GluTesselator.GLUvertex v, vHead = tess.mesh.vHead; Mogre.Utils.GluTesselator.GLUhalfEdge e; /* When we compute the normal automatically, we choose the orientation * so that the the sum of the signed areas of all contours is non-negative. */ area = 0; for (f = fHead.next; f != fHead; f = f.next) { e = f.anEdge; if (e.winding <= 0) { continue; } do { area += (e.Org.s - e.Sym.Org.s) * (e.Org.t + e.Sym.Org.t); e = e.Lnext; }while (e != f.anEdge); } if (area < 0) { /* Reverse the orientation by flipping all the t-coordinates */ for (v = vHead.next; v != vHead; v = v.next) { v.t = -v.t; } tess.tUnit[0] = -tess.tUnit[0]; tess.tUnit[1] = -tess.tUnit[1]; tess.tUnit[2] = -tess.tUnit[2]; } }
internal static void RenderLonelyTriangles(GLUtessellatorImpl tess, Mogre.Utils.GluTesselator.GLUface f) { /* Now we render all the separate triangles which could not be * grouped into a triangle fan or strip. */ Mogre.Utils.GluTesselator.GLUhalfEdge e; int newState; int edgeState = -1; /* force edge state output for first vertex */ tess.callBeginOrBeginData(GL.GL_TRIANGLES); for (; f != null; f = f.trail) { /* Loop once for each edge (there will always be 3 edges) */ e = f.anEdge; do { if (tess.flagBoundary) { /* Set the "edge state" to true just before we output the * first vertex of each edge on the polygon boundary. */ newState = (!e.Sym.Lface.inside)?1:0; if (edgeState != newState) { edgeState = newState; tess.callEdgeFlagOrEdgeFlagData(edgeState != 0); } } tess.callVertexOrVertexData(e.Org.data); e = e.Lnext; }while (e != f.anEdge); } tess.callEndOrEndData(); }
/* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in * both meshes, and returns the new mesh (the old meshes are destroyed). */ internal static Mogre.Utils.GluTesselator.GLUmesh __gl_meshUnion(Mogre.Utils.GluTesselator.GLUmesh mesh1, Mogre.Utils.GluTesselator.GLUmesh mesh2) { Mogre.Utils.GluTesselator.GLUface f1 = mesh1.fHead; Mogre.Utils.GluTesselator.GLUvertex v1 = mesh1.vHead; Mogre.Utils.GluTesselator.GLUhalfEdge e1 = mesh1.eHead; Mogre.Utils.GluTesselator.GLUface f2 = mesh2.fHead; Mogre.Utils.GluTesselator.GLUvertex v2 = mesh2.vHead; Mogre.Utils.GluTesselator.GLUhalfEdge e2 = mesh2.eHead; /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */ if (f2.next != f2) { f1.prev.next = f2.next; f2.next.prev = f1.prev; f2.prev.next = f1; f1.prev = f2.prev; } if (v2.next != v2) { v1.prev.next = v2.next; v2.next.prev = v1.prev; v2.prev.next = v1; v1.prev = v2.prev; } if (e2.next != e2) { e1.Sym.next.Sym.next = e2.next; e2.next.Sym.next = e1.Sym.next; e2.Sym.next.Sym.next = e1; e1.Sym.next = e2.Sym.next; } return(mesh1); }
/* __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. */ internal static bool __gl_meshDelete(Mogre.Utils.GluTesselator.GLUhalfEdge eDel) { Mogre.Utils.GluTesselator.GLUhalfEdge eDelSym = eDel.Sym; bool 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.Sym.Lface) { /* We are joining two loops into one -- remove the left face */ joiningLoops = true; KillFace(eDel.Lface, eDel.Sym.Lface); } if (eDel.Onext == eDel) { KillVertex(eDel.Org, null); } else { /* Make sure that eDel.Org and eDel.Sym.Lface point to valid half-edges */ eDel.Sym.Lface.anEdge = eDel.Sym.Lnext; eDel.Org.anEdge = eDel.Onext; Splice(eDel, eDel.Sym.Lnext); if (!joiningLoops) { Mogre.Utils.GluTesselator.GLUface newFace = new Mogre.Utils.GluTesselator.GLUface(); /* We are splitting one loop into two -- create a new loop for eDel. */ MakeFace(newFace, eDel, eDel.Lface); } } /* Claim: the mesh is now in a consistent state, except that eDel.Org * may have been deleted. Now we disconnect eDel.Dst. */ if (eDelSym.Onext == eDelSym) { KillVertex(eDelSym.Org, null); KillFace(eDelSym.Lface, null); } else { /* Make sure that eDel.Dst and eDel.Lface point to valid half-edges */ eDel.Lface.anEdge = eDelSym.Sym.Lnext; eDelSym.Org.anEdge = eDelSym.Onext; Splice(eDelSym, eDelSym.Sym.Lnext); } /* Any isolated vertices or faces have already been freed. */ KillEdge(eDel); return true; }
private static GLUface AddToTrail(Mogre.Utils.GluTesselator.GLUface f, Mogre.Utils.GluTesselator.GLUface t) { f.trail = t; f.marked = true; return(f); }
internal static FaceCount MaximumStrip(Mogre.Utils.GluTesselator.GLUhalfEdge eOrig) { /* Here we are looking for a maximal strip that contains the vertices * eOrig.Org, eOrig.Dst, eOrig.Lnext.Dst (in that order or the * reverse, such that all triangles are oriented CCW). * * Again we walk forward and backward as far as possible. However for * strips there is a twist: to get CCW orientations, there must be * an *even* number of triangles in the strip on one side of eOrig. * We walk the strip starting on a side with an even number of triangles; * if both side have an odd number, we are forced to shorten one side. */ FaceCount newFace = new FaceCount(0, null, renderStrip); long headSize = 0, tailSize = 0; Mogre.Utils.GluTesselator.GLUface trail = null; Mogre.Utils.GluTesselator.GLUhalfEdge e, eTail, eHead; for (e = eOrig; !Marked(e.Lface); ++tailSize, e = e.Onext) { trail = AddToTrail(e.Lface, trail); ++tailSize; e = e.Lnext.Sym; if (Marked(e.Lface)) { break; } trail = AddToTrail(e.Lface, trail); } eTail = e; for (e = eOrig; !Marked(e.Sym.Lface); ++headSize, e = e.Sym.Onext.Sym) { trail = AddToTrail(e.Sym.Lface, trail); ++headSize; e = e.Sym.Lnext; if (Marked(e.Sym.Lface)) { break; } trail = AddToTrail(e.Sym.Lface, trail); } eHead = e; newFace.size = tailSize + headSize; if (IsEven(tailSize)) { newFace.eStart = eTail.Sym; } else if (IsEven(headSize)) { newFace.eStart = eHead; } else { /* Both sides have odd length, we must shorten one of them. In fact, * we must start from eHead to guarantee inclusion of eOrig.Lface. */ --newFace.size; newFace.eStart = eHead.Onext; } /*LINTED*/ FreeTrail(trail); return(newFace); }
/* Macros which keep track of faces we have marked temporarily, and allow * us to backtrack when necessary. With triangle fans, this is not * really necessary, since the only awkward case is a loop of triangles * around a single origin vertex. However with strips the situation is * more complicated, and we need a general tracking method like the * one here. */ private static bool Marked(Mogre.Utils.GluTesselator.GLUface f) { return(!f.inside || f.marked); }
/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg.Sym.Org * to eDst.Org, and returns the corresponding half-edge eNew. * If eOrg.Lface == eDst.Lface, this splits one loop into two, * and the newly created loop is eNew.Lface. Otherwise, two disjoint * loops are merged into one, and the loop eDst.Lface is destroyed. * * If (eOrg == eDst), the new face will have only two edges. * If (eOrg.Lnext == eDst), the old face is reduced to a single edge. * If (eOrg.Lnext.Lnext == eDst), the old face is reduced to two edges. */ internal static Mogre.Utils.GluTesselator.GLUhalfEdge __gl_meshConnect(Mogre.Utils.GluTesselator.GLUhalfEdge eOrg, Mogre.Utils.GluTesselator.GLUhalfEdge eDst) { Mogre.Utils.GluTesselator.GLUhalfEdge eNewSym; bool joiningLoops = false; Mogre.Utils.GluTesselator.GLUhalfEdge eNew = MakeEdge(eOrg); eNewSym = eNew.Sym; if (eDst.Lface != eOrg.Lface) { /* We are connecting two disjoint loops -- destroy eDst.Lface */ joiningLoops = true; KillFace(eDst.Lface, eOrg.Lface); } /* Connect the new edge appropriately */ Splice(eNew, eOrg.Lnext); Splice(eNewSym, eDst); /* Set the vertex and face information */ eNew.Org = eOrg.Sym.Org; eNewSym.Org = eDst.Org; eNew.Lface = eNewSym.Lface = eOrg.Lface; /* Make sure the old face points to a valid half-edge */ eOrg.Lface.anEdge = eNewSym; if (!joiningLoops) { Mogre.Utils.GluTesselator.GLUface newFace = new Mogre.Utils.GluTesselator.GLUface(); /* We split one loop into two -- the new loop is eNew.Lface */ MakeFace(newFace, eNew, eOrg.Lface); } return eNew; }
/* __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. */ public static bool __gl_meshSplice(Mogre.Utils.GluTesselator.GLUhalfEdge eOrg, Mogre.Utils.GluTesselator.GLUhalfEdge eDst) { bool joiningLoops = false; bool joiningVertices = false; if (eOrg == eDst) return true; 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) { Mogre.Utils.GluTesselator.GLUvertex newVertex = new Mogre.Utils.GluTesselator.GLUvertex(); /* 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) { Mogre.Utils.GluTesselator.GLUface newFace = new Mogre.Utils.GluTesselator.GLUface(); /* 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 true; }
/// <summary>*************** Basic Edge Operations *********************</summary> /* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face). * The loop consists of the two new half-edges. */ public static Mogre.Utils.GluTesselator.GLUhalfEdge __gl_meshMakeEdge(Mogre.Utils.GluTesselator.GLUmesh mesh) { Mogre.Utils.GluTesselator.GLUvertex newVertex1 = new Mogre.Utils.GluTesselator.GLUvertex(); Mogre.Utils.GluTesselator.GLUvertex newVertex2 = new Mogre.Utils.GluTesselator.GLUvertex(); Mogre.Utils.GluTesselator.GLUface newFace = new Mogre.Utils.GluTesselator.GLUface(); Mogre.Utils.GluTesselator.GLUhalfEdge e; 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; }