diff options
| -rw-r--r-- | CGAL_renderer.h | 660 | ||||
| -rw-r--r-- | MainWindow.ui | 10 | ||||
| -rw-r--r-- | Preferences.h | 39 | ||||
| -rw-r--r-- | Preferences.ui | 199 | ||||
| -rw-r--r-- | mainwin.cc | 132 | ||||
| -rw-r--r-- | openscad.pro | 13 | ||||
| -rw-r--r-- | polyset.cc | 9 | 
7 files changed, 1003 insertions, 59 deletions
diff --git a/CGAL_renderer.h b/CGAL_renderer.h new file mode 100644 index 0000000..3c36db4 --- /dev/null +++ b/CGAL_renderer.h @@ -0,0 +1,660 @@ +// 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);  +		} + +		inline void CGAL_GLU_TESS_CALLBACK combineCallback(GLdouble coords[3], GLvoid *d[4], GLfloat w[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 diff --git a/MainWindow.ui b/MainWindow.ui index a85859a..afdb61c 100644 --- a/MainWindow.ui +++ b/MainWindow.ui @@ -142,6 +142,7 @@      <addaction name="separator"/>      <addaction name="editActionZoomIn"/>      <addaction name="editActionZoomOut"/> +    <addaction name="editActionPreferences"/>     </widget>     <widget class="QMenu" name="menu_Design">      <property name="title"> @@ -605,6 +606,11 @@      <string>Ctrl+W</string>     </property>    </action> +  <action name="editActionPreferences"> +   <property name="text"> +    <string>Preferences</string> +   </property> +  </action>    <action name="designActionFlushCaches">     <property name="text">      <string>Flush Caches</string> @@ -619,7 +625,9 @@     <container>1</container>    </customwidget>   </customwidgets> - <resources/> + <resources> +  <include location="openscad.qrc"/> + </resources>   <connections>    <connection>     <sender>fileActionQuit</sender> diff --git a/Preferences.h b/Preferences.h new file mode 100644 index 0000000..88cd590 --- /dev/null +++ b/Preferences.h @@ -0,0 +1,39 @@ +#ifndef PREFERENCES_H_ +#define PREFERENCES_H_ + +#include <QMainWindow> +#include "ui_Preferences.h" + +class Preferences : public QMainWindow, public Ui::Preferences +{ +	Q_OBJECT; + +public: +	~Preferences(); +	static Preferences *inst() { if (!instance) instance = new Preferences(); return instance; } + +	enum RenderColor { +		BACKGROUND_COLOR, +		OPENCSG_FACE_FRONT_COLOR, +		OPENCSG_FACE_BACK_COLOR, +		CGAL_FACE_FRONT_COLOR, +		CGAL_FACE_2D_COLOR, +		CGAL_FACE_BACK_COLOR, +		CGAL_EDGE_FRONT_COLOR, +		CGAL_EDGE_BACK_COLOR, +		CGAL_EDGE_2D_COLOR +	}; +	void setColor(RenderColor idx, const QColor &color) { this->colormap[idx] = color; } +	const QColor &color(RenderColor idx) { return this->colormap[idx]; } + +public slots: +	void actionTriggered(class QAction *); + +private: +	Preferences(QWidget *parent = NULL); +	QMap<RenderColor, QColor> colormap; + +	static Preferences *instance; +}; + +#endif diff --git a/Preferences.ui b/Preferences.ui new file mode 100644 index 0000000..3a2f127 --- /dev/null +++ b/Preferences.ui @@ -0,0 +1,199 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Preferences</class> + <widget class="QMainWindow" name="Preferences"> +  <property name="geometry"> +   <rect> +    <x>0</x> +    <y>0</y> +    <width>435</width> +    <height>362</height> +   </rect> +  </property> +  <property name="windowTitle"> +   <string>Preferences</string> +  </property> +  <property name="unifiedTitleAndToolBarOnMac"> +   <bool>true</bool> +  </property> +  <widget class="QWidget" name="centralwidget"> +   <layout class="QVBoxLayout" name="verticalLayout"> +    <item> +     <widget class="QStackedWidget" name="stackedWidget"> +      <property name="currentIndex"> +       <number>0</number> +      </property> +      <widget class="QWidget" name="page3DView"> +       <layout class="QVBoxLayout" name="verticalLayout_2"> +        <property name="margin"> +         <number>0</number> +        </property> +        <item> +         <layout class="QHBoxLayout" name="horizontalLayout"> +          <item> +           <widget class="QLabel" name="label"> +            <property name="text"> +             <string>Background color:</string> +            </property> +           </widget> +          </item> +          <item> +           <spacer name="horizontalSpacer"> +            <property name="orientation"> +             <enum>Qt::Horizontal</enum> +            </property> +            <property name="sizeHint" stdset="0"> +             <size> +              <width>40</width> +              <height>20</height> +             </size> +            </property> +           </spacer> +          </item> +         </layout> +        </item> +        <item> +         <spacer name="verticalSpacer"> +          <property name="orientation"> +           <enum>Qt::Vertical</enum> +          </property> +          <property name="sizeHint" stdset="0"> +           <size> +            <width>20</width> +            <height>241</height> +           </size> +          </property> +         </spacer> +        </item> +       </layout> +      </widget> +      <widget class="QWidget" name="pageAdvanced"> +       <layout class="QVBoxLayout" name="verticalLayout_3"> +        <property name="margin"> +         <number>0</number> +        </property> +        <item> +         <spacer name="verticalSpacer_2"> +          <property name="orientation"> +           <enum>Qt::Vertical</enum> +          </property> +          <property name="sizeHint" stdset="0"> +           <size> +            <width>20</width> +            <height>120</height> +           </size> +          </property> +         </spacer> +        </item> +        <item> +         <layout class="QHBoxLayout" name="horizontalLayout_2"> +          <item> +           <spacer name="horizontalSpacer_2"> +            <property name="orientation"> +             <enum>Qt::Horizontal</enum> +            </property> +            <property name="sizeHint" stdset="0"> +             <size> +              <width>40</width> +              <height>20</height> +             </size> +            </property> +           </spacer> +          </item> +          <item> +           <widget class="QLabel" name="label_2"> +            <property name="text"> +             <string>advanced</string> +            </property> +           </widget> +          </item> +          <item> +           <spacer name="horizontalSpacer_3"> +            <property name="orientation"> +             <enum>Qt::Horizontal</enum> +            </property> +            <property name="sizeHint" stdset="0"> +             <size> +              <width>40</width> +              <height>20</height> +             </size> +            </property> +           </spacer> +          </item> +         </layout> +        </item> +        <item> +         <spacer name="verticalSpacer_3"> +          <property name="orientation"> +           <enum>Qt::Vertical</enum> +          </property> +          <property name="sizeHint" stdset="0"> +           <size> +            <width>20</width> +            <height>120</height> +           </size> +          </property> +         </spacer> +        </item> +       </layout> +      </widget> +     </widget> +    </item> +   </layout> +  </widget> +  <widget class="QToolBar" name="toolBar"> +   <property name="windowTitle"> +    <string>toolBar</string> +   </property> +   <property name="movable"> +    <bool>false</bool> +   </property> +   <property name="allowedAreas"> +    <set>Qt::TopToolBarArea</set> +   </property> +   <property name="toolButtonStyle"> +    <enum>Qt::ToolButtonTextUnderIcon</enum> +   </property> +   <property name="floatable"> +    <bool>false</bool> +   </property> +   <attribute name="toolBarArea"> +    <enum>TopToolBarArea</enum> +   </attribute> +   <attribute name="toolBarBreak"> +    <bool>false</bool> +   </attribute> +   <addaction name="prefsAction3DView"/> +   <addaction name="prefsActionAdvanced"/> +  </widget> +  <action name="prefsAction3DView"> +   <property name="checkable"> +    <bool>true</bool> +   </property> +   <property name="icon"> +    <iconset resource="openscad.qrc"> +     <normaloff>:/prefs3DView.png</normaloff> +     <normalon>:/openscad.ico</normalon>:/prefs3DView.png</iconset> +   </property> +   <property name="text"> +    <string>3D View</string> +   </property> +  </action> +  <action name="prefsActionAdvanced"> +   <property name="checkable"> +    <bool>true</bool> +   </property> +   <property name="icon"> +    <iconset resource="openscad.qrc"> +     <normaloff>:/prefsAdvanced.png</normaloff>:/prefsAdvanced.png</iconset> +   </property> +   <property name="text"> +    <string>Advanced</string> +   </property> +  </action> + </widget> + <resources> +  <include location="openscad.qrc"/> + </resources> + <connections/> +</ui> @@ -22,6 +22,7 @@  #include "openscad.h"  #include "MainWindow.h" +#include "Preferences.h"  #include "printutils.h"  #include <QMenu> @@ -50,6 +51,13 @@  #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' @@ -64,8 +72,12 @@  #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 +#endif // ENABLE_CGAL  #define QUOTE(x__) # x__  #define QUOTED(x__) QUOTE(x__) @@ -88,7 +100,6 @@ MainWindow::MainWindow(const char *filename)  {  	setupUi(this); -  	root_ctx.functions_p = &builtin_functions;  	root_ctx.modules_p = &builtin_modules;  	root_ctx.set_variable("$fn", Value(0.0)); @@ -110,8 +121,8 @@ MainWindow::MainWindow(const char *filename)  	root_norm_term = NULL;  	root_chain = NULL;  #ifdef ENABLE_CGAL -	root_N = NULL; -	recreate_cgal_ogl_p = false; +	this->root_N = NULL; +	this->recreate_cgal_ogl_p = false;  	cgal_ogl_p = NULL;  	cgal_ogl_ps = NULL;  #endif @@ -180,6 +191,7 @@ MainWindow::MainWindow(const char *filename)  	connect(this->editActionZoomIn, SIGNAL(triggered()), editor, SLOT(zoomIn()));  	connect(this->editActionZoomOut, SIGNAL(triggered()), editor, SLOT(zoomOut()));  	connect(this->editActionHide, SIGNAL(triggered()), this, SLOT(hideEditor())); +	connect(this->editActionPreferences, SIGNAL(triggered()), this, SLOT(preferences()));  	// Design menu  	connect(this->designActionReloadAndCompile, SIGNAL(triggered()), this, SLOT(actionReloadCompile())); @@ -288,10 +300,10 @@ MainWindow::~MainWindow()  	if (root_node)  		delete root_node;  #ifdef ENABLE_CGAL -	if (root_N) -		delete root_N; +	if (this->root_N) +		delete this->root_N;  	if (cgal_ogl_p) { -		CGAL::OGL::Polyhedron *p = (CGAL::OGL::Polyhedron*)cgal_ogl_p; +		Polyhedron *p = (Polyhedron*)cgal_ogl_p;  		delete p;  	}  	if (cgal_ogl_ps) @@ -916,10 +928,10 @@ void MainWindow::actionRenderCGAL()  	if (!root_module || !root_node)  		return; -	if (root_N) { -		delete root_N; -		root_N = NULL; -		recreate_cgal_ogl_p = true; +	if (this->root_N) { +		delete this->root_N; +		this->root_N = NULL; +		this->recreate_cgal_ogl_p = true;  	}  	PRINT("Rendering Polygon Mesh using CGAL..."); @@ -935,51 +947,51 @@ void MainWindow::actionRenderCGAL()  	QApplication::processEvents();  	progress_report_prep(root_node, report_func, pd); -	root_N = new CGAL_Nef_polyhedron(root_node->render_cgal_nef_polyhedron()); +	this->root_N = new CGAL_Nef_polyhedron(root_node->render_cgal_nef_polyhedron());  	progress_report_fin();  	PRINTF("Number of vertices currently in CGAL cache: %d", AbstractNode::cgal_nef_cache.totalCost());  	PRINTF("Number of objects currently in CGAL cache: %d", AbstractNode::cgal_nef_cache.size());  	QApplication::processEvents(); -	if (root_N->dim == 2) { +	if (this->root_N->dim == 2) {  		PRINTF("   Top level object is a 2D object:");  		QApplication::processEvents(); -		PRINTF("   Empty:      %6s", root_N->p2.is_empty() ? "yes" : "no"); +		PRINTF("   Empty:      %6s", this->root_N->p2.is_empty() ? "yes" : "no");  		QApplication::processEvents(); -		PRINTF("   Plane:      %6s", root_N->p2.is_plane() ? "yes" : "no"); +		PRINTF("   Plane:      %6s", this->root_N->p2.is_plane() ? "yes" : "no");  		QApplication::processEvents(); -		PRINTF("   Vertices:   %6d", (int)root_N->p2.explorer().number_of_vertices()); +		PRINTF("   Vertices:   %6d", (int)this->root_N->p2.explorer().number_of_vertices());  		QApplication::processEvents(); -		PRINTF("   Halfedges:  %6d", (int)root_N->p2.explorer().number_of_halfedges()); +		PRINTF("   Halfedges:  %6d", (int)this->root_N->p2.explorer().number_of_halfedges());  		QApplication::processEvents(); -		PRINTF("   Edges:      %6d", (int)root_N->p2.explorer().number_of_edges()); +		PRINTF("   Edges:      %6d", (int)this->root_N->p2.explorer().number_of_edges());  		QApplication::processEvents(); -		PRINTF("   Faces:      %6d", (int)root_N->p2.explorer().number_of_faces()); +		PRINTF("   Faces:      %6d", (int)this->root_N->p2.explorer().number_of_faces());  		QApplication::processEvents(); -		PRINTF("   FaceCycles: %6d", (int)root_N->p2.explorer().number_of_face_cycles()); +		PRINTF("   FaceCycles: %6d", (int)this->root_N->p2.explorer().number_of_face_cycles());  		QApplication::processEvents(); -		PRINTF("   ConnComp:   %6d", (int)root_N->p2.explorer().number_of_connected_components()); +		PRINTF("   ConnComp:   %6d", (int)this->root_N->p2.explorer().number_of_connected_components());  		QApplication::processEvents();  	} -	if (root_N->dim == 3) { +	if (this->root_N->dim == 3) {  		PRINTF("   Top level object is a 3D object:"); -		PRINTF("   Simple:     %6s", root_N->p3.is_simple() ? "yes" : "no"); +		PRINTF("   Simple:     %6s", this->root_N->p3.is_simple() ? "yes" : "no");  		QApplication::processEvents(); -		PRINTF("   Valid:      %6s", root_N->p3.is_valid() ? "yes" : "no"); +		PRINTF("   Valid:      %6s", this->root_N->p3.is_valid() ? "yes" : "no");  		QApplication::processEvents(); -		PRINTF("   Vertices:   %6d", (int)root_N->p3.number_of_vertices()); +		PRINTF("   Vertices:   %6d", (int)this->root_N->p3.number_of_vertices());  		QApplication::processEvents(); -		PRINTF("   Halfedges:  %6d", (int)root_N->p3.number_of_halfedges()); +		PRINTF("   Halfedges:  %6d", (int)this->root_N->p3.number_of_halfedges());  		QApplication::processEvents(); -		PRINTF("   Edges:      %6d", (int)root_N->p3.number_of_edges()); +		PRINTF("   Edges:      %6d", (int)this->root_N->p3.number_of_edges());  		QApplication::processEvents(); -		PRINTF("   Halffacets: %6d", (int)root_N->p3.number_of_halffacets()); +		PRINTF("   Halffacets: %6d", (int)this->root_N->p3.number_of_halffacets());  		QApplication::processEvents(); -		PRINTF("   Facets:     %6d", (int)root_N->p3.number_of_facets()); +		PRINTF("   Facets:     %6d", (int)this->root_N->p3.number_of_facets());  		QApplication::processEvents(); -		PRINTF("   Volumes:    %6d", (int)root_N->p3.number_of_volumes()); +		PRINTF("   Volumes:    %6d", (int)this->root_N->p3.number_of_volumes());  		QApplication::processEvents();  	} @@ -996,7 +1008,6 @@ void MainWindow::actionRenderCGAL()  	delete pd;  	current_win = NULL; -  }  #endif /* ENABLE_CGAL */ @@ -1054,19 +1065,19 @@ void MainWindow::actionExportSTLorOFF(bool)  #ifdef ENABLE_CGAL  	current_win = this; -	if (!root_N) { +	if (!this->root_N) {  		PRINT("Nothing to export! Try building first (press F6).");  		current_win = NULL;  		return;  	} -	if (root_N->dim != 3) { +	if (this->root_N->dim != 3) {  		PRINT("Current top level object is not a 3D object.");  		current_win = NULL;  		return;  	} -	if (!root_N->p3.is_simple()) { +	if (!this->root_N->p3.is_simple()) {  		PRINT("Object isn't a valid 2-manifold! Modify your design..");  		current_win = NULL;  		return; @@ -1083,16 +1094,16 @@ void MainWindow::actionExportSTLorOFF(bool)  	QProgressDialog *pd = new QProgressDialog(  			stl_mode ? "Exporting object to STL file..." : "Exporting object to OFF file...", -			QString(), 0, root_N->p3.number_of_facets() + 1); +			QString(), 0, this->root_N->p3.number_of_facets() + 1);  	pd->setValue(0);  	pd->setAutoClose(false);  	pd->show();  	QApplication::processEvents();  	if (stl_mode) -		export_stl(root_N, stl_filename, pd); +		export_stl(this->root_N, stl_filename, pd);  	else -		export_off(root_N, stl_filename, pd); +		export_off(this->root_N, stl_filename, pd);  	PRINTF("%s export finished.", stl_mode ? "STL" : "OFF"); @@ -1117,13 +1128,13 @@ void MainWindow::actionExportDXF()  #ifdef ENABLE_CGAL  	current_win = this; -	if (!root_N) { +	if (!this->root_N) {  		PRINT("Nothing to export! Try building first (press F6).");  		current_win = NULL;  		return;  	} -	if (root_N->dim != 2) { +	if (this->root_N->dim != 2) {  		PRINT("Current top level object is not a 2D object.");  		current_win = NULL;  		return; @@ -1137,7 +1148,7 @@ void MainWindow::actionExportDXF()  		return;  	} -	export_dxf(root_N, stl_filename, NULL); +	export_dxf(this->root_N, stl_filename, NULL);  	PRINTF("DXF export finished.");  	current_win = NULL; @@ -1206,6 +1217,7 @@ static void renderCSGChainviaOpenCSG(CSGChain *chain, GLint *shaderinfo, bool hi  				} 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]); @@ -1301,14 +1313,15 @@ static void renderGLviaCGAL(void *vp)  	MainWindow *m = (MainWindow*)vp;  	if (m->recreate_cgal_ogl_p) {  		m->recreate_cgal_ogl_p = false; -		CGAL::OGL::Polyhedron *p = (CGAL::OGL::Polyhedron*)m->cgal_ogl_p; +		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 && m->root_N->dim == 2) +	if (!m->root_N) return; +	if (m->root_N->dim == 2)  	{  		if (m->cgal_ogl_ps == NULL) {  			DxfData dd(*m->root_N); @@ -1317,8 +1330,10 @@ static void renderGLviaCGAL(void *vp)  			dxf_tesselate(m->cgal_ogl_ps, &dd, 0, true, false, 0);  		} +		// Draw 2D polygons  		glDisable(GL_LIGHTING); -		glColor3d(0.0, 0.75, 0.6); +		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); @@ -1335,10 +1350,12 @@ static void renderGLviaCGAL(void *vp)  		typedef Explorer::Point Point;  		Explorer E = m->root_N->p2.explorer(); +		// Draw 2D edges  		glDisable(GL_DEPTH_TEST);  		glDisable(GL_LIGHTING);  		glLineWidth(2); -		glColor3d(0.0, 0.0, 0.0); +		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(), fend = E.faces_end(); fit != fend; ++fit) @@ -1366,22 +1383,30 @@ static void renderGLviaCGAL(void *vp)  		glEnable(GL_DEPTH_TEST);  	} -	if (m->root_N && m->root_N->dim == 3) +	else if (m->root_N->dim == 3)  	{ -		CGAL::OGL::Polyhedron *p = (CGAL::OGL::Polyhedron*)m->cgal_ogl_p; +		Polyhedron *p = (Polyhedron*)m->cgal_ogl_p;  		if (!p) { -			m->cgal_ogl_p = p = new CGAL::OGL::Polyhedron(); -			CGAL::OGL::Nef3_Converter<CGAL_Nef_polyhedron3>::convert_to_OGLPolyhedron(m->root_N->p3, 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(CGAL::OGL::SNC_BOUNDARY); +			p->set_style(SNC_BOUNDARY);  		if (m->viewActionCGALGrid->isChecked()) -			p->set_style(CGAL::OGL::SNC_SKELETON); +			p->set_style(SNC_SKELETON);  #if 0  		p->draw();  #else -		if (p->style == CGAL::OGL::SNC_BOUNDARY) { +		if (p->style == SNC_BOUNDARY) {  			glCallList(p->object_list_+2);  			if (m->viewActionShowEdges->isChecked()) {  				glDisable(GL_LIGHTING); @@ -1709,3 +1734,8 @@ void MainWindow::closeEvent(QCloseEvent *event)  	}  } +void +MainWindow::preferences() +{ +	Preferences::inst()->show(); +} diff --git a/openscad.pro b/openscad.pro index 0216876..7e7ca16 100644 --- a/openscad.pro +++ b/openscad.pro @@ -1,6 +1,7 @@  isEmpty(VERSION) VERSION = $$system(date "+%Y.%m.%d")  DEFINES += OPENSCAD_VERSION=$$VERSION  TEMPLATE = app +RESOURCES = openscad.qrc  macx {    TARGET = OpenSCAD @@ -18,7 +19,7 @@ QT += opengl  # Application configuration  CONFIG += debug  # CONFIG += release -# CONFIG += mdi +CONFIG += mdi  CONFIG += cgal  CONFIG += opencsg @@ -74,12 +75,15 @@ QMAKE_CXXFLAGS_DEBUG = -O0 -ggdb  LEXSOURCES += lexer.l  YACCSOURCES += parser.y -FORMS   += MainWindow.ui +FORMS   += MainWindow.ui \ +           Preferences.ui  HEADERS += openscad.h \             MainWindow.h \ +           Preferences.h \             GLView.h \ -           printutils.h +           printutils.h \ +           CGAL_renderer.h  macx: HEADERS += EventFilter.h @@ -90,7 +94,8 @@ SOURCES += openscad.cc mainwin.cc glview.cc export.cc \             import.cc dxfdata.cc dxftess.cc dxftess-glu.cc \             dxftess-cgal.cc dxfdim.cc \             dxflinextrude.cc dxfrotextrude.cc highlighter.cc \ -           printutils.cc nef2dxf.cc +           printutils.cc nef2dxf.cc \ +           Preferences.cc  target.path = /usr/local/bin/  INSTALLS += target @@ -22,6 +22,7 @@  #include "openscad.h"  #include "printutils.h" +#include "Preferences.h"  QCache<QString,PolySet::ps_cache_entry> PolySet::ps_cache(100); @@ -133,16 +134,18 @@ void PolySet::render_surface(colormode_e colormode, csgmode_e csgmode, double *m  	bool mirrored = m_scale_rotate_det < 0;  	if (colormode == COLORMODE_MATERIAL) { -		glColor3ub(249, 215, 44); +		const QColor &col = Preferences::inst()->color(Preferences::OPENCSG_FACE_FRONT_COLOR); +		glColor3f(col.redF(), col.greenF(), col.blueF());  #ifdef ENABLE_OPENCSG  		if (shaderinfo) { -			glUniform4f(shaderinfo[1], 249 / 255.0, 215 / 255.0, 44 / 255.0, 1.0); +			glUniform4f(shaderinfo[1], col.redF(), col.greenF(), col.blueF(), 1.0f);  			glUniform4f(shaderinfo[2], 255 / 255.0, 236 / 255.0, 94 / 255.0, 1.0);  		}  #endif /* ENABLE_OPENCSG */  	}  	if (colormode == COLORMODE_CUTOUT) { -		glColor3ub(157, 203, 81); +		const QColor &col = Preferences::inst()->color(Preferences::OPENCSG_FACE_BACK_COLOR); +		glColor3f(col.redF(), col.greenF(), col.blueF());  #ifdef ENABLE_OPENCSG  		if (shaderinfo) {  			glUniform4f(shaderinfo[1], 157 / 255.0, 203 / 255.0, 81 / 255.0, 1.0);  | 
