diff options
author | kintel <kintel@b57f626f-c46c-0410-a088-ec61d464b74c> | 2010-01-15 01:00:41 (GMT) |
---|---|---|
committer | kintel <kintel@b57f626f-c46c-0410-a088-ec61d464b74c> | 2010-01-15 01:00:41 (GMT) |
commit | f2bad69cf51c6e5b278bf38a2bd7eca2163aff9b (patch) | |
tree | db30b829f246fd8e0e1b9a261c43d2eb531a7ccb | |
parent | 812e8064aa99abd168e45a7b14ec533bb30823b6 (diff) |
Started collecting GL colors in one place; added Preferences class which will become a preferences dialog, forked CGAL OGL_Helper to make colors configurable
git-svn-id: http://svn.clifford.at/openscad/trunk@301 b57f626f-c46c-0410-a088-ec61d464b74c
-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); |