diff options
31 files changed, 258 insertions, 105 deletions
diff --git a/RELEASE_NOTES b/RELEASE_NOTES index f25de79..2681482 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -14,7 +14,7 @@ o Strings can now be lexographically compared using the <, <=, >, >= operators  o The version() function will return the OpenSCAD version as a vector, e.g. [2011, 09]  o The version_num() function will return the OpenSCAD version as a number, e.g. 20110923  o Added PI constant. -o Now uses standard shortcuts for save and reload on Linux and Windows. F2/F3 will still work but is deprecated. +o Now uses standard shortcuts for save, reload and quit on Linux and Windows. F2/F3 will still work but is deprecated.  o Number literals in scientific notation are now accepted by the parser  o Added len() function. Takes one vector or string parameter and returns its length.  o The index operator [] now works on strings @@ -26,6 +26,7 @@ o STL export should be a bit more robust  o Dropping a file into the editor under Windows didn't work (double C:/C:/ problem)  o On some platforms it was possible to insertion rich text in the editor, causing confusion.  o Less crashes due to CGAL assertions +o OpenCSG should now work on systems with OpenGL 1.x, given that the right extensions are available  Deprecations:  o dxf_linear_extrude() and dxf_rotate_extrude() are now deprecated. diff --git a/contrib/scad.el b/contrib/scad.el index 1e5c9b5..912b7ae 100644 --- a/contrib/scad.el +++ b/contrib/scad.el @@ -3,7 +3,7 @@  ;; Author:     Len Trigg  ;; Maintainer: Len Trigg <lenbok@gmail.com>  ;; Created:    March 2010 -;; Modified:   March 2010 +;; Modified:   November 2011  ;; Version:    $Revision: 88 $  ;; This program is free software; you can redistribute it and/or modify @@ -38,6 +38,12 @@  ;;; Autoload mode trigger  (add-to-list 'auto-mode-alist '("\\.scad$" . scad-mode)) +(defcustom scad-command +  '"openscad" +  "Path to openscad executable" +  :type 'string +  ) +  (defcustom scad-keywords    '("return" "true" "false")    "SCAD keywords." @@ -45,25 +51,32 @@    :group 'scad-font-lock)  (defcustom scad-functions -  '("cos" "acos" "sin" "asin" "tan" "atan"  -    "pow" "log" "ln" -    "abs" "min" "max" "sqrt" "round" "ceil" "floor" "lookup"  +  '("cos" "acos" "sin" "asin" "tan" "atan" "atan2"                      ;;func.cc +    "abs" "sign" "rands" "min" "max"  +    "round" "ceil" "floor"  +    "pow" "sqrt" "exp" "log" "ln"      "str"  -    "dxf_dim" "dxf_cross" +    "lookup" "version" "version_num" +    "dxf_dim" "dxf_cross"                                               ;;dxfdim.cc      )    "SCAD functions."    :type 'list    :group 'scad-font-lock)  (defcustom scad-modules -  '("for" "if" "assign" "intersection_for" -    "echo" -    "cube" "sphere" "cylinder" "polyhedron"  -    "scale" "rotate" "translate" "mirror" "multmatrix" "color" -    "union" "difference" "intersection" "render" "surface" -    "square" "circle" "polygon" "dxf_linear_extrude" "linear_extrude" "dxf_rotate_extrude" "rotate_extrude" -    "import_stl" "import_off" "import_dxf" "group" -    "projection" "minkowski" "glide" "subdiv" "child" +  '("child" "echo" "assign" "for" "intersection_for" "if"               ;;control.cc +    "cube" "sphere" "cylinder" "polyhedron" "square" "circle" "polygon" ;;primitives.cc +    "scale" "rotate" "translate" "mirror" "multmatrix"                  ;;transform.cc +    "union" "difference" "intersection"                                 ;;csgops.cc +    "render"                                                            ;;render.cc +    "color"                                                             ;;color.cc +    "surface"                                                           ;;surface.cc +    "dxf_linear_extrude" "linear_extrude"                               ;;linearextrude.cc +    "dxf_rotate_extrude" "rotate_extrude"                               ;;rotateextrude.cc +    "import_stl" "import_off" "import_dxf" "import"                     ;;import.cc +    "group"                                                             ;;builtin.cc +    "projection"                                                        ;;projection.cc +    "minkowski" "glide" "subdiv" "hull"                                 ;;cgaladv.cc      )    "SCAD modules."    :type 'list @@ -81,6 +94,7 @@  (defvar scad-mode-map    (let ((map (make-sparse-keymap)))      (define-key map "\t" 'scad-indent-line) +    (define-key map [(control c) (control o)] 'scad-open-current-buffer)      (define-key map [return] 'newline-and-indent)       map)    "Keymap for `scad-mode'.") @@ -200,6 +214,9 @@             )))        (- open-count close-count)))) +(defun scad-open-current-buffer () +  (interactive) +  (call-process scad-command nil 0 nil (buffer-file-name)))  (provide 'scad)  ;;; scad.el ends here diff --git a/doc/TODO.txt b/doc/TODO.txt index a456c6a..4212c21 100644 --- a/doc/TODO.txt +++ b/doc/TODO.txt @@ -58,7 +58,6 @@ o MDI    - currentPath is global but is used by each document, e.g. parser      and handle_dep.  o 3D View -  - OpenGL 2.0 test: What, exactly, is needed from OpenGL 2.0? Can we use 1.x with extensions?    - Improve mouse rotation/zoom/pan    - Add modifier key combos to handle pan and zoom on 1 mouse button systems    - Show grid @@ -253,9 +252,12 @@ o define modules  o define functions  o built-in variables and constants (builtin-tests.scad)  o Write a regression test for the hexagonal cylinder orientation issue +o Caching +  - Test that caching is actually performed (speedup + same results) +  - Test the modifier characters correctly influence the cache (also when +    added/removed)  o other tests    - export    - cmd-line tests    - leaf nodes having children, e.g. cube() cylinder(); -  - caching    - dependency tracking diff --git a/scripts/publish-macosx.sh b/scripts/publish-macosx.sh index 088e64e..2036e3b 100755 --- a/scripts/publish-macosx.sh +++ b/scripts/publish-macosx.sh @@ -3,6 +3,9 @@  VERSION=`date "+%Y.%m.%d"`  #VERSION=2011.06 +# Turn off ccache, just for safety +PATH=${PATH//\/opt\/local\/libexec\/ccache:} +  # This is the same location as DEPLOYDIR in macosx-build-dependencies.sh  export MACOSX_DEPLOY_DIR=$PWD/../libraries/install diff --git a/src/GLView.h b/src/GLView.h index 3a36a15..c31e7af 100644 --- a/src/GLView.h +++ b/src/GLView.h @@ -79,8 +79,10 @@ private:  	void normalizeAngle(GLdouble& angle);  #ifdef ENABLE_OPENCSG +  bool is_opencsg_capable; +  bool has_shaders;  private slots: -	void display_opengl20_warning(); +	void display_opencsg_warning();  #endif  signals: diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 4d5ff22..dc73c05 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -270,6 +270,9 @@     <property name="text">      <string>&Quit</string>     </property> +   <property name="shortcut"> +    <string>Ctrl+Q</string> +   </property>    </action>    <action name="editActionUndo">     <property name="text"> diff --git a/src/Preferences.cc b/src/Preferences.cc index eb6af61..d240a9f 100644 --- a/src/Preferences.cc +++ b/src/Preferences.cc @@ -98,8 +98,8 @@ Preferences::Preferences(QWidget *parent) : QMainWindow(parent)  					this, SLOT(fontFamilyChanged(const QString &)));  	connect(this->fontSize, SIGNAL(editTextChanged(const QString &)),  					this, SLOT(fontSizeChanged(const QString &))); -	connect(this->OpenGL20WarningCheckbox, SIGNAL(clicked(bool)), -					this, SLOT(OpenGL20WarningChanged(bool))); +	connect(this->openCSGWarningBox, SIGNAL(clicked(bool)), +					this, SLOT(openCSGWarningChanged(bool)));  	updateGUI();  } @@ -151,7 +151,7 @@ void Preferences::fontSizeChanged(const QString &size)  }  void -Preferences::OpenGL20WarningChanged(bool state) +Preferences::openCSGWarningChanged(bool state)  {  	QSettings settings;  	settings.setValue("editor/opengl20_warning_show",state); @@ -215,8 +215,7 @@ void Preferences::updateGUI()  		this->fontSize->setEditText(fontsize);  	} -	bool opengl20_warning_show = getValue("editor/opengl20_warning_show").toBool(); -	this->OpenGL20WarningCheckbox->setChecked(opengl20_warning_show); +	this->openCSGWarningBox->setChecked(getValue("editor/opengl20_warning_show").toBool());  }  void Preferences::apply() const diff --git a/src/Preferences.h b/src/Preferences.h index 79fa7ab..bdc707d 100644 --- a/src/Preferences.h +++ b/src/Preferences.h @@ -34,7 +34,7 @@ public slots:  	void colorSchemeChanged();  	void fontFamilyChanged(const QString &);  	void fontSizeChanged(const QString &); -	void OpenGL20WarningChanged(bool); +	void openCSGWarningChanged(bool);  signals:  	void requestRedraw() const; diff --git a/src/Preferences.ui b/src/Preferences.ui index 2ab7646..556172c 100644 --- a/src/Preferences.ui +++ b/src/Preferences.ui @@ -6,7 +6,7 @@     <rect>      <x>0</x>      <y>0</y> -    <width>384</width> +    <width>418</width>      <height>243</height>     </rect>    </property> @@ -21,7 +21,7 @@      <item>       <widget class="QStackedWidget" name="stackedWidget">        <property name="currentIndex"> -       <number>1</number> +       <number>2</number>        </property>        <widget class="QWidget" name="page3DView">         <layout class="QVBoxLayout" name="verticalLayout_4"> @@ -181,9 +181,9 @@          <item>           <layout class="QVBoxLayout" name="verticalLayout_6">            <item> -           <widget class="QCheckBox" name="OpenGL20WarningCheckbox"> +           <widget class="QCheckBox" name="openCSGWarningBox">              <property name="text"> -             <string>Show OpenGL 2.0 warning && rendering info</string> +             <string>Show OpenCSG capability warning</string>              </property>             </widget>            </item> @@ -239,7 +239,7 @@      <bool>true</bool>     </property>     <property name="icon"> -    <iconset resource="openscad.qrc"> +    <iconset>       <normaloff>:/icons/prefs3DView.png</normaloff>:/icons/prefs3DView.png</iconset>     </property>     <property name="text"> @@ -251,7 +251,7 @@      <bool>true</bool>     </property>     <property name="icon"> -    <iconset resource="openscad.qrc"> +    <iconset>       <normaloff>:/icons/prefsAdvanced.png</normaloff>:/icons/prefsAdvanced.png</iconset>     </property>     <property name="text"> @@ -263,7 +263,7 @@      <bool>true</bool>     </property>     <property name="icon"> -    <iconset resource="openscad.qrc"> +    <iconset>       <normaloff>:/icons/prefsEditor.png</normaloff>:/icons/prefsEditor.png</iconset>     </property>     <property name="text"> diff --git a/src/ThrownTogetherRenderer.cc b/src/ThrownTogetherRenderer.cc index 01c7513..336c4c7 100644 --- a/src/ThrownTogetherRenderer.cc +++ b/src/ThrownTogetherRenderer.cc @@ -30,6 +30,8 @@  #include "system-gl.h" +#include <boost/unordered_map.hpp> +  ThrownTogetherRenderer::ThrownTogetherRenderer(CSGChain *root_chain,   																							 CSGChain *highlights_chain,  																							 CSGChain *background_chain) @@ -60,9 +62,9 @@ void ThrownTogetherRenderer::renderCSGChain(CSGChain *chain, bool highlight,  																						bool fberror) const  {  	glDepthFunc(GL_LEQUAL); -	QHash<QPair<PolySet*,Transform3d*>,int> polySetVisitMark; +	boost::unordered_map<std::pair<PolySet*,Transform3d*>,int> polySetVisitMark;  	for (size_t i = 0; i < chain->polysets.size(); i++) { -		if (polySetVisitMark[QPair<PolySet*,Transform3d*>(chain->polysets[i].get(), &chain->matrices[i])]++ > 0) +		if (polySetVisitMark[std::make_pair(chain->polysets[i].get(), &chain->matrices[i])]++ > 0)  			continue;  		const Transform3d &m = chain->matrices[i];  		double *c = chain->colors[i]; diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc index a587987..cf5b75d 100644 --- a/src/dxftess-cgal.cc +++ b/src/dxftess-cgal.cc @@ -25,6 +25,8 @@ typedef CDT::Point CDTPoint;  #include <CGAL/Mesh_2/Face_badness.h> +#include <boost/unordered_map.hpp> +  template <class T> class DummyCriteria {  public:  	typedef double Quality; @@ -51,7 +53,7 @@ struct point_info_t  	double x, y;  	int pathidx, pointidx;  	int max_pointidx_in_path; -	QList<int> triangles; +	std::vector<int> triangles;  	struct point_info_t *neigh_next;  	struct point_info_t *neigh_prev; @@ -61,10 +63,11 @@ struct point_info_t  	point_info_t() : x(0), y(0), pathidx(-1), pointidx(-1), max_pointidx_in_path(-1) { }  }; -typedef QPair<point_info_t*,point_info_t*> edge_t; +typedef std::pair<point_info_t*,point_info_t*> edge_t; -void mark_inner_outer(QList<struct triangle> &tri, Grid2d<point_info_t> &point_info, -		QHash<edge_t,int> &edge_to_triangle, QHash<edge_t,int> &edge_to_path, int idx, bool inner) +void mark_inner_outer(std::vector<struct triangle> &tri, Grid2d<point_info_t> &point_info, +											boost::unordered_map<edge_t,int> &edge_to_triangle, +											boost::unordered_map<edge_t,int> &edge_to_path, int idx, bool inner)  {  	if (tri[idx].is_marked)  		return; @@ -85,8 +88,8 @@ void mark_inner_outer(QList<struct triangle> &tri, Grid2d<point_info_t> &point_i  	};  	for (int i = 0; i < 3; i++) { -		if (edge_to_triangle.contains(edges[i])) { -			bool next_inner = edge_to_path.contains(edges[i]) ? !inner : inner; +		if (edge_to_triangle.find(edges[i]) != edge_to_triangle.end()) { +			bool next_inner = (edge_to_path.find(edges[i]) != edge_to_path.end()) ? !inner : inner;  			mark_inner_outer(tri, point_info, edge_to_triangle, edge_to_path,  					edge_to_triangle[edges[i]], next_inner);  		} @@ -97,10 +100,10 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool /* do_tr  {  	CDT cdt; -	QList<struct triangle> tri; +	std::vector<struct triangle> tri;  	Grid2d<point_info_t> point_info(GRID_FINE); -	QHash<edge_t,int> edge_to_triangle; -	QHash<edge_t,int> edge_to_path; +	boost::unordered_map<edge_t,int> edge_to_triangle; +	boost::unordered_map<edge_t,int> edge_to_path;  	CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);  	try { @@ -177,14 +180,14 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool /* do_tr  			continue;  		int idx = tri.size(); -		tri.append(triangle()); +		tri.push_back(triangle());  		point_info_t *pi[3];  		for (int i=0; i<3; i++) {  			double px = iter->vertex(i)->point()[0];  			double py = iter->vertex(i)->point()[1];  			pi[i] = &point_info.align(px, py); -			pi[i]->triangles.append(idx); +			pi[i]->triangles.push_back(idx);  			tri[idx].p[i].x = px;  			tri[idx].p[i].y = py;  		} @@ -200,7 +203,7 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool /* do_tr  		double far_left_x = 0;  		struct point_info_t *far_left_p = NULL; -		for (int i = 0; i < tri.size(); i++) +		for (size_t i = 0; i < tri.size(); i++)  		{  			if (tri[i].is_marked)  				continue; @@ -219,7 +222,7 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool /* do_tr  			break;  		// find one inner triangle and run recursive marking -		for (int i = 0; i < far_left_p->triangles.size(); i++) +		for (size_t i = 0; i < far_left_p->triangles.size(); i++)  		{  			int idx = far_left_p->triangles[i]; @@ -273,7 +276,7 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool /* do_tr  		// far left point is in the middle of a vertical segment  		// -> it is ok to use any unmarked triangle connected to this point -		for (int i = 0; i < far_left_p->triangles.size(); i++) +		for (size_t i = 0; i < far_left_p->triangles.size(); i++)  		{  			int idx = far_left_p->triangles[i]; @@ -288,7 +291,7 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool /* do_tr  	}  	// add all inner triangles to target polyset -	for(int i = 0; i < tri.size(); i++) +	for(size_t i = 0; i < tri.size(); i++)  	{  		if (!tri[i].is_inner)  			continue; diff --git a/src/dxftess-glu.cc b/src/dxftess-glu.cc index 4ad2051..4207bcd 100644 --- a/src/dxftess-glu.cc +++ b/src/dxftess-glu.cc @@ -8,6 +8,8 @@  #include "mathc99.h"  #include <QVector> +#include <QPair> +#include <QHash>  #ifdef WIN32  #  define STDCALL __stdcall diff --git a/src/glview.cc b/src/glview.cc index d69e43d..8454cd6 100644 --- a/src/glview.cc +++ b/src/glview.cc @@ -46,6 +46,12 @@  #  include <opencsg.h>  #endif +#ifdef _WIN32 +#include <GL/wglew.h> +#elif !defined(__APPLE__) +#include <GL/glxew.h> +#endif +  #define FAR_FAR_AWAY 100000.0  GLView::GLView(QWidget *parent) : QGLWidget(parent), renderer(NULL) @@ -83,6 +89,8 @@ void GLView::init()  	setMouseTracking(true);  #ifdef ENABLE_OPENCSG +	this->is_opencsg_capable = false; +	this->has_shaders = false;  	this->opencsg_support = true;  	static int sId = 0;  	this->opencsg_id = sId++; @@ -124,11 +132,36 @@ void GLView::initializeGL()  	if (GLEW_OK != err) {  		fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));  	} +  	const char *openscad_disable_gl20_env = getenv("OPENSCAD_DISABLE_GL20"); -	if (openscad_disable_gl20_env && !strcmp(openscad_disable_gl20_env, "0")) +	if (openscad_disable_gl20_env && !strcmp(openscad_disable_gl20_env, "0")) {  		openscad_disable_gl20_env = NULL; -	if (glewIsSupported("GL_VERSION_2_0") && openscad_disable_gl20_env == NULL) -	{ +	} + +	// All OpenGL 2 contexts are OpenCSG capable +	if (GLEW_VERSION_2_0 && !openscad_disable_gl20_env) this->is_opencsg_capable = true; +	// If OpenGL < 2, check for extensions +	else if (GLEW_ARB_framebuffer_object) this->is_opencsg_capable = true; +	else if (GLEW_EXT_framebuffer_object && GLEW_EXT_packed_depth_stencil) { +		this->is_opencsg_capable = true; +	} +#ifdef WIN32 +	else if (WGLEW_ARB_pbuffer && WGLEW_ARB_pixel_format) this->is_opencsg_capable = true; +#elif !defined(__APPLE__) +	else if (GLXEW_SGIX_pbuffer && GLXEW_SGIX_fbconfig) this->is_opencsg_capable = true; +#endif + +	if (GLEW_VERSION_2_0 && !openscad_disable_gl20_env) this->has_shaders = true; + +	if (!this->is_opencsg_capable) { +		opencsg_support = false; +		QSettings settings; +		// FIXME: This should be an OpenCSG capability warning, not an OpenGL 2 warning +		if (settings.value("editor/opengl20_warning_show",true).toBool()) { +			QTimer::singleShot(0, this, SLOT(display_opencsg_warning())); +		} +	} +	if (opencsg_support && this->has_shaders) {  		const char *vs_source =  			"uniform float xscale, yscale;\n"  			"attribute vec3 pos_b, pos_c;\n" @@ -212,21 +245,15 @@ void GLView::initializeGL()  				fprintf(stderr, "OpenGL Program Validation results:\n%.*s", loglen, logbuffer);  			}  		} -	} else { -		opencsg_support = false; -		QSettings settings; -		if (settings.value("editor/opengl20_warning_show",true).toBool()) { -			QTimer::singleShot(0, this, SLOT(display_opengl20_warning())); -		}  	}  #endif /* ENABLE_OPENCSG */  }  #ifdef ENABLE_OPENCSG -void GLView::display_opengl20_warning() +void GLView::display_opencsg_warning()  {  	// data -	QString title = QString("GLEW: GL_VERSION_2_0 is not supported!"); +	QString title = QString("OpenGL context is not OpenCSG capable");  	QString rendererinfo;  	rendererinfo.sprintf("GLEW version %s\n" @@ -236,10 +263,10 @@ void GLView::display_opengl20_warning()  											 glGetString(GL_RENDERER), glGetString(GL_VENDOR),  											 glGetString(GL_VERSION)); -	QString message = QString("Warning: No support for OpenGL 2.0 found! OpenCSG View has been disabled.\n\n" -			"It is highly recommended to use OpenSCAD on a system with OpenGL 2.0 " -			"support. Please check if OpenGL 2.0 drivers are available for your "	 -			"graphics hardware. Your renderer information is as follows:\n\n%1").arg(rendererinfo); +	QString message = QString("Warning: Missing OpenGL capabilities for OpenCSG - OpenCSG has been disabled.\n\n" +			"It is highly recommended to use OpenSCAD on a system with OpenGL 2.0, " +			"or support for the framebuffer_object or pbuffer extensions. " +			"Your renderer information is as follows:\n\n%1").arg(rendererinfo);  	QString note = QString("Uncheck to hide this message in the future"); @@ -269,9 +296,9 @@ void GLView::display_opengl20_warning()  	// action  	connect(buttonbox, SIGNAL(accepted()), dialog, SLOT(accept()));  	connect(checkbox, SIGNAL(clicked(bool)), -		Preferences::inst()->OpenGL20WarningCheckbox, SLOT(setChecked(bool))); +		Preferences::inst()->openCSGWarningBox, SLOT(setChecked(bool)));  	connect(checkbox, SIGNAL(clicked(bool)), -		Preferences::inst(), SLOT(OpenGL20WarningChanged(bool))); +		Preferences::inst(), SLOT(openCSGWarningChanged(bool)));  	dialog->exec();  }  #endif @@ -508,7 +535,14 @@ void GLView::mouseMoveEvent(QMouseEvent *event)  	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) { +		int i = event->buttons(); +		if (event->buttons() & Qt::LeftButton +#ifdef Q_WS_MAC +				&& !(event->modifiers() & Qt::MetaModifier) +#endif +			) { +			// Left button rotates in xz, Shift-left rotates in xy +			// On Mac, Ctrl-Left is handled as right button on other platforms  			object_rot_x += dy;  			if ((QApplication::keyboardModifiers() & Qt::ShiftModifier) != 0)  				object_rot_y += dx; @@ -519,6 +553,8 @@ void GLView::mouseMoveEvent(QMouseEvent *event)  			normalizeAngle(object_rot_y);  			normalizeAngle(object_rot_z);  		} else { +			// Right button pans +			// Shift-right zooms  			if ((QApplication::keyboardModifiers() & Qt::ShiftModifier) != 0) {  				viewer_distance += (GLdouble)dy;  			} else { @@ -1,7 +1,6 @@  #ifndef GRID_H_  #define GRID_H_ -#include <QHash>  #include "mathc99.h"  #ifdef WIN32  typedef __int64 int64_t; @@ -9,6 +8,8 @@ typedef __int64 int64_t;  #include <stdint.h>  #endif  #include <stdlib.h> +#include <boost/unordered_map.hpp> +#include <utility>  const double GRID_COARSE = 0.001;  const double GRID_FINE   = 0.000001; @@ -18,7 +19,7 @@ class Grid2d  {  public:  	double res; -	QHash<QPair<int64_t,int64_t>, T> db; +	boost::unordered_map<std::pair<int64_t,int64_t>, T> db;  	Grid2d(double resolution) {  		res = resolution; @@ -31,11 +32,11 @@ public:  	T &align(double &x, double &y) {  		int64_t ix = (int64_t)round(x / res);  		int64_t iy = (int64_t)round(y / res); -		if (!db.contains(QPair<int64_t,int64_t>(ix, iy))) { +		if (db.find(std::make_pair(ix, iy)) == db.end()) {  			int dist = 10;  			for (int64_t jx = ix - 1; jx <= ix + 1; jx++) {  				for (int64_t jy = iy - 1; jy <= iy + 1; jy++) { -					if (!db.contains(QPair<int64_t,int64_t>(jx, jy))) +					if (db.find(std::make_pair(jx, jy)) == db.end())  						continue;  					int d = abs(int(ix-jx)) + abs(int(iy-jy));  					if (d < dist) { @@ -47,16 +48,16 @@ public:  			}  		}  		x = ix * res, y = iy * res; -		return db[QPair<int64_t,int64_t>(ix, iy)]; +		return db[std::make_pair(ix, iy)];  	}  	bool has(double x, double y) const {  		int64_t ix = (int64_t)round(x / res);  		int64_t iy = (int64_t)round(y / res); -		if (db.contains(QPair<int64_t,int64_t>(ix, iy))) +		if (db.find(std::make_pair(ix, iy)) != db.end())  			return true;  		for (int64_t jx = ix - 1; jx <= ix + 1; jx++)  		for (int64_t jy = iy - 1; jy <= iy + 1; jy++) { -			if (db.contains(QPair<int64_t,int64_t>(jx, jy))) +			if (db.find(std::make_pair(jx, jy)) != db.end())  				return true;  		}  		return false; @@ -81,7 +82,7 @@ class Grid3d  {  public:  	double res; -	QHash<QPair<QPair<int64_t,int64_t>,int64_t>, T> db; +	boost::unordered_map<std::pair<std::pair<int64_t,int64_t>,int64_t>, T> db;  	Grid3d(double resolution) {  		res = resolution; @@ -90,12 +91,12 @@ public:  		int64_t ix = (int64_t)round(x / res);  		int64_t iy = (int64_t)round(y / res);  		int64_t iz = (int64_t)round(z / res); -		if (!db.contains(QPair<QPair<int64_t,int64_t>,int64_t>(QPair<int64_t,int64_t>(ix, iy), iz))) { +		if (db.find(std::make_pair(std::make_pair(ix, iy), iz)) == db.end()) {  			int dist = 10;  			for (int64_t jx = ix - 1; jx <= ix + 1; jx++) {  				for (int64_t jy = iy - 1; jy <= iy + 1; jy++) {  					for (int64_t jz = iz - 1; jz <= iz + 1; jz++) { -						if (!db.contains(QPair<QPair<int64_t,int64_t>,int64_t>(QPair<int64_t,int64_t>(jx, jy), jz))) +						if (db.find(std::make_pair(std::make_pair(jx, jy), jz)) == db.end())  							continue;  						int d = abs(int(ix-jx)) + abs(int(iy-jy)) + abs(int(iz-jz));  						if (d < dist) { @@ -109,18 +110,18 @@ public:  			}  		}  		x = ix * res, y = iy * res, z = iz * res; -		return db[QPair<QPair<int64_t,int64_t>,int64_t>(QPair<int64_t,int64_t>(ix, iy), iz)]; +			return db[std::make_pair(std::make_pair(ix, iy), iz)];  	}  	bool has(double x, double y, double z) {  		int64_t ix = (int64_t)round(x / res);  		int64_t iy = (int64_t)round(y / res);  		int64_t iz = (int64_t)round(z / res); -		if (db.contains(QPair<QPair<int64_t,int64_t>,int64_t>(QPair<int64_t,int64_t>(ix, iy), iz))) +		if (db.find(std::make_pair(std::make_pair(ix, iy), iz)) != db.end())  			return true;  		for (int64_t jx = ix - 1; jx <= ix + 1; jx++)  		for (int64_t jy = iy - 1; jy <= iy + 1; jy++)  		for (int64_t jz = iz - 1; jz <= iz + 1; jz++) { -			if (db.contains(QPair<QPair<int64_t,int64_t>,int64_t>(QPair<int64_t,int64_t>(jx, jy), jz))) +			if (db.find(std::make_pair(std::make_pair(jx, jy), jz)) != db.end())  				return true;  		}  		return false; diff --git a/src/node.cc b/src/node.cc index a4d70be..eccb9a6 100644 --- a/src/node.cc +++ b/src/node.cc @@ -96,6 +96,8 @@ void AbstractNode::progress_report() const  std::ostream &operator<<(std::ostream &stream, const AbstractNode &node)  { +	// FIXME: Don't use deep access to modinst members +	if (node.modinst->tag_background) stream << "%";  	stream << node.toString();  	return stream;  } diff --git a/src/system-gl.h b/src/system-gl.h index cdbf3dc..76b49e7 100644 --- a/src/system-gl.h +++ b/src/system-gl.h @@ -2,6 +2,7 @@  #define SYSTEMGL_H_  #include <GL/glew.h> +  #ifdef __APPLE__  #include <OpenGL/OpenGL.h>  #else diff --git a/tests/.gitignore b/tests/.gitignore index e525181..ba02d4c 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,3 +1,4 @@ +/*.dSYM  /*.a  /*-output  /*.scad diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ac021e5..58df471 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -27,11 +27,7 @@ endif()  if(WIN32_STATIC_BUILD)    if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") -    set(EMSG "\nTo build Win32 STATIC OpenSCAD tests you must run") -    set(EMSG "${EMSG} \ncmake .. -DCMAKE_BUILD_TYPE=Release") -    set(EMSG "${EMSG} \nthen replace /MD with /MT in CMakeCache.txt") -    set(EMSG "${EMSG} \ni.e. sed -i s/\\/MD/\\/MT/ CMakeCache.txt")  -    set(EMSG "${EMSG} \nthen re-run cmake ..")  +    set(EMSG "\nTo build Win32 STATIC OpenSCAD please see doc/testing.txt")      message(FATAL_ERROR ${EMSG})    endif()  endif() @@ -158,7 +154,9 @@ include_directories(${OPENCSG_INCLUDE_DIR})  # GLEW -if (NOT $ENV{MACOSX_DEPLOY_DIR} STREQUAL "") +if (NOT $ENV{GLEW_DIR} STREQUAL "") +  set(GLEW_DIR "$ENV{GLEW_DIR}") +elseif (NOT $ENV{MACOSX_DEPLOY_DIR} STREQUAL "")    set(GLEW_DIR "$ENV{MACOSX_DEPLOY_DIR}")  endif() @@ -195,8 +193,13 @@ elseif (NOT $ENV{MACOSX_DEPLOY_DIR} STREQUAL "")    set(CGAL_DIR "$ENV{MACOSX_DEPLOY_DIR}/lib/CGAL")    set(CMAKE_MODULE_PATH "${CGAL_DIR}")  endif() +message(STATUS "CGAL_DIR: " ${CGAL_DIR})  find_package(CGAL REQUIRED) -message(STATUS "CGAL found in ${CGAL_USE_FILE} ${CGAL_INCLUDE_DIRS} ${CGAL_LIBRARIES_DIR}") +message(STATUS "CGAL config found in " ${CGAL_USE_FILE} ) +foreach(cgal_incdir ${CGAL_INCLUDE_DIRS}) +  message(STATUS "CGAL include found in " ${cgal_incdir} ) +endforeach() +message(STATUS "CGAL libraries found in " ${CGAL_LIBRARIES_DIR} )  if("${CGAL_MAJOR_VERSION}.${CGAL_MINOR_VERSION}" VERSION_LESS 3.6)    message(FATAL_ERROR "CGAL >= 3.6 required")  endif() @@ -255,7 +258,7 @@ set(NOCGAL_SOURCES  set(CGAL_SOURCES    ${NOCGAL_SOURCES} -  ../src/CSGTermEvaluator.cc  +	  ../src/CSGTermEvaluator.cc     ../src/CGAL_Nef_polyhedron.cc     ../src/cgalutils.cc     ../src/CGALEvaluator.cc @@ -459,13 +462,12 @@ enable_testing()  # set up custom pretty printing of results  set(INFOCMD "execute_process(COMMAND ${CMAKE_CURRENT_BINARY_DIR}/opencsgtest --info OUTPUT_FILE sysinfo.txt)") -set(PRETTYCMD "\"${PYTHON_EXECUTABLE} test_pretty_print.py\"") +set(PRETTYCMD "\"${PYTHON_EXECUTABLE} test_pretty_print.py --builddir=${CMAKE_CURRENT_BINARY_DIR}\"")  set(CTEST_CUSTOM_FILE ${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake)  set(CTEST_CUSTOM_TXT "\n    message(\"running 'opencsgtest --info' to generate sysinfo.txt\")\n    ${INFOCMD}\n -  # set(CTEST_CUSTOM_POST_TEST ${PRETTYCMD})\n # doesn't work. log is written -  # after all tests run. +  set(CTEST_CUSTOM_POST_TEST ${PRETTYCMD})\n  ")  file(WRITE ${CTEST_CUSTOM_FILE} ${CTEST_CUSTOM_TXT}) @@ -476,6 +478,7 @@ endforeach()  set_directory_properties(PROPERTIES TEST_INCLUDE_FILE "${CMAKE_SOURCE_DIR}/EnforceConfig.cmake") +  # Find all scad files  file(GLOB MINIMAL_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/minimal/*.scad)  file(GLOB FEATURES_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/features/*.scad) @@ -523,6 +526,9 @@ disable_tests(dumptest_transform-tests  # Reenable it when this is improved  disable_tests(opencsgtest_child-background) +# FIXME: This single test takes over an hour to run on a 2.7 GHz P4 +disable_tests(opencsgtest_example006) +  # These tests only makes sense in OpenCSG mode  disable_tests(cgalpngtest_child-background                cgalpngtest_highlight-and-background-modifier diff --git a/tests/FindGLEW.cmake b/tests/FindGLEW.cmake index 32c2d6e..8093ed3 100644 --- a/tests/FindGLEW.cmake +++ b/tests/FindGLEW.cmake @@ -44,7 +44,8 @@ ENDIF (WIN32)  IF (GLEW_INCLUDE_PATH)  	SET( GLEW_FOUND 1 CACHE STRING "Set to 1 if GLEW is found, 0 otherwise") -        MESSAGE(STATUS "GLEW found in " ${GLEW_INCLUDE_PATH} " " ${GLEW_LIBRARY}) +        MESSAGE(STATUS "GLEW include found in " ${GLEW_INCLUDE_PATH} ) +        MESSAGE(STATUS "GLEW library found in " ${GLEW_LIBRARY} )  ELSE (GLEW_INCLUDE_PATH)  	SET( GLEW_FOUND 0 CACHE STRING "Set to 1 if GLEW is found, 0 otherwise")  ENDIF (GLEW_INCLUDE_PATH) diff --git a/tests/cgalpngtest.cc b/tests/cgalpngtest.cc index eabea86..7aa4b25 100644 --- a/tests/cgalpngtest.cc +++ b/tests/cgalpngtest.cc @@ -199,6 +199,9 @@ int main(int argc, char **argv)  	csgInfo.glview->paintGL();  	csgInfo.glview->save(outfile); +	delete root_node; +	delete root_module; +  	Builtins::instance(true);  	return 0; diff --git a/tests/csgtermtest.cc b/tests/csgtermtest.cc index 8f2d76e..2383126 100644 --- a/tests/csgtermtest.cc +++ b/tests/csgtermtest.cc @@ -143,6 +143,10 @@ int main(int argc, char **argv)  	}  	outfile.close(); +	if (root_term) root_term->unlink(); +	delete root_node; +	delete root_module; +  	Builtins::instance(true);  	return rc; diff --git a/tests/csgtestcore.cc b/tests/csgtestcore.cc index 418738d..cd4d4b4 100644 --- a/tests/csgtestcore.cc +++ b/tests/csgtestcore.cc @@ -87,6 +87,10 @@ string info_dump(OffscreenView *glview)  #define compiler_info "unknown compiler"  #endif +#ifndef OPENCSG_VERSION_STRING +#define OPENCSG_VERSION_STRING "unknown, <1.3.2" +#endif +  	std::stringstream out;  #define STRINGIFY(x) #x  #define TOSTRING(x) STRINGIFY(x) @@ -97,7 +101,7 @@ string info_dump(OffscreenView *glview)  	    << "\nEigen version: " << EIGEN_WORLD_VERSION << "."  	    << EIGEN_MAJOR_VERSION << "." << EIGEN_MINOR_VERSION  	    << "\nCGAL version: " << TOSTRING(CGAL_VERSION) -	    // << "\nOpenCSG" << ??? +	    << "\nOpenCSG version: " << OPENCSG_VERSION_STRING  	    << "\n" << glview->getInfo()  	    << "\n"; @@ -395,6 +399,9 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type)  	csgInfo.glview->save(outfilename); +	delete root_node; +	delete root_module; +  	Builtins::instance(true);  	return 0; diff --git a/tests/csgtexttest.cc b/tests/csgtexttest.cc index 76f6eb1..d7f94f1 100644 --- a/tests/csgtexttest.cc +++ b/tests/csgtexttest.cc @@ -129,6 +129,9 @@ int main(int argc, char **argv)  	outfile << csgcache[*root_node] << "\n";  	outfile.close(); +	delete root_node; +	delete root_module; +  	Builtins::instance(true);  	return rc; diff --git a/tests/dumptest.cc b/tests/dumptest.cc index 4071669..22dd96c 100644 --- a/tests/dumptest.cc +++ b/tests/dumptest.cc @@ -139,6 +139,9 @@ int main(int argc, char **argv)  	outfile << dumpstdstr << "\n";  	outfile.close(); +	delete root_node; +	delete root_module; +  	root_module = parsefile(outfilename);  	if (!root_module) {  		fprintf(stderr, "Error: Unable to read back dumped file\n"); @@ -159,6 +162,9 @@ int main(int argc, char **argv)  		exit(1);  	} +	delete root_node; +	delete root_module; +  	Builtins::instance(true);  	return rc; diff --git a/tests/echotest.cc b/tests/echotest.cc index 2f7ae4c..afa3d03 100644 --- a/tests/echotest.cc +++ b/tests/echotest.cc @@ -124,6 +124,9 @@ int main(int argc, char **argv)  	AbstractNode::resetIndexCounter();  	root_node = root_module->evaluate(&root_ctx, &root_inst); +	delete root_node; +	delete root_module; +  	Builtins::instance(true);  	ofile.close();  	return rc; diff --git a/tests/regression/dumptest/background-modifier-expected.txt b/tests/regression/dumptest/background-modifier-expected.txt index ca75e52..b52612f 100644 --- a/tests/regression/dumptest/background-modifier-expected.txt +++ b/tests/regression/dumptest/background-modifier-expected.txt @@ -1,5 +1,5 @@  	difference() {  		sphere($fn = 0, $fa = 12, $fs = 1, r = 10); -		cylinder($fn = 0, $fa = 12, $fs = 1, h = 30, r1 = 6, r2 = 6, center = true); +		%cylinder($fn = 0, $fa = 12, $fs = 1, h = 30, r1 = 6, r2 = 6, center = true);  	} diff --git a/tests/regression/dumptest/example009-expected.txt b/tests/regression/dumptest/example009-expected.txt index df05fe2..47ada91 100644 --- a/tests/regression/dumptest/example009-expected.txt +++ b/tests/regression/dumptest/example009-expected.txt @@ -1,7 +1,7 @@ -	linear_extrude(height = 22, center = true, convexity = 10, $fn = 0, $fa = 12, $fs = 1) { +	%linear_extrude(height = 22, center = true, convexity = 10, $fn = 0, $fa = 12, $fs = 1) {  		import(file = "example009.dxf", layer = "body", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 1);  	} -	group() { +	%group() {  		multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 12], [0, 0, 0, 1]]) {  			linear_extrude(height = 2, center = true, convexity = 10, $fn = 0, $fa = 12, $fs = 1) {  				import(file = "example009.dxf", layer = "plate", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 1); diff --git a/tests/regression/dumptest/example017-expected.txt b/tests/regression/dumptest/example017-expected.txt index 42ef321..3f4ded6 100644 --- a/tests/regression/dumptest/example017-expected.txt +++ b/tests/regression/dumptest/example017-expected.txt @@ -187,7 +187,7 @@  					}  				}  			} -			multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 12], [0, 0, 0, 1]]) { +			%multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 12], [0, 0, 0, 1]]) {  				group() {  					rotate_extrude(convexity = 2, $fn = 0, $fa = 12, $fs = 1) {  						square(size = [25, 68], center = false); diff --git a/tests/regression/dumptest/highlight-and-background-modifier-expected.txt b/tests/regression/dumptest/highlight-and-background-modifier-expected.txt index 16f7b2a..8f13dcd 100644 --- a/tests/regression/dumptest/highlight-and-background-modifier-expected.txt +++ b/tests/regression/dumptest/highlight-and-background-modifier-expected.txt @@ -1,11 +1,11 @@  	difference() {  		sphere($fn = 0, $fa = 12, $fs = 1, r = 10); -		cylinder($fn = 0, $fa = 12, $fs = 1, h = 30, r1 = 6, r2 = 6, center = true); +		%cylinder($fn = 0, $fa = 12, $fs = 1, h = 30, r1 = 6, r2 = 6, center = true);  	}  	multmatrix([[1, 0, 0, 13], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {  		difference() {  			sphere($fn = 0, $fa = 12, $fs = 1, r = 10); -			cylinder($fn = 0, $fa = 12, $fs = 1, h = 30, r1 = 6, r2 = 6, center = true); +			%cylinder($fn = 0, $fa = 12, $fs = 1, h = 30, r1 = 6, r2 = 6, center = true);  		}  	} diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py index 62ed062..8f519d7 100755 --- a/tests/test_pretty_print.py +++ b/tests/test_pretty_print.py @@ -1,4 +1,21 @@  #!/usr/bin/python + +#  Copyright (C) 2011 Don Bright <hugh.m.bright@gmail.com>  +# +#  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. +# +#  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 +  #  # This program 'pretty prints' the ctest output, namely  # files from builddir/Testing/Temporary.  @@ -6,6 +23,12 @@  # wiki uploading is available by running   #   #  python test_pretty_print.py --upload +# +# Design philosophy +# +# 1. parse the data (images, logs) into easy-to-use data structures +# 2. wikifiy the data  +# 3. save the wikified data to disk  # todo  # repair html output @@ -200,14 +223,18 @@ TESTLOG  '''Failed text tests''' -{|border=1 cellspacing=0 cellpadding=1 -! Testname   <REPEAT2> +{|border=1 cellspacing=0 cellpadding=1  |-  | FTESTNAME -</REPEAT2>  |} +<pre> +TESTLOG +</pre> + +</REPEAT2> +  '''build.make and flags.make'''  <REPEAT3>  *[[MAKEFILE_NAME]] @@ -227,12 +254,10 @@ TESTLOG  		'NUMTESTS':len(tests), 'NUMPASSED':len(passed_tests), 'PERCENTPASSED':percent }  	for key in dic.keys():  		s = s.replace(key,str(dic[key])) -	testlogs = ''  	for t in failed_tests: -		testlogs += '\n\n'+t.fulltestlog  		if t.type=='txt': -			newchunk = re.sub('FTEST_OUTPUTFILE',t.fullname,repeat2)  			newchunk = re.sub('FTESTNAME',t.fullname,repeat2) +			newchunk = newchunk.replace('TESTLOG',t.fulltestlog)  			s = s.replace(repeat2, newchunk+repeat2)  		elif t.type=='png':  			tmp = t.actualfile.replace(builddir,'') @@ -339,12 +364,21 @@ def upload(wikiurl,api_php_path='/',wiki_rootpath='test', sysid='null', botname=  def findlogfile(builddir):  	logpath = os.path.join(builddir,'Testing','Temporary') -	logfilename = os.path.join(logpath,'LastTest.log') +	logfilename = os.path.join(logpath,'LastTest.log.tmp') +	if not os.path.isfile(logfilename): +		logfilename = os.path.join(logpath,'LastTest.log') +	if not os.path.isfile(logfilename): +		print 'cant find and/or open logfile',logfilename +		sys.exit()  	return logpath, logfilename  def main():  	dry = False +	print 'running test_pretty_print'  	if '--dryrun' in sys.argv: dry=True +	suffix = ezsearch('--suffix=(.*?) ',string.join(sys.argv)+' ') +	builddir = ezsearch('--builddir=(.*?) ',string.join(sys.argv)+' ') +	if builddir=='': builddir=os.getcwd()  	print 'build dir set to', builddir  	sysinfo, sysid = read_sysinfo(os.path.join(builddir,'sysinfo.txt')) @@ -358,7 +392,7 @@ def main():  	imgs, txtpages = towiki(wiki_rootpath, startdate, tests, enddate, sysinfo, sysid, makefiles) -	wikidir = os.path.join(logpath,'wiki') +	wikidir = os.path.join(logpath,sysid+'_wiki')  	print 'writing',len(imgs),'images and',len(txtpages),'wiki pages to:\n ', wikidir  	for k in sorted(imgs): trysave( os.path.join(wikidir,k), imgs[k])  	for k in sorted(txtpages): trysave( os.path.join(wikidir,k), txtpages[k]) diff --git a/valgrind.supp b/valgrind.supp index e6aaa59..261b977 100644 --- a/valgrind.supp +++ b/valgrind.supp @@ -39,3 +39,14 @@     fun:(below main)  } +{ +   Qt misc leaks +   Memcheck:Leak +   fun:calloc +   ... +   fun:_Z7qt_initP19QApplicationPrivatei +   fun:_ZN19QApplicationPrivate9constructEv +   fun:_ZN12QApplicationC2ERiPPcbi +   fun:main +} +  | 
