diff options
author | Marius Kintel <marius@kintel.net> | 2011-07-30 23:58:51 (GMT) |
---|---|---|
committer | Marius Kintel <marius@kintel.net> | 2011-07-30 23:58:51 (GMT) |
commit | 6882228058d313bb7b98fddd90239bdb1a3e25ef (patch) | |
tree | 9e3f0077a319939df7496fc6b18350c44cc4b0ec | |
parent | dd9dfcb4ece4dcd1ae7f3374ef03a4babdb91dd8 (diff) | |
parent | c79ad5010e4ae8a612de5423cd52a518ed6b4d65 (diff) |
Merge branch 'master' into visitor
Conflicts:
src/GLView.h
src/glview.cc
src/mainwin.cc
src/render-opencsg.cc
47 files changed, 1814 insertions, 1325 deletions
diff --git a/doc/OpenSCAD-compile.graffle b/doc/OpenSCAD-compile.graffle Binary files differindex 02e8bc8..bb505c3 100644 --- a/doc/OpenSCAD-compile.graffle +++ b/doc/OpenSCAD-compile.graffle diff --git a/doc/OpenSCAD-csg.graffle b/doc/OpenSCAD-csg.graffle Binary files differindex 7ad552c..ca0a0ff 100644 --- a/doc/OpenSCAD-csg.graffle +++ b/doc/OpenSCAD-csg.graffle diff --git a/doc/OpenSCAD-polygons.graffle b/doc/OpenSCAD-polygons.graffle Binary files differindex 3e8b5bd..40df7ab 100644 --- a/doc/OpenSCAD-polygons.graffle +++ b/doc/OpenSCAD-polygons.graffle diff --git a/doc/TODO.txt b/doc/TODO.txt index c0772f6..74e1f3f 100644 --- a/doc/TODO.txt +++ b/doc/TODO.txt @@ -49,7 +49,6 @@ o non-convex minkowski example from chrysn fails with an exception USER INTERFACE -------------- o Preferences - - Remember settings done in menus between sessions (automatic reload, perspective, show*, hide*) - Beautify color schemes - Color schemes read from file - Color scheme editor @@ -57,7 +56,6 @@ o Preferences - pointsize - OpenGL params - Default language feature settings - - Auto-view CSG/thrown together on load - Make the library search path configurable? o MDI - Think about how to do MDI the right way diff --git a/opencsg.pri b/opencsg.pri index 8538f99..02be596 100644 --- a/opencsg.pri +++ b/opencsg.pri @@ -3,8 +3,8 @@ opencsg { CONFIG += glew include(glew.pri) - HEADERS += src/render-opencsg.h - SOURCES += src/render-opencsg.cc + HEADERS += src/opencsgrenderer.h + SOURCES += src/opencsgrenderer.cc isEmpty(DEPLOYDIR) { # Optionally specify location of OpenCSG using the diff --git a/openscad.pro b/openscad.pro index 4a785fd..a4381be 100644 --- a/openscad.pro +++ b/openscad.pro @@ -118,7 +118,11 @@ include(boost.pri) FORMS += src/MainWindow.ui \ src/Preferences.ui -HEADERS += src/CGAL_renderer.h \ +HEADERS += src/renderer.h \ + src/cgalrenderer.h \ + src/throwntogetherrenderer.h \ + src/CGAL_renderer.h \ + src/OGL_helper.h \ src/GLView.h \ src/MainWindow.h \ src/Preferences.h \ @@ -154,16 +158,18 @@ HEADERS += src/CGAL_renderer.h \ src/traverser.h \ src/nodecache.h \ src/nodedumper.h \ - src/CGALRenderer.h \ - src/PolySetRenderer.h \ - src/PolySetCGALRenderer.h \ - src/CSGTermRenderer.h \ + src/CGALEvaluator.h \ + src/PolySetEvaluator.h \ + src/PolySetCGALEvaluator.h \ + src/CSGTermEvaluator.h \ src/myqhash.h \ src/Tree.h \ src/mathc99.h SOURCES += src/openscad.cc \ src/mainwin.cc \ + src/cgalrenderer.cc \ + src/throwntogetherrenderer.cc \ src/glview.cc \ src/export.cc \ src/value.cc \ @@ -201,10 +207,10 @@ SOURCES += src/openscad.cc \ src/editor.cc \ src/traverser.cc \ src/nodedumper.cc \ - src/CGALRenderer.cc \ - src/PolySetRenderer.cc \ - src/PolySetCGALRenderer.cc \ - src/CSGTermRenderer.cc \ + src/CGALEvaluator.cc \ + src/PolySetEvaluator.cc \ + src/PolySetCGALEvaluator.cc \ + src/CSGTermEvaluator.cc \ src/qhash.cc \ src/Tree.cc \ src/mathc99.cc diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh index 9a59789..0c2f456 100755 --- a/scripts/macosx-build-dependencies.sh +++ b/scripts/macosx-build-dependencies.sh @@ -119,7 +119,9 @@ build_cgal() version=$1 echo "Building CGAL" $version "..." cd $BASEDIR/src - curl -O https://gforge.inria.fr/frs/download.php/27641/CGAL-$version.tar.gz + rm -rf CGAL* + curl -O https://gforge.inria.fr/frs/download.php/28500/CGAL-$version.tar.gz +# curl -O https://gforge.inria.fr/frs/download.php/27641/CGAL-$version.tar.gz tar xzf CGAL-$version.tar.gz cd CGAL-$version # We build a static lib. Not really necessary, but it's well tested. @@ -160,7 +162,8 @@ echo "Using basedir:" $BASEDIR mkdir -p $SRCDIR $DEPLOYDIR build_gmp 5.0.1 build_mpfr 3.0.1 -build_boost 1.46.1 -build_cgal 3.7 -build_glew 1.5.8 +build_boost 1.47.0 +# NB! For CGAL, also update the actual download URL in the function +build_cgal 3.8 +build_glew 1.6.0 build_opencsg 1.3.0 diff --git a/src/CGALRenderer.cc b/src/CGALEvaluator.cc index f5bcbda..021537c 100644 --- a/src/CGALRenderer.cc +++ b/src/CGALEvaluator.cc @@ -1,4 +1,4 @@ -#include "CGALRenderer.h" +#include "CGALEvaluator.h" #include "visitor.h" #include "state.h" #include "module.h" // FIXME: Temporarily for ModuleInstantiation @@ -21,17 +21,17 @@ #include <assert.h> #include <QRegExp> -CGAL_Nef_polyhedron CGALRenderer::renderCGALMesh(const AbstractNode &node) +CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const AbstractNode &node) { if (!isCached(node)) { - Traverser render(*this, node, Traverser::PRE_AND_POSTFIX); - render.execute(); + Traverser evaluate(*this, node, Traverser::PRE_AND_POSTFIX); + evaluate.execute(); assert(isCached(node)); } return this->cache[this->tree.getString(node)]; } -bool CGALRenderer::isCached(const AbstractNode &node) const +bool CGALEvaluator::isCached(const AbstractNode &node) const { return this->cache.contains(this->tree.getString(node)); } @@ -40,7 +40,7 @@ bool CGALRenderer::isCached(const AbstractNode &node) const Modifies target by applying op to target and src: target = target [op] src */ -void CGALRenderer::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CsgOp op) +void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CsgOp op) { if (target.dim != 2 && target.dim != 3) { assert(false && "Dimension of Nef polyhedron must be 2 or 3"); @@ -92,7 +92,7 @@ void CGALRenderer::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedro FIXME: Let caller insert into the cache since caller might modify the result (e.g. transform) */ -void CGALRenderer::applyToChildren(const AbstractNode &node, CGALRenderer::CsgOp op) +void CGALEvaluator::applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op) { CGAL_Nef_polyhedron N; if (this->visitedchildren[node.index()].size() > 0) { @@ -126,7 +126,7 @@ void CGALRenderer::applyToChildren(const AbstractNode &node, CGALRenderer::CsgOp o In postfix: addToParent() */ -Response CGALRenderer::visit(State &state, const AbstractNode &node) +Response CGALEvaluator::visit(State &state, const AbstractNode &node) { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { @@ -136,7 +136,7 @@ Response CGALRenderer::visit(State &state, const AbstractNode &node) return ContinueTraversal; } -Response CGALRenderer::visit(State &state, const AbstractIntersectionNode &node) +Response CGALEvaluator::visit(State &state, const AbstractIntersectionNode &node) { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { @@ -146,7 +146,7 @@ Response CGALRenderer::visit(State &state, const AbstractIntersectionNode &node) return ContinueTraversal; } -Response CGALRenderer::visit(State &state, const CsgNode &node) +Response CGALEvaluator::visit(State &state, const CsgNode &node) { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { @@ -170,7 +170,7 @@ Response CGALRenderer::visit(State &state, const CsgNode &node) return ContinueTraversal; } -Response CGALRenderer::visit(State &state, const TransformNode &node) +Response CGALEvaluator::visit(State &state, const TransformNode &node) { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { @@ -203,7 +203,7 @@ Response CGALRenderer::visit(State &state, const TransformNode &node) ps.is2d = true; dxf_tesselate(&ps, &dd, 0, true, false, 0); - N = renderCGALMesh(ps); + N = evaluateCGALMesh(ps); ps.refcount = 0; } else if (N.dim == 3) { @@ -220,7 +220,7 @@ Response CGALRenderer::visit(State &state, const TransformNode &node) return ContinueTraversal; } -// FIXME: RenderNode: Union over children + some magic +// FIXME: EvaluateNode: Union over children + some magic // FIXME: CgaladvNode: Iterate over children. Special operation // FIXME: Subtypes of AbstractPolyNode: @@ -229,7 +229,7 @@ Response CGALRenderer::visit(State &state, const TransformNode &node) // DxfRotateExtrudeNode // (SurfaceNode) // (PrimitiveNode) -Response CGALRenderer::visit(State &state, const AbstractPolyNode &node) +Response CGALEvaluator::visit(State &state, const AbstractPolyNode &node) { if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPostfix()) { @@ -238,10 +238,10 @@ Response CGALRenderer::visit(State &state, const AbstractPolyNode &node) applyToChildren(node, UNION); // Then apply polyset operation - PolySet *ps = node.render_polyset(AbstractPolyNode::RENDER_CGAL, &this->psrenderer); + PolySet *ps = node.evaluate_polyset(AbstractPolyNode::RENDER_CGAL, &this->psevaluator); if (ps) { try { - CGAL_Nef_polyhedron N = renderCGALMesh(*ps); + CGAL_Nef_polyhedron N = evaluateCGALMesh(*ps); // print_messages_pop(); node.progress_report(); @@ -263,7 +263,7 @@ Response CGALRenderer::visit(State &state, const AbstractPolyNode &node) Adds ourself to out parent's list of traversed children. Call this for _every_ node which affects output during the postfix traversal. */ -void CGALRenderer::addToParent(const State &state, const AbstractNode &node) +void CGALEvaluator::addToParent(const State &state, const AbstractNode &node) { assert(state.isPostfix()); this->visitedchildren.erase(node.index()); @@ -274,19 +274,19 @@ void CGALRenderer::addToParent(const State &state, const AbstractNode &node) #if 0 /*! - Static function to render CGAL meshes. + Static function to evaluate CGAL meshes. NB! This is just a support function used for development and debugging */ -CGAL_Nef_polyhedron CGALRenderer::renderCGALMesh(const AbstractPolyNode &node) +CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const AbstractPolyNode &node) { // FIXME: Lookup Nef polyhedron in cache. // print_messages_push(); - PolySet *ps = node.render_polyset(AbstractPolyNode::RENDER_CGAL); + PolySet *ps = node.evaluate_polyset(AbstractPolyNode::RENDER_CGAL); if (ps) { try { - CGAL_Nef_polyhedron N = ps->renderCSGMesh(); + CGAL_Nef_polyhedron N = ps->evaluateCSGMesh(); // FIXME: Insert into cache // print_messages_pop(); node.progress_report(); @@ -389,7 +389,7 @@ public: #endif /* ENABLE_CGAL */ -CGAL_Nef_polyhedron CGALRenderer::renderCGALMesh(const PolySet &ps) +CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps) { if (ps.is2d) { diff --git a/src/CGALRenderer.h b/src/CGALEvaluator.h index 045691a..282d6ab 100644 --- a/src/CGALRenderer.h +++ b/src/CGALEvaluator.h @@ -1,11 +1,11 @@ -#ifndef CGALRENDERER_H_ -#define CGALRENDERER_H_ +#ifndef CGALEVALUATOR_H_ +#define CGALEVALUATOR_H_ #include "myqhash.h" #include "visitor.h" #include "Tree.h" #include "cgal.h" -#include "PolySetCGALRenderer.h" +#include "PolySetCGALEvaluator.h" #include <string> #include <map> @@ -19,13 +19,13 @@ using std::map; using std::list; using std::pair; -class CGALRenderer : public Visitor +class CGALEvaluator : public Visitor { public: enum CsgOp {UNION, INTERSECTION, DIFFERENCE, MINKOWSKI, HULL}; // FIXME: If a cache is not given, we need to fix this ourselves - CGALRenderer(QHash<string, CGAL_Nef_polyhedron> &cache, const Tree &tree) : cache(cache), tree(tree), psrenderer(*this) {} - virtual ~CGALRenderer() {} + CGALEvaluator(QHash<string, CGAL_Nef_polyhedron> &cache, const Tree &tree) : cache(cache), tree(tree), psevaluator(*this) {} + virtual ~CGALEvaluator() {} virtual Response visit(State &state, const AbstractNode &node); virtual Response visit(State &state, const AbstractIntersectionNode &node); @@ -33,16 +33,16 @@ public: virtual Response visit(State &state, const TransformNode &node); virtual Response visit(State &state, const AbstractPolyNode &node); - CGAL_Nef_polyhedron renderCGALMesh(const AbstractNode &node); - CGAL_Nef_polyhedron renderCGALMesh(const PolySet &polyset); + CGAL_Nef_polyhedron evaluateCGALMesh(const AbstractNode &node); + CGAL_Nef_polyhedron evaluateCGALMesh(const PolySet &polyset); const Tree &getTree() const { return this->tree; } private: void addToParent(const State &state, const AbstractNode &node); bool isCached(const AbstractNode &node) const; - void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CGALRenderer::CsgOp op); - void applyToChildren(const AbstractNode &node, CGALRenderer::CsgOp op); + void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CGALEvaluator::CsgOp op); + void applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op); string currindent; typedef list<pair<const AbstractNode *, string> > ChildList; @@ -50,7 +50,7 @@ private: QHash<string, CGAL_Nef_polyhedron> &cache; const Tree &tree; - PolySetCGALRenderer psrenderer; + PolySetCGALEvaluator psevaluator; }; #endif diff --git a/src/CGAL_renderer.h b/src/CGAL_renderer.h index 0758339..acc902f 100644 --- a/src/CGAL_renderer.h +++ b/src/CGAL_renderer.h @@ -1,660 +1,104 @@ -// Copyright (c) 1997-2002 Max-Planck-Institute Saarbruecken (Germany). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org); you may redistribute it under -// the terms of the Q Public License version 1.0. -// See the file LICENSE.QPL distributed with CGAL. -// -// Licensees holding a valid commercial license may use this file in -// accordance with the commercial license agreement provided with the software. -// -// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// -// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.5-branch/Nef_3/include/CGAL/Nef_3/OGL_helper.h $ -// $Id: OGL_helper.h 44713 2008-08-01 15:38:58Z hachenb $ -// -// -// Author(s) : Peter Hachenberger <hachenberger@mpi-sb.mpg.de> - -#ifndef CGAL_NEF_OPENGL_HELPER_H -#define CGAL_NEF_OPENGL_HELPER_H - -#include <CGAL/Nef_S2/OGL_base_object.h> -#include <CGAL/Simple_cartesian.h> -#include <CGAL/Nef_3/SNC_decorator.h> -#include <qgl.h> -#include <cstdlib> - -#ifdef _WIN32 -#define CGAL_GLU_TESS_CALLBACK CALLBACK -#else -#define CGAL_GLU_TESS_CALLBACK -#endif - -#ifdef __APPLE__ -# include <AvailabilityMacros.h> -#endif - -#if defined __APPLE__ && !defined MAC_OS_X_VERSION_10_5 -#define CGAL_GLU_TESS_DOTS ... -#else -#define CGAL_GLU_TESS_DOTS -#endif - -using namespace CGAL; -using namespace CGAL::OGL; - -namespace OpenSCAD { - - namespace OGL { - -// ---------------------------------------------------------------------------- -// Drawable double types: -// ---------------------------------------------------------------------------- - - typedef CGAL::Simple_cartesian<double> DKernel; - typedef DKernel::Point_3 Double_point; - typedef DKernel::Vector_3 Double_vector; - typedef DKernel::Segment_3 Double_segment; - typedef DKernel::Aff_transformation_3 Affine_3; - - // DPoint = a double point including a mark - class DPoint : public Double_point { - bool m_; - public: - DPoint() {} - DPoint(const Double_point& p, bool m) : Double_point(p) { m_ = m; } - DPoint(const DPoint& p) : Double_point(p) { m_ = p.m_; } - DPoint& operator=(const DPoint& p) - { Double_point::operator=(p); m_ = p.m_; return *this; } - bool mark() const { return m_; } - }; - - // DSegment = a double segment including a mark - class DSegment : public Double_segment { - bool m_; - public: - DSegment() {} - DSegment(const Double_segment& s, bool m) : Double_segment(s) { m_ = m; } - DSegment(const DSegment& s) : Double_segment(s) { m_ = s.m_; } - DSegment& operator=(const DSegment& s) - { Double_segment::operator=(s); m_ = s.m_; return *this; } - bool mark() const { return m_; } - }; - - // Double_triple = a class that stores a triple of double - // coordinates; we need a pointer to the coordinates in a C array - // for OpenGL - class Double_triple { - typedef double* double_ptr; - typedef const double* const_double_ptr; - double coords_[3]; - public: - Double_triple() - { coords_[0]=coords_[1]=coords_[2]=0.0; } - Double_triple(double x, double y, double z) - { coords_[0]=x; coords_[1]=y; coords_[2]=z; } - Double_triple(const Double_triple& t) - { coords_[0]=t.coords_[0]; - coords_[1]=t.coords_[1]; - coords_[2]=t.coords_[2]; - } - Double_triple& operator=(const Double_triple& t) - { coords_[0]=t.coords_[0]; - coords_[1]=t.coords_[1]; - coords_[2]=t.coords_[2]; - return *this; } - operator double_ptr() const - { return const_cast<Double_triple&>(*this).coords_; } - double operator[](unsigned i) - { CGAL_assertion(i<3); return coords_[i]; } - }; // Double_triple - - static std::ostream& operator << (std::ostream& os, - const Double_triple& t) - { os << "(" << t[0] << "," << t[1] << "," << t[2] << ")"; - return os; } - - - // DFacet stores the facet cycle vertices in a continuus C array - // of three double components, this is necessary due to the OpenGL - // tesselator input format ! - class DFacet { - typedef std::vector<Double_triple> Coord_vector; - typedef std::vector<unsigned> Cycle_vector; - Coord_vector coords_; // stores all vertex coordinates - Cycle_vector fc_ends_; // stores entry points of facet cycles - Double_triple normal_; // stores normal and mark of facet - bool mark_; - - public: - typedef Coord_vector::iterator Coord_iterator; - typedef Coord_vector::const_iterator Coord_const_iterator; - - DFacet() {} - - void push_back_vertex(double x, double y, double z) - { coords_.push_back(Double_triple(x,y,z)); } - - DFacet(const DFacet& f) - { coords_ = f.coords_; - fc_ends_ = f.fc_ends_; - normal_ = f.normal_; - mark_ = f.mark_; - } - - DFacet& operator=(const DFacet& f) - { coords_ = f.coords_; - fc_ends_ = f.fc_ends_; - normal_ = f.normal_; - mark_ = f.mark_; - return *this; - } - - ~DFacet() - { coords_.clear(); fc_ends_.clear(); } - - void push_back_vertex(const Double_point& p) - { push_back_vertex(p.x(),p.y(),p.z()); } - - void set_normal(double x, double y, double z, bool m) - { double l = sqrt(x*x + y*y + z*z); - normal_ = Double_triple(x/l,y/l,z/l); mark_ = m; } - - double dx() const { return normal_[0]; } - double dy() const { return normal_[1]; } - double dz() const { return normal_[2]; } - bool mark() const { return mark_; } - double* normal() const - { return static_cast<double*>(normal_); } - - void new_facet_cycle() - { fc_ends_.push_back(coords_.size()); } - - unsigned number_of_facet_cycles() const - { return fc_ends_.size(); } - - Coord_iterator facet_cycle_begin(unsigned i) - { CGAL_assertion(i<number_of_facet_cycles()); - if (i==0) return coords_.begin(); - else return coords_.begin()+fc_ends_[i]; } - - Coord_iterator facet_cycle_end(unsigned i) - { CGAL_assertion(i<number_of_facet_cycles()); - if (i<fc_ends_.size()-1) return coords_.begin()+fc_ends_[i+1]; - else return coords_.end(); } - - Coord_const_iterator facet_cycle_begin(unsigned i) const - { CGAL_assertion(i<number_of_facet_cycles()); - if (i==0) return coords_.begin(); - else return coords_.begin()+fc_ends_[i]; } - - Coord_const_iterator facet_cycle_end(unsigned i) const - { CGAL_assertion(i<number_of_facet_cycles()); - if (i<fc_ends_.size()-1) return coords_.begin()+fc_ends_[i+1]; - else return coords_.end(); } - - void debug(std::ostream& os = std::cerr) const - { os << "DFacet, normal=" << normal_ << ", mark=" << mark() << std::endl; - for(unsigned i=0; i<number_of_facet_cycles(); ++i) { - os << " facet cycle "; - // put all vertices in facet cycle into contour: - Coord_const_iterator cit; - for(cit = facet_cycle_begin(i); cit != facet_cycle_end(i); ++cit) - os << *cit; - os << std::endl; - } - } - - }; // DFacet - - -// ---------------------------------------------------------------------------- -// OGL Drawable Polyhedron: -// ---------------------------------------------------------------------------- - - inline void CGAL_GLU_TESS_CALLBACK beginCallback(GLenum which) - { glBegin(which); } - - inline void CGAL_GLU_TESS_CALLBACK endCallback(void) - { glEnd(); } - - inline void CGAL_GLU_TESS_CALLBACK errorCallback(GLenum errorCode) - { const GLubyte *estring; - estring = gluErrorString(errorCode); - fprintf(stderr, "Tessellation Error: %s\n", estring); - std::exit (0); - } - - inline void CGAL_GLU_TESS_CALLBACK vertexCallback(GLvoid* vertex, - GLvoid* user) - { GLdouble* pc(static_cast<GLdouble*>(vertex)); - GLdouble* pu(static_cast<GLdouble*>(user)); - // CGAL_NEF_TRACEN("vertexCallback coord "<<pc[0]<<","<<pc[1]<<","<<pc[2]); - // CGAL_NEF_TRACEN("vertexCallback normal "<<pu[0]<<","<<pu[1]<<","<<pu[2]); - glNormal3dv(pu); - glVertex3dv(pc); +/* + * 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 + * + */ + +#ifndef CGAL_RENDERER_H +#define CGAL_RENDERER_H + +#include "OGL_helper.h" +#undef CGAL_NEF3_MARKED_VERTEX_COLOR +#undef CGAL_NEF3_MARKED_EDGE_COLOR +#undef CGAL_NEF3_MARKED_FACET_COLOR + +#undef CGAL_NEF3_UNMARKED_VERTEX_COLOR +#undef CGAL_NEF3_UNMARKED_EDGE_COLOR +#undef CGAL_NEF3_UNMARKED_FACET_COLOR + +using CGAL::OGL::SNC_BOUNDARY; +using CGAL::OGL::SNC_SKELETON; + +class Polyhedron : public CGAL::OGL::Polyhedron +{ +public: + + enum RenderColor { + CGAL_NEF3_MARKED_VERTEX_COLOR, + CGAL_NEF3_MARKED_EDGE_COLOR, + CGAL_NEF3_MARKED_FACET_COLOR, + CGAL_NEF3_UNMARKED_VERTEX_COLOR, + CGAL_NEF3_UNMARKED_EDGE_COLOR, + CGAL_NEF3_UNMARKED_FACET_COLOR, + NUM_COLORS + }; + + Polyhedron() { + setColor(CGAL_NEF3_MARKED_VERTEX_COLOR,0xb7,0xe8,0x5c); + setColor(CGAL_NEF3_MARKED_EDGE_COLOR,0xab,0xd8,0x56); + setColor(CGAL_NEF3_MARKED_FACET_COLOR,0x9d,0xcb,0x51); + setColor(CGAL_NEF3_UNMARKED_VERTEX_COLOR,0xff,0xf6,0x7c); + setColor(CGAL_NEF3_UNMARKED_EDGE_COLOR,0xff,0xec,0x5e); + setColor(CGAL_NEF3_UNMARKED_FACET_COLOR,0xf9,0xd7,0x2c); + } + + void draw(bool showedges) const { + if(this->style == SNC_BOUNDARY) { + glCallList(this->object_list_+2); + if(showedges) { + glDisable(GL_LIGHTING); + glCallList(this->object_list_+1); + glCallList(this->object_list_); + } + } else { + glDisable(GL_LIGHTING); + glCallList(this->object_list_+1); + glCallList(this->object_list_); } - - 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 }; - - class Polyhedron : public CGAL::OGL::OGL_base_object { - public: - std::list<DPoint> vertices_; - std::list<DSegment> edges_; - std::list<DFacet> halffacets_; - - GLuint object_list_; - bool init_; - - Bbox_3 bbox_; - - int style; - std::vector<bool> switches; - - typedef std::list<DPoint>::const_iterator Vertex_iterator; - typedef std::list<DSegment>::const_iterator Edge_iterator; - typedef std::list<DFacet>::const_iterator Halffacet_iterator; - - enum RenderColor { - CGAL_NEF3_MARKED_VERTEX_COLOR, - CGAL_NEF3_MARKED_EDGE_COLOR, - CGAL_NEF3_MARKED_FACET_COLOR, - CGAL_NEF3_UNMARKED_VERTEX_COLOR, - CGAL_NEF3_UNMARKED_EDGE_COLOR, - CGAL_NEF3_UNMARKED_FACET_COLOR, - NUM_COLORS - }; - static unsigned char colors[NUM_COLORS][3]; - public: - Polyhedron() : bbox_(-1,-1,-1,1,1,1), switches(1) { - object_list_ = 0; - init_ = false; - style = SNC_BOUNDARY; - switches[SNC_AXES] = false; - } - - ~Polyhedron() - { if (object_list_) glDeleteLists(object_list_, 4); } - - void push_back(const Double_point& p, bool m) { - vertices_.push_back(DPoint(p,m)); - } - void push_back(const Double_segment& s, bool m) - { edges_.push_back(DSegment(s,m)); } - void push_back(const DFacet& f) - { halffacets_.push_back(f); } - - void toggle(int index) { - switches[index] = !switches[index]; - } - - void set_style(int index) { - style = index; - } - - bool is_initialized() const { return init_; } - - Bbox_3 bbox() const { return bbox_; } - Bbox_3& bbox() { return bbox_; } - - void draw(Vertex_iterator v) const { - // CGAL_NEF_TRACEN("drawing vertex "<<*v); - unsigned char *c = v->mark() ? colors[CGAL_NEF3_UNMARKED_VERTEX_COLOR] : colors[CGAL_NEF3_MARKED_VERTEX_COLOR]; - glPointSize(10); - glColor3ubv(c); - glBegin(GL_POINTS); - glVertex3d(v->x(),v->y(),v->z()); -#ifdef CGAL_NEF_EMPHASIZE_VERTEX - glColor3ub(255,0,0); - glVertex3d(CGAL_NEF_EMPHASIZE_VERTEX); -#endif - glEnd(); - } - - void draw(Edge_iterator e) const { - // CGAL_NEF_TRACEN("drawing edge "<<*e); - Double_point p = e->source(), q = e->target(); - unsigned char *c = e->mark() ? colors[CGAL_NEF3_UNMARKED_EDGE_COLOR] : colors[CGAL_NEF3_MARKED_EDGE_COLOR]; - glLineWidth(5); - glColor3ubv(c); - glBegin(GL_LINE_STRIP); - glVertex3d(p.x(), p.y(), p.z()); - glVertex3d(q.x(), q.y(), q.z()); - glEnd(); - } - - void draw(Halffacet_iterator f) const { - // CGAL_NEF_TRACEN("drawing facet "<<(f->debug(),"")); - 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), - (GLvoid (CGAL_GLU_TESS_CALLBACK *)(CGAL_GLU_TESS_DOTS)) &endCallback); - gluTessCallback(tess_, GLenum(GLU_TESS_ERROR), - (GLvoid (CGAL_GLU_TESS_CALLBACK *)(CGAL_GLU_TESS_DOTS)) &errorCallback); - gluTessProperty(tess_, GLenum(GLU_TESS_WINDING_RULE), - GLU_TESS_WINDING_POSITIVE); - - DFacet::Coord_const_iterator cit; - unsigned char *c = f->mark() ? colors[CGAL_NEF3_UNMARKED_FACET_COLOR] : colors[CGAL_NEF3_MARKED_FACET_COLOR]; - glColor3ubv(c); - gluTessBeginPolygon(tess_,f->normal()); - // CGAL_NEF_TRACEN(" "); - // CGAL_NEF_TRACEN("Begin Polygon"); - gluTessNormal(tess_,f->dx(),f->dy(),f->dz()); - // forall facet cycles of f: - for(unsigned i = 0; i < f->number_of_facet_cycles(); ++i) { - gluTessBeginContour(tess_); - // CGAL_NEF_TRACEN(" Begin Contour"); - // put all vertices in facet cycle into contour: - for(cit = f->facet_cycle_begin(i); - cit != f->facet_cycle_end(i); ++cit) { - gluTessVertex(tess_, *cit, *cit); - // CGAL_NEF_TRACEN(" add Vertex"); - } - gluTessEndContour(tess_); - // CGAL_NEF_TRACEN(" End Contour"); - } - gluTessEndPolygon(tess_); - // CGAL_NEF_TRACEN("End Polygon"); - gluDeleteTess(tess_); - combineCallback(NULL, NULL, NULL, NULL); - } - - void construct_axes() const - { - glLineWidth(2.0); - // red x-axis - glColor3f(1.0,0.0,0.0); - glBegin(GL_LINES); - glVertex3f(0.0,0.0,0.0); - glVertex3f(5000.0,0.0,0.0); - glEnd(); - // green y-axis - glColor3f(0.0,1.0,0.0); - glBegin(GL_LINES); - glVertex3f(0.0,0.0,0.0); - glVertex3f(0.0,5000.0,0.0); - glEnd(); - // blue z-axis and equator - glColor3f(0.0,0.0,1.0); - glBegin(GL_LINES); - glVertex3f(0.0,0.0,0.0); - glVertex3f(0.0,0.0,5000.0); - glEnd(); - // six coordinate points in pink: - glPointSize(10); - glBegin(GL_POINTS); - glColor3f(1.0,0.0,0.0); - glVertex3d(5,0,0); - glColor3f(0.0,1.0,0.0); - glVertex3d(0,5,0); - glColor3f(0.0,0.0,1.0); - glVertex3d(0,0,5); - glEnd(); - } - - - void fill_display_lists() { - glNewList(object_list_, GL_COMPILE); - Vertex_iterator v; - for(v=vertices_.begin();v!=vertices_.end();++v) - draw(v); - glEndList(); - - glNewList(object_list_+1, GL_COMPILE); - Edge_iterator e; - for(e=edges_.begin();e!=edges_.end();++e) - draw(e); - glEndList(); - - glNewList(object_list_+2, GL_COMPILE); - Halffacet_iterator f; - for(f=halffacets_.begin();f!=halffacets_.end();++f) - draw(f); - glEndList(); - - glNewList(object_list_+3, GL_COMPILE); // axes: - construct_axes(); - glEndList(); - - } - - void init() { - if (init_) return; - init_ = true; - switches[SNC_AXES] = false; - style = SNC_BOUNDARY; - object_list_ = glGenLists(4); - CGAL_assertion(object_list_); - fill_display_lists(); - } - - - void draw() const - { - if (!is_initialized()) const_cast<Polyhedron&>(*this).init(); - double l = (std::max)( (std::max)( bbox().xmax() - bbox().xmin(), - bbox().ymax() - bbox().ymin()), - bbox().zmax() - bbox().zmin()); - if ( l < 1) // make sure that a single point doesn't screw up here - l = 1; - glScaled( 4.0/l, 4.0/l, 4.0/l); - glTranslated( -(bbox().xmax() + bbox().xmin()) / 2.0, - -(bbox().ymax() + bbox().ymin()) / 2.0, - -(bbox().zmax() + bbox().zmin()) / 2.0); - if (style == SNC_BOUNDARY) { - //glEnable(GL_LIGHTING); - glCallList(object_list_+2); // facets - //glDisable(GL_LIGHTING); - } - // move edges and vertices a bit towards the view-point, - // i.e., 1/100th of the unit vector in camera space - // double f = l / 4.0 / 100.0; - // glTranslated( z_vec[0] * f, z_vec[1] * f, z_vec[2] * f); - glCallList(object_list_+1); // edges - glCallList(object_list_); // vertices - if (switches[SNC_AXES]) glCallList(object_list_+3); // axis - } - - void debug(std::ostream& os = std::cerr) const - { - os << "OGL::Polyhedron" << std::endl; - os << "Vertices:" << std::endl; - Vertex_iterator v; - for(v=vertices_.begin();v!=vertices_.end();++v) - os << " "<<*v<<", mark="<<v->mark()<<std::endl; - os << "Edges:" << std::endl; - Edge_iterator e; - for(e=edges_.begin();e!=edges_.end();++e) - os << " "<<*e<<", mark="<<e->mark()<<std::endl; - os << "Facets:" << std::endl; - Halffacet_iterator f; - for(f=halffacets_.begin();f!=halffacets_.end();++f) - f->debug(); os << std::endl; - os << std::endl; - } - - }; // Polyhedron - unsigned char Polyhedron::colors[][3] = { - {0xb7, 0xe8, 0x5c}, - {0xab, 0xd8, 0x56}, - {0x9d, 0xcb, 0x51}, - {0xff, 0xf6, 0x7c}, - {0xff, 0xec, 0x5e}, - {0xf9, 0xd7, 0x2c} - }; - - template<typename Nef_polyhedron> - class Nef3_Converter { - typedef typename Nef_polyhedron::SNC_structure SNC_structure; - typedef CGAL::SNC_decorator<SNC_structure> Base; - typedef CGAL::SNC_FM_decorator<SNC_structure> FM_decorator; - - public: - typedef typename SNC_structure::Vertex_const_iterator Vertex_const_iterator; - typedef typename SNC_structure::Halfedge_const_iterator Halfedge_const_iterator; - typedef typename SNC_structure::Halffacet_const_iterator Halffacet_const_iterator; - typedef typename SNC_structure::Halffacet_cycle_const_iterator Halffacet_cycle_const_iterator; - - typedef typename SNC_structure::Object_const_handle Object_const_handle; - typedef typename SNC_structure::SHalfedge_const_handle SHalfedge_const_handle; - typedef typename SNC_structure::SHalfloop_const_handle SHalfloop_const_handle; - - typedef typename SNC_structure::Vertex_const_handle Vertex_const_handle; - typedef typename SNC_structure::Halfedge_const_handle Halfedge_const_handle; - typedef typename SNC_structure::Halffacet_const_handle Halffacet_const_handle; - - typedef typename SNC_structure::Point_3 Point_3; - typedef typename SNC_structure::Vector_3 Vector_3; - typedef typename SNC_structure::Segment_3 Segment_3; - typedef typename SNC_structure::Plane_3 Plane_3; - typedef typename SNC_structure::Mark Mark; - typedef typename SNC_structure::SHalfedge_around_facet_const_circulator - SHalfedge_around_facet_const_circulator; - - private: - static OGL::Double_point double_point(const Point_3& p) - { return OGL::Double_point(CGAL::to_double(p.x()), - CGAL::to_double(p.y()), - CGAL::to_double(p.z())); } - - static OGL::Double_segment double_segment(const Segment_3& s) - { return OGL::Double_segment(double_point(s.source()), - double_point(s.target())); } - - static void draw(Vertex_const_handle v, const Nef_polyhedron& , - Polyhedron& P) { - Point_3 bp = v->point(); - // CGAL_NEF_TRACEN("vertex " << bp); - P.push_back(double_point(bp), v->mark()); - } - - static void draw(Halfedge_const_handle e, const Nef_polyhedron& , - Polyhedron& P) { - Vertex_const_handle s = e->source(); - Vertex_const_handle t = e->twin()->source(); - Segment_3 seg(s->point(),t->point()); - // CGAL_NEF_TRACEN("edge " << seg); - P.push_back(double_segment(seg), e->mark()); - } - - static void draw(Halffacet_const_handle f, const Nef_polyhedron& , - Polyhedron& P) { - OGL::DFacet g; - Halffacet_cycle_const_iterator fc; // all facet cycles: - CGAL_forall_facet_cycles_of(fc,f) - if ( fc.is_shalfedge() ) { // non-trivial facet cycle - g.new_facet_cycle(); - SHalfedge_const_handle h = fc; - SHalfedge_around_facet_const_circulator hc(h), he(hc); - CGAL_For_all(hc,he){ // all vertex coordinates in facet cycle - Point_3 sp = hc->source()->source()->point(); - // CGAL_NEF_TRACEN(" ");CGAL_NEF_TRACEN("facet" << sp); - g.push_back_vertex(double_point(sp)); - } - } - Vector_3 v = f->plane().orthogonal_vector(); - g.set_normal(CGAL::to_double(v.x()), - CGAL::to_double(v.y()), - CGAL::to_double(v.z()), - f->mark()); - P.push_back(g); - } - - // Returns the bounding box of the finite vertices of the polyhedron. - // Returns $[-1,+1]^3$ as bounding box if no finite vertex exists. - - static Bbox_3 bounded_bbox(const Nef_polyhedron& N) { - bool first_vertex = true; - Bbox_3 bbox( -1.0, -1.0, -1.0, 1.0, 1.0, 1.0); - Vertex_const_iterator vi; - CGAL_forall_vertices(vi, N) { - Point_3 p = vi->point(); - double x = CGAL::to_double(p.hx()); - double y = CGAL::to_double(p.hy()); - double z = CGAL::to_double(p.hz()); - double w = CGAL::to_double(p.hw()); - if (N.is_standard(vi)) { - if(first_vertex) { - bbox = Bbox_3(x/w, y/w, z/w, x/w, y/w, z/w); - first_vertex = false; - } else { - bbox = bbox + Bbox_3(x/w, y/w, z/w, x/w, y/w, z/w); - first_vertex = false; - } - } - } - return bbox; - } - - static void set_R(Bbox_3& bbox, const Nef_polyhedron& N) { - if(N.is_standard_kernel()) return; - double size = abs(bbox.xmin()); - if(size < bbox.xmax()) size = bbox.xmax(); - if(size < bbox.ymin()) size = bbox.ymin(); - if(size < bbox.ymax()) size = bbox.ymax(); - if(size < bbox.zmin()) size = bbox.zmin(); - if(size < bbox.zmax()) size = bbox.zmax(); - N.set_size_of_infimaximal_box(size*50); - // CGAL_NEF_TRACEN("set infi box size to " << size); - Vertex_const_iterator vi; - CGAL_forall_vertices(vi, N) - if(N.is_standard(vi)) - return; - bbox = Bbox_3(bbox.xmin()*10,bbox.ymin()*10,bbox.zmin()*10, - bbox.xmax()*10,bbox.ymax()*10,bbox.zmax()*10); - } - public: - static void setColor(Polyhedron::RenderColor color_index, - unsigned char r, unsigned char g, unsigned char b) { - assert(color_index < Polyhedron::NUM_COLORS); - Polyhedron::colors[color_index][0] = r; - Polyhedron::colors[color_index][1] = g; - Polyhedron::colors[color_index][2] = b; - } - - static void convert_to_OGLPolyhedron(const Nef_polyhedron& N, Polyhedron* P) { - Bbox_3 bbox(bounded_bbox(N)); - set_R(bbox,N); - P->bbox() = bbox; - Vertex_const_iterator v; - CGAL_forall_vertices(v,*N.sncp()) draw(v,N,*P); - Halfedge_const_iterator e; - CGAL_forall_edges(e,*N.sncp()) draw(e,N,*P); - Halffacet_const_iterator f; - CGAL_forall_facets(f,*N.sncp()) draw(f,N,*P); - } - - }; // Nef3_Converter - - } // namespace OGL - -} // namespace OpenSCAD - -#endif // CGAL_NEF_OPENGL_HELPER_H + } + CGAL::Color getVertexColor(Vertex_iterator v) const { + CGAL::Color c = v->mark() ? colors[CGAL_NEF3_UNMARKED_VERTEX_COLOR] : colors[CGAL_NEF3_MARKED_VERTEX_COLOR]; + return c; + } + + CGAL::Color getEdgeColor(Edge_iterator e) const { + CGAL::Color c = e->mark() ? colors[CGAL_NEF3_UNMARKED_EDGE_COLOR] : colors[CGAL_NEF3_MARKED_EDGE_COLOR]; + return c; + } + + CGAL::Color getFacetColor(Halffacet_iterator f) const { + CGAL::Color c = f->mark() ? colors[CGAL_NEF3_UNMARKED_FACET_COLOR] : colors[CGAL_NEF3_MARKED_FACET_COLOR]; + return c; + } + + void setColor(Polyhedron::RenderColor color_index, + unsigned char r, unsigned char g, unsigned char b) { + assert(color_index < Polyhedron::NUM_COLORS); + this->colors[color_index] = CGAL::Color(r,g,b); + } +private: + CGAL::Color colors[NUM_COLORS]; + +}; // Polyhedron + +#endif // CGAL_RENDERER_H diff --git a/src/CSGTermRenderer.cc b/src/CSGTermEvaluator.cc index 648783a..b4b4e70 100644 --- a/src/CSGTermRenderer.cc +++ b/src/CSGTermEvaluator.cc @@ -1,4 +1,4 @@ -#include "CSGTermRenderer.h" +#include "CSGTermEvaluator.h" #include "visitor.h" #include "state.h" #include "csgterm.h" @@ -16,22 +16,22 @@ #include <assert.h> /*! - \class CSGTermRenderer + \class CSGTermEvaluator A visitor responsible for creating a tree of CSGTerm nodes used for rendering with OpenCSG. */ -CSGTerm *CSGTermRenderer::renderCSGTerm(const AbstractNode &node, +CSGTerm *CSGTermEvaluator::evaluateCSGTerm(const AbstractNode &node, vector<CSGTerm*> *highlights, vector<CSGTerm*> *background) { - Traverser render(*this, node, Traverser::PRE_AND_POSTFIX); - render.execute(); + Traverser evaluate(*this, node, Traverser::PRE_AND_POSTFIX); + evaluate.execute(); return this->stored_term[node.index()]; } -void CSGTermRenderer::applyToChildren(const AbstractNode &node, CSGTermRenderer::CsgOp op) +void CSGTermEvaluator::applyToChildren(const AbstractNode &node, CSGTermEvaluator::CsgOp op) { CSGTerm *t1 = NULL; for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin(); @@ -62,7 +62,7 @@ void CSGTermRenderer::applyToChildren(const AbstractNode &node, CSGTermRenderer: this->stored_term[node.index()] = t1; } -Response CSGTermRenderer::visit(State &state, const AbstractNode &node) +Response CSGTermEvaluator::visit(State &state, const AbstractNode &node) { if (state.isPostfix()) { applyToChildren(node, UNION); @@ -71,7 +71,7 @@ Response CSGTermRenderer::visit(State &state, const AbstractNode &node) return ContinueTraversal; } -Response CSGTermRenderer::visit(State &state, const AbstractIntersectionNode &node) +Response CSGTermEvaluator::visit(State &state, const AbstractIntersectionNode &node) { if (state.isPostfix()) { applyToChildren(node, INTERSECTION); @@ -80,7 +80,7 @@ Response CSGTermRenderer::visit(State &state, const AbstractIntersectionNode &no return ContinueTraversal; } -static CSGTerm *render_csg_term_from_ps(const double m[20], +static CSGTerm *evaluate_csg_term_from_ps(const double m[20], vector<CSGTerm*> *highlights, vector<CSGTerm*> *background, PolySet *ps, @@ -97,13 +97,13 @@ static CSGTerm *render_csg_term_from_ps(const double m[20], return t; } -Response CSGTermRenderer::visit(State &state, const AbstractPolyNode &node) +Response CSGTermEvaluator::visit(State &state, const AbstractPolyNode &node) { if (state.isPostfix()) { CSGTerm *t1 = NULL; - PolySet *ps = node.render_polyset(AbstractPolyNode::RENDER_OPENCSG, this->psrenderer); + PolySet *ps = node.evaluate_polyset(AbstractPolyNode::RENDER_OPENCSG, this->psevaluator); if (ps) { - t1 = render_csg_term_from_ps(state.matrix(), this->highlights, this->background, + t1 = evaluate_csg_term_from_ps(state.matrix(), this->highlights, this->background, ps, node.modinst, node); } this->stored_term[node.index()] = t1; @@ -112,7 +112,7 @@ Response CSGTermRenderer::visit(State &state, const AbstractPolyNode &node) return ContinueTraversal; } -Response CSGTermRenderer::visit(State &state, const CsgNode &node) +Response CSGTermEvaluator::visit(State &state, const CsgNode &node) { if (state.isPostfix()) { CsgOp op; @@ -133,7 +133,7 @@ Response CSGTermRenderer::visit(State &state, const CsgNode &node) return ContinueTraversal; } -Response CSGTermRenderer::visit(State &state, const TransformNode &node) +Response CSGTermEvaluator::visit(State &state, const TransformNode &node) { if (state.isPrefix()) { double m[20]; @@ -162,7 +162,7 @@ Response CSGTermRenderer::visit(State &state, const TransformNode &node) } // FIXME: Find out how to best call into CGAL from this visitor -Response CSGTermRenderer::visit(State &state, const RenderNode &node) +Response CSGTermEvaluator::visit(State &state, const RenderNode &node) { PRINT("WARNING: Found render() statement but compiled without CGAL support!"); if (state.isPostfix()) { @@ -176,7 +176,7 @@ Response CSGTermRenderer::visit(State &state, const RenderNode &node) Adds ourself to out parent's list of traversed children. Call this for _every_ node which affects output during the postfix traversal. */ -void CSGTermRenderer::addToParent(const State &state, const AbstractNode &node) +void CSGTermEvaluator::addToParent(const State &state, const AbstractNode &node) { assert(state.isPostfix()); this->visitedchildren.erase(node.index()); @@ -190,26 +190,26 @@ void CSGTermRenderer::addToParent(const State &state, const AbstractNode &node) // FIXME: #ifdef ENABLE_CGAL #if 0 -CSGTerm *CgaladvNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const +CSGTerm *CgaladvNode::evaluate_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const { if (type == MINKOWSKI) - return render_csg_term_from_nef(m, highlights, background, "minkowski", this->convexity); + return evaluate_csg_term_from_nef(m, highlights, background, "minkowski", this->convexity); if (type == GLIDE) - return render_csg_term_from_nef(m, highlights, background, "glide", this->convexity); + return evaluate_csg_term_from_nef(m, highlights, background, "glide", this->convexity); if (type == SUBDIV) - return render_csg_term_from_nef(m, highlights, background, "subdiv", this->convexity); + return evaluate_csg_term_from_nef(m, highlights, background, "subdiv", this->convexity); if (type == HULL) - return render_csg_term_from_nef(m, highlights, background, "hull", this->convexity); + return evaluate_csg_term_from_nef(m, highlights, background, "hull", this->convexity); return NULL; } #else // ENABLE_CGAL -CSGTerm *CgaladvNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const +CSGTerm *CgaladvNode::evaluate_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const { PRINT("WARNING: Found minkowski(), glide(), subdiv() or hull() statement but compiled without CGAL support!"); return NULL; @@ -221,12 +221,12 @@ CSGTerm *CgaladvNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlight // FIXME: #ifdef ENABLE_CGAL #if 0 -CSGTerm *AbstractNode::render_csg_term_from_nef(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background, const char *statement, int convexity) const +CSGTerm *AbstractNode::evaluate_csg_term_from_nef(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background, const char *statement, int convexity) const { QString key = mk_cache_id(); if (PolySet::ps_cache.contains(key)) { PRINT(PolySet::ps_cache[key]->msg); - return AbstractPolyNode::render_csg_term_from_ps(m, highlights, background, + return AbstractPolyNode::evaluate_csg_term_from_ps(m, highlights, background, PolySet::ps_cache[key]->ps->link(), modinst, idx); } @@ -248,10 +248,10 @@ CSGTerm *AbstractNode::render_csg_term_from_nef(double m[20], QVector<CSGTerm*> QTime t; t.start(); - N = this->renderCSGMesh(); + N = this->evaluateCSGMesh(); int s = t.elapsed() / 1000; - PRINTF_NOCACHE("..rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60); + PRINTF_NOCACHE("..processing time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60); } PolySet *ps = NULL; @@ -315,19 +315,19 @@ CSGTerm *AbstractNode::render_csg_term_from_nef(double m[20], QVector<CSGTerm*> return NULL; } -CSGTerm *RenderNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const +CSGTerm *RenderNode::evaluate_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const { - return render_csg_term_from_nef(m, highlights, background, "render", this->convexity); + return evaluate_csg_term_from_nef(m, highlights, background, "render", this->convexity); } #else -CSGTerm *RenderNode::render_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const +CSGTerm *RenderNode::evaluate_csg_term(double m[20], QVector<CSGTerm*> *highlights, QVector<CSGTerm*> *background) const { CSGTerm *t1 = NULL; PRINT("WARNING: Found render() statement but compiled without CGAL support!"); foreach(AbstractNode * v, children) { - CSGTerm *t2 = v->render_csg_term(m, highlights, background); + CSGTerm *t2 = v->evaluate_csg_term(m, highlights, background); if (t2 && !t1) { t1 = t2; } else if (t2 && t1) { diff --git a/src/CSGTermRenderer.h b/src/CSGTermEvaluator.h index ec3ee9c..d1ea28e 100644 --- a/src/CSGTermRenderer.h +++ b/src/CSGTermEvaluator.h @@ -1,5 +1,5 @@ -#ifndef CSGTERMRENDERER_H_ -#define CSGTERMRENDERER_H_ +#ifndef CSGTERMEVALUATOR_H_ +#define CSGTERMEVALUATOR_H_ #include <string> #include <map> @@ -14,13 +14,13 @@ using std::map; using std::list; using std::vector; -class CSGTermRenderer : public Visitor +class CSGTermEvaluator : public Visitor { public: - CSGTermRenderer(const Tree &tree, class PolySetRenderer *psrenderer = NULL) - : highlights(NULL), background(NULL), tree(tree), psrenderer(psrenderer) { + CSGTermEvaluator(const Tree &tree, class PolySetEvaluator *psevaluator = NULL) + : highlights(NULL), background(NULL), tree(tree), psevaluator(psevaluator) { } - virtual ~CSGTermRenderer() {} + virtual ~CSGTermEvaluator() {} virtual Response visit(State &state, const AbstractNode &node); virtual Response visit(State &state, const AbstractIntersectionNode &node); @@ -29,25 +29,25 @@ public: virtual Response visit(State &state, const TransformNode &node); virtual Response visit(State &state, const RenderNode &node); - class CSGTerm *renderCSGTerm(const AbstractNode &node, + class CSGTerm *evaluateCSGTerm(const AbstractNode &node, vector<CSGTerm*> *highlights, vector<CSGTerm*> *background); private: enum CsgOp {UNION, INTERSECTION, DIFFERENCE, MINKOWSKI}; void addToParent(const State &state, const AbstractNode &node); - void applyToChildren(const AbstractNode &node, CSGTermRenderer::CsgOp op); + void applyToChildren(const AbstractNode &node, CSGTermEvaluator::CsgOp op); const AbstractNode *root; typedef list<const AbstractNode *> ChildList; map<int, ChildList> visitedchildren; public: - map<int, class CSGTerm*> stored_term; // The term rendered from each node index + map<int, class CSGTerm*> stored_term; // The term evaluated from each node index vector<CSGTerm*> *highlights; vector<CSGTerm*> *background; const Tree &tree; - class PolySetRenderer *psrenderer; + class PolySetEvaluator *psevaluator; }; #endif diff --git a/src/GLView.h b/src/GLView.h index f729838..1001754 100644 --- a/src/GLView.h +++ b/src/GLView.h @@ -12,6 +12,8 @@ class GLView : public QGLWidget { Q_OBJECT + Q_PROPERTY(bool showFaces READ showFaces WRITE setShowFaces); + Q_PROPERTY(bool showEdges READ showEdges WRITE setShowEdges); Q_PROPERTY(bool showAxes READ showAxes WRITE setShowAxes); Q_PROPERTY(bool showCrosshairs READ showCrosshairs WRITE setShowCrosshairs); Q_PROPERTY(bool orthoMode READ orthoMode WRITE setOrthoMode); @@ -19,18 +21,23 @@ class GLView : public QGLWidget public: GLView(QWidget *parent = NULL); GLView(const QGLFormat & format, QWidget *parent = NULL); - void setRenderFunc(void (*func)(void*), void *userdata); + void setRenderer(class Renderer* r); #ifdef ENABLE_OPENCSG bool hasOpenCSGSupport() { return this->opencsg_support; } #endif // Properties + bool showFaces() const { return this->showfaces; } + void setShowFaces(bool enabled) { this->showfaces = enabled; } + bool showEdges() const { return this->showedges; } + void setShowEdges(bool enabled) { this->showedges = enabled; } bool showAxes() const { return this->showaxes; } void setShowAxes(bool enabled) { this->showaxes = enabled; } bool showCrosshairs() const { return this->showcrosshairs; } void setShowCrosshairs(bool enabled) { this->showcrosshairs = enabled; } bool orthoMode() const { return this->orthomode; } void setOrthoMode(bool enabled) { this->orthomode = enabled; } - + +public: QLabel *statusLabel; double object_rot_x; double object_rot_y; @@ -47,10 +54,10 @@ public: private: void init(); + Renderer *renderer; - void (*renderfunc)(void*); - void *renderfunc_vp; - + bool showfaces; + bool showedges; bool showaxes; bool showcrosshairs; bool orthomode; @@ -60,8 +67,7 @@ private: double w_h_ratio; bool mouse_drag_active; - int last_mouse_x; - int last_mouse_y; + QPoint last_mouse; void keyPressEvent(QKeyEvent *event); void wheelEvent(QWheelEvent *event); @@ -71,7 +77,10 @@ private: void initializeGL(); void resizeGL(int w, int h); + void setupPerspective(); + void setupOrtho(double distance,bool offset=false); void paintGL(); + void normalizeAngle(GLdouble& angle); #ifdef ENABLE_OPENCSG private slots: diff --git a/src/MainWindow.h b/src/MainWindow.h index a44644a..0745935 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -41,17 +41,18 @@ public: class CSGChain *root_chain; #ifdef ENABLE_CGAL class CGAL_Nef_polyhedron *root_N; - bool recreate_cgal_ogl_p; - void *cgal_ogl_p; - PolySet *cgal_ogl_ps; + class CGALRenderer *cgalRenderer; #endif +#ifdef ENABLE_OPENCSG + class OpenCSGRenderer *opencsgRenderer; +#endif + class ThrownTogetherRenderer *thrownTogetherRenderer; std::vector<CSGTerm*> highlight_terms; CSGChain *highlights_chain; std::vector<CSGTerm*> background_terms; CSGChain *background_chain; QString last_compiled_doc; - bool enableOpenCSG; static const int maxRecentFiles = 10; QAction *actionRecentFile[maxRecentFiles]; diff --git a/src/OGL_helper.h b/src/OGL_helper.h new file mode 100644 index 0000000..2aae31b --- /dev/null +++ b/src/OGL_helper.h @@ -0,0 +1,687 @@ +// Copyright (c) 1997-2002 Max-Planck-Institute Saarbruecken (Germany). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org); you may redistribute it under +// the terms of the Q Public License version 1.0. +// See the file LICENSE.QPL distributed with CGAL. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.7-branch/Nef_3/include/CGAL/Nef_3/OGL_helper.h $ +// $Id: OGL_helper.h 56667 2010-06-09 07:37:13Z sloriot $ +// +// +// Author(s) : Peter Hachenberger <hachenberger@mpi-sb.mpg.de> + +#ifndef CGAL_NEF_OPENGL_HELPER_H +#define CGAL_NEF_OPENGL_HELPER_H + +#include <CGAL/Nef_S2/OGL_base_object.h> +#include <CGAL/Simple_cartesian.h> +#include <CGAL/Nef_3/SNC_decorator.h> +#include <qgl.h> +#include <cstdlib> + +#define CGAL_NEF3_MARKED_VERTEX_COLOR 183,232,92 +#define CGAL_NEF3_MARKED_EDGE_COLOR 171,216,86 +#define CGAL_NEF3_MARKED_FACET_COLOR 157,203,81 + +#define CGAL_NEF3_UNMARKED_VERTEX_COLOR 255,246,124 +#define CGAL_NEF3_UNMARKED_EDGE_COLOR 255,236,94 +#define CGAL_NEF3_UNMARKED_FACET_COLOR 249,215,44 + +#ifdef _WIN32 +#define CGAL_GLU_TESS_CALLBACK CALLBACK +#else +#define CGAL_GLU_TESS_CALLBACK +#endif + +#ifdef __APPLE__ +# include <AvailabilityMacros.h> +#endif + +#if defined __APPLE__ && !defined MAC_OS_X_VERSION_10_5 + #define CGAL_GLU_TESS_DOTS ... +#else + #define CGAL_GLU_TESS_DOTS +#endif + + +namespace CGAL { + +namespace OGL { + +// ---------------------------------------------------------------------------- +// Drawable double types: +// ---------------------------------------------------------------------------- + + typedef CGAL::Simple_cartesian<double> DKernel; + typedef DKernel::Point_3 Double_point; + typedef DKernel::Vector_3 Double_vector; + typedef DKernel::Segment_3 Double_segment; + typedef DKernel::Aff_transformation_3 Affine_3; + + // DPoint = a double point including a mark + class DPoint : public Double_point { + bool m_; + public: + DPoint() {} + DPoint(const Double_point& p, bool m) : Double_point(p) { m_ = m; } + DPoint(const DPoint& p) : Double_point(p) { m_ = p.m_; } + DPoint& operator=(const DPoint& p) + { Double_point::operator=(p); m_ = p.m_; return *this; } + bool mark() const { return m_; } + }; + + // DSegment = a double segment including a mark + class DSegment : public Double_segment { + bool m_; + public: + DSegment() {} + DSegment(const Double_segment& s, bool m) : Double_segment(s) { m_ = m; } + DSegment(const DSegment& s) : Double_segment(s) { m_ = s.m_; } + DSegment& operator=(const DSegment& s) + { Double_segment::operator=(s); m_ = s.m_; return *this; } + bool mark() const { return m_; } + }; + + // Double_triple = a class that stores a triple of double + // coordinates; we need a pointer to the coordinates in a C array + // for OpenGL + class Double_triple { + typedef double* double_ptr; + typedef const double* const_double_ptr; + double coords_[3]; + public: + Double_triple() + { coords_[0]=coords_[1]=coords_[2]=0.0; } + Double_triple(double x, double y, double z) + { coords_[0]=x; coords_[1]=y; coords_[2]=z; } + Double_triple(const Double_triple& t) + { coords_[0]=t.coords_[0]; + coords_[1]=t.coords_[1]; + coords_[2]=t.coords_[2]; + } + Double_triple& operator=(const Double_triple& t) + { coords_[0]=t.coords_[0]; + coords_[1]=t.coords_[1]; + coords_[2]=t.coords_[2]; + return *this; } + operator double_ptr() const + { return const_cast<Double_triple&>(*this).coords_; } + double operator[](unsigned i) + { CGAL_assertion(i<3); return coords_[i]; } + }; // Double_triple + + static std::ostream& operator << (std::ostream& os, + const Double_triple& t) + { os << "(" << t[0] << "," << t[1] << "," << t[2] << ")"; + return os; } + + + // DFacet stores the facet cycle vertices in a continuus C array + // of three double components, this is necessary due to the OpenGL + // tesselator input format ! + class DFacet { + typedef std::vector<Double_triple> Coord_vector; + typedef std::vector<unsigned> Cycle_vector; + Coord_vector coords_; // stores all vertex coordinates + Cycle_vector fc_ends_; // stores entry points of facet cycles + Double_triple normal_; // stores normal and mark of facet + bool mark_; + + public: + typedef Coord_vector::iterator Coord_iterator; + typedef Coord_vector::const_iterator Coord_const_iterator; + + DFacet() {} + + void push_back_vertex(double x, double y, double z) + { coords_.push_back(Double_triple(x,y,z)); } + + DFacet(const DFacet& f) + { coords_ = f.coords_; + fc_ends_ = f.fc_ends_; + normal_ = f.normal_; + mark_ = f.mark_; + } + + DFacet& operator=(const DFacet& f) + { coords_ = f.coords_; + fc_ends_ = f.fc_ends_; + normal_ = f.normal_; + mark_ = f.mark_; + return *this; + } + + ~DFacet() + { coords_.clear(); fc_ends_.clear(); } + + void push_back_vertex(const Double_point& p) + { push_back_vertex(p.x(),p.y(),p.z()); } + + void set_normal(double x, double y, double z, bool m) + { double l = sqrt(x*x + y*y + z*z); + normal_ = Double_triple(x/l,y/l,z/l); mark_ = m; } + + double dx() const { return normal_[0]; } + double dy() const { return normal_[1]; } + double dz() const { return normal_[2]; } + bool mark() const { return mark_; } + double* normal() const + { return static_cast<double*>(normal_); } + + void new_facet_cycle() + { fc_ends_.push_back(coords_.size()); } + + unsigned number_of_facet_cycles() const + { return fc_ends_.size(); } + + Coord_iterator facet_cycle_begin(unsigned i) + { CGAL_assertion(i<number_of_facet_cycles()); + if (i==0) return coords_.begin(); + else return coords_.begin()+fc_ends_[i]; } + + Coord_iterator facet_cycle_end(unsigned i) + { CGAL_assertion(i<number_of_facet_cycles()); + if (i<fc_ends_.size()-1) return coords_.begin()+fc_ends_[i+1]; + else return coords_.end(); } + + Coord_const_iterator facet_cycle_begin(unsigned i) const + { CGAL_assertion(i<number_of_facet_cycles()); + if (i==0) return coords_.begin(); + else return coords_.begin()+fc_ends_[i]; } + + Coord_const_iterator facet_cycle_end(unsigned i) const + { CGAL_assertion(i<number_of_facet_cycles()); + if (i<fc_ends_.size()-1) return coords_.begin()+fc_ends_[i+1]; + else return coords_.end(); } + + void debug(std::ostream& os = std::cerr) const + { os << "DFacet, normal=" << normal_ << ", mark=" << mark() << std::endl; + for(unsigned i=0; i<number_of_facet_cycles(); ++i) { + os << " facet cycle "; + // put all vertices in facet cycle into contour: + Coord_const_iterator cit; + for(cit = facet_cycle_begin(i); cit != facet_cycle_end(i); ++cit) + os << *cit; + os << std::endl; + } + } + + }; // DFacet + + +// ---------------------------------------------------------------------------- +// OGL Drawable Polyhedron: +// ---------------------------------------------------------------------------- + + inline void CGAL_GLU_TESS_CALLBACK beginCallback(GLenum which) + { glBegin(which); } + + inline void CGAL_GLU_TESS_CALLBACK endCallback(void) + { glEnd(); } + + inline void CGAL_GLU_TESS_CALLBACK errorCallback(GLenum errorCode) + { const GLubyte *estring; + estring = gluErrorString(errorCode); + fprintf(stderr, "Tessellation Error: %s\n", estring); + std::exit (0); + } + + inline void CGAL_GLU_TESS_CALLBACK vertexCallback(GLvoid* vertex, + GLvoid* user) + { GLdouble* pc(static_cast<GLdouble*>(vertex)); + GLdouble* pu(static_cast<GLdouble*>(user)); + // CGAL_NEF_TRACEN("vertexCallback coord "<<pc[0]<<","<<pc[1]<<","<<pc[2]); + // CGAL_NEF_TRACEN("vertexCallback normal "<<pu[0]<<","<<pu[1]<<","<<pu[2]); + glNormal3dv(pu); + glVertex3dv(pc); + } + + + enum { SNC_AXES}; + enum { SNC_BOUNDARY, SNC_SKELETON }; + + class Polyhedron : public OGL_base_object { + protected: + std::list<DPoint> vertices_; + std::list<DSegment> edges_; + std::list<DFacet> halffacets_; + + GLuint object_list_; + bool init_; + + Bbox_3 bbox_; + + int style; + std::vector<bool> switches; + + typedef std::list<DPoint>::const_iterator Vertex_iterator; + typedef std::list<DSegment>::const_iterator Edge_iterator; + typedef std::list<DFacet>::const_iterator Halffacet_iterator; + + public: + Polyhedron() : bbox_(-1,-1,-1,1,1,1), switches(1) { + object_list_ = 0; + init_ = false; + style = SNC_BOUNDARY; + switches[SNC_AXES] = false; + } + + /* + Polyhedron(const Polyhedron& P) : + object_list_(0), + init_(false), + bbox_(P.bbox_), + style(P.style), + switches(2) { + + switches[SNC_AXES] = P.switches[SNC_AXES]; + + Vertex_iterator v; + for(v=P.vertices_.begin();v!=P.vertices_.end();++v) + vertices_.push_back(*v); + Edge_iterator e; + for(e=P.edges_.begin();e!=P.edges_.end();++e) + edges_.push_back(*e); + Halffacet_iterator f; + for(f=P.halffacets_.begin();f!=P.halffacets_.end();++f) + halffacets_.push_back(*f); + } + + Polyhedron& operator=(const Polyhedron& P) { + if (object_list_) glDeleteLists(object_list_, 4); + object_list_ = 0; + init_ = false; + style = P.style; + switches[SNC_AXES] = P.switches[SNC_AXES]; + + Vertex_iterator v; + vertices_.clear(); + for(v=P.vertices_.begin();v!=P.vertices_.end();++v) + vertices_.push_back(*v); + Edge_iterator e; + edges_.clear(); + for(e=P.edges_.begin();e!=P.edges_.end();++e) + edges_.push_back(*e); + Halffacet_iterator f; + halffacets_.clear(); + for(f=P.halffacets_.begin();f!=P.halffacets_.end();++f) + halffacets_.push_back(*f); + init(); + return *this; + } + */ + ~Polyhedron() + { if (object_list_) glDeleteLists(object_list_, 4); } + + void push_back(const Double_point& p, bool m) { + vertices_.push_back(DPoint(p,m)); + } + void push_back(const Double_segment& s, bool m) + { edges_.push_back(DSegment(s,m)); } + void push_back(const DFacet& f) + { halffacets_.push_back(f); } + + void toggle(int index) { + switches[index] = !switches[index]; + } + + void set_style(int index) { + style = index; + } + + bool is_initialized() const { return init_; } + + Bbox_3 bbox() const { return bbox_; } + Bbox_3& bbox() { return bbox_; } + + virtual CGAL::Color getVertexColor(Vertex_iterator v) const + { + CGAL::Color cf(CGAL_NEF3_MARKED_VERTEX_COLOR), + ct(CGAL_NEF3_UNMARKED_VERTEX_COLOR); // more blue-ish + CGAL::Color c = v->mark() ? ct : cf; + return c; + } + + void draw(Vertex_iterator v) const { + // CGAL_NEF_TRACEN("drawing vertex "<<*v); + CGAL::Color c = getVertexColor(v); + glPointSize(10); + glColor3ub(c.red(), c.green(), c.blue()); + glBegin(GL_POINTS); + glVertex3d(v->x(),v->y(),v->z()); +#ifdef CGAL_NEF_EMPHASIZE_VERTEX + glColor3ub(255,0,0); + glVertex3d(CGAL_NEF_EMPHASIZE_VERTEX); +#endif + glEnd(); + } + + virtual CGAL::Color getEdgeColor(Edge_iterator e) const + { + CGAL::Color cf(CGAL_NEF3_MARKED_EDGE_COLOR), + ct(CGAL_NEF3_UNMARKED_EDGE_COLOR); // more blue-ish + CGAL::Color c = e->mark() ? ct : cf; + return c; + } + + void draw(Edge_iterator e) const { + // CGAL_NEF_TRACEN("drawing edge "<<*e); + Double_point p = e->source(), q = e->target(); + CGAL::Color c = getEdgeColor(e); + glLineWidth(5); + glColor3ub(c.red(),c.green(),c.blue()); + glBegin(GL_LINE_STRIP); + glVertex3d(p.x(), p.y(), p.z()); + glVertex3d(q.x(), q.y(), q.z()); + glEnd(); + } + + virtual CGAL::Color getFacetColor(Halffacet_iterator f) const + { + CGAL::Color cf(CGAL_NEF3_MARKED_FACET_COLOR), + ct(CGAL_NEF3_UNMARKED_FACET_COLOR); // more blue-ish + CGAL::Color c = (f->mark() ? ct : cf); + return c; + } + + void draw(Halffacet_iterator f) const { + // CGAL_NEF_TRACEN("drawing facet "<<(f->debug(),"")); + 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_BEGIN), + (GLvoid (CGAL_GLU_TESS_CALLBACK *)(CGAL_GLU_TESS_DOTS)) &beginCallback); + gluTessCallback(tess_, GLenum(GLU_TESS_END), + (GLvoid (CGAL_GLU_TESS_CALLBACK *)(CGAL_GLU_TESS_DOTS)) &endCallback); + gluTessCallback(tess_, GLenum(GLU_TESS_ERROR), + (GLvoid (CGAL_GLU_TESS_CALLBACK *)(CGAL_GLU_TESS_DOTS)) &errorCallback); + gluTessProperty(tess_, GLenum(GLU_TESS_WINDING_RULE), + GLU_TESS_WINDING_POSITIVE); + + DFacet::Coord_const_iterator cit; + CGAL::Color c = getFacetColor(f); + glColor3ub(c.red(),c.green(),c.blue()); + gluTessBeginPolygon(tess_,f->normal()); + // CGAL_NEF_TRACEN(" "); + // CGAL_NEF_TRACEN("Begin Polygon"); + gluTessNormal(tess_,f->dx(),f->dy(),f->dz()); + // forall facet cycles of f: + for(unsigned i = 0; i < f->number_of_facet_cycles(); ++i) { + gluTessBeginContour(tess_); + // CGAL_NEF_TRACEN(" Begin Contour"); + // put all vertices in facet cycle into contour: + for(cit = f->facet_cycle_begin(i); + cit != f->facet_cycle_end(i); ++cit) { + gluTessVertex(tess_, *cit, *cit); + // CGAL_NEF_TRACEN(" add Vertex"); + } + gluTessEndContour(tess_); + // CGAL_NEF_TRACEN(" End Contour"); + } + gluTessEndPolygon(tess_); + // CGAL_NEF_TRACEN("End Polygon"); + gluDeleteTess(tess_); + } + + void construct_axes() const + { + glLineWidth(2.0); + // red x-axis + glColor3f(1.0,0.0,0.0); + glBegin(GL_LINES); + glVertex3f(0.0,0.0,0.0); + glVertex3f(5000.0,0.0,0.0); + glEnd(); + // green y-axis + glColor3f(0.0,1.0,0.0); + glBegin(GL_LINES); + glVertex3f(0.0,0.0,0.0); + glVertex3f(0.0,5000.0,0.0); + glEnd(); + // blue z-axis and equator + glColor3f(0.0,0.0,1.0); + glBegin(GL_LINES); + glVertex3f(0.0,0.0,0.0); + glVertex3f(0.0,0.0,5000.0); + glEnd(); + // six coordinate points in pink: + glPointSize(10); + glBegin(GL_POINTS); + glColor3f(1.0,0.0,0.0); + glVertex3d(5,0,0); + glColor3f(0.0,1.0,0.0); + glVertex3d(0,5,0); + glColor3f(0.0,0.0,1.0); + glVertex3d(0,0,5); + glEnd(); + } + + + void fill_display_lists() { + glNewList(object_list_, GL_COMPILE); + Vertex_iterator v; + for(v=vertices_.begin();v!=vertices_.end();++v) + draw(v); + glEndList(); + + glNewList(object_list_+1, GL_COMPILE); + Edge_iterator e; + for(e=edges_.begin();e!=edges_.end();++e) + draw(e); + glEndList(); + + glNewList(object_list_+2, GL_COMPILE); + Halffacet_iterator f; + for(f=halffacets_.begin();f!=halffacets_.end();++f) + draw(f); + glEndList(); + + glNewList(object_list_+3, GL_COMPILE); // axes: + construct_axes(); + glEndList(); + + } + + void init() { + if (init_) return; + init_ = true; + switches[SNC_AXES] = false; + style = SNC_BOUNDARY; + object_list_ = glGenLists(4); + CGAL_assertion(object_list_); + fill_display_lists(); + } + + + void draw() const + { + if (!is_initialized()) const_cast<Polyhedron&>(*this).init(); + double l = (std::max)( (std::max)( bbox().xmax() - bbox().xmin(), + bbox().ymax() - bbox().ymin()), + bbox().zmax() - bbox().zmin()); + if ( l < 1) // make sure that a single point doesn't screw up here + l = 1; + glScaled( 4.0/l, 4.0/l, 4.0/l); + glTranslated( -(bbox().xmax() + bbox().xmin()) / 2.0, + -(bbox().ymax() + bbox().ymin()) / 2.0, + -(bbox().zmax() + bbox().zmin()) / 2.0); + if (style == SNC_BOUNDARY) { + //glEnable(GL_LIGHTING); + glCallList(object_list_+2); // facets + //glDisable(GL_LIGHTING); + } + // move edges and vertices a bit towards the view-point, + // i.e., 1/100th of the unit vector in camera space + // double f = l / 4.0 / 100.0; + // glTranslated( z_vec[0] * f, z_vec[1] * f, z_vec[2] * f); + glCallList(object_list_+1); // edges + glCallList(object_list_); // vertices + if (switches[SNC_AXES]) glCallList(object_list_+3); // axis + } + + void debug(std::ostream& os = std::cerr) const + { + os << "OGL::Polyhedron" << std::endl; + os << "Vertices:" << std::endl; + Vertex_iterator v; + for(v=vertices_.begin();v!=vertices_.end();++v) + os << " "<<*v<<", mark="<<v->mark()<<std::endl; + os << "Edges:" << std::endl; + Edge_iterator e; + for(e=edges_.begin();e!=edges_.end();++e) + os << " "<<*e<<", mark="<<e->mark()<<std::endl; + os << "Facets:" << std::endl; + Halffacet_iterator f; + for(f=halffacets_.begin();f!=halffacets_.end();++f) + f->debug(); os << std::endl; + os << std::endl; + } + + }; // Polyhedron + + template<typename Nef_polyhedron> + class Nef3_Converter { + typedef typename Nef_polyhedron::SNC_structure SNC_structure; + typedef CGAL::SNC_decorator<SNC_structure> Base; + typedef CGAL::SNC_FM_decorator<SNC_structure> FM_decorator; + + public: + typedef typename SNC_structure::Vertex_const_iterator Vertex_const_iterator; + typedef typename SNC_structure::Halfedge_const_iterator Halfedge_const_iterator; + typedef typename SNC_structure::Halffacet_const_iterator Halffacet_const_iterator; + typedef typename SNC_structure::Halffacet_cycle_const_iterator Halffacet_cycle_const_iterator; + + typedef typename SNC_structure::Object_const_handle Object_const_handle; + typedef typename SNC_structure::SHalfedge_const_handle SHalfedge_const_handle; + typedef typename SNC_structure::SHalfloop_const_handle SHalfloop_const_handle; + + typedef typename SNC_structure::Vertex_const_handle Vertex_const_handle; + typedef typename SNC_structure::Halfedge_const_handle Halfedge_const_handle; + typedef typename SNC_structure::Halffacet_const_handle Halffacet_const_handle; + + typedef typename SNC_structure::Point_3 Point_3; + typedef typename SNC_structure::Vector_3 Vector_3; + typedef typename SNC_structure::Segment_3 Segment_3; + typedef typename SNC_structure::Plane_3 Plane_3; + typedef typename SNC_structure::Mark Mark; + typedef typename SNC_structure::SHalfedge_around_facet_const_circulator + SHalfedge_around_facet_const_circulator; + + private: + static OGL::Double_point double_point(const Point_3& p) + { return OGL::Double_point(CGAL::to_double(p.x()), + CGAL::to_double(p.y()), + CGAL::to_double(p.z())); } + + static OGL::Double_segment double_segment(const Segment_3& s) + { return OGL::Double_segment(double_point(s.source()), + double_point(s.target())); } + + static void draw(Vertex_const_handle v, const Nef_polyhedron& , + CGAL::OGL::Polyhedron& P) { + Point_3 bp = v->point(); + // CGAL_NEF_TRACEN("vertex " << bp); + P.push_back(double_point(bp), v->mark()); + } + + static void draw(Halfedge_const_handle e, const Nef_polyhedron& , + CGAL::OGL::Polyhedron& P) { + Vertex_const_handle s = e->source(); + Vertex_const_handle t = e->twin()->source(); + Segment_3 seg(s->point(),t->point()); + // CGAL_NEF_TRACEN("edge " << seg); + P.push_back(double_segment(seg), e->mark()); + } + + static void draw(Halffacet_const_handle f, const Nef_polyhedron& , + CGAL::OGL::Polyhedron& P) { + OGL::DFacet g; + Halffacet_cycle_const_iterator fc; // all facet cycles: + CGAL_forall_facet_cycles_of(fc,f) + if ( fc.is_shalfedge() ) { // non-trivial facet cycle + g.new_facet_cycle(); + SHalfedge_const_handle h = fc; + SHalfedge_around_facet_const_circulator hc(h), he(hc); + CGAL_For_all(hc,he){ // all vertex coordinates in facet cycle + Point_3 sp = hc->source()->source()->point(); + // CGAL_NEF_TRACEN(" ");CGAL_NEF_TRACEN("facet" << sp); + g.push_back_vertex(double_point(sp)); + } + } + Vector_3 v = f->plane().orthogonal_vector(); + g.set_normal(CGAL::to_double(v.x()), + CGAL::to_double(v.y()), + CGAL::to_double(v.z()), + f->mark()); + P.push_back(g); + } + + // Returns the bounding box of the finite vertices of the polyhedron. + // Returns $[-1,+1]^3$ as bounding box if no finite vertex exists. + + static Bbox_3 bounded_bbox(const Nef_polyhedron& N) { + bool first_vertex = true; + Bbox_3 bbox( -1.0, -1.0, -1.0, 1.0, 1.0, 1.0); + Vertex_const_iterator vi; + CGAL_forall_vertices(vi, N) { + Point_3 p = vi->point(); + double x = CGAL::to_double(p.hx()); + double y = CGAL::to_double(p.hy()); + double z = CGAL::to_double(p.hz()); + double w = CGAL::to_double(p.hw()); + if (N.is_standard(vi)) { + if(first_vertex) { + bbox = Bbox_3(x/w, y/w, z/w, x/w, y/w, z/w); + first_vertex = false; + } else { + bbox = bbox + Bbox_3(x/w, y/w, z/w, x/w, y/w, z/w); + first_vertex = false; + } + } + } + return bbox; + } + + static void set_R(Bbox_3& bbox, const Nef_polyhedron& N) { + if(N.is_standard_kernel()) return; + double size = abs(bbox.xmin()); + if(size < bbox.xmax()) size = bbox.xmax(); + if(size < bbox.ymin()) size = bbox.ymin(); + if(size < bbox.ymax()) size = bbox.ymax(); + if(size < bbox.zmin()) size = bbox.zmin(); + if(size < bbox.zmax()) size = bbox.zmax(); + N.set_size_of_infimaximal_box(size*50); + // CGAL_NEF_TRACEN("set infi box size to " << size); + Vertex_const_iterator vi; + CGAL_forall_vertices(vi, N) + if(N.is_standard(vi)) + return; + bbox = Bbox_3(bbox.xmin()*10,bbox.ymin()*10,bbox.zmin()*10, + bbox.xmax()*10,bbox.ymax()*10,bbox.zmax()*10); + } + public: + static void convert_to_OGLPolyhedron(const Nef_polyhedron& N, CGAL::OGL::Polyhedron* P) { + Bbox_3 bbox(bounded_bbox(N)); + set_R(bbox,N); + P->bbox() = bbox; + Vertex_const_iterator v; + CGAL_forall_vertices(v,*N.sncp()) draw(v,N,*P); + Halfedge_const_iterator e; + CGAL_forall_edges(e,*N.sncp()) draw(e,N,*P); + Halffacet_const_iterator f; + CGAL_forall_facets(f,*N.sncp()) draw(f,N,*P); + } + + }; // Nef3_Converter + +} // namespace OGL + +} //namespace CGAL +#endif // CGAL_NEF_OPENGL_HELPER_H diff --git a/src/PolySetCGALRenderer.cc b/src/PolySetCGALEvaluator.cc index 71a8056..e769730 100644 --- a/src/PolySetCGALRenderer.cc +++ b/src/PolySetCGALEvaluator.cc @@ -1,6 +1,6 @@ -#include "PolySetCGALRenderer.h" +#include "PolySetCGALEvaluator.h" #include "polyset.h" -#include "CGALRenderer.h" +#include "CGALEvaluator.h" #include "projectionnode.h" #include "dxflinextrudenode.h" #include "dxfrotextrudenode.h" @@ -12,12 +12,12 @@ #include "export.h" // void cgal_nef3_to_polyset() #include "openscad.h" // get_fragments_from_r() -PolySet *PolySetCGALRenderer::renderPolySet(const ProjectionNode &node, AbstractPolyNode::render_mode_e) +PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node, AbstractPolyNode::render_mode_e) { - const string &cacheid = this->cgalrenderer.getTree().getString(node); + const string &cacheid = this->cgalevaluator.getTree().getString(node); if (this->cache.contains(cacheid)) return this->cache[cacheid]->ps->link(); - CGAL_Nef_polyhedron N = this->cgalrenderer.renderCGALMesh(node); + CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(node); PolySet *ps = new PolySet(); ps->convexity = node.convexity; @@ -64,7 +64,7 @@ PolySet *PolySetCGALRenderer::renderPolySet(const ProjectionNode &node, Abstract cube->append_vertex(x1, y1, z1); cube->append_vertex(x1, y1, z2); cube->append_vertex(x1, y2, z2); - CGAL_Nef_polyhedron Ncube = this->cgalrenderer.renderCGALMesh(*cube); + CGAL_Nef_polyhedron Ncube = this->cgalevaluator.evaluateCGALMesh(*cube); cube->unlink(); // N.p3 *= CGAL_Nef_polyhedron3(CGAL_Plane(0, 0, 1, 0), CGAL_Nef_polyhedron3::INCLUDED); @@ -234,9 +234,9 @@ static void add_slice(PolySet *ps, DxfData::Path *pt, double rot1, double rot2, } } -PolySet *PolySetCGALRenderer::renderPolySet(const DxfLinearExtrudeNode &node, AbstractPolyNode::render_mode_e) +PolySet *PolySetCGALEvaluator::evaluatePolySet(const DxfLinearExtrudeNode &node, AbstractPolyNode::render_mode_e) { - const string &cacheid = this->cgalrenderer.getTree().getString(node); + const string &cacheid = this->cgalevaluator.getTree().getString(node); if (this->cache.contains(cacheid)) return this->cache[cacheid]->ps->link(); DxfData *dxf; @@ -249,7 +249,7 @@ PolySet *PolySetCGALRenderer::renderPolySet(const DxfLinearExtrudeNode &node, Ab N.dim = 2; foreach (AbstractNode * v, node.getChildren()) { if (v->modinst->tag_background) continue; - N.p2 += this->cgalrenderer.renderCGALMesh(*v).p2; + N.p2 += this->cgalevaluator.evaluateCGALMesh(*v).p2; } dxf = new DxfData(N); @@ -324,10 +324,10 @@ PolySet *PolySetCGALRenderer::renderPolySet(const DxfLinearExtrudeNode &node, Ab return ps; } -PolySet *PolySetCGALRenderer::renderPolySet(const DxfRotateExtrudeNode &node, +PolySet *PolySetCGALEvaluator::evaluatePolySet(const DxfRotateExtrudeNode &node, AbstractPolyNode::render_mode_e) { - const string &cacheid = this->cgalrenderer.getTree().getString(node); + const string &cacheid = this->cgalevaluator.getTree().getString(node); if (this->cache.contains(cacheid)) return this->cache[cacheid]->ps->link(); DxfData *dxf; @@ -340,7 +340,7 @@ PolySet *PolySetCGALRenderer::renderPolySet(const DxfRotateExtrudeNode &node, N.dim = 2; foreach (AbstractNode * v, node.getChildren()) { if (v->modinst->tag_background) continue; - N.p2 += this->cgalrenderer.renderCGALMesh(*v).p2; + N.p2 += this->cgalevaluator.evaluateCGALMesh(*v).p2; } dxf = new DxfData(N); diff --git a/src/PolySetCGALEvaluator.h b/src/PolySetCGALEvaluator.h new file mode 100644 index 0000000..5089e0e --- /dev/null +++ b/src/PolySetCGALEvaluator.h @@ -0,0 +1,24 @@ +#ifndef POLYSETCGALEVALUATOR_H_ +#define POLYSETCGALEVALUATOR_H_ + +#include "PolySetEvaluator.h" + +/*! + This is a PolySet evaluator which uses the CGALEvaluator to support building + polysets. +*/ +class PolySetCGALEvaluator : public PolySetEvaluator +{ +public: + PolySetCGALEvaluator(class CGALEvaluator &CGALEvaluator) : + PolySetEvaluator(), cgalevaluator(CGALEvaluator) { } + virtual ~PolySetCGALEvaluator() { } + virtual PolySet *evaluatePolySet(const ProjectionNode &node, AbstractPolyNode::render_mode_e); + virtual PolySet *evaluatePolySet(const DxfLinearExtrudeNode &node, AbstractPolyNode::render_mode_e); + virtual PolySet *evaluatePolySet(const DxfRotateExtrudeNode &node, AbstractPolyNode::render_mode_e); + +private: + CGALEvaluator &cgalevaluator; +}; + +#endif diff --git a/src/PolySetCGALRenderer.h b/src/PolySetCGALRenderer.h deleted file mode 100644 index d6ef63c..0000000 --- a/src/PolySetCGALRenderer.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef POLYSETCGALRENDERER_H_ -#define POLYSETCGALRENDERER_H_ - -#include "PolySetRenderer.h" - -/*! - This is a PolySet renderer which uses the CGALRenderer to support building - polysets. -*/ -class PolySetCGALRenderer : public PolySetRenderer -{ -public: - PolySetCGALRenderer(class CGALRenderer &cgalrenderer) : - PolySetRenderer(), cgalrenderer(cgalrenderer) { } - virtual ~PolySetCGALRenderer() { } - virtual PolySet *renderPolySet(const ProjectionNode &node, AbstractPolyNode::render_mode_e); - virtual PolySet *renderPolySet(const DxfLinearExtrudeNode &node, AbstractPolyNode::render_mode_e); - virtual PolySet *renderPolySet(const DxfRotateExtrudeNode &node, AbstractPolyNode::render_mode_e); - -private: - CGALRenderer &cgalrenderer; -}; - -#endif diff --git a/src/PolySetEvaluator.cc b/src/PolySetEvaluator.cc new file mode 100644 index 0000000..56acb1d --- /dev/null +++ b/src/PolySetEvaluator.cc @@ -0,0 +1,15 @@ +#include "PolySetEvaluator.h" +#include "printutils.h" +#include "polyset.h" + +PolySetEvaluator *PolySetEvaluator::global_evaluator = NULL; + +PolySetEvaluator::cache_entry::cache_entry(PolySet *ps) : + ps(ps), msg(print_messages_stack.last()) +{ +} + +PolySetEvaluator::cache_entry::~cache_entry() +{ + ps->unlink(); +} diff --git a/src/PolySetEvaluator.h b/src/PolySetEvaluator.h new file mode 100644 index 0000000..dcc67db --- /dev/null +++ b/src/PolySetEvaluator.h @@ -0,0 +1,39 @@ +#ifndef POLYSETEVALUATOR_H_ +#define POLYSETEVALUATOR_H_ + +#include "myqhash.h" +#include "node.h" +#include <QCache> + +class PolySetEvaluator +{ +public: + enum EvaluateMode { EVALUATE_CGAL, EVALUATE_OPENCSG }; + PolySetEvaluator() : cache(100) {} + + virtual ~PolySetEvaluator() {} + + virtual PolySet *evaluatePolySet(const class ProjectionNode &, AbstractPolyNode::render_mode_e) = 0; + virtual PolySet *evaluatePolySet(const class DxfLinearExtrudeNode &, AbstractPolyNode::render_mode_e) = 0; + virtual PolySet *evaluatePolySet(const class DxfRotateExtrudeNode &, AbstractPolyNode::render_mode_e) = 0; + + void clearCache() { + this->cache.clear(); + } + +protected: + + struct cache_entry { + class PolySet *ps; + QString msg; + cache_entry(PolySet *ps); + ~cache_entry(); + }; + + QCache<std::string, cache_entry> cache; + +private: + static PolySetEvaluator *global_evaluator; +}; + +#endif diff --git a/src/PolySetRenderer.cc b/src/PolySetRenderer.cc deleted file mode 100644 index c2fddf0..0000000 --- a/src/PolySetRenderer.cc +++ /dev/null @@ -1,15 +0,0 @@ -#include "PolySetRenderer.h" -#include "printutils.h" -#include "polyset.h" - -PolySetRenderer *PolySetRenderer::global_renderer = NULL; - -PolySetRenderer::cache_entry::cache_entry(PolySet *ps) : - ps(ps), msg(print_messages_stack.last()) -{ -} - -PolySetRenderer::cache_entry::~cache_entry() -{ - ps->unlink(); -} diff --git a/src/PolySetRenderer.h b/src/PolySetRenderer.h deleted file mode 100644 index c175825..0000000 --- a/src/PolySetRenderer.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef POLYSETRENDERER_H_ -#define POLYSETRENDERER_H_ - -#include "myqhash.h" -#include "node.h" -#include <QCache> - -class PolySetRenderer -{ -public: - enum RenderMode { RENDER_CGAL, RENDER_OPENCSG }; - PolySetRenderer() : cache(100) {} - - virtual ~PolySetRenderer() {} - - virtual PolySet *renderPolySet(const class ProjectionNode &, AbstractPolyNode::render_mode_e) = 0; - virtual PolySet *renderPolySet(const class DxfLinearExtrudeNode &, AbstractPolyNode::render_mode_e) = 0; - virtual PolySet *renderPolySet(const class DxfRotateExtrudeNode &, AbstractPolyNode::render_mode_e) = 0; - - void clearCache() { - this->cache.clear(); - } - -protected: - - struct cache_entry { - class PolySet *ps; - QString msg; - cache_entry(PolySet *ps); - ~cache_entry(); - }; - - QCache<std::string, cache_entry> cache; - -private: - static PolySetRenderer *global_renderer; -}; - -#endif diff --git a/src/cgalrenderer.cc b/src/cgalrenderer.cc new file mode 100644 index 0000000..551c061 --- /dev/null +++ b/src/cgalrenderer.cc @@ -0,0 +1,126 @@ +/* + * 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 "cgalrenderer.h" +#include "polyset.h" +#include "CGAL_renderer.h" +#include "dxfdata.h" +#include "dxftess.h" + +#include "Preferences.h" + +CGALRenderer::CGALRenderer(const CGAL_Nef_polyhedron &root) : root(root) +{ + if (root.dim == 2) { + DxfData dd(root); + this->polyset = new PolySet(); + this->polyset->is2d = true; + dxf_tesselate(this->polyset, &dd, 0, true, false, 0); + } + else if (root.dim == 3) { + this->polyhedron = new Polyhedron(); + // FIXME: Make independent of Preferences + this->polyhedron->setColor(Polyhedron::CGAL_NEF3_MARKED_FACET_COLOR, + Preferences::inst()->color(Preferences::CGAL_FACE_BACK_COLOR).red(), + Preferences::inst()->color(Preferences::CGAL_FACE_BACK_COLOR).green(), + Preferences::inst()->color(Preferences::CGAL_FACE_BACK_COLOR).blue()); + this->polyhedron->setColor(Polyhedron::CGAL_NEF3_UNMARKED_FACET_COLOR, + Preferences::inst()->color(Preferences::CGAL_FACE_FRONT_COLOR).red(), + Preferences::inst()->color(Preferences::CGAL_FACE_FRONT_COLOR).green(), + Preferences::inst()->color(Preferences::CGAL_FACE_FRONT_COLOR).blue()); + + CGAL::OGL::Nef3_Converter<CGAL_Nef_polyhedron3>::convert_to_OGLPolyhedron(this->root.p3, this->polyhedron); + this->polyhedron->init(); + } +} + +CGALRenderer::~CGALRenderer() +{ + if (this->polyset) this->polyset->unlink(); +} + +void CGALRenderer::draw(bool showfaces, bool showedges) const +{ + if (this->root.dim == 2) { + // Draw 2D polygons + glDisable(GL_LIGHTING); + const QColor &col = Preferences::inst()->color(Preferences::CGAL_FACE_2D_COLOR); + glColor3f(col.redF(), col.greenF(), col.blueF()); + + for (int i=0; i < this->polyset->polygons.size(); i++) { + glBegin(GL_POLYGON); + for (int j=0; j < this->polyset->polygons[i].size(); j++) { + PolySet::Point p = this->polyset->polygons[i][j]; + glVertex3d(p.x, p.y, -0.1); + } + glEnd(); + } + + typedef CGAL_Nef_polyhedron2::Explorer Explorer; + typedef Explorer::Face_const_iterator fci_t; + typedef Explorer::Halfedge_around_face_const_circulator heafcc_t; + typedef Explorer::Point Point; + Explorer E = this->root.p2.explorer(); + + // Draw 2D edges + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glLineWidth(2); + const QColor &col2 = Preferences::inst()->color(Preferences::CGAL_EDGE_2D_COLOR); + glColor3f(col2.redF(), col2.greenF(), col2.blueF()); + + // Extract the boundary, including inner boundaries of the polygons + for (fci_t fit = E.faces_begin(), facesend = E.faces_end(); fit != facesend; ++fit) { + bool fset = false; + double fx = 0.0, fy = 0.0; + heafcc_t fcirc(E.halfedge(fit)), fend(fcirc); + CGAL_For_all(fcirc, fend) { + if(E.is_standard(E.target(fcirc))) { + Point p = E.point(E.target(fcirc)); + double x = to_double(p.x()), y = to_double(p.y()); + if (!fset) { + glBegin(GL_LINE_STRIP); + fx = x, fy = y; + fset = true; + } + glVertex3d(x, y, -0.1); + } + } + if (fset) { + glVertex3d(fx, fy, -0.1); + glEnd(); + } + } + + glEnable(GL_DEPTH_TEST); + } + else if (this->root.dim == 3) { + if (showfaces) this->polyhedron->set_style(SNC_BOUNDARY); + else this->polyhedron->set_style(SNC_SKELETON); + + this->polyhedron->draw(showfaces && showedges); + } +} diff --git a/src/cgalrenderer.h b/src/cgalrenderer.h new file mode 100644 index 0000000..b3c1638 --- /dev/null +++ b/src/cgalrenderer.h @@ -0,0 +1,20 @@ +#ifndef CGALRENDERER_H_ +#define CGALRENDERER_H_ + +#include "renderer.h" +#include "cgal.h" + +class CGALRenderer : public Renderer +{ +public: + CGALRenderer(const CGAL_Nef_polyhedron &root); + ~CGALRenderer(); + void draw(bool showfaces, bool showedges) const; + +private: + const CGAL_Nef_polyhedron &root; + class Polyhedron *polyhedron; + class PolySet *polyset; +}; + +#endif diff --git a/src/dxflinextrude.cc b/src/dxflinextrude.cc index bb4a7dd..64c4c35 100644 --- a/src/dxflinextrude.cc +++ b/src/dxflinextrude.cc @@ -35,7 +35,7 @@ #include "polyset.h" #include "progress.h" #include "visitor.h" -#include "PolySetRenderer.h" +#include "PolySetEvaluator.h" #include "openscad.h" // get_fragments_from_r() #include <sstream> @@ -126,11 +126,11 @@ void register_builtin_dxf_linear_extrude() builtin_modules["linear_extrude"] = new DxfLinearExtrudeModule(); } -PolySet *DxfLinearExtrudeNode::render_polyset(render_mode_e mode, - PolySetRenderer *renderer) const +PolySet *DxfLinearExtrudeNode::evaluate_polyset(render_mode_e mode, + PolySetEvaluator *evaluator) const { - if (!renderer) { - PRINTF("WARNING: No suitable PolySetRenderer found for %s module!", this->name().c_str()); + if (!evaluator) { + PRINTF("WARNING: No suitable PolySetEvaluator found for %s module!", this->name().c_str()); PolySet *ps = new PolySet(); ps->is2d = true; return ps; @@ -138,7 +138,7 @@ PolySet *DxfLinearExtrudeNode::render_polyset(render_mode_e mode, print_messages_push(); - PolySet *ps = renderer->renderPolySet(*this, mode); + PolySet *ps = evaluator->evaluatePolySet(*this, mode); print_messages_pop(); diff --git a/src/dxflinextrudenode.h b/src/dxflinextrudenode.h index 8f829ea..dba03e8 100644 --- a/src/dxflinextrudenode.h +++ b/src/dxflinextrudenode.h @@ -24,7 +24,7 @@ public: double origin_x, origin_y, scale; bool center, has_twist; QString filename, layername; - virtual PolySet *render_polyset(render_mode_e mode, class PolySetRenderer *) const; + virtual PolySet *evaluate_polyset(render_mode_e mode, class PolySetEvaluator *) const; }; #endif diff --git a/src/dxfrotextrude.cc b/src/dxfrotextrude.cc index 06892aa..ec75a52 100644 --- a/src/dxfrotextrude.cc +++ b/src/dxfrotextrude.cc @@ -33,7 +33,7 @@ #include "dxfdata.h" #include "progress.h" #include "visitor.h" -#include "PolySetRenderer.h" +#include "PolySetEvaluator.h" #include "openscad.h" // get_fragments_from_r() #include <sstream> @@ -102,11 +102,11 @@ void register_builtin_dxf_rotate_extrude() builtin_modules["rotate_extrude"] = new DxfRotateExtrudeModule(); } -PolySet *DxfRotateExtrudeNode::render_polyset(render_mode_e mode, - PolySetRenderer *renderer) const +PolySet *DxfRotateExtrudeNode::evaluate_polyset(render_mode_e mode, + PolySetEvaluator *evaluator) const { - if (!renderer) { - PRINTF("WARNING: No suitable PolySetRenderer found for %s module!", this->name().c_str()); + if (!evaluator) { + PRINTF("WARNING: No suitable PolySetEvaluator found for %s module!", this->name().c_str()); PolySet *ps = new PolySet(); ps->is2d = true; return ps; @@ -114,7 +114,7 @@ PolySet *DxfRotateExtrudeNode::render_polyset(render_mode_e mode, print_messages_push(); - PolySet *ps = renderer->renderPolySet(*this, mode); + PolySet *ps = evaluator->evaluatePolySet(*this, mode); print_messages_pop(); diff --git a/src/dxfrotextrudenode.h b/src/dxfrotextrudenode.h index 0372cb3..38ca087 100644 --- a/src/dxfrotextrudenode.h +++ b/src/dxfrotextrudenode.h @@ -22,7 +22,7 @@ public: double fn, fs, fa; double origin_x, origin_y, scale; QString filename, layername; - virtual PolySet *render_polyset(render_mode_e mode, class PolySetRenderer *) const; + virtual PolySet *evaluate_polyset(render_mode_e mode, class PolySetEvaluator *) const; }; #endif diff --git a/src/glview.cc b/src/glview.cc index 3daa064..896ff0a 100644 --- a/src/glview.cc +++ b/src/glview.cc @@ -26,6 +26,7 @@ #include "GLView.h" #include "Preferences.h" +#include "renderer.h" #include <QApplication> #include <QWheelEvent> @@ -41,9 +42,13 @@ #include "mathc99.h" #include <stdio.h> +#ifdef ENABLE_OPENCSG +# include <opencsg.h> +#endif + #define FAR_FAR_AWAY 100000.0 -GLView::GLView(QWidget *parent) : QGLWidget(parent) +GLView::GLView(QWidget *parent) : QGLWidget(parent), renderer(NULL) { init(); } @@ -64,16 +69,13 @@ void GLView::init() this->object_trans_z = 0; this->mouse_drag_active = false; - this->last_mouse_x = 0; - this->last_mouse_y = 0; + this->showedges = false; + this->showfaces = true; this->orthomode = false; this->showaxes = false; this->showcrosshairs = false; - this->renderfunc = NULL; - this->renderfunc_vp = NULL; - for (int i = 0; i < 10; i++) this->shaderinfo[i] = 0; @@ -87,10 +89,10 @@ void GLView::init() #endif } -void GLView::setRenderFunc(void (*func)(void*), void *userdata) +void GLView::setRenderer(Renderer *r) { - this->renderfunc = func; - this->renderfunc_vp = userdata; + this->renderer = r; + updateGL(); } void GLView::initializeGL() @@ -101,6 +103,22 @@ void GLView::initializeGL() glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0}; + GLfloat light_position0[] = {-1.0, -1.0, +1.0, 0.0}; + GLfloat light_position1[] = {+1.0, +1.0, -1.0, 0.0}; + + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); + glLightfv(GL_LIGHT0, GL_POSITION, light_position0); + glEnable(GL_LIGHT0); + glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); + glLightfv(GL_LIGHT1, GL_POSITION, light_position1); + glEnable(GL_LIGHT1); + glEnable(GL_LIGHTING); + glEnable(GL_NORMALIZE); + + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + glEnable(GL_COLOR_MATERIAL); + #ifdef ENABLE_OPENCSG GLenum err = glewInit(); if (GLEW_OK != err) { @@ -266,43 +284,47 @@ void GLView::resizeGL(int w, int h) #endif glViewport(0, 0, w, h); w_h_ratio = sqrt((double)w / (double)h); + + setupPerspective(); } -void GLView::paintGL() +void GLView::setupPerspective() { - const QColor &bgcol = Preferences::inst()->color(Preferences::BACKGROUND_COLOR); - glClearColor(bgcol.redF(), bgcol.greenF(), bgcol.blueF(), 0.0); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-w_h_ratio, +w_h_ratio, -(1/w_h_ratio), +(1/w_h_ratio), +10.0, +FAR_FAR_AWAY); +} +void GLView::setupOrtho(double distance, bool offset) +{ glMatrixMode(GL_PROJECTION); glLoadIdentity(); + if(offset) + glTranslated(-0.8, -0.8, 0); + double l = distance/10; + glOrtho(-w_h_ratio*l, +w_h_ratio*l, + -(1/w_h_ratio)*l, +(1/w_h_ratio)*l, + -FAR_FAR_AWAY, +FAR_FAR_AWAY); +} + +void GLView::paintGL() +{ + glEnable(GL_LIGHTING); + if (orthomode) - glOrtho(-w_h_ratio*viewer_distance/10, +w_h_ratio*viewer_distance/10, - -(1/w_h_ratio)*viewer_distance/10, +(1/w_h_ratio)*viewer_distance/10, - -FAR_FAR_AWAY, +FAR_FAR_AWAY); - else - glFrustum(-w_h_ratio, +w_h_ratio, -(1/w_h_ratio), +(1/w_h_ratio), +10.0, +FAR_FAR_AWAY); - gluLookAt(0.0, -viewer_distance, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); + setupOrtho(viewer_distance); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0}; - GLfloat light_position0[] = {-1.0, -1.0, +1.0, 0.0}; - GLfloat light_position1[] = {+1.0, +1.0, -1.0, 0.0}; + const QColor &bgcol = Preferences::inst()->color(Preferences::BACKGROUND_COLOR); + glClearColor(bgcol.redF(), bgcol.greenF(), bgcol.blueF(), 0.0); - glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT0, GL_POSITION, light_position0); - glEnable(GL_LIGHT0); - glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse); - glLightfv(GL_LIGHT1, GL_POSITION, light_position1); - glEnable(GL_LIGHT1); - glEnable(GL_LIGHTING); - glEnable(GL_NORMALIZE); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - glEnable(GL_COLOR_MATERIAL); + gluLookAt(0.0, -viewer_distance, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); + + glTranslated(object_trans_x, object_trans_y, object_trans_z); glRotated(object_rot_x, 1.0, 0.0, 0.0); glRotated(object_rot_y, 0.0, 1.0, 0.0); @@ -325,8 +347,6 @@ void GLView::paintGL() glEnd(); } - glTranslated(object_trans_x, object_trans_y, object_trans_z); - // Large gray axis cross inline with the model // FIXME: This is always gray - adjust color to keep contrast with background if (showaxes) @@ -334,12 +354,13 @@ void GLView::paintGL() glLineWidth(1); glColor3d(0.5, 0.5, 0.5); glBegin(GL_LINES); - glVertex3d(-viewer_distance/10, 0, 0); - glVertex3d(+viewer_distance/10, 0, 0); - glVertex3d(0, -viewer_distance/10, 0); - glVertex3d(0, +viewer_distance/10, 0); - glVertex3d(0, 0, -viewer_distance/10); - glVertex3d(0, 0, +viewer_distance/10); + double l = viewer_distance/10; + glVertex3d(-l, 0, 0); + glVertex3d(+l, 0, 0); + glVertex3d(0, -l, 0); + glVertex3d(0, +l, 0); + glVertex3d(0, 0, -l); + glVertex3d(0, 0, +l); glEnd(); } @@ -350,20 +371,21 @@ void GLView::paintGL() glLineWidth(2); glColor3d(1.0, 0.0, 0.0); - if (renderfunc) - renderfunc(renderfunc_vp); + if (this->renderer) { +#if defined(ENABLE_MDI) && defined(ENABLE_OPENCSG) + // FIXME: This belongs in the OpenCSG renderer, but it doesn't know about this ID yet + OpenCSG::setContext(this->opencsg_id); +#endif + this->renderer->draw(showfaces, showedges); + } // Small axis cross in the lower left corner if (showaxes) { glDepthFunc(GL_ALWAYS); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glTranslated(-0.8, -0.8, 0); - glOrtho(-w_h_ratio*1000/10, +w_h_ratio*1000/10, - -(1/w_h_ratio)*1000/10, +(1/w_h_ratio)*1000/10, - -FAR_FAR_AWAY, +FAR_FAR_AWAY); + setupOrtho(1000,true); + gluLookAt(0.0, -1000, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0); glMatrixMode(GL_MODELVIEW); @@ -428,6 +450,10 @@ void GLView::paintGL() glVertex3d(zlabel_x-3, zlabel_y+3, 0); glVertex3d(zlabel_x+3, zlabel_y+3, 0); glVertex3d(zlabel_x-3, zlabel_y-3, 0); glVertex3d(zlabel_x+3, zlabel_y+3, 0); glEnd(); + + //Restore perspective for next paint + if(!orthomode) + setupPerspective(); } if (statusLabel) { @@ -462,101 +488,48 @@ void GLView::wheelEvent(QWheelEvent *event) void GLView::mousePressEvent(QMouseEvent *event) { mouse_drag_active = true; - last_mouse_x = event->globalX(); - last_mouse_y = event->globalY(); + last_mouse = event->globalPos(); grabMouse(); setFocus(); } -static void mat_id(double *trg) -{ - for (int i = 0; i < 16; i++) - trg[i] = i%5 == 0; -} -static void mat_mul(double *trg, const double *m1, const double *m2) +void GLView::normalizeAngle(GLdouble& angle) { - double m[16]; - for (int x = 0; x < 4; x++) - for (int y = 0; y < 4; y++) - { - m[x+y*4] = 0; - for (int i = 0; i < 4; i++) - m[x+y*4] += m1[i+y*4] * m2[x+i*4]; - } - for (int i = 0; i < 16; i++) - trg[i] = m[i]; -} - -static void mat_rot(double *trg, double angle, double x, double y, double z) -{ - double s = sin(M_PI*angle/180), c = cos(M_PI*angle/180); - double cc = 1 - c; - double m[16] = { - x*x*cc+c, x*y*cc-z*s, x*z*cc+y*s, 0, - y*x*cc+z*s, y*y*cc+c, y*z*cc-x*s, 0, - x*z*cc-y*s, y*z*cc+x*s, z*z*cc+c, 0, - 0, 0, 0, 1 - }; - for (int i = 0; i < 16; i++) - trg[i] = m[i]; + while(angle < 0) + angle += 360; + while(angle > 360) + angle -= 360; } void GLView::mouseMoveEvent(QMouseEvent *event) { - int this_mouse_x = event->globalX(); - int this_mouse_y = event->globalY(); + QPoint this_mouse = event->globalPos(); + double dx = (this_mouse.x()-last_mouse.x()) * 0.7; + double dy = (this_mouse.y()-last_mouse.y()) * 0.7; if (mouse_drag_active) { if ((event->buttons() & Qt::LeftButton) != 0) { - object_rot_x += (this_mouse_y-last_mouse_y) * 0.7; + object_rot_x += dy; if ((QApplication::keyboardModifiers() & Qt::ShiftModifier) != 0) - object_rot_y += (this_mouse_x-last_mouse_x) * 0.7; + object_rot_y += dx; else - object_rot_z += (this_mouse_x-last_mouse_x) * 0.7; - while (object_rot_x < 0) - object_rot_x += 360; - while (object_rot_x >= 360) - object_rot_x -= 360; - while (object_rot_y < 0) - object_rot_y += 360; - while (object_rot_y >= 360) - object_rot_y -= 360; - while (object_rot_z < 0) - object_rot_z += 360; - while (object_rot_z >= 360) - object_rot_z -= 360; + object_rot_z += dx; + + normalizeAngle(object_rot_x); + normalizeAngle(object_rot_y); + normalizeAngle(object_rot_z); } else { - double mx = +(this_mouse_x-last_mouse_x) * viewer_distance/1000; - double my = -(this_mouse_y-last_mouse_y) * viewer_distance/1000; - double rx[16], ry[16], rz[16], tm[16]; - mat_rot(rx, -object_rot_x, 1.0, 0.0, 0.0); - mat_rot(ry, -object_rot_y, 0.0, 1.0, 0.0); - mat_rot(rz, -object_rot_z, 0.0, 0.0, 1.0); - mat_id(tm); - mat_mul(tm, rx, tm); - mat_mul(tm, ry, tm); - mat_mul(tm, rz, tm); - double vec[16] = { - 0, 0, 0, mx, - 0, 0, 0, 0, - 0, 0, 0, my, - 0, 0, 0, 1 - }; if ((QApplication::keyboardModifiers() & Qt::ShiftModifier) != 0) { - vec[3] = 0; - vec[7] = my; - vec[11] = 0; + viewer_distance += (GLdouble)dy; + } else { + object_trans_x += dx; + object_trans_z -= dy; } - mat_mul(tm, tm, vec); - object_trans_x += tm[3]; - object_trans_y += tm[7]; - object_trans_z += tm[11]; } updateGL(); emit doAnimateUpdate(); } - last_mouse_x = this_mouse_x; - last_mouse_y = this_mouse_y; + last_mouse = this_mouse; } void GLView::mouseReleaseEvent(QMouseEvent*) diff --git a/src/import.cc b/src/import.cc index 4586237..fdac5b9 100644 --- a/src/import.cc +++ b/src/import.cc @@ -105,7 +105,7 @@ void register_builtin_import() builtin_modules["import_dxf"] = new ImportModule(TYPE_DXF); } -PolySet *ImportNode::render_polyset(render_mode_e, class PolySetRenderer *) const +PolySet *ImportNode::evaluate_polyset(render_mode_e, class PolySetEvaluator *) const { PolySet *p = new PolySet(); p->convexity = this->convexity; diff --git a/src/importnode.h b/src/importnode.h index a010d4c..bdbf193 100644 --- a/src/importnode.h +++ b/src/importnode.h @@ -26,7 +26,7 @@ public: int convexity; double fn, fs, fa; double origin_x, origin_y, scale; - virtual PolySet *render_polyset(render_mode_e mode, class PolySetRenderer *) const; + virtual PolySet *evaluate_polyset(render_mode_e mode, class PolySetEvaluator *) const; }; #endif diff --git a/src/mainwin.cc b/src/mainwin.cc index 1f5644c..5bc16cb 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -40,14 +40,15 @@ #include "dxftess.h" #include "progress.h" #ifdef ENABLE_OPENCSG -#include "render-opencsg.h" -#include "CSGTermRenderer.h" +#include "CSGTermEvaluator.h" +#include "opencsgRenderer.h" #endif #ifdef USE_PROGRESSWIDGET #include "ProgressWidget.h" #endif -#include "CGALRenderer.h" -#include "PolySetCGALRenderer.h" +#include "CGALEvaluator.h" +#include "PolySetCGALEvaluator.h" +#include "thrownTogetherRenderer.h" #include <QMenu> #include <QTime> @@ -83,32 +84,8 @@ using namespace boost::lambda; #ifdef ENABLE_CGAL -#if 1 -#include "CGAL_renderer.h" -using OpenSCAD::OGL::Polyhedron; -using OpenSCAD::OGL::SNC_BOUNDARY; -using OpenSCAD::OGL::SNC_SKELETON; -using OpenSCAD::OGL::Nef3_Converter; -#else -// a little hackish: we need access to default-private members of -// CGAL::OGL::Nef3_Converter so we can implement our own draw function -// that does not scale the model. so we define 'class' to 'struct' -// for this header.. -// -// theoretically there could be two problems: -// 1.) defining language keyword with the pre processor is illegal afair -// 2.) the compiler could use a different memory layout or name mangling for structs -// -// both does not seam to be the case with todays compilers... -// -#define class struct -#include <CGAL/Nef_3/OGL_helper.h> -#undef class -using CGAL::OGL::Polyhedron; -using CGAL::OGL::SNC_BOUNDARY; -using CGAL::OGL::SNC_SKELETON; -using CGAL::OGL::Nef3_Converter; -#endif +#include "cgalrenderer.h" + #endif // ENABLE_CGAL // Global application state @@ -187,15 +164,16 @@ MainWindow::MainWindow(const QString &filename) root_chain = NULL; #ifdef ENABLE_CGAL this->root_N = NULL; - this->recreate_cgal_ogl_p = false; - cgal_ogl_p = NULL; - cgal_ogl_ps = NULL; + this->cgalRenderer = NULL; #endif +#ifdef ENABLE_OPENCSG + this->opencsgRenderer = NULL; +#endif + this->thrownTogetherRenderer = NULL; highlights_chain = NULL; background_chain = NULL; root_node = NULL; - enableOpenCSG = false; tval = 0; fps = 0; @@ -339,11 +317,6 @@ MainWindow::MainWindow(const QString &filename) connect(this->viewActionOrthogonal, SIGNAL(triggered()), this, SLOT(viewOrthogonal())); connect(this->viewActionHide, SIGNAL(triggered()), this, SLOT(hideConsole())); -// #ifdef ENABLE_CGAL -// viewActionCGALSurface = menu->addAction("CGAL Surfaces", this, SLOT(viewModeCGALSurface()), QKeySequence(Qt::Key_F10)); -// viewActionCGALGrid = menu->addAction("CGAL Grid Only", this, SLOT(viewModeCGALGrid()), QKeySequence(Qt::Key_F11)); -// #endif - // Help menu connect(this->helpActionAbout, SIGNAL(triggered()), this, SLOT(helpAbout())); connect(this->helpActionHomepage, SIGNAL(triggered()), this, SLOT(helpHomepage())); @@ -443,19 +416,14 @@ MainWindow::loadDesignSettings() MainWindow::~MainWindow() { - if (root_module) - delete root_module; - if (root_node) - delete root_node; + if (root_module) delete root_module; + if (root_node) delete root_node; #ifdef ENABLE_CGAL - if (this->root_N) - delete this->root_N; - if (cgal_ogl_p) { - Polyhedron *p = (Polyhedron*)cgal_ogl_p; - delete p; - } - if (cgal_ogl_ps) - cgal_ogl_ps->unlink(); + if (this->root_N) delete this->root_N; + delete this->cgalRenderer; +#endif +#ifdef ENABLE_OPENCSG + delete this->opencsgRenderer; #endif } @@ -624,6 +592,16 @@ void MainWindow::compile(bool procevents) if (procevents) QApplication::processEvents(); + // Invalidate renderers before we kill the CSG tree + this->glview->setRenderer(NULL); + if (this->opencsgRenderer) { + delete this->opencsgRenderer; + this->opencsgRenderer = NULL; + } + if (this->thrownTogetherRenderer) { + delete this->thrownTogetherRenderer; + this->thrownTogetherRenderer = NULL; + } // Remove previous CSG tree if (this->root_module) { @@ -666,7 +644,6 @@ void MainWindow::compile(bool procevents) this->root_node = NULL; this->tree.setRoot(NULL); - this->enableOpenCSG = false; // Initialize special variables this->root_ctx.set_variable("$t", Value(e_tval->text().toDouble())); @@ -799,10 +776,10 @@ void MainWindow::compileCSG(bool procevents) try { // FIXME: put cache somewhere else as it's pretty useless now QHash<std::string, CGAL_Nef_polyhedron> cache; - CGALRenderer cgalrenderer(cache, this->tree); - PolySetCGALRenderer psrenderer(cgalrenderer); - CSGTermRenderer csgrenderer(this->tree, &psrenderer); - root_raw_term = csgrenderer.renderCSGTerm(*root_node, &highlight_terms, &background_terms); + CGALEvaluator cgalevaluator(cache, this->tree); + PolySetCGALEvaluator psevaluator(cgalevaluator); + CSGTermEvaluator csgrenderer(this->tree, &psevaluator); + root_raw_term = csgrenderer.evaluateCSGTerm(*root_node, &highlight_terms, &background_terms); if (!root_raw_term) { PRINT("ERROR: CSG generation failed! (no top level object found)"); if (procevents) @@ -839,13 +816,6 @@ void MainWindow::compileCSG(bool procevents) root_chain = new CSGChain(); root_chain->import(root_norm_term); - if (root_chain->polysets.size() > 1000) { - PRINTF("WARNING: Normalized tree has %u elements!", root_chain->polysets.size()); - PRINTF("WARNING: OpenCSG rendering has been disabled."); - } else { - enableOpenCSG = true; - } - if (highlight_terms.size() > 0) { PRINTF("Compiling highlights (%zu CSG Trees)...", highlight_terms.size()); @@ -883,6 +853,20 @@ void MainWindow::compileCSG(bool procevents) background_chain->import(background_terms[i]); } } + + if (root_chain->polysets.size() > 1000) { + PRINTF("WARNING: Normalized tree has %d elements!", root_chain->polysets.size()); + PRINTF("WARNING: OpenCSG rendering has been disabled."); + } + else { + this->opencsgRenderer = new OpenCSGRenderer(this->root_chain, + this->highlights_chain, + this->background_chain, + this->glview->shaderinfo); + } + this->thrownTogetherRenderer = new ThrownTogetherRenderer(this->root_chain, + this->highlights_chain, + this->background_chain); PRINT("CSG generation finished."); int s = t.elapsed() / 1000; @@ -1155,16 +1139,16 @@ void MainWindow::actionCompile() if (this->root_node) compileCSG(!viewActionAnimate->isChecked()); // Go to non-CGAL view mode - if (!viewActionOpenCSG->isChecked() && !viewActionThrownTogether->isChecked()) { + if (viewActionThrownTogether->isChecked()) { + viewModeThrownTogether(); + } + else { #ifdef ENABLE_OPENCSG viewModeOpenCSG(); #else viewModeThrownTogether(); #endif } - else { - this->glview->updateGL(); - } if (viewActionAnimate->isChecked() && e_dump->isChecked()) { QImage img = this->glview->grabFrameBuffer(); @@ -1194,10 +1178,12 @@ void MainWindow::actionRenderCGAL() return; } + this->glview->setRenderer(NULL); + delete this->cgalRenderer; + this->cgalRenderer = NULL; if (this->root_N) { delete this->root_N; this->root_N = NULL; - this->recreate_cgal_ogl_p = true; } PRINT("Rendering Polygon Mesh using CGAL..."); @@ -1226,8 +1212,8 @@ void MainWindow::actionRenderCGAL() try { // FIXME: put cache somewhere else as it's pretty useless now QHash<std::string, CGAL_Nef_polyhedron> cache; - CGALRenderer renderer(cache, this->tree); - this->root_N = new CGAL_Nef_polyhedron(renderer.renderCGALMesh(*this->root_node)); + CGALEvaluator evaluator(cache, this->tree); + this->root_N = new CGAL_Nef_polyhedron(evaluator.evaluateCGALMesh(*this->root_node)); } catch (ProgressCancelException e) { PRINT("Rendering cancelled."); @@ -1285,10 +1271,13 @@ void MainWindow::actionRenderCGAL() int s = t.elapsed() / 1000; PRINTF("Total rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60); - if (!viewActionCGALSurfaces->isChecked() && !viewActionCGALGrid->isChecked()) { + this->cgalRenderer = new CGALRenderer(*this->root_N); + // Go to CGAL view mode + if (viewActionCGALGrid->isChecked()) { + viewModeCGALGrid(); + } + else { viewModeCGALSurface(); - } else { - this->glview->updateGL(); } PRINT("Rendering finished."); @@ -1491,11 +1480,11 @@ void MainWindow::actionExportImage() void MainWindow::actionFlushCaches() { -// FIXME: Polycache -> PolySetRenderer -// FIXME: PolySetRenderer->clearCache(); +// FIXME: Polycache -> PolySetEvaluator +// FIXME: PolySetEvaluator->clearCache(); #ifdef ENABLE_CGAL // FIXME: Flush caches through whatever channels we have - // CGALRenderer::renderer()->getCache().clear(); + // CGALEvaluator::evaluator()->getCache().clear(); // this->dumper->clearCache(); #endif dxf_dim_cache.clear(); @@ -1514,37 +1503,6 @@ void MainWindow::viewModeActionsUncheck() #ifdef ENABLE_OPENCSG -static void renderGLThrownTogether(void *vp); - -static void renderGLviaOpenCSG(void *vp) -{ - MainWindow *mainwin = (MainWindow *)vp; - if (!mainwin->enableOpenCSG) { - renderGLThrownTogether(vp); - return; - } - static int glew_initialized = 0; - if (!glew_initialized) { - glew_initialized = 1; - glewInit(); - } -#ifdef ENABLE_MDI - OpenCSG::setContext(mainwin->glview->opencsg_id); -#endif - if (mainwin->root_chain) { - GLint *shaderinfo = mainwin->glview->shaderinfo; - if (!shaderinfo[0]) - shaderinfo = NULL; - renderCSGChainviaOpenCSG(mainwin->root_chain, mainwin->viewActionShowEdges->isChecked() ? shaderinfo : NULL, false, false); - if (mainwin->background_chain) { - renderCSGChainviaOpenCSG(mainwin->background_chain, mainwin->viewActionShowEdges->isChecked() ? shaderinfo : NULL, false, true); - } - if (mainwin->highlights_chain) { - renderCSGChainviaOpenCSG(mainwin->highlights_chain, mainwin->viewActionShowEdges->isChecked() ? shaderinfo : NULL, true, false); - } - } -} - /*! Go to the OpenCSG view mode. Falls back to thrown together mode if OpenCSG is not available @@ -1554,8 +1512,7 @@ void MainWindow::viewModeOpenCSG() if (this->glview->hasOpenCSGSupport()) { viewModeActionsUncheck(); viewActionOpenCSG->setChecked(true); - this->glview->setRenderFunc(renderGLviaOpenCSG, this); - this->glview->updateGL(); + this->glview->setRenderer(this->opencsgRenderer ? (Renderer *)this->opencsgRenderer : (Renderer *)this->thrownTogetherRenderer); } else { viewModeThrownTogether(); } @@ -1565,125 +1522,12 @@ void MainWindow::viewModeOpenCSG() #ifdef ENABLE_CGAL -static void renderGLviaCGAL(void *vp) -{ - MainWindow *m = (MainWindow*)vp; - if (m->recreate_cgal_ogl_p) { - m->recreate_cgal_ogl_p = false; - Polyhedron *p = (Polyhedron*)m->cgal_ogl_p; - delete p; - m->cgal_ogl_p = NULL; - if (m->cgal_ogl_ps) - m->cgal_ogl_ps->unlink(); - m->cgal_ogl_ps = NULL; - } - if (!m->root_N) return; - if (m->root_N->dim == 2) - { - if (m->cgal_ogl_ps == NULL) { - DxfData dd(*m->root_N); - m->cgal_ogl_ps = new PolySet(); - m->cgal_ogl_ps->is2d = true; - dxf_tesselate(m->cgal_ogl_ps, &dd, 0, true, false, 0); - } - - // Draw 2D polygons - glDisable(GL_LIGHTING); - const QColor &col = Preferences::inst()->color(Preferences::CGAL_FACE_2D_COLOR); - glColor3f(col.redF(), col.greenF(), col.blueF()); - - for (int i=0; i < m->cgal_ogl_ps->polygons.size(); i++) { - glBegin(GL_POLYGON); - for (int j=0; j < m->cgal_ogl_ps->polygons[i].size(); j++) { - PolySet::Point p = m->cgal_ogl_ps->polygons[i][j]; - glVertex3d(p.x, p.y, -0.1); - } - glEnd(); - } - - typedef CGAL_Nef_polyhedron2::Explorer Explorer; - typedef Explorer::Face_const_iterator fci_t; - typedef Explorer::Halfedge_around_face_const_circulator heafcc_t; - typedef Explorer::Point Point; - Explorer E = m->root_N->p2.explorer(); - - // Draw 2D edges - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glLineWidth(2); - const QColor &col2 = Preferences::inst()->color(Preferences::CGAL_EDGE_2D_COLOR); - glColor3f(col2.redF(), col2.greenF(), col2.blueF()); - - // Extract the boundary, including inner boundaries of the polygons - for (fci_t fit = E.faces_begin(), facesend = E.faces_end(); fit != facesend; ++fit) - { - bool fset = false; - double fx = 0.0, fy = 0.0; - heafcc_t fcirc(E.halfedge(fit)), fend(fcirc); - CGAL_For_all(fcirc, fend) { - if(E.is_standard(E.target(fcirc))) { - Point p = E.point(E.target(fcirc)); - double x = to_double(p.x()), y = to_double(p.y()); - if (!fset) { - glBegin(GL_LINE_STRIP); - fx = x, fy = y; - fset = true; - } - glVertex3d(x, y, -0.1); - } - } - if (fset) { - glVertex3d(fx, fy, -0.1); - glEnd(); - } - } - - glEnable(GL_DEPTH_TEST); - } - else if (m->root_N->dim == 3) - { - Polyhedron *p = (Polyhedron*)m->cgal_ogl_p; - if (!p) { - Nef3_Converter<CGAL_Nef_polyhedron3>::setColor(Polyhedron::CGAL_NEF3_MARKED_FACET_COLOR, - Preferences::inst()->color(Preferences::CGAL_FACE_BACK_COLOR).red(), - Preferences::inst()->color(Preferences::CGAL_FACE_BACK_COLOR).green(), - Preferences::inst()->color(Preferences::CGAL_FACE_BACK_COLOR).blue()); - Nef3_Converter<CGAL_Nef_polyhedron3>::setColor(Polyhedron::CGAL_NEF3_UNMARKED_FACET_COLOR, - Preferences::inst()->color(Preferences::CGAL_FACE_FRONT_COLOR).red(), - Preferences::inst()->color(Preferences::CGAL_FACE_FRONT_COLOR).green(), - Preferences::inst()->color(Preferences::CGAL_FACE_FRONT_COLOR).blue()); - m->cgal_ogl_p = p = new Polyhedron(); - Nef3_Converter<CGAL_Nef_polyhedron3>::convert_to_OGLPolyhedron(m->root_N->p3, p); - p->init(); - } - if (m->viewActionCGALSurfaces->isChecked()) - p->set_style(SNC_BOUNDARY); - if (m->viewActionCGALGrid->isChecked()) - p->set_style(SNC_SKELETON); -#if 0 - p->draw(); -#else - if (p->style == SNC_BOUNDARY) { - glCallList(p->object_list_+2); - if (m->viewActionShowEdges->isChecked()) { - glDisable(GL_LIGHTING); - glCallList(p->object_list_+1); - glCallList(p->object_list_); - } - } else { - glDisable(GL_LIGHTING); - glCallList(p->object_list_+1); - glCallList(p->object_list_); - } -#endif - } -} - void MainWindow::viewModeCGALSurface() { viewModeActionsUncheck(); viewActionCGALSurfaces->setChecked(true); - this->glview->setRenderFunc(renderGLviaCGAL, this); + this->glview->setShowFaces(true); + this->glview->setRenderer(this->cgalRenderer); this->glview->updateGL(); } @@ -1691,104 +1535,24 @@ void MainWindow::viewModeCGALGrid() { viewModeActionsUncheck(); viewActionCGALGrid->setChecked(true); - this->glview->setRenderFunc(renderGLviaCGAL, this); - this->glview->updateGL(); + this->glview->setShowFaces(false); + this->glview->setRenderer(this->cgalRenderer); } #endif /* ENABLE_CGAL */ -static void renderGLThrownTogetherChain(MainWindow *m, CSGChain *chain, bool highlight, bool background, bool fberror) -{ - glDepthFunc(GL_LEQUAL); - QHash<QPair<PolySet*,double*>,int> polySetVisitMark; - bool showEdges = m->viewActionShowEdges->isChecked(); - 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(); - } -} - -static void renderGLThrownTogether(void *vp) -{ - MainWindow *m = (MainWindow*)vp; - if (m->root_chain) { - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - renderGLThrownTogetherChain(m, m->root_chain, false, false, false); - glCullFace(GL_FRONT); - glColor3ub(255, 0, 255); - renderGLThrownTogetherChain(m, m->root_chain, false, false, true); - glDisable(GL_CULL_FACE); - } - if (m->background_chain) - renderGLThrownTogetherChain(m, m->background_chain, false, true, false); - if (m->highlights_chain) - renderGLThrownTogetherChain(m, m->highlights_chain, true, false, false); -} - void MainWindow::viewModeThrownTogether() { viewModeActionsUncheck(); viewActionThrownTogether->setChecked(true); - this->glview->setRenderFunc(renderGLThrownTogether, this); - this->glview->updateGL(); + this->glview->setRenderer(this->thrownTogetherRenderer); } void MainWindow::viewModeShowEdges() { QSettings settings; settings.setValue("view/showEdges",viewActionShowEdges->isChecked()); + this->glview->setShowEdges(viewActionShowEdges->isChecked()); this->glview->updateGL(); } diff --git a/src/namedcolors.cpp b/src/namedcolors.cpp new file mode 100644 index 0000000..3150a40 --- /dev/null +++ b/src/namedcolors.cpp @@ -0,0 +1,155 @@ +#define rgb(r,g,b) (0xff000000 | (r << 16) | (g << 8) | b) + +static const struct RGBData { + const char *name; + uint value; +} named_colors[] = { + { "aliceblue", rgb(240, 248, 255) }, + { "antiquewhite", rgb(250, 235, 215) }, + { "aqua", rgb( 0, 255, 255) }, + { "aquamarine", rgb(127, 255, 212) }, + { "azure", rgb(240, 255, 255) }, + { "beige", rgb(245, 245, 220) }, + { "bisque", rgb(255, 228, 196) }, + { "black", rgb( 0, 0, 0) }, + { "blanchedalmond", rgb(255, 235, 205) }, + { "blue", rgb( 0, 0, 255) }, + { "blueviolet", rgb(138, 43, 226) }, + { "brown", rgb(165, 42, 42) }, + { "burlywood", rgb(222, 184, 135) }, + { "cadetblue", rgb( 95, 158, 160) }, + { "chartreuse", rgb(127, 255, 0) }, + { "chocolate", rgb(210, 105, 30) }, + { "coral", rgb(255, 127, 80) }, + { "cornflowerblue", rgb(100, 149, 237) }, + { "cornsilk", rgb(255, 248, 220) }, + { "crimson", rgb(220, 20, 60) }, + { "cyan", rgb( 0, 255, 255) }, + { "darkblue", rgb( 0, 0, 139) }, + { "darkcyan", rgb( 0, 139, 139) }, + { "darkgoldenrod", rgb(184, 134, 11) }, + { "darkgray", rgb(169, 169, 169) }, + { "darkgreen", rgb( 0, 100, 0) }, + { "darkgrey", rgb(169, 169, 169) }, + { "darkkhaki", rgb(189, 183, 107) }, + { "darkmagenta", rgb(139, 0, 139) }, + { "darkolivegreen", rgb( 85, 107, 47) }, + { "darkorange", rgb(255, 140, 0) }, + { "darkorchid", rgb(153, 50, 204) }, + { "darkred", rgb(139, 0, 0) }, + { "darksalmon", rgb(233, 150, 122) }, + { "darkseagreen", rgb(143, 188, 143) }, + { "darkslateblue", rgb( 72, 61, 139) }, + { "darkslategray", rgb( 47, 79, 79) }, + { "darkslategrey", rgb( 47, 79, 79) }, + { "darkturquoise", rgb( 0, 206, 209) }, + { "darkviolet", rgb(148, 0, 211) }, + { "deeppink", rgb(255, 20, 147) }, + { "deepskyblue", rgb( 0, 191, 255) }, + { "dimgray", rgb(105, 105, 105) }, + { "dimgrey", rgb(105, 105, 105) }, + { "dodgerblue", rgb( 30, 144, 255) }, + { "firebrick", rgb(178, 34, 34) }, + { "floralwhite", rgb(255, 250, 240) }, + { "forestgreen", rgb( 34, 139, 34) }, + { "fuchsia", rgb(255, 0, 255) }, + { "gainsboro", rgb(220, 220, 220) }, + { "ghostwhite", rgb(248, 248, 255) }, + { "gold", rgb(255, 215, 0) }, + { "goldenrod", rgb(218, 165, 32) }, + { "gray", rgb(128, 128, 128) }, + { "green", rgb( 0, 128, 0) }, + { "greenyellow", rgb(173, 255, 47) }, + { "grey", rgb(128, 128, 128) }, + { "honeydew", rgb(240, 255, 240) }, + { "hotpink", rgb(255, 105, 180) }, + { "indianred", rgb(205, 92, 92) }, + { "indigo", rgb( 75, 0, 130) }, + { "ivory", rgb(255, 255, 240) }, + { "khaki", rgb(240, 230, 140) }, + { "lavender", rgb(230, 230, 250) }, + { "lavenderblush", rgb(255, 240, 245) }, + { "lawngreen", rgb(124, 252, 0) }, + { "lemonchiffon", rgb(255, 250, 205) }, + { "lightblue", rgb(173, 216, 230) }, + { "lightcoral", rgb(240, 128, 128) }, + { "lightcyan", rgb(224, 255, 255) }, + { "lightgoldenrodyellow", rgb(250, 250, 210) }, + { "lightgray", rgb(211, 211, 211) }, + { "lightgreen", rgb(144, 238, 144) }, + { "lightgrey", rgb(211, 211, 211) }, + { "lightpink", rgb(255, 182, 193) }, + { "lightsalmon", rgb(255, 160, 122) }, + { "lightseagreen", rgb( 32, 178, 170) }, + { "lightskyblue", rgb(135, 206, 250) }, + { "lightslategray", rgb(119, 136, 153) }, + { "lightslategrey", rgb(119, 136, 153) }, + { "lightsteelblue", rgb(176, 196, 222) }, + { "lightyellow", rgb(255, 255, 224) }, + { "lime", rgb( 0, 255, 0) }, + { "limegreen", rgb( 50, 205, 50) }, + { "linen", rgb(250, 240, 230) }, + { "magenta", rgb(255, 0, 255) }, + { "maroon", rgb(128, 0, 0) }, + { "mediumaquamarine", rgb(102, 205, 170) }, + { "mediumblue", rgb( 0, 0, 205) }, + { "mediumorchid", rgb(186, 85, 211) }, + { "mediumpurple", rgb(147, 112, 219) }, + { "mediumseagreen", rgb( 60, 179, 113) }, + { "mediumslateblue", rgb(123, 104, 238) }, + { "mediumspringgreen", rgb( 0, 250, 154) }, + { "mediumturquoise", rgb( 72, 209, 204) }, + { "mediumvioletred", rgb(199, 21, 133) }, + { "midnightblue", rgb( 25, 25, 112) }, + { "mintcream", rgb(245, 255, 250) }, + { "mistyrose", rgb(255, 228, 225) }, + { "moccasin", rgb(255, 228, 181) }, + { "navajowhite", rgb(255, 222, 173) }, + { "navy", rgb( 0, 0, 128) }, + { "oldlace", rgb(253, 245, 230) }, + { "olive", rgb(128, 128, 0) }, + { "olivedrab", rgb(107, 142, 35) }, + { "orange", rgb(255, 165, 0) }, + { "orangered", rgb(255, 69, 0) }, + { "orchid", rgb(218, 112, 214) }, + { "palegoldenrod", rgb(238, 232, 170) }, + { "palegreen", rgb(152, 251, 152) }, + { "paleturquoise", rgb(175, 238, 238) }, + { "palevioletred", rgb(219, 112, 147) }, + { "papayawhip", rgb(255, 239, 213) }, + { "peachpuff", rgb(255, 218, 185) }, + { "peru", rgb(205, 133, 63) }, + { "pink", rgb(255, 192, 203) }, + { "plum", rgb(221, 160, 221) }, + { "powderblue", rgb(176, 224, 230) }, + { "purple", rgb(128, 0, 128) }, + { "red", rgb(255, 0, 0) }, + { "rosybrown", rgb(188, 143, 143) }, + { "royalblue", rgb( 65, 105, 225) }, + { "saddlebrown", rgb(139, 69, 19) }, + { "salmon", rgb(250, 128, 114) }, + { "sandybrown", rgb(244, 164, 96) }, + { "seagreen", rgb( 46, 139, 87) }, + { "seashell", rgb(255, 245, 238) }, + { "sienna", rgb(160, 82, 45) }, + { "silver", rgb(192, 192, 192) }, + { "skyblue", rgb(135, 206, 235) }, + { "slateblue", rgb(106, 90, 205) }, + { "slategray", rgb(112, 128, 144) }, + { "slategrey", rgb(112, 128, 144) }, + { "snow", rgb(255, 250, 250) }, + { "springgreen", rgb( 0, 255, 127) }, + { "steelblue", rgb( 70, 130, 180) }, + { "tan", rgb(210, 180, 140) }, + { "teal", rgb( 0, 128, 128) }, + { "thistle", rgb(216, 191, 216) }, + { "tomato", rgb(255, 99, 71) }, + { "transparent", 0 }, + { "turquoise", rgb( 64, 224, 208) }, + { "violet", rgb(238, 130, 238) }, + { "wheat", rgb(245, 222, 179) }, + { "white", rgb(255, 255, 255) }, + { "whitesmoke", rgb(245, 245, 245) }, + { "yellow", rgb(255, 255, 0) }, + { "yellowgreen", rgb(154, 205, 50) } +}; @@ -83,7 +83,7 @@ public: /*! Should return a PolySet of the given geometry. It's normal to return an empty PolySet if smth. is wrong, but don't return NULL unless we change the calling strategy for this method. */ - virtual class PolySet *render_polyset(render_mode_e mode, class PolySetRenderer *renderer) const = 0; + virtual class PolySet *evaluate_polyset(render_mode_e mode, class PolySetEvaluator *evaluator) const = 0; }; std::ostream &operator<<(std::ostream &stream, const AbstractNode &node); diff --git a/src/opencsgrenderer.cc b/src/opencsgrenderer.cc new file mode 100644 index 0000000..768176c --- /dev/null +++ b/src/opencsgrenderer.cc @@ -0,0 +1,138 @@ +/* + * 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 "opencsgrenderer.h" +#include "polyset.h" +#include "csgterm.h" + +class OpenCSGPrim : public OpenCSG::Primitive +{ +public: + OpenCSGPrim(OpenCSG::Operation operation, unsigned int convexity) : + OpenCSG::Primitive(operation, convexity) { } + PolySet *p; + double *m; + int csgmode; + virtual void render() { + glPushMatrix(); + glMultMatrixd(m); + p->render_surface(PolySet::COLORMODE_NONE, PolySet::csgmode_e(csgmode), m); + glPopMatrix(); + } +}; + +OpenCSGRenderer::OpenCSGRenderer(CSGChain *root_chain, CSGChain *highlights_chain, + CSGChain *background_chain, GLint *shaderinfo) + : root_chain(root_chain), highlights_chain(highlights_chain), + background_chain(background_chain), shaderinfo(shaderinfo) +{ +} + +void OpenCSGRenderer::draw(bool showfaces, bool showedges) const +{ + static int glew_initialized = 0; + if (!glew_initialized) { + glew_initialized = 1; + glewInit(); + } + if (this->root_chain) { + GLint *shaderinfo = this->shaderinfo; + if (!shaderinfo[0]) shaderinfo = NULL; + renderCSGChain(this->root_chain, showedges ? shaderinfo : NULL, false, false); + if (this->background_chain) { + renderCSGChain(this->background_chain, showedges ? shaderinfo : NULL, false, true); + } + if (this->highlights_chain) { + renderCSGChain(this->highlights_chain, showedges ? shaderinfo : NULL, true, false); + } + } +} + +void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo, + bool highlight, bool background) const +{ + std::vector<OpenCSG::Primitive*> primitives; + int j = 0; + for (int i = 0;; i++) + { + bool last = i == chain->polysets.size(); + + if (last || chain->types[i] == CSGTerm::TYPE_UNION) + { + if (j+1 != i) { + OpenCSG::render(primitives); + glDepthFunc(GL_EQUAL); + } + if (shaderinfo) + glUseProgram(shaderinfo[0]); + for (; j < i; j++) { + double *m = chain->matrices[j]; + glPushMatrix(); + glMultMatrixd(m); + int csgmode = chain->types[j] == CSGTerm::TYPE_DIFFERENCE ? PolySet::CSGMODE_DIFFERENCE : PolySet::CSGMODE_NORMAL; + if (highlight) { + chain->polysets[j]->render_surface(PolySet::COLORMODE_HIGHLIGHT, PolySet::csgmode_e(csgmode + 20), m, shaderinfo); + } else if (background) { + chain->polysets[j]->render_surface(PolySet::COLORMODE_BACKGROUND, PolySet::csgmode_e(csgmode + 10), m, shaderinfo); + } else if (m[16] >= 0 || m[17] >= 0 || m[18] >= 0 || m[19] >= 0) { + // User-defined color from source + glColor4d(m[16], m[17], m[18], m[19]); + if (shaderinfo) { + glUniform4f(shaderinfo[1], m[16], m[17], m[18], m[19]); + glUniform4f(shaderinfo[2], (m[16]+1)/2, (m[17]+1)/2, (m[18]+1)/2, 1.0); + } + chain->polysets[j]->render_surface(PolySet::COLORMODE_NONE, PolySet::csgmode_e(csgmode), m, shaderinfo); + } else if (chain->types[j] == CSGTerm::TYPE_DIFFERENCE) { + chain->polysets[j]->render_surface(PolySet::COLORMODE_CUTOUT, PolySet::csgmode_e(csgmode), m, shaderinfo); + } else { + chain->polysets[j]->render_surface(PolySet::COLORMODE_MATERIAL, PolySet::csgmode_e(csgmode), m, shaderinfo); + } + glPopMatrix(); + } + if (shaderinfo) + glUseProgram(0); + for (unsigned int k = 0; k < primitives.size(); k++) { + delete primitives[k]; + } + glDepthFunc(GL_LEQUAL); + primitives.clear(); + } + + if (last) + break; + + OpenCSGPrim *prim = new OpenCSGPrim(chain->types[i] == CSGTerm::TYPE_DIFFERENCE ? + OpenCSG::Subtraction : OpenCSG::Intersection, chain->polysets[i]->convexity); + prim->p = chain->polysets[i]; + prim->m = chain->matrices[i]; + prim->csgmode = chain->types[i] == CSGTerm::TYPE_DIFFERENCE ? PolySet::CSGMODE_DIFFERENCE : PolySet::CSGMODE_NORMAL; + if (highlight) + prim->csgmode += 20; + else if (background) + prim->csgmode += 10; + primitives.push_back(prim); + } +} diff --git a/src/opencsgrenderer.h b/src/opencsgrenderer.h new file mode 100644 index 0000000..95ffc8e --- /dev/null +++ b/src/opencsgrenderer.h @@ -0,0 +1,24 @@ +#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/openscad.cc b/src/openscad.cc index 979a68f..f3aee76 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -33,8 +33,8 @@ #include "export.h" #include "builtin.h" #include "nodedumper.h" -#include "CGALRenderer.h" -#include "PolySetCGALRenderer.h" +#include "CGALEvaluator.h" +#include "PolySetCGALEvaluator.h" #include "printutils.h" #include <string> @@ -261,8 +261,8 @@ int main(int argc, char **argv) Tree tree; // FIXME: enforce some maximum cache size (old version had 100K vertices as limit) QHash<std::string, CGAL_Nef_polyhedron> cache; - CGALRenderer cgalrenderer(cache, tree); - PolySetCGALRenderer psrenderer(cgalrenderer); + CGALEvaluator cgalevaluator(cache, tree); + PolySetCGALEvaluator psevaluator(cgalevaluator); if (stl_output_file || off_output_file || dxf_output_file) { @@ -315,7 +315,7 @@ int main(int argc, char **argv) root_node = root_module->evaluate(&root_ctx, &root_inst); tree.setRoot(root_node); - CGAL_Nef_polyhedron root_N = cgalrenderer.renderCGALMesh(*tree.root()); + CGAL_Nef_polyhedron root_N = cgalevaluator.evaluateCGALMesh(*tree.root()); QDir::setCurrent(original_path.absolutePath()); diff --git a/src/polyset.h b/src/polyset.h index 0183fd8..aae32f6 100644 --- a/src/polyset.h +++ b/src/polyset.h @@ -1,10 +1,7 @@ #ifndef POLYSET_H_ #define POLYSET_H_ -#ifdef ENABLE_OPENCSG -// this must be included before the GL headers -# include <GL/glew.h> -#endif +#include <GL/glew.h> // this must be included before the GL headers #include <qgl.h> #include "grid.h" diff --git a/src/primitives.cc b/src/primitives.cc index 7e399dc..204bb11 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -100,7 +100,7 @@ public: primitive_type_e type; int convexity; Value points, paths, triangles; - virtual PolySet *render_polyset(render_mode_e mode, class PolySetRenderer *) const; + virtual PolySet *evaluate_polyset(render_mode_e mode, class PolySetEvaluator *) const; }; AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const @@ -272,7 +272,7 @@ static void generate_circle(point2d *circle, double r, int fragments) } } -PolySet *PrimitiveNode::render_polyset(render_mode_e, class PolySetRenderer *) const +PolySet *PrimitiveNode::evaluate_polyset(render_mode_e, class PolySetEvaluator *) const { PolySet *p = new PolySet(); diff --git a/src/projection.cc b/src/projection.cc index 125607d..8497405 100644 --- a/src/projection.cc +++ b/src/projection.cc @@ -35,7 +35,7 @@ #include "export.h" #include "progress.h" #include "visitor.h" -#include "PolySetRenderer.h" +#include "PolySetEvaluator.h" #ifdef ENABLE_CGAL # include <CGAL/assertions_behaviour.h> @@ -83,10 +83,10 @@ AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstant return node; } -PolySet *ProjectionNode::render_polyset(render_mode_e mode, PolySetRenderer *renderer) const +PolySet *ProjectionNode::evaluate_polyset(render_mode_e mode, PolySetEvaluator *evaluator) const { - if (!renderer) { - PRINTF("WARNING: No suitable PolySetRenderer found for %s module!", this->name().c_str()); + if (!evaluator) { + PRINTF("WARNING: No suitable PolySetEvaluator found for %s module!", this->name().c_str()); PolySet *ps = new PolySet(); ps->is2d = true; return ps; @@ -94,7 +94,7 @@ PolySet *ProjectionNode::render_polyset(render_mode_e mode, PolySetRenderer *ren print_messages_push(); - PolySet *ps = renderer->renderPolySet(*this, mode); + PolySet *ps = evaluator->evaluatePolySet(*this, mode); print_messages_pop(); diff --git a/src/projectionnode.h b/src/projectionnode.h index 295e48c..0c32181 100644 --- a/src/projectionnode.h +++ b/src/projectionnode.h @@ -18,7 +18,7 @@ public: int convexity; bool cut_mode; - virtual PolySet *render_polyset(render_mode_e mode, class PolySetRenderer *renderer) const; + virtual PolySet *evaluate_polyset(render_mode_e mode, class PolySetEvaluator *evaluator) const; }; #endif diff --git a/src/render-opencsg.cc b/src/render-opencsg.cc.org index fe0fc60..fe0fc60 100644 --- a/src/render-opencsg.cc +++ b/src/render-opencsg.cc.org diff --git a/src/render-opencsg.h b/src/render-opencsg.h deleted file mode 100644 index 9433cbe..0000000 --- a/src/render-opencsg.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef RENDER_OPENCSG_H_ -#define RENDER_OPENCSG_H_ - -#include <GL/glew.h> - -void renderCSGChainviaOpenCSG(class CSGChain *chain, GLint *shaderinfo, bool highlight, bool background); - -#endif diff --git a/src/renderer.h b/src/renderer.h new file mode 100644 index 0000000..3c25e98 --- /dev/null +++ b/src/renderer.h @@ -0,0 +1,11 @@ +#ifndef RENDERER_H_ +#define RENDERER_H_ + +class Renderer +{ +public: + virtual ~Renderer() {} + virtual void draw(bool showfaces, bool showedges) const = 0; +}; + +#endif // RENDERER_H diff --git a/src/surface.cc b/src/surface.cc index 8bad3e5..94d039e 100644 --- a/src/surface.cc +++ b/src/surface.cc @@ -57,7 +57,7 @@ public: QString filename; bool center; int convexity; - virtual PolySet *render_polyset(render_mode_e mode, class PolySetRenderer *) const; + virtual PolySet *evaluate_polyset(render_mode_e mode, class PolySetEvaluator *) const; }; AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const @@ -92,7 +92,7 @@ void register_builtin_surface() builtin_modules["surface"] = new SurfaceModule(); } -PolySet *SurfaceNode::render_polyset(render_mode_e, class PolySetRenderer *) const +PolySet *SurfaceNode::evaluate_polyset(render_mode_e, class PolySetEvaluator *) const { PolySet *p = new PolySet(); handle_dep(filename); diff --git a/src/throwntogetherrenderer.cc b/src/throwntogetherrenderer.cc new file mode 100644 index 0000000..0a0c9c8 --- /dev/null +++ b/src/throwntogetherrenderer.cc @@ -0,0 +1,120 @@ +/* + * 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 new file mode 100644 index 0000000..09d13f3 --- /dev/null +++ b/src/throwntogetherrenderer.h @@ -0,0 +1,21 @@ +#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 |