diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/OGL_helper.h | 17 | ||||
-rw-r--r-- | src/OpenCSGRenderer.cc (renamed from src/opencsgrenderer.cc) | 2 | ||||
-rw-r--r-- | src/dxftess-cgal.cc | 2 | ||||
-rw-r--r-- | src/lexer.l | 2 | ||||
-rw-r--r-- | src/mainwin.cc | 4 | ||||
-rw-r--r-- | src/opencsgrenderer.h | 24 | ||||
-rw-r--r-- | src/polyset.cc | 357 | ||||
-rw-r--r-- | src/throwntogetherrenderer.cc | 120 | ||||
-rw-r--r-- | src/throwntogetherrenderer.h | 21 |
9 files changed, 379 insertions, 170 deletions
diff --git a/src/OGL_helper.h b/src/OGL_helper.h index 2aae31b..2764561 100644 --- a/src/OGL_helper.h +++ b/src/OGL_helper.h @@ -243,6 +243,21 @@ namespace OGL { glVertex3dv(pc); } + inline void CGAL_GLU_TESS_CALLBACK combineCallback(GLdouble coords[3], GLvoid *[4], GLfloat [4], GLvoid **dataOut) + { static std::list<GLdouble*> pcache; + if (dataOut) { + GLdouble *n = new GLdouble[3]; + n[0] = coords[0]; + n[1] = coords[1]; + n[2] = coords[2]; + pcache.push_back(n); + *dataOut = n; + } else { + for (std::list<GLdouble*>::const_iterator i = pcache.begin(); i != pcache.end(); i++) + delete[] *i; + pcache.clear(); + } + } enum { SNC_AXES}; enum { SNC_BOUNDARY, SNC_SKELETON }; @@ -396,6 +411,8 @@ namespace OGL { GLUtesselator* tess_ = gluNewTess(); gluTessCallback(tess_, GLenum(GLU_TESS_VERTEX_DATA), (GLvoid (CGAL_GLU_TESS_CALLBACK *)(CGAL_GLU_TESS_DOTS)) &vertexCallback); + gluTessCallback(tess_, GLenum(GLU_TESS_COMBINE), + (GLvoid (CGAL_GLU_TESS_CALLBACK *)(CGAL_GLU_TESS_DOTS)) &combineCallback); gluTessCallback(tess_, GLenum(GLU_TESS_BEGIN), (GLvoid (CGAL_GLU_TESS_CALLBACK *)(CGAL_GLU_TESS_DOTS)) &beginCallback); gluTessCallback(tess_, GLenum(GLU_TESS_END), diff --git a/src/opencsgrenderer.cc b/src/OpenCSGRenderer.cc index 2c9c3d0..9030d11 100644 --- a/src/opencsgrenderer.cc +++ b/src/OpenCSGRenderer.cc @@ -25,7 +25,7 @@ */ #include <GL/glew.h> -#include "opencsgrenderer.h" +#include "OpenCSGRenderer.h" #include "polyset.h" #include "csgterm.h" diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc index 2e80fea..adb7e9a 100644 --- a/src/dxftess-cgal.cc +++ b/src/dxftess-cgal.cc @@ -158,7 +158,7 @@ void dxf_tesselate(PolySet *ps, DxfData *dxf, double rot, bool up, bool /* do_tr } catch (CGAL::Assertion_exception e) { - PRINTF("ERROR: Polygon intersection detected. Skipping affected polygons."); + PRINTF("CGAL error: %s", e.what()); CGAL::set_error_behaviour(old_behaviour); return; } diff --git a/src/lexer.l b/src/lexer.l index bc61c20..5e62b19 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -35,7 +35,7 @@ //isatty for visual c++ #ifdef _MSC_VER -int __cdecl _isatty(int _FileHandle); +extern "C" int __cdecl _isatty(int _FileHandle); #define isatty _isatty #endif diff --git a/src/mainwin.cc b/src/mainwin.cc index 5bc16cb..badb01f 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -41,14 +41,14 @@ #include "progress.h" #ifdef ENABLE_OPENCSG #include "CSGTermEvaluator.h" -#include "opencsgRenderer.h" +#include "OpenCSGRenderer.h" #endif #ifdef USE_PROGRESSWIDGET #include "ProgressWidget.h" #endif #include "CGALEvaluator.h" #include "PolySetCGALEvaluator.h" -#include "thrownTogetherRenderer.h" +#include "ThrownTogetherRenderer.h" #include <QMenu> #include <QTime> diff --git a/src/opencsgrenderer.h b/src/opencsgrenderer.h deleted file mode 100644 index 95ffc8e..0000000 --- a/src/opencsgrenderer.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef OPENCSGRENDERER_H_ -#define OPENCSGRENDERER_H_ - -#include "renderer.h" -#include <GL/glew.h> // this must be included before the GL headers -#include <qgl.h> - -class OpenCSGRenderer : public Renderer -{ -public: - OpenCSGRenderer(class CSGChain *root_chain, CSGChain *highlights_chain, - CSGChain *background_chain, GLint *shaderinfo); - void draw(bool showfaces, bool showedges) const; -private: - void renderCSGChain(class CSGChain *chain, GLint *shaderinfo, - bool highlight, bool background) const; - - CSGChain *root_chain; - CSGChain *highlights_chain; - CSGChain *background_chain; - GLint *shaderinfo; -}; - -#endif diff --git a/src/polyset.cc b/src/polyset.cc index eda6304..679d754 100644 --- a/src/polyset.cc +++ b/src/polyset.cc @@ -318,3 +318,360 @@ void PolySet::render_edges(colormode_e colormode, csgmode_e csgmode) const } } } +<<<<<<< HEAD +======= + +#ifdef ENABLE_CGAL + +#undef GEN_SURFACE_DEBUG + +class CGAL_Build_PolySet : public CGAL::Modifier_base<CGAL_HDS> +{ +public: + typedef CGAL_HDS::Vertex::Point Point; + + const PolySet *ps; + CGAL_Build_PolySet(const PolySet *ps) : ps(ps) { } + + void operator()(CGAL_HDS& hds) + { + CGAL_Polybuilder B(hds, true); + + QList<PolySet::Point> vertices; + Grid3d<int> vertices_idx(GRID_FINE); + + for (int i = 0; i < ps->polygons.size(); i++) { + const PolySet::Polygon *poly = &ps->polygons[i]; + for (int j = 0; j < poly->size(); j++) { + const PolySet::Point *p = &poly->at(j); + if (!vertices_idx.has(p->x, p->y, p->z)) { + vertices_idx.data(p->x, p->y, p->z) = vertices.size(); + vertices.append(*p); + } + } + } + + B.begin_surface(vertices.size(), ps->polygons.size()); +#ifdef GEN_SURFACE_DEBUG + printf("=== CGAL Surface ===\n"); +#endif + + for (int i = 0; i < vertices.size(); i++) { + const PolySet::Point *p = &vertices[i]; + B.add_vertex(Point(p->x, p->y, p->z)); +#ifdef GEN_SURFACE_DEBUG + printf("%d: %f %f %f\n", i, p->x, p->y, p->z); +#endif + } + + for (int i = 0; i < ps->polygons.size(); i++) { + const PolySet::Polygon *poly = &ps->polygons[i]; + QHash<int,int> fc; + bool facet_is_degenerated = false; + for (int j = 0; j < poly->size(); j++) { + const PolySet::Point *p = &poly->at(j); + int v = vertices_idx.data(p->x, p->y, p->z); + if (fc[v]++ > 0) + facet_is_degenerated = true; + } + + if (!facet_is_degenerated) + B.begin_facet(); +#ifdef GEN_SURFACE_DEBUG + printf("F:"); +#endif + for (int j = 0; j < poly->size(); j++) { + const PolySet::Point *p = &poly->at(j); +#ifdef GEN_SURFACE_DEBUG + printf(" %d (%f,%f,%f)", vertices_idx.data(p->x, p->y, p->z), p->x, p->y, p->z); +#endif + if (!facet_is_degenerated) + B.add_vertex_to_facet(vertices_idx.data(p->x, p->y, p->z)); + } +#ifdef GEN_SURFACE_DEBUG + if (facet_is_degenerated) + printf(" (degenerated)"); + printf("\n"); +#endif + if (!facet_is_degenerated) + B.end_facet(); + } + +#ifdef GEN_SURFACE_DEBUG + printf("====================\n"); +#endif + B.end_surface(); + + #undef PointKey + } +}; + +CGAL_Nef_polyhedron PolySet::render_cgal_nef_polyhedron() const +{ + if (this->is2d) + { +#if 0 + // This version of the code causes problems in some cases. + // Example testcase: import_dxf("testdata/polygon8.dxf"); + // + typedef std::list<CGAL_Nef_polyhedron2::Point> point_list_t; + typedef point_list_t::iterator point_list_it; + std::list< point_list_t > pdata_point_lists; + std::list < std::pair < point_list_it, point_list_it > > pdata; + Grid2d<CGAL_Nef_polyhedron2::Point> grid(GRID_COARSE); + + for (int i = 0; i < this->polygons.size(); i++) { + pdata_point_lists.push_back(point_list_t()); + for (int j = 0; j < this->polygons[i].size(); j++) { + double x = this->polygons[i][j].x; + double y = this->polygons[i][j].y; + CGAL_Nef_polyhedron2::Point p; + if (grid.has(x, y)) { + p = grid.data(x, y); + } else { + p = CGAL_Nef_polyhedron2::Point(x, y); + grid.data(x, y) = p; + } + pdata_point_lists.back().push_back(p); + } + pdata.push_back(std::make_pair(pdata_point_lists.back().begin(), + pdata_point_lists.back().end())); + } + + CGAL_Nef_polyhedron2 N(pdata.begin(), pdata.end(), CGAL_Nef_polyhedron2::POLYGONS); + return CGAL_Nef_polyhedron(N); +#endif +#if 0 + // This version of the code works fine but is pretty slow. + // + CGAL_Nef_polyhedron2 N; + Grid2d<CGAL_Nef_polyhedron2::Point> grid(GRID_COARSE); + + for (int i = 0; i < this->polygons.size(); i++) { + std::list<CGAL_Nef_polyhedron2::Point> plist; + for (int j = 0; j < this->polygons[i].size(); j++) { + double x = this->polygons[i][j].x; + double y = this->polygons[i][j].y; + CGAL_Nef_polyhedron2::Point p; + if (grid.has(x, y)) { + p = grid.data(x, y); + } else { + p = CGAL_Nef_polyhedron2::Point(x, y); + grid.data(x, y) = p; + } + plist.push_back(p); + } + N += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED); + } + + return CGAL_Nef_polyhedron(N); +#endif +#if 1 + // This version of the code does essentially the same thing as the 2nd + // version but merges some triangles before sending them to CGAL. This adds + // complexity but speeds up things.. + // + struct PolyReducer + { + Grid2d<int> grid; + QHash< QPair<int,int>, QPair<int,int> > egde_to_poly; + QHash< int, CGAL_Nef_polyhedron2::Point > points; + QHash< int, QList<int> > polygons; + int poly_n; + + void add_edges(int pn) + { + for (int j = 1; j <= this->polygons[pn].size(); j++) { + int a = this->polygons[pn][j-1]; + int b = this->polygons[pn][j % this->polygons[pn].size()]; + if (a > b) { a = a^b; b = a^b; a = a^b; } + if (this->egde_to_poly[QPair<int,int>(a, b)].first == 0) + this->egde_to_poly[QPair<int,int>(a, b)].first = pn; + else if (this->egde_to_poly[QPair<int,int>(a, b)].second == 0) + this->egde_to_poly[QPair<int,int>(a, b)].second = pn; + else + abort(); + } + } + + void del_poly(int pn) + { + for (int j = 1; j <= this->polygons[pn].size(); j++) { + int a = this->polygons[pn][j-1]; + int b = this->polygons[pn][j % this->polygons[pn].size()]; + if (a > b) { a = a^b; b = a^b; a = a^b; } + if (this->egde_to_poly[QPair<int,int>(a, b)].first == pn) + this->egde_to_poly[QPair<int,int>(a, b)].first = 0; + if (this->egde_to_poly[QPair<int,int>(a, b)].second == pn) + this->egde_to_poly[QPair<int,int>(a, b)].second = 0; + } + this->polygons.remove(pn); + } + + PolyReducer(const PolySet *ps) : grid(GRID_COARSE), poly_n(1) + { + int point_n = 1; + for (int i = 0; i < ps->polygons.size(); i++) { + for (int j = 0; j < ps->polygons[i].size(); j++) { + double x = ps->polygons[i][j].x; + double y = ps->polygons[i][j].y; + if (this->grid.has(x, y)) { + this->polygons[this->poly_n].append(this->grid.data(x, y)); + } else { + this->grid.align(x, y) = point_n; + this->polygons[this->poly_n].append(point_n); + this->points[point_n] = CGAL_Nef_polyhedron2::Point(x, y); + point_n++; + } + } + add_edges(this->poly_n); + this->poly_n++; + } + } + + int merge(int p1, int p1e, int p2, int p2e) + { + for (int i = 1; i < this->polygons[p1].size(); i++) { + int j = (p1e + i) % this->polygons[p1].size(); + this->polygons[this->poly_n].append(this->polygons[p1][j]); + } + for (int i = 1; i < this->polygons[p2].size(); i++) { + int j = (p2e + i) % this->polygons[p2].size(); + this->polygons[this->poly_n].append(this->polygons[p2][j]); + } + del_poly(p1); + del_poly(p2); + add_edges(this->poly_n); + return this->poly_n++; + } + + void reduce() + { + QList<int> work_queue; + QHashIterator< int, QList<int> > it(polygons); + while (it.hasNext()) { + it.next(); + work_queue.append(it.key()); + } + while (!work_queue.isEmpty()) { + int poly1_n = work_queue.first(); + work_queue.removeFirst(); + if (!this->polygons.contains(poly1_n)) + continue; + for (int j = 1; j <= this->polygons[poly1_n].size(); j++) { + int a = this->polygons[poly1_n][j-1]; + int b = this->polygons[poly1_n][j % this->polygons[poly1_n].size()]; + if (a > b) { a = a^b; b = a^b; a = a^b; } + if (this->egde_to_poly[QPair<int,int>(a, b)].first != 0 && + this->egde_to_poly[QPair<int,int>(a, b)].second != 0) { + int poly2_n = this->egde_to_poly[QPair<int,int>(a, b)].first + + this->egde_to_poly[QPair<int,int>(a, b)].second - poly1_n; + int poly2_edge = -1; + for (int k = 1; k <= this->polygons[poly2_n].size(); k++) { + int c = this->polygons[poly2_n][k-1]; + int d = this->polygons[poly2_n][k % this->polygons[poly2_n].size()]; + if (c > d) { c = c^d; d = c^d; c = c^d; } + if (a == c && b == d) { + poly2_edge = k-1; + continue; + } + int poly3_n = this->egde_to_poly[QPair<int,int>(c, d)].first + + this->egde_to_poly[QPair<int,int>(c, d)].second - poly2_n; + if (poly3_n < 0) + continue; + if (poly3_n == poly1_n) + goto next_poly1_edge; + } + work_queue.append(merge(poly1_n, j-1, poly2_n, poly2_edge)); + goto next_poly1; + } + next_poly1_edge:; + } + next_poly1:; + } + } + + CGAL_Nef_polyhedron2 toNef() + { + CGAL_Nef_polyhedron2 N; + + QHashIterator< int, QList<int> > it(polygons); + while (it.hasNext()) { + it.next(); + std::list<CGAL_Nef_polyhedron2::Point> plist; + for (int j = 0; j < it.value().size(); j++) { + int p = it.value()[j]; + plist.push_back(points[p]); + } + N += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED); + } + + return N; + } + }; + + PolyReducer pr(this); + // printf("Number of polygons before reduction: %d\n", pr.polygons.size()); + pr.reduce(); + // printf("Number of polygons after reduction: %d\n", pr.polygons.size()); + return CGAL_Nef_polyhedron(pr.toNef()); +#endif +#if 0 + // This is another experimental version. I should run faster than the above, + // is a lot simpler and has only one known weakness: Degenerate polygons, which + // get repaired by GLUTess, might trigger a CGAL crash here. The only + // known case for this is triangle-with-duplicate-vertex.dxf + // FIXME: If we just did a projection, we need to recreate the border! + if (this->polygons.size() > 0) assert(this->borders.size() > 0); + CGAL_Nef_polyhedron2 N; + Grid2d<CGAL_Nef_polyhedron2::Point> grid(GRID_COARSE); + + for (int i = 0; i < this->borders.size(); i++) { + std::list<CGAL_Nef_polyhedron2::Point> plist; + for (int j = 0; j < this->borders[i].size(); j++) { + double x = this->borders[i][j].x; + double y = this->borders[i][j].y; + CGAL_Nef_polyhedron2::Point p; + if (grid.has(x, y)) { + p = grid.data(x, y); + } else { + p = CGAL_Nef_polyhedron2::Point(x, y); + grid.data(x, y) = p; + } + plist.push_back(p); + } + // FIXME: If a border (path) has a duplicate vertex in dxf, + // the CGAL_Nef_polyhedron2 constructor will crash. + N ^= CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED); + } + + return CGAL_Nef_polyhedron(N); + +#endif + } + else // not (this->is2d) + { + CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); + try { + CGAL_Polyhedron P; + CGAL_Build_PolySet builder(this); + P.delegate(builder); +#if 0 + std::cout << P; +#endif + CGAL_Nef_polyhedron3 N(P); + return CGAL_Nef_polyhedron(N); + } + catch (CGAL::Assertion_exception e) { + PRINTF("CGAL error: %s", e.what()); + CGAL::set_error_behaviour(old_behaviour); + return CGAL_Nef_polyhedron(); + } + CGAL::set_error_behaviour(old_behaviour); + } + return CGAL_Nef_polyhedron(); +} + +#endif /* ENABLE_CGAL */ + +>>>>>>> master diff --git a/src/throwntogetherrenderer.cc b/src/throwntogetherrenderer.cc deleted file mode 100644 index 0a0c9c8..0000000 --- a/src/throwntogetherrenderer.cc +++ /dev/null @@ -1,120 +0,0 @@ -/* - * OpenSCAD (www.openscad.org) - * Copyright (C) 2009-2011 Clifford Wolf <clifford@clifford.at> and - * Marius Kintel <marius@kintel.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * As a special exception, you have permission to link this program - * with the CGAL library and distribute executables, as long as you - * follow the requirements of the GNU GPL in regard to all of the - * software in the executable aside from CGAL. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include "ThrownTogetherRenderer.h" -#include "polyset.h" -#include "csgterm.h" - -#include <GL/glew.h> // this must be included before the GL headers -#include <qgl.h> - -ThrownTogetherRenderer::ThrownTogetherRenderer(CSGChain *root_chain, - CSGChain *highlights_chain, - CSGChain *background_chain) - : root_chain(root_chain), highlights_chain(highlights_chain), - background_chain(background_chain) -{ -} - -void ThrownTogetherRenderer::draw(bool showfaces, bool showedges) const -{ - if (this->root_chain) { - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - renderCSGChain(this->root_chain, false, false, showedges, false); - glCullFace(GL_FRONT); - glColor3ub(255, 0, 255); - renderCSGChain(this->root_chain, false, false, showedges, true); - glDisable(GL_CULL_FACE); - } - if (this->background_chain) - renderCSGChain(this->background_chain, false, true, showedges, false); - if (this->highlights_chain) - renderCSGChain(this->highlights_chain, true, false, showedges, false); -} - -void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool highlight, - bool background, bool showedges, - bool fberror) const -{ - glDepthFunc(GL_LEQUAL); - QHash<QPair<PolySet*,double*>,int> polySetVisitMark; - for (int i = 0; i < chain->polysets.size(); i++) { - if (polySetVisitMark[QPair<PolySet*,double*>(chain->polysets[i], chain->matrices[i])]++ > 0) - continue; - double *m = chain->matrices[i]; - glPushMatrix(); - glMultMatrixd(m); - int csgmode = chain->types[i] == CSGTerm::TYPE_DIFFERENCE ? PolySet::CSGMODE_DIFFERENCE : PolySet::CSGMODE_NORMAL; - if (highlight) { - chain->polysets[i]->render_surface(PolySet::COLORMODE_HIGHLIGHT, PolySet::csgmode_e(csgmode + 20), m); - if (showedges) { - glDisable(GL_LIGHTING); - chain->polysets[i]->render_edges(PolySet::COLORMODE_HIGHLIGHT, PolySet::csgmode_e(csgmode + 20)); - glEnable(GL_LIGHTING); - } - } else if (background) { - chain->polysets[i]->render_surface(PolySet::COLORMODE_BACKGROUND, PolySet::csgmode_e(csgmode + 10), m); - if (showedges) { - glDisable(GL_LIGHTING); - chain->polysets[i]->render_edges(PolySet::COLORMODE_BACKGROUND, PolySet::csgmode_e(csgmode + 10)); - glEnable(GL_LIGHTING); - } - } else if (fberror) { - if (highlight) { - chain->polysets[i]->render_surface(PolySet::COLORMODE_NONE, PolySet::csgmode_e(csgmode + 20), m); - } else if (background) { - chain->polysets[i]->render_surface(PolySet::COLORMODE_NONE, PolySet::csgmode_e(csgmode + 10), m); - } else { - chain->polysets[i]->render_surface(PolySet::COLORMODE_NONE, PolySet::csgmode_e(csgmode), m); - } - } else if (m[16] >= 0 || m[17] >= 0 || m[18] >= 0 || m[19] >= 0) { - glColor4d(m[16], m[17], m[18], m[19]); - chain->polysets[i]->render_surface(PolySet::COLORMODE_NONE, PolySet::csgmode_e(csgmode), m); - if (showedges) { - glDisable(GL_LIGHTING); - glColor4d((m[16]+1)/2, (m[17]+1)/2, (m[18]+1)/2, 1.0); - chain->polysets[i]->render_edges(PolySet::COLORMODE_NONE, PolySet::csgmode_e(csgmode)); - glEnable(GL_LIGHTING); - } - } else if (chain->types[i] == CSGTerm::TYPE_DIFFERENCE) { - chain->polysets[i]->render_surface(PolySet::COLORMODE_CUTOUT, PolySet::csgmode_e(csgmode), m); - if (showedges) { - glDisable(GL_LIGHTING); - chain->polysets[i]->render_edges(PolySet::COLORMODE_CUTOUT, PolySet::csgmode_e(csgmode)); - glEnable(GL_LIGHTING); - } - } else { - chain->polysets[i]->render_surface(PolySet::COLORMODE_MATERIAL, PolySet::csgmode_e(csgmode), m); - if (showedges) { - glDisable(GL_LIGHTING); - chain->polysets[i]->render_edges(PolySet::COLORMODE_MATERIAL, PolySet::csgmode_e(csgmode)); - glEnable(GL_LIGHTING); - } - } - glPopMatrix(); - } -} diff --git a/src/throwntogetherrenderer.h b/src/throwntogetherrenderer.h deleted file mode 100644 index 09d13f3..0000000 --- a/src/throwntogetherrenderer.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef THROWNTOGETHERRENDERER_H_ -#define THROWNTOGETHERRENDERER_H_ - -#include "renderer.h" - -class ThrownTogetherRenderer : public Renderer -{ -public: - ThrownTogetherRenderer(class CSGChain *root_chain, - CSGChain *highlights_chain, CSGChain *background_chain); - void draw(bool showfaces, bool showedges) const; -private: - void renderCSGChain(CSGChain *chain, bool highlight, bool background, bool showedges, - bool fberror) const; - - CSGChain *root_chain; - CSGChain *highlights_chain; - CSGChain *background_chain; -}; - -#endif |