From 7c4d305895d562ecc89dfcbb2ed0a3adae1c613d Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Thu, 22 May 2008 02:28:28 -0800 Subject: [PATCH] Add polygon triangulation, by cheating. I'm using the gl tesselator for that, and storing the triangles instead of rendering them immediately. Not sure if that's smart; in theory could change from implementation to implementation, but the results look much better than I would get myself. [git-p4: depot-paths = "//depot/solvespace/": change = 1733] --- Makefile | 1 + entity.cpp | 5 +- glhelper.cpp | 57 +++++++++++--- graphicswin.cpp | 9 ++- polygon.cpp | 205 +++++++++++++++++++++++++++++++----------------- polygon.h | 25 +++--- sketch.cpp | 6 +- solvespace.h | 7 ++ util.cpp | 7 +- 9 files changed, 211 insertions(+), 111 deletions(-) diff --git a/Makefile b/Makefile index 2c4a0a7..dedf65e 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,7 @@ SSOBJS = $(OBJDIR)\solvespace.obj \ $(OBJDIR)\file.obj \ $(OBJDIR)\system.obj \ $(OBJDIR)\polygon.obj \ + $(OBJDIR)\mesh.obj \ LIBS = user32.lib gdi32.lib comctl32.lib advapi32.lib opengl32.lib glu32.lib diff --git a/entity.cpp b/entity.cpp index 3dbe80f..1e6e412 100644 --- a/entity.cpp +++ b/entity.cpp @@ -527,10 +527,7 @@ void Entity::LineDrawOrGetDistance(Vector a, Vector b) { void Entity::LineDrawOrGetDistanceOrEdge(Vector a, Vector b) { LineDrawOrGetDistance(a, b); if(dogd.edges && !construction) { - SEdge edge; - edge.tag = 0; - edge.a = a; edge.b = b; - dogd.edges->l.Add(&edge); + dogd.edges->AddEdge(a, b); } } diff --git a/glhelper.cpp b/glhelper.cpp index ca4e547..b7031e1 100644 --- a/glhelper.cpp +++ b/glhelper.cpp @@ -111,11 +111,24 @@ void glxColor4d(double r, double g, double b, double a) if(!ColorLocked) glColor4d(r, g, b, a); } -static void __stdcall Vertex(Vector *p) { +static void GLX_CALLBACK Vertex(Vector *p) { glxVertex3v(*p); } -static void __stdcall Combine(double coords[3], void *vertexData[4], - float weight[4], void **outData) + +void glxFillPolygon(SPolygon *p) +{ + GLUtesselator *gt = gluNewTess(); + gluTessCallback(gt, GLU_TESS_BEGIN, (glxCallbackFptr *)glBegin); + gluTessCallback(gt, GLU_TESS_END, (glxCallbackFptr *)glEnd); + gluTessCallback(gt, GLU_TESS_VERTEX, (glxCallbackFptr *)Vertex); + + glxTesselatePolygon(gt, p); + + gluDeleteTess(gt); +} + +static void GLX_CALLBACK Combine(double coords[3], void *vertexData[4], + float weight[4], void **outData) { Vector *n = (Vector *)AllocTemporary(sizeof(Vector)); n->x = coords[0]; @@ -124,16 +137,11 @@ static void __stdcall Combine(double coords[3], void *vertexData[4], *outData = n; } -void glxFillPolygon(SPolygon *p) +void glxTesselatePolygon(GLUtesselator *gt, SPolygon *p) { int i, j; - GLUtesselator *gt = gluNewTess(); - typedef void __stdcall cf(void); - gluTessCallback(gt, GLU_TESS_BEGIN, (cf *)glBegin); - gluTessCallback(gt, GLU_TESS_END, (cf *)glEnd); - gluTessCallback(gt, GLU_TESS_VERTEX, (cf *)Vertex); - gluTessCallback(gt, GLU_TESS_COMBINE, (cf *)Combine); + gluTessCallback(gt, GLU_TESS_COMBINE, (glxCallbackFptr *)Combine); gluTessProperty(gt, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); Vector normal = p->normal; @@ -155,7 +163,6 @@ void glxFillPolygon(SPolygon *p) gluTessEndContour(gt); } gluTessEndPolygon(gt); - gluDeleteTess(gt); } void glxDebugPolygon(SPolygon *p) @@ -196,7 +203,7 @@ void glxDebugEdgeList(SEdgeList *el) if(se->tag) continue; Vector a = se->a, b = se->b; - glxLockColorTo(0, 1, 0); + glxLockColorTo(0, 1, 1); Vector d = (a.Minus(b)).WithMagnitude(-0); glBegin(GL_LINES); glxVertex3v(a.Plus(d)); @@ -210,6 +217,32 @@ void glxDebugEdgeList(SEdgeList *el) } } +void glxDebugMesh(SMesh *m) +{ + int i; + glLineWidth(2); + glPointSize(7); + glDisable(GL_DEPTH_TEST); + glxUnlockColor(); + for(i = 0; i < m->l.n; i++) { + STriangle *t = &(m->l.elem[i]); + if(t->tag) continue; + + glxColor4d(0, 1, 0, 0.3); + glBegin(GL_LINE_LOOP); + glxVertex3v(t->a); + glxVertex3v(t->b); + glxVertex3v(t->c); + glEnd(); + glxColor4d(0, 0, 1, 0.4); + glBegin(GL_POINTS); + glxVertex3v(t->a); + glxVertex3v(t->b); + glxVertex3v(t->c); + glEnd(); + } +} + void glxMarkPolygonNormal(SPolygon *p) { Vector tail = Vector::MakeFrom(0, 0, 0); diff --git a/graphicswin.cpp b/graphicswin.cpp index 10bcab1..8dc5e2a 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -1181,10 +1181,11 @@ void GraphicsWindow::Paint(int w, int h) { selection[i].Draw(); } - if(SS.group.n >= 5) { - if(1) { - //XXX - } + if(SS.group.n >= 2) { + SMesh m; ZERO(&m); + (SS.group.elem[1].poly).TriangulateInto(&m); + glxDebugMesh(&m); + m.Clear(); } } diff --git a/polygon.cpp b/polygon.cpp index 2798a56..e58b6d4 100644 --- a/polygon.cpp +++ b/polygon.cpp @@ -1,5 +1,16 @@ #include "solvespace.h" +void SEdgeList::Clear(void) { + l.Clear(); +} + +void SEdgeList::AddEdge(Vector a, Vector b) { + SEdge e; ZERO(&e); + e.a = a; + e.b = b; + l.Add(&e); +} + bool SEdgeList::AssemblePolygon(SPolygon *dest, SEdge *errorAt) { dest->Clear(); @@ -52,79 +63,6 @@ bool SEdgeList::AssemblePolygon(SPolygon *dest, SEdge *errorAt) { } } -void SPolygon::Clear(void) { - int i; - for(i = 0; i < l.n; i++) { - (l.elem[i]).l.Clear(); - } - l.Clear(); -} - -void SPolygon::AddEmptyContour(void) { - SContour c; - memset(&c, 0, sizeof(c)); - l.Add(&c); -} - -void SPolygon::AddPoint(Vector p) { - if(l.n < 1) oops(); - - SPoint sp; - sp.tag = 0; - sp.p = p; - - // Add to the last contour in the list - (l.elem[l.n-1]).l.Add(&sp); -} - -void SPolygon::MakeEdgesInto(SEdgeList *el) { - int i; - for(i = 0; i < l.n; i++) { - (l.elem[i]).MakeEdgesInto(el); - } -} - -Vector SPolygon::ComputeNormal(void) { - if(l.n < 1) return Vector::MakeFrom(0, 0, 0); - return (l.elem[0]).ComputeNormal(); -} - -bool SPolygon::ContainsPoint(Vector p) { - bool inside = false; - int i; - for(i = 0; i < l.n; i++) { - SContour *sc = &(l.elem[i]); - if(sc->ContainsPointProjdToNormal(normal, p)) { - inside = !inside; - } - } - return inside; -} - -void SPolygon::FixContourDirections(void) { - // Outside curve looks counterclockwise, projected against our normal. - int i, j; - for(i = 0; i < l.n; i++) { - SContour *sc = &(l.elem[i]); - if(sc->l.n < 1) continue; - Vector pt = (sc->l.elem[0]).p; - - bool outer = true; - for(j = 0; j < l.n; j++) { - if(i == j) continue; - SContour *sct = &(l.elem[j]); - if(sct->ContainsPointProjdToNormal(normal, pt)) { - outer = !outer; - } - } - - bool clockwise = sc->IsClockwiseProjdToNormal(normal); - if(clockwise && outer || (!clockwise && !outer)) { - sc->Reverse(); - } - } -} - void SContour::MakeEdgesInto(SEdgeList *el) { int i; for(i = 0; i < (l.n-1); i++) { @@ -208,3 +146,124 @@ void SContour::Reverse(void) { } } + +void SPolygon::Clear(void) { + int i; + for(i = 0; i < l.n; i++) { + (l.elem[i]).l.Clear(); + } + l.Clear(); +} + +void SPolygon::AddEmptyContour(void) { + SContour c; + memset(&c, 0, sizeof(c)); + l.Add(&c); +} + +void SPolygon::AddPoint(Vector p) { + if(l.n < 1) oops(); + + SPoint sp; + sp.tag = 0; + sp.p = p; + + // Add to the last contour in the list + (l.elem[l.n-1]).l.Add(&sp); +} + +void SPolygon::MakeEdgesInto(SEdgeList *el) { + int i; + for(i = 0; i < l.n; i++) { + (l.elem[i]).MakeEdgesInto(el); + } +} + +Vector SPolygon::ComputeNormal(void) { + if(l.n < 1) return Vector::MakeFrom(0, 0, 0); + return (l.elem[0]).ComputeNormal(); +} + +bool SPolygon::ContainsPoint(Vector p) { + bool inside = false; + int i; + for(i = 0; i < l.n; i++) { + SContour *sc = &(l.elem[i]); + if(sc->ContainsPointProjdToNormal(normal, p)) { + inside = !inside; + } + } + return inside; +} + +void SPolygon::FixContourDirections(void) { + // Outside curve looks counterclockwise, projected against our normal. + int i, j; + for(i = 0; i < l.n; i++) { + SContour *sc = &(l.elem[i]); + if(sc->l.n < 1) continue; + Vector pt = (sc->l.elem[0]).p; + + bool outer = true; + for(j = 0; j < l.n; j++) { + if(i == j) continue; + SContour *sct = &(l.elem[j]); + if(sct->ContainsPointProjdToNormal(normal, pt)) { + outer = !outer; + } + } + + bool clockwise = sc->IsClockwiseProjdToNormal(normal); + if(clockwise && outer || (!clockwise && !outer)) { + sc->Reverse(); + } + } +} + +static int TriMode, TriVertexCount; +static Vector Tri1, TriNMinus1, TriNMinus2; +static SMesh *TriMesh; +static void GLX_CALLBACK TriBegin(int mode) +{ + TriMode = mode; + TriVertexCount = 0; +} +static void GLX_CALLBACK TriEnd(void) +{ +} +static void GLX_CALLBACK TriVertex(Vector *triN) +{ + if(TriVertexCount == 0) { + Tri1 = *triN; + } + if(TriMode == GL_TRIANGLES) { + if((TriVertexCount % 3) == 2) { + TriMesh->AddTriangle(TriNMinus2, TriNMinus1, *triN); + } + } else if(TriMode == GL_TRIANGLE_FAN) { + if(TriVertexCount >= 2) { + TriMesh->AddTriangle(Tri1, TriNMinus1, *triN); + } + } else if(TriMode == GL_TRIANGLE_STRIP) { + if(TriVertexCount >= 2) { + TriMesh->AddTriangle(TriNMinus2, TriNMinus1, *triN); + } + } else oops(); + + TriNMinus2 = TriNMinus1; + TriNMinus1 = *triN; + TriVertexCount++; +} +void SPolygon::TriangulateInto(SMesh *m) { + TriMesh = m; + + GLUtesselator *gt = gluNewTess(); + gluTessCallback(gt, GLU_TESS_BEGIN, (glxCallbackFptr *)TriBegin); + gluTessCallback(gt, GLU_TESS_END, (glxCallbackFptr *)TriEnd); + gluTessCallback(gt, GLU_TESS_VERTEX, (glxCallbackFptr *)TriVertex); + + glxTesselatePolygon(gt, this); + + gluDeleteTess(gt); +} + diff --git a/polygon.h b/polygon.h index e8755fc..a7c5da3 100644 --- a/polygon.h +++ b/polygon.h @@ -3,6 +3,7 @@ #define __POLYGON_H class SPolygon; +class SMesh; template class SList { @@ -43,12 +44,9 @@ class SEdgeList { public: SList l; + void Clear(void); + void AddEdge(Vector a, Vector b); bool AssemblePolygon(SPolygon *dest, SEdge *errorAt); - void CopyBreaking(SEdgeList *dest); - static const int UNION = 0, DIFF = 1, INTERSECT = 2; - bool BooleanOp(int op, bool inA, bool inB); - void CullForBoolean(int op, SPolygon *a, SPolygon *b); - void CullDuplicates(void); }; class SPoint { @@ -66,8 +64,6 @@ public: Vector ComputeNormal(void); bool IsClockwiseProjdToNormal(Vector n); bool ContainsPointProjdToNormal(Vector n, Vector p); - void IntersectAgainstPlane(double *inter, int *inters, - Vector u, Vector v, double vp); }; class SPolygon { @@ -81,20 +77,24 @@ public: bool ContainsPoint(Vector p); void MakeEdgesInto(SEdgeList *el); void FixContourDirections(void); + void TriangulateInto(SMesh *m); void Clear(void); }; class STriangle { public: - Vector a, b, c; + int tag; + Vector a, b, c; }; class SBsp2 { +public: SEdge edge; -}; -class SBsp1d { - SEdge edge; + SBsp2 *pos; + SBsp2 *neg; + + SBsp2 *more; }; class SBsp3 { @@ -112,6 +112,9 @@ public: class SMesh { public: SList l; + + void Clear(void); + void AddTriangle(Vector a, Vector b, Vector c); }; #endif diff --git a/sketch.cpp b/sketch.cpp index 8138915..3ea380a 100644 --- a/sketch.cpp +++ b/sketch.cpp @@ -418,7 +418,7 @@ void Group::MakePolygons(void) { } // Get the source polygon to extrude, and break it down to edges - edges.l.Clear(); + edges.Clear(); Group *src = SS.GetGroup(opA); (src->poly).MakeEdgesInto(&edges); @@ -440,7 +440,7 @@ void Group::MakePolygons(void) { np.FixContourDirections(); // Regenerate the edges, with the contour directions fixed up. - edges.l.Clear(); + edges.Clear(); np.MakeEdgesInto(&edges); // The sides @@ -465,7 +465,7 @@ void Group::MakePolygons(void) { if(!edges.AssemblePolygon(&np, NULL)) oops(); np.normal = n.ScaledBy(-1); } - edges.l.Clear(); + edges.Clear(); } void Group::Draw(void) { diff --git a/solvespace.h b/solvespace.h index fb30b7d..cb2f067 100644 --- a/solvespace.h +++ b/solvespace.h @@ -14,6 +14,9 @@ #define SWAP(T, a, b) do { T temp = (a); (a) = (b); (b) = temp; } while(0) #define ZERO(v) memset((v), 0, sizeof(*(v))) +#define CO(v) (v).x, (v).y, (v).z + +#define LENGTH_EPS (0.0001) #define isforname(c) (isalnum(c) || (c) == '_' || (c) == '-' || (c) == '#') @@ -70,9 +73,13 @@ void vl(void); // debug function to validate // Utility functions that are provided in the platform-independent code. void glxVertex3v(Vector u); +#define GLX_CALLBACK __stdcall +typedef void GLX_CALLBACK glxCallbackFptr(void); +void glxTesselatePolygon(GLUtesselator *gt, SPolygon *p); void glxFillPolygon(SPolygon *p); void glxDebugPolygon(SPolygon *p); void glxDebugEdgeList(SEdgeList *l); +void glxDebugMesh(SMesh *m); void glxMarkPolygonNormal(SPolygon *p); void glxWriteText(char *str); void glxWriteTextRefCenter(char *str); diff --git a/util.cpp b/util.cpp index 2ca5d79..cb16610 100644 --- a/util.cpp +++ b/util.cpp @@ -178,10 +178,9 @@ Vector Vector::MakeFrom(double x, double y, double z) { } bool Vector::Equals(Vector v) { - double tol = 0.00001; - if(fabs(x - v.x) > tol) return false; - if(fabs(y - v.y) > tol) return false; - if(fabs(z - v.z) > tol) return false; + if(fabs(x - v.x) > LENGTH_EPS) return false; + if(fabs(y - v.y) > LENGTH_EPS) return false; + if(fabs(z - v.z) > LENGTH_EPS) return false; return true; }