/* 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. */ internal static void MakeVertex(Mogre.Utils.GluTesselator.GLUvertex newVertex, Mogre.Utils.GluTesselator.GLUhalfEdge eOrig, Mogre.Utils.GluTesselator.GLUvertex vNext) { Mogre.Utils.GluTesselator.GLUhalfEdge e; Mogre.Utils.GluTesselator.GLUvertex vPrev; Mogre.Utils.GluTesselator.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); }
/* __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_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); }
/* 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. */ internal static void KillVertex(Mogre.Utils.GluTesselator.GLUvertex vDel, Mogre.Utils.GluTesselator.GLUvertex newOrg) { Mogre.Utils.GluTesselator.GLUhalfEdge e, eStart = vDel.anEdge; Mogre.Utils.GluTesselator.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; }
/// <summary>***************** Other Edge Operations *********************</summary> /* All these routines can be implemented with the basic edge * operations above. They are provided for convenience and efficiency. */ /* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that * eNew == eOrg.Lnext, and eNew.Dst is a newly created vertex. * eOrg and eNew will have the same left face. */ internal static Mogre.Utils.GluTesselator.GLUhalfEdge __gl_meshAddEdgeVertex(Mogre.Utils.GluTesselator.GLUhalfEdge eOrg) { Mogre.Utils.GluTesselator.GLUhalfEdge eNewSym; Mogre.Utils.GluTesselator.GLUhalfEdge eNew = MakeEdge(eOrg); eNewSym = eNew.Sym; /* Connect the new edge appropriately */ Splice(eNew, eOrg.Lnext); /* Set the vertex and face information */ eNew.Org = eOrg.Sym.Org; { Mogre.Utils.GluTesselator.GLUvertex newVertex = new Mogre.Utils.GluTesselator.GLUvertex(); MakeVertex(newVertex, eNewSym, eNew.Org); } eNew.Lface = eNewSym.Lface = 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]; } }
/* __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); }
internal static void ComputeNormal(GLUtessellatorImpl tess, double[] norm) { Mogre.Utils.GluTesselator.GLUvertex v, v1, v2; double c, tLen2, maxLen2; double[] maxVal, minVal, d1, d2, tNorm; Mogre.Utils.GluTesselator.GLUvertex[] maxVert, minVert; Mogre.Utils.GluTesselator.GLUvertex vHead = tess.mesh.vHead; int i; maxVal = new double[3]; minVal = new double[3]; minVert = new Mogre.Utils.GluTesselator.GLUvertex[3]; maxVert = new Mogre.Utils.GluTesselator.GLUvertex[3]; d1 = new double[3]; d2 = new double[3]; tNorm = new double[3]; maxVal[0] = maxVal[1] = maxVal[2] = (- 2) * GLU.GLU_TESS_MAX_COORD; minVal[0] = minVal[1] = minVal[2] = 2 * GLU.GLU_TESS_MAX_COORD; for (v = vHead.next; v != vHead; v = v.next) { for (i = 0; i < 3; ++i) { c = v.coords[i]; if (c < minVal[i]) { minVal[i] = c; minVert[i] = v; } if (c > maxVal[i]) { maxVal[i] = c; maxVert[i] = v; } } } /* Find two vertices separated by at least 1/sqrt(3) of the maximum * distance between any two vertices */ i = 0; if (maxVal[1] - minVal[1] > maxVal[0] - minVal[0]) { i = 1; } if (maxVal[2] - minVal[2] > maxVal[i] - minVal[i]) { i = 2; } if (minVal[i] >= maxVal[i]) { /* All vertices are the same -- normal doesn't matter */ norm[0] = 0; norm[1] = 0; norm[2] = 1; return ; } /* Look for a third vertex which forms the triangle with maximum area * (Length of normal == twice the triangle area) */ maxLen2 = 0; v1 = minVert[i]; v2 = maxVert[i]; d1[0] = v1.coords[0] - v2.coords[0]; d1[1] = v1.coords[1] - v2.coords[1]; d1[2] = v1.coords[2] - v2.coords[2]; for (v = vHead.next; v != vHead; v = v.next) { d2[0] = v.coords[0] - v2.coords[0]; d2[1] = v.coords[1] - v2.coords[1]; d2[2] = v.coords[2] - v2.coords[2]; tNorm[0] = d1[1] * d2[2] - d1[2] * d2[1]; tNorm[1] = d1[2] * d2[0] - d1[0] * d2[2]; tNorm[2] = d1[0] * d2[1] - d1[1] * d2[0]; tLen2 = tNorm[0] * tNorm[0] + tNorm[1] * tNorm[1] + tNorm[2] * tNorm[2]; if (tLen2 > maxLen2) { maxLen2 = tLen2; norm[0] = tNorm[0]; norm[1] = tNorm[1]; norm[2] = tNorm[2]; } } if (maxLen2 <= 0) { /* All points lie on a single line -- any decent normal will do */ norm[0] = norm[1] = norm[2] = 0; norm[LongAxis(d1)] = 1; } }
/// <summary>***************** Other Edge Operations *********************</summary> /* All these routines can be implemented with the basic edge * operations above. They are provided for convenience and efficiency. */ /* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that * eNew == eOrg.Lnext, and eNew.Dst is a newly created vertex. * eOrg and eNew will have the same left face. */ internal static Mogre.Utils.GluTesselator.GLUhalfEdge __gl_meshAddEdgeVertex(Mogre.Utils.GluTesselator.GLUhalfEdge eOrg) { Mogre.Utils.GluTesselator.GLUhalfEdge eNewSym; Mogre.Utils.GluTesselator.GLUhalfEdge eNew = MakeEdge(eOrg); eNewSym = eNew.Sym; /* Connect the new edge appropriately */ Splice(eNew, eOrg.Lnext); /* Set the vertex and face information */ eNew.Org = eOrg.Sym.Org; { Mogre.Utils.GluTesselator.GLUvertex newVertex = new Mogre.Utils.GluTesselator.GLUvertex(); MakeVertex(newVertex, eNewSym, eNew.Org); } eNew.Lface = eNewSym.Lface = 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; }
internal static void ComputeNormal(GLUtessellatorImpl tess, double[] norm) { Mogre.Utils.GluTesselator.GLUvertex v, v1, v2; double c, tLen2, maxLen2; double[] maxVal, minVal, d1, d2, tNorm; Mogre.Utils.GluTesselator.GLUvertex[] maxVert, minVert; Mogre.Utils.GluTesselator.GLUvertex vHead = tess.mesh.vHead; int i; maxVal = new double[3]; minVal = new double[3]; minVert = new Mogre.Utils.GluTesselator.GLUvertex[3]; maxVert = new Mogre.Utils.GluTesselator.GLUvertex[3]; d1 = new double[3]; d2 = new double[3]; tNorm = new double[3]; maxVal[0] = maxVal[1] = maxVal[2] = (-2) * GLU.GLU_TESS_MAX_COORD; minVal[0] = minVal[1] = minVal[2] = 2 * GLU.GLU_TESS_MAX_COORD; for (v = vHead.next; v != vHead; v = v.next) { for (i = 0; i < 3; ++i) { c = v.coords[i]; if (c < minVal[i]) { minVal[i] = c; minVert[i] = v; } if (c > maxVal[i]) { maxVal[i] = c; maxVert[i] = v; } } } /* Find two vertices separated by at least 1/sqrt(3) of the maximum * distance between any two vertices */ i = 0; if (maxVal[1] - minVal[1] > maxVal[0] - minVal[0]) { i = 1; } if (maxVal[2] - minVal[2] > maxVal[i] - minVal[i]) { i = 2; } if (minVal[i] >= maxVal[i]) { /* All vertices are the same -- normal doesn't matter */ norm[0] = 0; norm[1] = 0; norm[2] = 1; return; } /* Look for a third vertex which forms the triangle with maximum area * (Length of normal == twice the triangle area) */ maxLen2 = 0; v1 = minVert[i]; v2 = maxVert[i]; d1[0] = v1.coords[0] - v2.coords[0]; d1[1] = v1.coords[1] - v2.coords[1]; d1[2] = v1.coords[2] - v2.coords[2]; for (v = vHead.next; v != vHead; v = v.next) { d2[0] = v.coords[0] - v2.coords[0]; d2[1] = v.coords[1] - v2.coords[1]; d2[2] = v.coords[2] - v2.coords[2]; tNorm[0] = d1[1] * d2[2] - d1[2] * d2[1]; tNorm[1] = d1[2] * d2[0] - d1[0] * d2[2]; tNorm[2] = d1[0] * d2[1] - d1[1] * d2[0]; tLen2 = tNorm[0] * tNorm[0] + tNorm[1] * tNorm[1] + tNorm[2] * tNorm[2]; if (tLen2 > maxLen2) { maxLen2 = tLen2; norm[0] = tNorm[0]; norm[1] = tNorm[1]; norm[2] = tNorm[2]; } } if (maxLen2 <= 0) { /* All points lie on a single line -- any decent normal will do */ norm[0] = norm[1] = norm[2] = 0; norm[LongAxis(d1)] = 1; } }
/* Determine the polygon normal and project vertices onto the plane * of the polygon. */ public static void __gl_projectPolygon(GLUtessellatorImpl tess) { Mogre.Utils.GluTesselator.GLUvertex v, vHead = tess.mesh.vHead; double w; double[] norm = new double[3]; double[] sUnit, tUnit; int i; bool computedNormal = false; norm[0] = tess.normal[0]; norm[1] = tess.normal[1]; norm[2] = tess.normal[2]; if (norm[0] == 0 && norm[1] == 0 && norm[2] == 0) { ComputeNormal(tess, norm); computedNormal = true; } sUnit = tess.sUnit; tUnit = tess.tUnit; i = LongAxis(norm); if (TRUE_PROJECT) { /* Choose the initial sUnit vector to be approximately perpendicular * to the normal. */ Normalize(norm); sUnit[i] = 0; sUnit[(i + 1) % 3] = S_UNIT_X; sUnit[(i + 2) % 3] = S_UNIT_Y; /* Now make it exactly perpendicular */ w = Dot(sUnit, norm); sUnit[0] -= w * norm[0]; sUnit[1] -= w * norm[1]; sUnit[2] -= w * norm[2]; Normalize(sUnit); /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */ tUnit[0] = norm[1] * sUnit[2] - norm[2] * sUnit[1]; tUnit[1] = norm[2] * sUnit[0] - norm[0] * sUnit[2]; tUnit[2] = norm[0] * sUnit[1] - norm[1] * sUnit[0]; Normalize(tUnit); } else { /* Project perpendicular to a coordinate axis -- better numerically */ sUnit[i] = 0; sUnit[(i + 1) % 3] = S_UNIT_X; sUnit[(i + 2) % 3] = S_UNIT_Y; tUnit[i] = 0; tUnit[(i + 1) % 3] = (norm[i] > 0)?-S_UNIT_Y:S_UNIT_Y; tUnit[(i + 2) % 3] = (norm[i] > 0)?S_UNIT_X:-S_UNIT_X; } /* Project the vertices onto the sweep plane */ for (v = vHead.next; v != vHead; v = v.next) { v.s = Dot(v.coords, sUnit); v.t = Dot(v.coords, tUnit); } if (computedNormal) { CheckOrientation(tess); } }