diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/AboutDialog.html | 23 | ||||
-rw-r--r-- | src/CGALEvaluator.cc | 98 | ||||
-rw-r--r-- | src/CGALRenderer.cc | 11 | ||||
-rw-r--r-- | src/CGAL_Nef_polyhedron.cc | 5 | ||||
-rw-r--r-- | src/CGAL_Nef_polyhedron.h | 7 | ||||
-rw-r--r-- | src/OpenCSGWarningDialog.cc | 4 | ||||
-rw-r--r-- | src/PolySetCGALEvaluator.cc | 28 | ||||
-rw-r--r-- | src/editor.cc | 2 | ||||
-rw-r--r-- | src/editor.h | 16 | ||||
-rw-r--r-- | src/highlighter.cc | 299 | ||||
-rw-r--r-- | src/highlighter.h | 23 | ||||
-rw-r--r-- | src/mainwin.cc | 109 | ||||
-rw-r--r-- | src/openscad.cc | 15 | ||||
-rw-r--r-- | src/polyset.cc | 6 | ||||
-rw-r--r-- | src/polyset.h | 15 | ||||
-rw-r--r-- | src/version_check.h | 16 |
16 files changed, 459 insertions, 218 deletions
diff --git a/src/AboutDialog.html b/src/AboutDialog.html index 371ea46..34e8127 100644 --- a/src/AboutDialog.html +++ b/src/AboutDialog.html @@ -22,7 +22,7 @@ </p> <p> -Copyright (C) 2009-2012 <a href="https://github.com/kintel">Marius Kintel</a> <marius@kintel.net> and <a href="http://clifford.at">Clifford Wolf</a> <clifford@clifford.at> +Copyright (C) 2009-2013 <a href="https://github.com/kintel">Marius Kintel</a> <marius@kintel.net> and <a href="http://clifford.at">Clifford Wolf</a> <clifford@clifford.at> </p> <p> @@ -84,7 +84,7 @@ Please visit this link for a copy of the license: <a href="http://www.gnu.org/li <p> <b><a href="http://www.debian.org">Debian</a> maintainer:</b> - <a href="http://christian.amsuess.com/">Christian M. Amsuess</a> + <a href="http://christian.amsuess.com/">chrysn</a> </p> <p> @@ -105,16 +105,17 @@ Please visit this link for a copy of the license: <a href="http://www.gnu.org/li <p> -<b>Mailing list, bug reports, testing, &c</b> +<b>Mailing list, bug reports, testing, contribs, &c</b> </p> nop head, Triffid Hunter, Len Trigg, Kliment Yanev, Christian Siefkes, -Whosawhatsis, MichaelAtOz, Tony Buser, mrhdias, ibyte8bits, Koen Kooi, -Tomas Mudrunka, knuds, cadr, mshearn, Hans L, Brett Sutton, hmnapier, -Eero af Heurlin, caliston, 5263, ghost, 42loop, uniqx, Michael Thomson, -Michael Ivko, Pierre Doucet, myglc2, Alan Cox, Peter Falke, Michael -Ambrus, Gordon Wrigley, Ed Nisley, Stony Smith, Pasca Andrei, David -Goodenough, William A Adams ... and many others +Andrew Plumb, Whosawhatsis, MichaelAtOz, Tony Buser, mrhdias, +ibyte8bits, Koen Kooi, Tomas Mudrunka, knuds, cadr, mshearn, Hans L, +Brett Sutton, hmnapier, Eero af Heurlin, caliston, 5263, ghost, 42loop, +uniqx, Michael Thomson, Michael Ivko, Pierre Doucet, myglc2, Alan Cox, +Peter Falke, Michael Ambrus, Gordon Wrigley, Ed Nisley, Stony Smith, +Pasca Andrei, David Goodenough, William A Adams, mrrobinson, 1i7, +benhowes ... and many others <p> <b>Hosting & resources</b> @@ -135,6 +136,10 @@ Goodenough, William A Adams ... and many others </p> <p> +Trademarks are property of their owners and do not imply affiliation with OpenSCAD +</p> + +<p> Apologies to anyone left out. Please file an issue on OpenSCAD's github if you know of someone who belongs here. </p> diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc index a4744c2..4deb3b3 100644 --- a/src/CGALEvaluator.cc +++ b/src/CGALEvaluator.cc @@ -61,14 +61,16 @@ void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedr if (target.dim != 2 && target.dim != 3) { assert(false && "Dimension of Nef polyhedron must be 2 or 3"); } - if (src.empty()) return; // Empty polyhedron. This can happen for e.g. square([0,0]) + if (src.isEmpty()) return; // Empty polyhedron. This can happen for e.g. square([0,0]) + if (target.isEmpty() && op != CGE_UNION) return; // empty op <something> => empty if (target.dim != src.dim) return; // If someone tries to e.g. union 2d and 3d objects CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); try { switch (op) { case CGE_UNION: - target += src; + if (target.isEmpty()) target = src.copy(); + else target += src; break; case CGE_INTERSECTION: target *= src; @@ -110,7 +112,8 @@ CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, CGA if (!isCached(*chnode)) { CGALCache::instance()->insert(this->tree.getIdString(*chnode), chN); } - if (N.empty()) N = chN.copy(); + // Initialize N on first iteration with first expected geometric object + if (N.isNull() && !N.isEmpty()) N = chN.copy(); else process(N, chN, op); chnode->progress_report(); @@ -245,7 +248,6 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node) if (!isCached(node)) { // First union all children N = applyToChildren(node, CGE_UNION); - if ( matrix_contains_infinity( node.matrix ) || matrix_contains_nan( node.matrix ) ) { // due to the way parse/eval works we can't currently distinguish between NaN and Inf PRINT("Warning: Transformation matrix contains Not-a-Number and/or Infinity - removing object."); @@ -253,51 +255,53 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node) } // Then apply transform - // If there is no geometry under the transform, N will be empty and of dim 0, - // just just silently ignore such nodes - if (N.dim == 2) { - // Unfortunately CGAL provides no transform method for CGAL_Nef_polyhedron2 - // objects. So we convert in to our internal 2d data format, transform it, - // tesselate it and create a new CGAL_Nef_polyhedron2 from it.. What a hack! - - Eigen::Matrix2f testmat; - testmat << node.matrix(0,0), node.matrix(0,1), node.matrix(1,0), node.matrix(1,1); - if (testmat.determinant() == 0) { - PRINT("Warning: Scaling a 2D object with 0 - removing object"); - N.reset(); - } - else { - CGAL_Aff_transformation2 t( - node.matrix(0,0), node.matrix(0,1), node.matrix(0,3), - node.matrix(1,0), node.matrix(1,1), node.matrix(1,3), node.matrix(3,3)); + // If there is no geometry under the transform, N will be empty + // just silently ignore such nodes + if (!N.isNull()) { + if (N.dim == 2) { + // Unfortunately CGAL provides no transform method for CGAL_Nef_polyhedron2 + // objects. So we convert in to our internal 2d data format, transform it, + // tesselate it and create a new CGAL_Nef_polyhedron2 from it.. What a hack! - DxfData *dd = N.convertToDxfData(); - for (size_t i=0; i < dd->points.size(); i++) { - CGAL_Kernel2::Point_2 p = CGAL_Kernel2::Point_2(dd->points[i][0], dd->points[i][1]); - p = t.transform(p); - dd->points[i][0] = to_double(p.x()); - dd->points[i][1] = to_double(p.y()); + Eigen::Matrix2f testmat; + testmat << node.matrix(0,0), node.matrix(0,1), node.matrix(1,0), node.matrix(1,1); + if (testmat.determinant() == 0) { + PRINT("Warning: Scaling a 2D object with 0 - removing object"); + N.reset(); + } + else { + CGAL_Aff_transformation2 t( + node.matrix(0,0), node.matrix(0,1), node.matrix(0,3), + node.matrix(1,0), node.matrix(1,1), node.matrix(1,3), node.matrix(3,3)); + + DxfData *dd = N.convertToDxfData(); + for (size_t i=0; i < dd->points.size(); i++) { + CGAL_Kernel2::Point_2 p = CGAL_Kernel2::Point_2(dd->points[i][0], dd->points[i][1]); + p = t.transform(p); + dd->points[i][0] = to_double(p.x()); + dd->points[i][1] = to_double(p.y()); + } + + PolySet ps; + ps.is2d = true; + dxf_tesselate(&ps, *dd, 0, true, false, 0); + + N = evaluateCGALMesh(ps); + delete dd; } - - PolySet ps; - ps.is2d = true; - dxf_tesselate(&ps, *dd, 0, true, false, 0); - - N = evaluateCGALMesh(ps); - delete dd; - } - } - else if (N.dim == 3) { - if (node.matrix.matrix().determinant() == 0) { - PRINT("Warning: Scaling a 3D object with 0 - removing object"); - N.reset(); } - else { - CGAL_Aff_transformation t( - node.matrix(0,0), node.matrix(0,1), node.matrix(0,2), node.matrix(0,3), - node.matrix(1,0), node.matrix(1,1), node.matrix(1,2), node.matrix(1,3), - node.matrix(2,0), node.matrix(2,1), node.matrix(2,2), node.matrix(2,3), node.matrix(3,3)); - N.p3->transform(t); + else if (N.dim == 3) { + if (node.matrix.matrix().determinant() == 0) { + PRINT("Warning: Scaling a 3D object with 0 - removing object"); + N.reset(); + } + else { + CGAL_Aff_transformation t( + node.matrix(0,0), node.matrix(0,1), node.matrix(0,2), node.matrix(0,3), + node.matrix(1,0), node.matrix(1,1), node.matrix(1,2), node.matrix(1,3), + node.matrix(2,0), node.matrix(2,1), node.matrix(2,2), node.matrix(2,3), node.matrix(3,3)); + N.p3->transform(t); + } } } } @@ -388,7 +392,7 @@ void CGALEvaluator::addToParent(const State &state, const AbstractNode &node, co CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps) { - if (ps.empty()) return CGAL_Nef_polyhedron(); + if (ps.empty()) return CGAL_Nef_polyhedron(ps.is2d ? 2 : 3); if (ps.is2d) { diff --git a/src/CGALRenderer.cc b/src/CGALRenderer.cc index adf1217..4357e44 100644 --- a/src/CGALRenderer.cc +++ b/src/CGALRenderer.cc @@ -43,7 +43,11 @@ CGALRenderer::CGALRenderer(const CGAL_Nef_polyhedron &root) : root(root) { - if (root.dim == 2) { + if (this->root.isNull()) { + this->polyhedron = NULL; + this->polyset = NULL; + } + else if (root.dim == 2) { DxfData *dd = root.convertToDxfData(); this->polyhedron = NULL; this->polyset = new PolySet(); @@ -67,10 +71,6 @@ CGALRenderer::CGALRenderer(const CGAL_Nef_polyhedron &root) : root(root) CGAL::OGL::Nef3_Converter<CGAL_Nef_polyhedron3>::convert_to_OGLPolyhedron(*this->root.p3, this->polyhedron); this->polyhedron->init(); } - else { - this->polyhedron = NULL; - this->polyset = NULL; - } } CGALRenderer::~CGALRenderer() @@ -81,6 +81,7 @@ CGALRenderer::~CGALRenderer() void CGALRenderer::draw(bool showfaces, bool showedges) const { + if (this->root.isNull()) return; if (this->root.dim == 2) { // Draw 2D polygons glDisable(GL_LIGHTING); diff --git a/src/CGAL_Nef_polyhedron.cc b/src/CGAL_Nef_polyhedron.cc index ad2e4e2..8906595 100644 --- a/src/CGAL_Nef_polyhedron.cc +++ b/src/CGAL_Nef_polyhedron.cc @@ -61,7 +61,7 @@ CGAL_Nef_polyhedron &CGAL_Nef_polyhedron::minkowski(const CGAL_Nef_polyhedron &o int CGAL_Nef_polyhedron::weight() const { - if (this->empty()) return 0; + if (this->isNull()) return 0; size_t memsize = sizeof(CGAL_Nef_polyhedron); if (this->dim == 2) { @@ -84,8 +84,7 @@ int CGAL_Nef_polyhedron::weight() const */ PolySet *CGAL_Nef_polyhedron::convertToPolyset() { - if (this->empty()) - return new PolySet(); + if (this->isNull()) return new PolySet(); PolySet *ps = NULL; if (this->dim == 2) { ps = new PolySet(); diff --git a/src/CGAL_Nef_polyhedron.h b/src/CGAL_Nef_polyhedron.h index e8c505b..d949a2a 100644 --- a/src/CGAL_Nef_polyhedron.h +++ b/src/CGAL_Nef_polyhedron.h @@ -8,12 +8,15 @@ class CGAL_Nef_polyhedron { public: - CGAL_Nef_polyhedron() : dim(0) {} + CGAL_Nef_polyhedron(int dim = 0) : dim(dim) {} CGAL_Nef_polyhedron(CGAL_Nef_polyhedron2 *p); CGAL_Nef_polyhedron(CGAL_Nef_polyhedron3 *p); ~CGAL_Nef_polyhedron() {} - bool empty() const { return (dim == 0 || (!p2 && !p3)); } + // Empty means it is a geometric node which has zero area/volume + bool isEmpty() const { return (dim > 0 && !p2 && !p3); } + // Null means the node doesn't contain any geometry (for whatever reason) + bool isNull() const { return !p2 && !p3; } void reset() { dim=0; p2.reset(); p3.reset(); } CGAL_Nef_polyhedron &operator+=(const CGAL_Nef_polyhedron &other); CGAL_Nef_polyhedron &operator*=(const CGAL_Nef_polyhedron &other); diff --git a/src/OpenCSGWarningDialog.cc b/src/OpenCSGWarningDialog.cc index 5648576..926a55b 100644 --- a/src/OpenCSGWarningDialog.cc +++ b/src/OpenCSGWarningDialog.cc @@ -8,12 +8,12 @@ OpenCSGWarningDialog::OpenCSGWarningDialog(QWidget*) connect(this->showBox, SIGNAL(toggled(bool)), Preferences::inst()->openCSGWarningBox, SLOT(setChecked(bool))); connect(this->showBox, SIGNAL(toggled(bool)), - Preferences::inst(), SLOT(openCSGWarningChanged(bool))); + Preferences::inst(), SLOT(on_openCSGWarningBox_toggled(bool))); connect(this->enableOpenCSGBox, SIGNAL(toggled(bool)), Preferences::inst()->enableOpenCSGBox, SLOT(setChecked(bool))); connect(this->enableOpenCSGBox, SIGNAL(toggled(bool)), - Preferences::inst(), SLOT(enableOpenCSGChanged(bool))); + Preferences::inst(), SLOT(on_enableOpenCSGBox_toggled(bool))); } void OpenCSGWarningDialog::setText(const QString &text) diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc index 8e08e19..224e657 100644 --- a/src/PolySetCGALEvaluator.cc +++ b/src/PolySetCGALEvaluator.cc @@ -134,11 +134,11 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node) if (v->modinst->isBackground()) continue; CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v); if (N.dim == 3) { - if (sum.empty()) sum = N.copy(); + if (sum.isNull()) sum = N.copy(); else sum += N; } } - if (sum.empty()) return NULL; + if (sum.isNull()) return NULL; if (!sum.p3->is_simple()) { if (!node.cut_mode) { PRINT("WARNING: Body of projection(cut = false) isn't valid 2-manifold! Modify your design.."); @@ -149,7 +149,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node) //std::cout << sum.dump(); //std::cout.flush(); - CGAL_Nef_polyhedron nef_poly; + CGAL_Nef_polyhedron nef_poly(2); if (node.cut_mode) { CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); @@ -180,7 +180,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node) } } - if ( sum.p3->is_empty() ) { + if (sum.p3->is_empty()) { CGAL::set_error_behaviour(old_behaviour); PRINT("WARNING: projection() failed."); return NULL; @@ -204,7 +204,6 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node) log << "<!-- volume end. -->\n"; } nef_poly.p2 = zremover.output_nefpoly2d; - nef_poly.dim = 2; } catch (const CGAL::Failure_exception &e) { PRINTB("CGAL error in projection node while flattening: %s", e.what()); } @@ -284,8 +283,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node) plist.push_back(p); } // FIXME: Should the CGAL_Nef_polyhedron2 be cached? - if (nef_poly.empty()) { - nef_poly.dim = 2; + if (nef_poly.isEmpty()) { nef_poly.p2.reset(new CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED)); } else { @@ -385,18 +383,18 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const LinearExtrudeNode &node) BOOST_FOREACH (AbstractNode * v, node.getChildren()) { if (v->modinst->isBackground()) continue; CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v); - if (!N.empty()) { + if (!N.isNull()) { if (N.dim != 2) { PRINT("ERROR: linear_extrude() is not defined for 3D child objects!"); } else { - if (sum.empty()) sum = N.copy(); + if (sum.isNull()) sum = N.copy(); else sum += N; } } } - if (sum.empty()) return NULL; + if (sum.isNull()) return NULL; dxf = sum.convertToDxfData();; } else { dxf = new DxfData(node.fn, node.fs, node.fa, node.filename, node.layername, node.origin_x, node.origin_y, node.scale); @@ -485,18 +483,18 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const RotateExtrudeNode &node) BOOST_FOREACH (AbstractNode * v, node.getChildren()) { if (v->modinst->isBackground()) continue; CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v); - if (!N.empty()) { + if (!N.isNull()) { if (N.dim != 2) { PRINT("ERROR: rotate_extrude() is not defined for 3D child objects!"); } else { - if (sum.empty()) sum = N.copy(); + if (sum.isNull()) sum = N.copy(); else sum += N; } } } - if (sum.empty()) return NULL; + if (sum.isNull()) return NULL; dxf = sum.convertToDxfData(); } else { dxf = new DxfData(node.fn, node.fs, node.fa, node.filename, node.layername, node.origin_x, node.origin_y, node.scale); @@ -511,7 +509,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const CgaladvNode &node) { CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(node); PolySet *ps = NULL; - if (!N.empty()) { + if (!N.isNull()) { ps = N.convertToPolyset(); if (ps) ps->convexity = node.convexity; } @@ -523,7 +521,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const RenderNode &node) { CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(node); PolySet *ps = NULL; - if (!N.empty()) { + if (!N.isNull()) { if (N.dim == 3 && !N.p3->is_simple()) { PRINT("WARNING: Body of render() isn't valid 2-manifold!"); } diff --git a/src/editor.cc b/src/editor.cc index 92aeefe..08bf005 100644 --- a/src/editor.cc +++ b/src/editor.cc @@ -1,7 +1,6 @@ #include "editor.h" #include "Preferences.h" -#ifndef _QCODE_EDIT_ void Editor::indentSelection() { QTextCursor cursor = textCursor(); @@ -109,4 +108,3 @@ void Editor::wheelEvent ( QWheelEvent * event ) } } -#endif diff --git a/src/editor.h b/src/editor.h index bb338b0..09484f5 100644 --- a/src/editor.h +++ b/src/editor.h @@ -3,26 +3,11 @@ #include <QWidget> #include <QWheelEvent> -#ifdef _QCODE_EDIT_ -#include <qeditor.h> -class Editor : public QEditor -#else #include <QTextEdit> class Editor : public QTextEdit -#endif { Q_OBJECT public: -#ifdef _QCODE_EDIT_ - Editor(QWidget *parent) : QEditor(parent) {} - QString toPlainText() const { return text(); } - void setPlainText(const QString& text) { setText(text); } -public slots: - //void zoomIn() { zoom(1); } - void zoomIn(int n = 1) { zoom(n); } - //void zoomOut() { zoom(-1); } - void zoomOut(int n = 1) { zoom(-n); } -#else Editor(QWidget *parent) : QTextEdit(parent) { setAcceptRichText(false); } public slots: void zoomIn(); @@ -36,5 +21,4 @@ public slots: void uncommentSelection(); private: void wheelEvent ( QWheelEvent * event ); -#endif }; diff --git a/src/highlighter.cc b/src/highlighter.cc index 64ea980..77d1bb8 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -24,34 +24,295 @@ * */ +/* + Syntax Highlighter for OpenSCAD + based on Syntax Highlight code by Christopher Olah + + Speed Note: + + setFormat() is very slow. normally this doesnt matter because we + only highlight a block or two at once. But when OpenSCAD first starts, + QT automatigically calls 'highlightBlock' on every single textblock in the file + even if it's not visible in the window. On a large file (50,000 lines) this + can take several seconds. + + Also, QT 4.5 and lower do not have rehighlightBlock(), so they will be slow + on large files as well, as they re-highlight everything after each compile. + + The vast majority of OpenSCAD files, however, are not 50,000 lines and + most machines have Qt > 4.5 + + See Also: + + Giles Bathgate's Rapcad lexer-based highlighter: rapcad.org + + Test suite: + +1. action: open example001, remove first {, hit f5 + expected result: error highlight appears on last }, cursor moves there + action: replace first {, hit f5 + expected result: error highlight disappears + +1a. action: open example001, remove first {, hit f5 + expected result: error highlight appears on last }, cursor moves there + action: replace first { with the letter 'P', hit f5 + expected result: error highlight on last } disappears, appears on elsewhere + action: replace first {, hit f5 + expected result: error highlight disappears + +2. action: type a=b into any file + expected result: '=' is highlighted with its appropriate format + +2a. action: type a=b=c=d=e=f= into any file + expected result: each '=' is highlighted with its appropriate format + +3. action: open example001, put '===' after first ; hit f5 + expected result: error highlight appears in === + action: remove '===' + expected result: error highlight disappears + +3a. action: open example001, put '=' after first ; hit f5 + expected result: error highlight appears + action: remove '=' + expected result: error highlight disappears + +3b. action: open example001, put '=' after first { + expected result: error highlight appears + action: remove '=' + expected result: error highlight disappears + +3c. action: open example001, replace first { with '=' + expected result: error highlight appears + action: remove '=', replace with { + expected result: error highlight disappears + +4. action: open example001, remove last ';' but not trailing whitespace/\n + expected result: error highlight appears somewhere near end + action: replace last ';' + expected result: error highlight disappears + +5. action: open file, type in a multi-line comment + expected result: multiline comment should be highlighted appropriately + +6. action: open example001, remove first ')' + expected result: highlight should appear appropriately + +7. action: create a large file (50,000 lines). eg at a bash prompt: + for i in {1..2000}; do cat examples/example001.scad >> test5k.scad ; done + action: open file in openscad + expected result: it should load in a reasonable amount of time + action: scroll to bottom, put '=' after last ; + expected result: there should be a highlight, and a report of syntax error + action: comment out the highlighter code from mainwin.cc, recompile, + run openscad again on the large file. put '=' after last ; + expected result: there should be only a small difference in speed. + +8. action: open any file, and hold down 'f5' key to repeatedly reparse + expected result: no crashing! + +9. action: for i in examples/ex* ; do ./openscad $i ; done + expected result: make sure the colors look harmonious + +10. action: type random string of [][][][]()()[][90,3904,00,000] + expected result: all should be highlighted correctly + +*/ + #include "highlighter.h" -#include "parsersettings.h" // extern int parser_error_pos; +#include <QTextDocument> +#include <QTextCursor> +#include <QColor> +//#include <iostream> -#ifdef _QCODE_EDIT_ -Highlighter::Highlighter(QDocument *parent) -#else Highlighter::Highlighter(QTextDocument *parent) -#endif : QSyntaxHighlighter(parent) { + tokentypes["operator"] << "=" << "!" << "&&" << "||" << "+" << "-" << "*" << "/" << "%" << "!" << "#" << ";"; + typeformats["operator"].setForeground(Qt::blue); + + tokentypes["keyword"] << "module" << "function" << "for" << "intersection_for" << "if" << "assign"; + typeformats["keyword"].setForeground(QColor("Green")); + typeformats["keyword"].setToolTip("Keyword"); + + tokentypes["transform"] << "scale" << "translate" << "rotate" << "multmatrix" << "color" << "projection" << "hull"; + typeformats["transform"].setForeground(QColor("Indigo")); + + tokentypes["csgop"] << "union" << "intersection" << "difference" << "render"; + typeformats["csgop"].setForeground(QColor("DarkGreen")); + + tokentypes["prim3d"] << "cube" << "cylinder" << "sphere" << "polyhedron"; + typeformats["prim3d"].setForeground(QColor("DarkBlue")); + + tokentypes["prim2d"] << "square" << "polygon" << "circle"; + typeformats["prim2d"].setForeground(QColor("MidnightBlue")); + + tokentypes["import"] << "include" << "use" << "import_stl" << "import" << "import_dxf" << "dxf_dim" << "dxf_cross"; + typeformats["import"].setForeground(Qt::darkYellow); + + tokentypes["special"] << "$children" << "child" << "$fn" << "$fa" << "$fb"; + typeformats["special"].setForeground(Qt::darkGreen); + + tokentypes["extrude"] << "linear_extrude" << "rotate_extrude"; + typeformats["extrude"].setForeground(Qt::darkGreen); + + tokentypes["bracket"] << "[" << "]" << "(" << ")"; + typeformats["bracket"].setForeground(QColor("Green")); + + tokentypes["curlies"] << "{" << "}"; + typeformats["curlies"].setForeground(QColor(32,32,20)); + + tokentypes["bool"] << "true" << "false"; + typeformats["bool"].setForeground(QColor("DarkRed")); + + // Put each tokens into single QHash, mapped to it's format + QList<QString>::iterator ki; + QList<QString> toktypes = tokentypes.keys(); + for ( ki=toktypes.begin(); ki!=toktypes.end(); ++ki ) { + QString toktype = *ki; + QStringList::iterator it; + for ( it = tokentypes[toktype].begin(); it < tokentypes[toktype].end(); ++it) { + QString token = *it; + //std::cout << token.toStdString() << "\n"; + tokenFormats[ token ] = typeformats [ toktype ]; + } + } + + quoteFormat.setForeground(Qt::darkMagenta); + commentFormat.setForeground(Qt::darkCyan); + errorFormat.setBackground(Qt::red); + numberFormat.setForeground(QColor("DarkRed")); + + errorState = false; + errorPos = -1; + lastErrorBlock = parent->begin(); +} + +void Highlighter::highlightError(int error_pos) +{ + errorState = true; + errorPos = error_pos; + + QTextBlock err_block = document()->findBlock( errorPos ); + //std::cout << "error pos: " << error_pos << " doc len: " << document()->characterCount() << "\n"; + + while (err_block.text().remove(QRegExp("\\s+")).size()==0) { + //std::cout << "special case - errors at end of file w whitespace\n"; + err_block = err_block.previous(); + errorPos = err_block.position()+err_block.length() - 2; + } + if ( errorPos == lastDocumentPos()-1 ) { + errorPos--; + } + + int block_last_pos = err_block.position() + err_block.length() - 1; + if ( errorPos == block_last_pos ) { + //std::cout << "special case - errors at ends of certain blocks\n"; + errorPos--; + } + err_block = document()->findBlock(errorPos); + + portable_rehighlightBlock( err_block ); + + errorState = false; + lastErrorBlock = err_block; } -void Highlighter::highlightBlock(const QString &text) +void Highlighter::unhighlightLastError() { - int n = previousBlockState(); - if (n < 0) - n = 0; - int k = n + text.size() + 1; - setCurrentBlockState(k); - if (parser_error_pos >= n && parser_error_pos < k) { - QTextCharFormat style; - style.setBackground(Qt::red); - setFormat(0, text.size(), style); -#if 0 - style.setBackground(Qt::black); - style.setForeground(Qt::white); - setFormat(parser_error_pos - n, 1, style); + portable_rehighlightBlock( lastErrorBlock ); +} + +void Highlighter::portable_rehighlightBlock( const QTextBlock &block ) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)) + rehighlightBlock( block ); +#else + rehighlight(); // slow on very large files #endif +} + +int Highlighter::lastDocumentPos() +{ +#if (QT_VERSION >= QT_VERSION_CHECK(4, 5, 0)) + return document()->characterCount(); +#else + QTextBlock lastblock = document()->lastBlock(); + return lastblock.position() + lastblock.length(); +#endif +} + +void Highlighter::highlightBlock(const QString &text) +{ + int block_first_pos = currentBlock().position(); + //int block_last_pos = block_first_pos + currentBlock().length() - 1; + //std::cout << "block[" << block_first_pos << ":" << block_last_pos << "]" + // << ", err:" << errorPos << "," << errorState + // << ", text:'" << text.toStdString() << "'\n"; + + // Split the block into pieces and highlight each as appropriate + QString newtext = text; + QStringList splitHelpers; + QStringList::iterator sh, token; + // splitHelpers - so "[a+b]" is treated as "[ a + b ]" and formatted + splitHelpers << tokentypes["operator"] << "(" << ")" << "[" << "]" << "," << ":"; + for ( sh = splitHelpers.begin(); sh!=splitHelpers.end(); ++sh ) { + newtext = newtext.replace( *sh, " " + *sh + " "); } + //std::cout << "\nnewtext: " << newtext.toStdString() << "\n"; + QStringList tokens = newtext.split(QRegExp("\\s")); + int tokindex = 0; // tokindex helps w duplicate tokens in a single block + bool numtest; + for ( token = tokens.begin(); token!=tokens.end(); ++token ){ + if ( tokenFormats.contains( *token ) ) { + tokindex = text.indexOf( *token, tokindex ); + setFormat( tokindex, token->size(), tokenFormats[ *token ]); + //std::cout << "found tok '" << (*token).toStdString() << "' at " << tokindex << "\n"; + tokindex += token->size(); + } else { + (*token).toDouble( &numtest ); + if ( numtest ) { + tokindex = text.indexOf( *token, tokindex ); + setFormat( tokindex, token->size(), numberFormat ); + //std::cout << "found num '" << (*token).toStdString() << "' at " << tokindex << "\n"; + tokindex += token->size(); + } + } + } + + // Quoting and Comments. + state_e state = (state_e) previousBlockState(); + for (int n = 0; n < text.size(); ++n){ + if (state == NORMAL){ + if (text[n] == '"'){ + state = QUOTE; + setFormat(n,1,quoteFormat); + } else if (text[n] == '/'){ + if (text[n+1] == '/'){ + setFormat(n,text.size(),commentFormat); + break; + } else if (text[n+1] == '*'){ + setFormat(n++,2,commentFormat); + state = COMMENT; + } + } + } else if (state == QUOTE){ + setFormat(n,1,quoteFormat); + if (text[n] == '"' && text[n-1] != '\\') + state = NORMAL; + } else if (state == COMMENT){ + setFormat(n,1,commentFormat); + if (text[n] == '*' && text[n+1] == '/'){ + setFormat(++n,1,commentFormat); + state = NORMAL; + } + } + } + setCurrentBlockState((int) state); + + // Highlight an error. Do it last to 'overwrite' other formatting. + if (errorState) { + setFormat( errorPos - block_first_pos, 1, errorFormat); + } + } diff --git a/src/highlighter.h b/src/highlighter.h index 1bd54d2..b4ffae8 100644 --- a/src/highlighter.h +++ b/src/highlighter.h @@ -2,20 +2,27 @@ #define HIGHLIGHTER_H_ #include <QSyntaxHighlighter> - -#ifdef _QCODE_EDIT_ -#include "qdocument.h" -#endif +#include <QTextFormat> +#include <QHash> class Highlighter : public QSyntaxHighlighter { public: -#ifdef _QCODE_EDIT_ - Highlighter(QDocument *parent); -#else + enum state_e {NORMAL=-1,QUOTE,COMMENT}; + QHash<QString, QTextCharFormat> tokenFormats; + QTextCharFormat errorFormat, commentFormat, quoteFormat, numberFormat; Highlighter(QTextDocument *parent); -#endif void highlightBlock(const QString &text); + void highlightError(int error_pos); + void unhighlightLastError(); +private: + QTextBlock lastErrorBlock; + int errorPos; + bool errorState; + QMap<QString,QStringList> tokentypes; + QMap<QString,QTextCharFormat> typeformats; + int lastDocumentPos(); + void portable_rehighlightBlock( const QTextBlock &text ); }; #endif diff --git a/src/mainwin.cc b/src/mainwin.cc index dc5b79b..251c6e1 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -70,11 +70,6 @@ #include <QSettings> #include <QProgressDialog> #include <QMutexLocker> -#ifdef _QCODE_EDIT_ -#include "qdocument.h" -#include "qformatscheme.h" -#include "qlanguagefactory.h" -#endif #include <fstream> @@ -115,7 +110,7 @@ static char helptitle[] = #endif "\nhttp://www.openscad.org\n\n"; static char copyrighttext[] = - "Copyright (C) 2009-2012 Marius Kintel <marius@kintel.net> and Clifford Wolf <clifford@clifford.at>\n" + "Copyright (C) 2009-2013 Marius Kintel <marius@kintel.net> and Clifford Wolf <clifford@clifford.at>\n" "\n" "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 " @@ -185,16 +180,8 @@ MainWindow::MainWindow(const QString &filename) fps = 0; fsteps = 1; - highlighter = NULL; -#ifdef _QCODE_EDIT_ - QFormatScheme *formats = new QFormatScheme("qxs/openscad.qxf"); - QDocument::setDefaultFormatScheme(formats); - QLanguageFactory *languages = new QLanguageFactory(formats,this); - languages->addDefinitionPath("qxs"); - languages->setLanguage(editor, "openscad"); -#else + highlighter = new Highlighter(editor->document()); editor->setTabStopWidth(30); -#endif editor->setLineWrapping(true); // Not designable this->glview->statusLabel = new QLabel(this); @@ -348,13 +335,8 @@ MainWindow::MainWindow(const QString &filename) updateRecentFileActions(); connect(editor->document(), SIGNAL(contentsChanged()), this, SLOT(animateUpdateDocChanged())); -#ifdef _QCODE_EDIT_ - connect(editor, SIGNAL(contentModified(bool)), this, SLOT(setWindowModified(bool))); - connect(editor, SIGNAL(contentModified(bool)), fileActionSave, SLOT(setEnabled(bool))); -#else connect(editor->document(), SIGNAL(modificationChanged(bool)), this, SLOT(setWindowModified(bool))); connect(editor->document(), SIGNAL(modificationChanged(bool)), fileActionSave, SLOT(setEnabled(bool))); -#endif connect(this->glview, SIGNAL(doAnimateUpdate()), this, SLOT(animateUpdate())); connect(Preferences::inst(), SIGNAL(requestRedraw()), this->glview, SLOT(updateGL())); @@ -462,6 +444,7 @@ void MainWindow::report_func(const class AbstractNode*, void *vp, int mark) QApplication::processEvents(); } + // FIXME: Check if cancel was requested by e.g. Application quit if (thisp->progresswidget->wasCanceled()) throw ProgressCancelException(); } @@ -483,12 +466,7 @@ void MainWindow::openFile(const QString &new_filename) { #ifdef ENABLE_MDI -#ifdef _QCODE_EDIT_ - if (this->editor->document()->lines() > 1 || - !this->editor->document()->text(true, false).trimmed().isEmpty()) { -#else if (!editor->toPlainText().isEmpty()) { -#endif new MainWindow(new_filename); clearCurrentOutput(); return; @@ -957,11 +935,7 @@ void MainWindow::hideEditor() void MainWindow::pasteViewportTranslation() { -#ifdef _QCODE_EDIT_ - QDocumentCursor cursor = editor->cursor(); -#else QTextCursor cursor = editor->textCursor(); -#endif QString txt; txt.sprintf("[ %.2f, %.2f, %.2f ]", -this->glview->object_trans_x, -this->glview->object_trans_y, -this->glview->object_trans_z); cursor.insertText(txt); @@ -969,11 +943,7 @@ void MainWindow::pasteViewportTranslation() void MainWindow::pasteViewportRotation() { -#ifdef _QCODE_EDIT_ - QDocumentCursor cursor = editor->cursor(); -#else QTextCursor cursor = editor->textCursor(); -#endif QString txt; txt.sprintf("[ %.2f, %.2f, %.2f ]", fmodf(360 - this->glview->object_rot_x + 90, 360), fmodf(360 - this->glview->object_rot_y, 360), fmodf(360 - this->glview->object_rot_z, 360)); @@ -1067,24 +1037,16 @@ bool MainWindow::compileTopLevelDocument(bool reload) QFileInfo(this->fileName).absolutePath().toLocal8Bit(), false); - // Error highlighting - delete this->highlighter; - this->highlighter = NULL; - - if (!this->root_module) { - this->highlighter = new Highlighter(editor->document()); - - if (!animate_panel->isVisible()) { -#ifdef _QCODE_EDIT_ - QDocumentCursor cursor = editor->cursor(); - cursor.setPosition(parser_error_pos); -#else + if (!animate_panel->isVisible()) { + highlighter->unhighlightLastError(); + if (!this->root_module) { QTextCursor cursor = editor->textCursor(); cursor.setPosition(parser_error_pos); editor->setTextCursor(cursor); -#endif + highlighter->highlightError( parser_error_pos ); } } + } bool changed = shouldcompiletoplevel; @@ -1236,35 +1198,37 @@ void MainWindow::actionRenderCGALDone(CGAL_Nef_polyhedron *root_N) PolySetCache::instance()->print(); CGALCache::instance()->print(); - if (root_N->dim == 2) { - PRINT(" Top level object is a 2D object:"); - PRINTB(" Empty: %6s", (root_N->p2->is_empty() ? "yes" : "no")); - PRINTB(" Plane: %6s", (root_N->p2->is_plane() ? "yes" : "no")); - PRINTB(" Vertices: %6d", root_N->p2->explorer().number_of_vertices()); - PRINTB(" Halfedges: %6d", root_N->p2->explorer().number_of_halfedges()); - PRINTB(" Edges: %6d", root_N->p2->explorer().number_of_edges()); - PRINTB(" Faces: %6d", root_N->p2->explorer().number_of_faces()); - PRINTB(" FaceCycles: %6d", root_N->p2->explorer().number_of_face_cycles()); - PRINTB(" ConnComp: %6d", root_N->p2->explorer().number_of_connected_components()); - } - - if (root_N->dim == 3) { - PRINT(" Top level object is a 3D object:"); - PRINTB(" Simple: %6s", (root_N->p3->is_simple() ? "yes" : "no")); - PRINTB(" Valid: %6s", (root_N->p3->is_valid() ? "yes" : "no")); - PRINTB(" Vertices: %6d", root_N->p3->number_of_vertices()); - PRINTB(" Halfedges: %6d", root_N->p3->number_of_halfedges()); - PRINTB(" Edges: %6d", root_N->p3->number_of_edges()); - PRINTB(" Halffacets: %6d", root_N->p3->number_of_halffacets()); - PRINTB(" Facets: %6d", root_N->p3->number_of_facets()); - PRINTB(" Volumes: %6d", root_N->p3->number_of_volumes()); + if (!root_N->isNull()) { + if (root_N->dim == 2) { + PRINT(" Top level object is a 2D object:"); + PRINTB(" Empty: %6s", (root_N->p2->is_empty() ? "yes" : "no")); + PRINTB(" Plane: %6s", (root_N->p2->is_plane() ? "yes" : "no")); + PRINTB(" Vertices: %6d", root_N->p2->explorer().number_of_vertices()); + PRINTB(" Halfedges: %6d", root_N->p2->explorer().number_of_halfedges()); + PRINTB(" Edges: %6d", root_N->p2->explorer().number_of_edges()); + PRINTB(" Faces: %6d", root_N->p2->explorer().number_of_faces()); + PRINTB(" FaceCycles: %6d", root_N->p2->explorer().number_of_face_cycles()); + PRINTB(" ConnComp: %6d", root_N->p2->explorer().number_of_connected_components()); + } + + if (root_N->dim == 3) { + PRINT(" Top level object is a 3D object:"); + PRINTB(" Simple: %6s", (root_N->p3->is_simple() ? "yes" : "no")); + PRINTB(" Valid: %6s", (root_N->p3->is_valid() ? "yes" : "no")); + PRINTB(" Vertices: %6d", root_N->p3->number_of_vertices()); + PRINTB(" Halfedges: %6d", root_N->p3->number_of_halfedges()); + PRINTB(" Edges: %6d", root_N->p3->number_of_edges()); + PRINTB(" Halffacets: %6d", root_N->p3->number_of_halffacets()); + PRINTB(" Facets: %6d", root_N->p3->number_of_facets()); + PRINTB(" Volumes: %6d", root_N->p3->number_of_volumes()); + } } int s = this->progresswidget->elapsedTime() / 1000; PRINTB("Total rendering time: %d hours, %d minutes, %d seconds", (s / (60*60)) % ((s / 60) % 60) % (s % 60)); this->root_N = root_N; - if (!this->root_N->empty()) { + if (!this->root_N->isNull()) { this->cgalRenderer = new CGALRenderer(*this->root_N); // Go to CGAL view mode if (viewActionCGALGrid->isChecked()) { @@ -1766,11 +1730,13 @@ void MainWindow::helpLibrary() libinfo.sprintf("Boost version: %s\n" "Eigen version: %d.%d.%d\n" "CGAL version: %s\n" - "OpenCSG version: %s\n\n", + "OpenCSG version: %s\n" + "Qt version: %s\n\n", BOOST_LIB_VERSION, EIGEN_WORLD_VERSION, EIGEN_MAJOR_VERSION, EIGEN_MINOR_VERSION, TOSTRING(CGAL_VERSION), - OPENCSG_VERSION_STRING); + OPENCSG_VERSION_STRING, + qVersion()); if (!this->openglbox) { this->openglbox = new QMessageBox(QMessageBox::Information, @@ -1843,6 +1809,7 @@ void MainWindow::quit() QCloseEvent ev; QApplication::sendEvent(QApplication::instance(), &ev); if (ev.isAccepted()) QApplication::instance()->quit(); + // FIXME: Cancel any CGAL calculations } void MainWindow::consoleOutput(const std::string &msg, void *userdata) diff --git a/src/openscad.cc b/src/openscad.cc index df7adb3..472b5d4 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -304,8 +304,19 @@ int main(int argc, char **argv) fs::current_path(original_path); if (deps_output_file) { - if (!write_deps(deps_output_file, - stl_output_file ? stl_output_file : off_output_file)) { + std::string deps_out( deps_output_file ); + std::string geom_out; + if ( stl_output_file ) geom_out = std::string(stl_output_file); + else if ( off_output_file ) geom_out = std::string(off_output_file); + else if ( dxf_output_file ) geom_out = std::string(dxf_output_file); + else { + PRINTB("Output file:%s\n",output_file); + PRINT("Sorry, don't know how to write deps for that file type. Exiting\n"); + exit(1); + } + int result = write_deps( deps_out, geom_out ); + if ( !result ) { + PRINT("error writing deps"); exit(1); } } diff --git a/src/polyset.cc b/src/polyset.cc index 3b3be34..e601585 100644 --- a/src/polyset.cc +++ b/src/polyset.cc @@ -157,7 +157,8 @@ void PolySet::render_surface(csgmode_e csgmode, const Transform3d &m, GLint *sha } #endif /* ENABLE_OPENCSG */ if (this->is2d) { - double zbase = 1; // Render 2D objects 1mm thick + // Render 2D objects 1mm thick, but differences slightly larger + double zbase = 1 + (csgmode & CSGMODE_DIFFERENCE_FLAG) * 0.1; glBegin(GL_TRIANGLES); for (double z = -zbase/2; z < zbase; z += zbase) { @@ -248,7 +249,8 @@ void PolySet::render_edges(csgmode_e csgmode) const { glDisable(GL_LIGHTING); if (this->is2d) { - double zbase = 1; // Render 2D objects 1mm thick + // Render 2D objects 1mm thick, but differences slightly larger + double zbase = 1 + (csgmode & CSGMODE_DIFFERENCE_FLAG) * 0.1; for (double z = -zbase/2; z < zbase; z += zbase) { for (size_t i = 0; i < borders.size(); i++) { diff --git a/src/polyset.h b/src/polyset.h index 4ca57bf..6626f79 100644 --- a/src/polyset.h +++ b/src/polyset.h @@ -29,14 +29,15 @@ public: BoundingBox getBoundingBox() const; +#define CSGMODE_DIFFERENCE_FLAG 0x10 enum csgmode_e { - CSGMODE_NONE, - CSGMODE_NORMAL = 1, - CSGMODE_DIFFERENCE = 2, - CSGMODE_BACKGROUND = 11, - CSGMODE_BACKGROUND_DIFFERENCE = 12, - CSGMODE_HIGHLIGHT = 21, - CSGMODE_HIGHLIGHT_DIFFERENCE = 22 + CSGMODE_NONE = 0x00, + CSGMODE_NORMAL = 0x01, + CSGMODE_DIFFERENCE = CSGMODE_NORMAL | CSGMODE_DIFFERENCE_FLAG, + CSGMODE_BACKGROUND = 0x02, + CSGMODE_BACKGROUND_DIFFERENCE = CSGMODE_BACKGROUND | CSGMODE_DIFFERENCE_FLAG, + CSGMODE_HIGHLIGHT = 0x03, + CSGMODE_HIGHLIGHT_DIFFERENCE = CSGMODE_HIGHLIGHT | CSGMODE_DIFFERENCE_FLAG }; void render_surface(csgmode_e csgmode, const Transform3d &m, GLint *shaderinfo = NULL) const; diff --git a/src/version_check.h b/src/version_check.h index b6a63ab..db17962 100644 --- a/src/version_check.h +++ b/src/version_check.h @@ -24,26 +24,26 @@ a time, to avoid confusion. #define GMPPATCH 0 #define SYS_GMP_VER (__GNU_MP_VERSION * 10000 + __GNU_MP_VERSION_MINOR * 100 + __GNU_MP_VERSION_PATCHLEVEL * 1) #if SYS_GMP_VER < GMPMAJOR * 10000 + GMPMINOR * 100 + GMPPATCH * 1 -#error GNU GMP library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check +#error GNU GMP library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check #else #include <mpfr.h> #if MPFR_VERSION < MPFR_VERSION_NUM( 3,0,0 ) -#error GNU MPFR library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check +#error GNU MPFR library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check #else #include <Eigen/Core> #if not EIGEN_VERSION_AT_LEAST( 2,0,13 ) -#error eigen2 library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check +#error eigen2 library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check #else #include <boost/version.hpp> // boost 1.3.5 = 103500 #if BOOST_VERSION < 103500 -#error boost library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check +#error boost library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check #else @@ -51,7 +51,7 @@ a time, to avoid confusion. #include <CGAL/version.h> #if CGAL_VERSION_NR < 1030601000 -#error CGAL library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check +#error CGAL library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check #else #if CGAL_VERSION_NR < 1040021000 @@ -76,20 +76,20 @@ a time, to avoid confusion. #include <GL/glew.h> // kludge - GLEW doesnt have compiler-accessible version numbering #ifndef GLEW_ARB_occlusion_query2 -#error GLEW library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check +#error GLEW library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check #else #include <opencsg.h> // 1.3.2 -> 0x0132 #if OPENCSG_VERSION < 0x0132 -#error OPENCSG library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check +#error OPENCSG library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check #else #endif // ENABLE_OPENCSG #include <QtCore/qglobal.h> #if QT_VERSION < 0x040400 -#error QT library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check +#error QT library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check #endif // QT |