merge master
|
@ -8,11 +8,12 @@ o New import() statement reads the correct file format based on the filename ext
|
||||||
(.stl, .dxf and .off is supported)
|
(.stl, .dxf and .off is supported)
|
||||||
o The color() statement now supports an alpha parameter, e.g. color(c=[1,0,0], alpha=0.4)
|
o The color() statement now supports an alpha parameter, e.g. color(c=[1,0,0], alpha=0.4)
|
||||||
o The color() statement now supports specifying colors as strings, e.g. color("Red")
|
o The color() statement now supports specifying colors as strings, e.g. color("Red")
|
||||||
o if() and else() can now take any value type as parameter. false, 0, empty string and empty vector or illegal value type will evaluate as false, everything else as true.
|
o if()/else() and the ternary operator can now take any value type as parameter. false, 0, empty string and empty vector or illegal value type will evaluate as false, everything else as true.
|
||||||
o Strings can now be lexographically compared using the <, <=, >, >= operators
|
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() 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 The version_num() function will return the OpenSCAD version as a number, e.g. 20110923
|
||||||
o Added PI constant.
|
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.
|
||||||
|
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
o square() crashed if any of the dimensions were zero
|
o square() crashed if any of the dimensions were zero
|
||||||
|
@ -27,6 +28,8 @@ o dxf_linear_extrude() and dxf_rotate_extrude() are now deprecated.
|
||||||
o The file, layer, origin and scale parameters to linear_extrude() and rotate_extrude()
|
o The file, layer, origin and scale parameters to linear_extrude() and rotate_extrude()
|
||||||
are now deprecated. Use an import() child instead.
|
are now deprecated. Use an import() child instead.
|
||||||
o import_dxf(), import_stl() and import_off() are now deprecated. Use import() instead.
|
o import_dxf(), import_stl() and import_off() are now deprecated. Use import() instead.
|
||||||
|
o When exporting geometry from the cmd-line, use the universal -o option. It will export to the correct file format based on the given suffix (dxf, stl, off).
|
||||||
|
o F2 and F3 for Save and Reload is now deprecated
|
||||||
|
|
||||||
OpenSCAD 2011.06
|
OpenSCAD 2011.06
|
||||||
================
|
================
|
||||||
|
|
14
boost.pri
|
@ -1,4 +1,5 @@
|
||||||
boost {
|
boost {
|
||||||
|
|
||||||
isEmpty(DEPLOYDIR) {
|
isEmpty(DEPLOYDIR) {
|
||||||
# Optionally specify location of boost using the
|
# Optionally specify location of boost using the
|
||||||
# BOOSTDIR env. variable
|
# BOOSTDIR env. variable
|
||||||
|
@ -10,9 +11,16 @@ boost {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
win32 {
|
CONFIG(mingw-cross-env) {
|
||||||
LIBS += -llibboost_thread-vc90-mt-s-1_46_1 -llibboost_program_options-vc90-mt-s-1_46_1
|
DEFINES += BOOST_STATIC
|
||||||
|
DEFINES += BOOST_THREAD_USE_LIB
|
||||||
|
DEFINES += Boost_USE_STATIC_LIBS
|
||||||
|
LIBS += -lboost_thread_win32-mt -lboost_program_options-mt
|
||||||
} else {
|
} else {
|
||||||
LIBS += -lboost_thread -lboost_program_options
|
win32 {
|
||||||
|
LIBS += -llibboost_thread-vc90-mt-s-1_46_1 -llibboost_program_options-vc90-mt-s-1_46_1
|
||||||
|
} else {
|
||||||
|
LIBS += -lboost_thread -lboost_program_options
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
17
cgal.pri
|
@ -13,10 +13,19 @@ cgal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
win32 {
|
CONFIG(mingw-cross-env) {
|
||||||
LIBS += $$CGAL_DIR/auxiliary/gmp/lib/libmpfr-4.lib -lCGAL-vc90-mt-s
|
|
||||||
} else {
|
|
||||||
LIBS += -lgmp -lmpfr -lCGAL
|
LIBS += -lgmp -lmpfr -lCGAL
|
||||||
|
QMAKE_CXXFLAGS += -frounding-math
|
||||||
|
} else {
|
||||||
|
windows {
|
||||||
|
*-g++* {
|
||||||
|
QMAKE_CXXFLAGS += -frounding-math
|
||||||
|
}
|
||||||
|
LIBS += $$CGAL_DIR/auxiliary/gmp/lib/libmpfr-4.lib -lCGAL-vc90-mt-s
|
||||||
|
} else {
|
||||||
|
LIBS += -lgmp -lmpfr -lCGAL
|
||||||
|
QMAKE_CXXFLAGS += -frounding-math
|
||||||
|
}
|
||||||
}
|
}
|
||||||
QMAKE_CXXFLAGS += -frounding-math
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,7 +217,6 @@ TESTING
|
||||||
o Caching and MDI looks suspicious when the code relies on external resources
|
o Caching and MDI looks suspicious when the code relies on external resources
|
||||||
which might be loaded from difference locations in different documents
|
which might be loaded from difference locations in different documents
|
||||||
-> we might get a false cache hit
|
-> we might get a false cache hit
|
||||||
o Are contructs like "child(0)" cached? Could this give false cache hits?
|
|
||||||
o Collect "all" available OpenSCAD scripts from the internets and run the integration
|
o Collect "all" available OpenSCAD scripts from the internets and run the integration
|
||||||
tests on them all
|
tests on them all
|
||||||
o dumptest tests:
|
o dumptest tests:
|
||||||
|
|
|
@ -10,6 +10,20 @@ cmake ..
|
||||||
make
|
make
|
||||||
make test
|
make test
|
||||||
|
|
||||||
|
Windows:
|
||||||
|
|
||||||
|
First, get a normal build working by following instructions at
|
||||||
|
http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Building_on_Windows
|
||||||
|
Then, from the QT command prompt:
|
||||||
|
|
||||||
|
cd tests
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||||
|
sed -i s/\/MD/\/MT/ CMakeCache.txt
|
||||||
|
cmake ..
|
||||||
|
nmake -f Makefile
|
||||||
|
nmake -f Makefile test
|
||||||
|
|
||||||
Adding a new regression test:
|
Adding a new regression test:
|
||||||
------------------------------
|
------------------------------
|
||||||
|
@ -27,3 +41,21 @@ Adding a new regression test:
|
||||||
|
|
||||||
Note that test files which don't have an *-expected.<suffix> file will
|
Note that test files which don't have an *-expected.<suffix> file will
|
||||||
be ignored for the test apps in question.
|
be ignored for the test apps in question.
|
||||||
|
|
||||||
|
Troubleshooting a failed test:
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
You can run a single test by passing the test name to ctest:
|
||||||
|
$ ctest -R throwntogethertest_sphere
|
||||||
|
|
||||||
|
You can run a series of tests by passing part of a name to ctest:
|
||||||
|
$ ctest -R cgalpng # runs all cgalpng tests
|
||||||
|
$ ctest -R sphere # runs all sphere tests
|
||||||
|
|
||||||
|
Logs of test runs are found in tests/build/Testing/Temporary
|
||||||
|
Expected results are found in tests/regression/*
|
||||||
|
Actual results are found in tests/build/testname-output/*
|
||||||
|
|
||||||
|
You can also compile a single test program:
|
||||||
|
|
||||||
|
$ make cgalpngtest
|
||||||
|
|
11
eigen2.pri
|
@ -5,10 +5,11 @@ EIGEN2_DIR = $$(EIGEN2DIR)
|
||||||
INCLUDEPATH += $$EIGEN2_DIR
|
INCLUDEPATH += $$EIGEN2_DIR
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
macx {
|
CONFIG(mingw-cross-env) {
|
||||||
INCLUDEPATH += /opt/local/include/eigen2
|
INCLUDEPATH += mingw-cross-env/include/eigen2
|
||||||
}
|
} else {
|
||||||
else {
|
freebsd-g++: INCLUDEPATH += /usr/local/include/eigen2
|
||||||
INCLUDEPATH += /usr/include/eigen2
|
macx: INCLUDEPATH += /opt/local/include/eigen2
|
||||||
|
!macx:!freebsd-g++:INCLUDEPATH += /usr/include/eigen2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
glew.pri
|
@ -16,4 +16,6 @@ glew {
|
||||||
|
|
||||||
unix:LIBS += -lGLEW
|
unix:LIBS += -lGLEW
|
||||||
win32:LIBS += -lglew32s
|
win32:LIBS += -lglew32s
|
||||||
|
CONFIG(mingw-cross-env):DEFINES += GLEW_STATIC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
50
openscad.pro
|
@ -8,17 +8,34 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Populate VERSION, VERSION_YEAR, VERSION_MONTH, VERSION_DATE from system date
|
||||||
|
include(version.pri)
|
||||||
|
|
||||||
|
# for debugging link problems (use nmake -f Makefile.Release > log.txt)
|
||||||
win32 {
|
win32 {
|
||||||
isEmpty(VERSION) VERSION = $$system(date /t)
|
# QMAKE_LFLAGS += -VERBOSE
|
||||||
} else {
|
}
|
||||||
isEmpty(VERSION) VERSION = $$system(date "+%Y.%m.%d")
|
|
||||||
|
# cross compilation unix->win32
|
||||||
|
|
||||||
|
CONFIG(mingw-cross-env) {
|
||||||
|
LIBS += mingw-cross-env/lib/libglew32s.a
|
||||||
|
LIBS += mingw-cross-env/lib/libglut.a
|
||||||
|
LIBS += mingw-cross-env/lib/libopengl32.a
|
||||||
|
LIBS += mingw-cross-env/lib/libGLEW.a
|
||||||
|
LIBS += mingw-cross-env/lib/libglaux.a
|
||||||
|
LIBS += mingw-cross-env/lib/libglu32.a
|
||||||
|
LIBS += mingw-cross-env/lib/libopencsg.a
|
||||||
|
LIBS += mingw-cross-env/lib/libmpfr.a
|
||||||
|
LIBS += mingw-cross-env/lib/libCGAL.a
|
||||||
|
QMAKE_CXXFLAGS += -fpermissive
|
||||||
}
|
}
|
||||||
VERSION_SPLIT=$$split(VERSION, ".")
|
|
||||||
VERSION_YEAR=$$member(VERSION_SPLIT, 0)
|
|
||||||
VERSION_MONTH=$$member(VERSION_SPLIT, 1)
|
|
||||||
VERSION_DAY=$$member(VERSION_SPLIT, 2)
|
|
||||||
|
|
||||||
#configure lex / yacc
|
#configure lex / yacc
|
||||||
|
unix:freebsd-g++ {
|
||||||
|
QMAKE_LEX = /usr/local/bin/flex
|
||||||
|
QMAKE_YACC = /usr/local/bin/bison
|
||||||
|
}
|
||||||
win32 {
|
win32 {
|
||||||
include(flex.pri)
|
include(flex.pri)
|
||||||
include(bison.pri)
|
include(bison.pri)
|
||||||
|
@ -39,9 +56,24 @@ DEFINES += OPENSCAD_VERSION=$$VERSION OPENSCAD_YEAR=$$VERSION_YEAR OPENSCAD_MONT
|
||||||
!isEmpty(VERSION_DAY): DEFINES += OPENSCAD_DAY=$$VERSION_DAY
|
!isEmpty(VERSION_DAY): DEFINES += OPENSCAD_DAY=$$VERSION_DAY
|
||||||
win32:DEFINES += _USE_MATH_DEFINES NOMINMAX _CRT_SECURE_NO_WARNINGS YY_NO_UNISTD_H
|
win32:DEFINES += _USE_MATH_DEFINES NOMINMAX _CRT_SECURE_NO_WARNINGS YY_NO_UNISTD_H
|
||||||
|
|
||||||
#disable warning about too long decorated names
|
# disable MSVC warnings that are of very low importance
|
||||||
win32:QMAKE_CXXFLAGS += -wd4503
|
win32:*msvc* {
|
||||||
|
# disable warning about too long decorated names
|
||||||
|
QMAKE_CXXFLAGS += -wd4503
|
||||||
|
# CGAL casting int to bool
|
||||||
|
QMAKE_CXXFLAGS += -wd4800
|
||||||
|
# CGAL's unreferenced formal parameters
|
||||||
|
QMAKE_CXXFLAGS += -wd4100
|
||||||
|
# lexer uses strdup() & other POSIX stuff
|
||||||
|
QMAKE_CXXFLAGS += -D_CRT_NONSTDC_NO_DEPRECATE
|
||||||
|
}
|
||||||
|
|
||||||
|
# disable Eigen SIMD optimizations for non-Mac OSX
|
||||||
|
!macx {
|
||||||
|
!freebsd-g++ {
|
||||||
|
QMAKE_CXXFLAGS += -DEIGEN_DONT_ALIGN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
RESOURCES = openscad.qrc
|
RESOURCES = openscad.qrc
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <QRegExp>
|
#include <QRegExp>
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const AbstractNode &node)
|
CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const AbstractNode &node)
|
||||||
{
|
{
|
||||||
if (!isCached(node)) {
|
if (!isCached(node)) {
|
||||||
|
@ -75,22 +77,23 @@ void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedr
|
||||||
CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op)
|
CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op)
|
||||||
{
|
{
|
||||||
CGAL_Nef_polyhedron N;
|
CGAL_Nef_polyhedron N;
|
||||||
if (this->visitedchildren[node.index()].size() > 0) {
|
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||||
for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin();
|
const AbstractNode *chnode = item.first;
|
||||||
iter != this->visitedchildren[node.index()].end();
|
const CGAL_Nef_polyhedron &chN = item.second;
|
||||||
iter++) {
|
// FIXME: Don't use deep access to modinst members
|
||||||
const AbstractNode *chnode = iter->first;
|
if (chnode->modinst->tag_background) continue;
|
||||||
const string &chcacheid = iter->second;
|
|
||||||
// FIXME: Don't use deep access to modinst members
|
// NB! We insert into the cache here to ensure that all children of
|
||||||
if (chnode->modinst->tag_background) continue;
|
// a node is a valid object. If we inserted as we created them, the
|
||||||
assert(isCached(*chnode));
|
// cache could have been modified before we reach this point due to a large
|
||||||
if (N.empty()) {
|
// sibling object.
|
||||||
N = CGALCache::instance()->get(chcacheid).copy();
|
if (!isCached(*chnode)) {
|
||||||
} else {
|
CGALCache::instance()->insert(this->tree.getIdString(*chnode), chN);
|
||||||
process(N, CGALCache::instance()->get(chcacheid), op);
|
|
||||||
}
|
|
||||||
chnode->progress_report();
|
|
||||||
}
|
}
|
||||||
|
if (N.empty()) N = chN.copy();
|
||||||
|
else process(N, chN, op);
|
||||||
|
|
||||||
|
chnode->progress_report();
|
||||||
}
|
}
|
||||||
return N;
|
return N;
|
||||||
}
|
}
|
||||||
|
@ -100,31 +103,25 @@ extern CGAL_Nef_polyhedron2 *convexhull2(std::list<CGAL_Nef_polyhedron2*> a);
|
||||||
CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
|
CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
|
||||||
{
|
{
|
||||||
CGAL_Nef_polyhedron N;
|
CGAL_Nef_polyhedron N;
|
||||||
if (this->visitedchildren[node.index()].size() > 0) {
|
std::list<CGAL_Nef_polyhedron2*> polys;
|
||||||
std::list<CGAL_Nef_polyhedron2*> polys;
|
bool all2d = true;
|
||||||
bool all2d = true;
|
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||||
for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin();
|
const AbstractNode *chnode = item.first;
|
||||||
iter != this->visitedchildren[node.index()].end();
|
const CGAL_Nef_polyhedron &chN = item.second;
|
||||||
iter++) {
|
// FIXME: Don't use deep access to modinst members
|
||||||
const AbstractNode *chnode = iter->first;
|
if (chnode->modinst->tag_background) continue;
|
||||||
const string &chcacheid = iter->second;
|
if (chN.dim == 2) {
|
||||||
// FIXME: Don't use deep access to modinst members
|
polys.push_back(chN.p2.get());
|
||||||
if (chnode->modinst->tag_background) continue;
|
|
||||||
assert(isCached(*chnode));
|
|
||||||
const CGAL_Nef_polyhedron &ch = CGALCache::instance()->get(chcacheid);
|
|
||||||
if (ch.dim == 2) {
|
|
||||||
polys.push_back(ch.p2.get());
|
|
||||||
}
|
|
||||||
else if (ch.dim == 3) {
|
|
||||||
PRINT("WARNING: hull() is not implemented yet for 3D objects!");
|
|
||||||
all2d = false;
|
|
||||||
}
|
|
||||||
chnode->progress_report();
|
|
||||||
}
|
}
|
||||||
|
else if (chN.dim == 3) {
|
||||||
if (all2d) {
|
PRINT("WARNING: hull() is not implemented yet for 3D objects!");
|
||||||
N = CGAL_Nef_polyhedron(convexhull2(polys));
|
all2d = false;
|
||||||
}
|
}
|
||||||
|
chnode->progress_report();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (all2d) {
|
||||||
|
N = CGAL_Nef_polyhedron(convexhull2(polys));
|
||||||
}
|
}
|
||||||
return N;
|
return N;
|
||||||
}
|
}
|
||||||
|
@ -140,11 +137,10 @@ Response CGALEvaluator::visit(State &state, const AbstractNode &node)
|
||||||
{
|
{
|
||||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||||
if (state.isPostfix()) {
|
if (state.isPostfix()) {
|
||||||
if (!isCached(node)) {
|
CGAL_Nef_polyhedron N;
|
||||||
CGAL_Nef_polyhedron N = applyToChildren(node, CGE_UNION);
|
if (!isCached(node)) N = applyToChildren(node, CGE_UNION);
|
||||||
CGALCache::instance()->insert(this->tree.getIdString(node), N);
|
else N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||||
}
|
addToParent(state, node, N);
|
||||||
addToParent(state, node);
|
|
||||||
}
|
}
|
||||||
return ContinueTraversal;
|
return ContinueTraversal;
|
||||||
}
|
}
|
||||||
|
@ -153,11 +149,10 @@ Response CGALEvaluator::visit(State &state, const AbstractIntersectionNode &node
|
||||||
{
|
{
|
||||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||||
if (state.isPostfix()) {
|
if (state.isPostfix()) {
|
||||||
if (!isCached(node)) {
|
CGAL_Nef_polyhedron N;
|
||||||
CGAL_Nef_polyhedron N = applyToChildren(node, CGE_INTERSECTION);
|
if (!isCached(node)) N = applyToChildren(node, CGE_INTERSECTION);
|
||||||
CGALCache::instance()->insert(this->tree.getIdString(node), N);
|
else N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||||
}
|
addToParent(state, node, N);
|
||||||
addToParent(state, node);
|
|
||||||
}
|
}
|
||||||
return ContinueTraversal;
|
return ContinueTraversal;
|
||||||
}
|
}
|
||||||
|
@ -166,6 +161,7 @@ Response CGALEvaluator::visit(State &state, const CsgNode &node)
|
||||||
{
|
{
|
||||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||||
if (state.isPostfix()) {
|
if (state.isPostfix()) {
|
||||||
|
CGAL_Nef_polyhedron N;
|
||||||
if (!isCached(node)) {
|
if (!isCached(node)) {
|
||||||
CGALEvaluator::CsgOp op;
|
CGALEvaluator::CsgOp op;
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
|
@ -181,10 +177,12 @@ Response CGALEvaluator::visit(State &state, const CsgNode &node)
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
CGAL_Nef_polyhedron N = applyToChildren(node, op);
|
N = applyToChildren(node, op);
|
||||||
CGALCache::instance()->insert(this->tree.getIdString(node), N);
|
|
||||||
}
|
}
|
||||||
addToParent(state, node);
|
else {
|
||||||
|
N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||||
|
}
|
||||||
|
addToParent(state, node, N);
|
||||||
}
|
}
|
||||||
return ContinueTraversal;
|
return ContinueTraversal;
|
||||||
}
|
}
|
||||||
|
@ -193,9 +191,10 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node)
|
||||||
{
|
{
|
||||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||||
if (state.isPostfix()) {
|
if (state.isPostfix()) {
|
||||||
|
CGAL_Nef_polyhedron N;
|
||||||
if (!isCached(node)) {
|
if (!isCached(node)) {
|
||||||
// First union all children
|
// First union all children
|
||||||
CGAL_Nef_polyhedron N = applyToChildren(node, CGE_UNION);
|
N = applyToChildren(node, CGE_UNION);
|
||||||
|
|
||||||
// Then apply transform
|
// Then apply transform
|
||||||
// If there is no geometry under the transform, N will be empty and of dim 0,
|
// If there is no geometry under the transform, N will be empty and of dim 0,
|
||||||
|
@ -231,9 +230,11 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node)
|
||||||
node.matrix(2,0), node.matrix(2,1), node.matrix(2,2), node.matrix(2,3), node.matrix(3,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);
|
N.p3->transform(t);
|
||||||
}
|
}
|
||||||
CGALCache::instance()->insert(this->tree.getIdString(node), N);
|
|
||||||
}
|
}
|
||||||
addToParent(state, node);
|
else {
|
||||||
|
N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||||
|
}
|
||||||
|
addToParent(state, node, N);
|
||||||
}
|
}
|
||||||
return ContinueTraversal;
|
return ContinueTraversal;
|
||||||
}
|
}
|
||||||
|
@ -242,18 +243,20 @@ Response CGALEvaluator::visit(State &state, const AbstractPolyNode &node)
|
||||||
{
|
{
|
||||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||||
if (state.isPostfix()) {
|
if (state.isPostfix()) {
|
||||||
|
CGAL_Nef_polyhedron N;
|
||||||
if (!isCached(node)) {
|
if (!isCached(node)) {
|
||||||
// Apply polyset operation
|
// Apply polyset operation
|
||||||
shared_ptr<PolySet> ps = this->psevaluator.getPolySet(node, false);
|
shared_ptr<PolySet> ps = this->psevaluator.getPolySet(node, false);
|
||||||
CGAL_Nef_polyhedron N;
|
|
||||||
if (ps) {
|
if (ps) {
|
||||||
N = evaluateCGALMesh(*ps);
|
N = evaluateCGALMesh(*ps);
|
||||||
// print_messages_pop();
|
// print_messages_pop();
|
||||||
node.progress_report();
|
node.progress_report();
|
||||||
}
|
}
|
||||||
CGALCache::instance()->insert(this->tree.getIdString(node), N);
|
|
||||||
}
|
}
|
||||||
addToParent(state, node);
|
else {
|
||||||
|
N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||||
|
}
|
||||||
|
addToParent(state, node, N);
|
||||||
}
|
}
|
||||||
return ContinueTraversal;
|
return ContinueTraversal;
|
||||||
}
|
}
|
||||||
|
@ -262,8 +265,8 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
|
||||||
{
|
{
|
||||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||||
if (state.isPostfix()) {
|
if (state.isPostfix()) {
|
||||||
|
CGAL_Nef_polyhedron N;
|
||||||
if (!isCached(node)) {
|
if (!isCached(node)) {
|
||||||
CGAL_Nef_polyhedron N;
|
|
||||||
CGALEvaluator::CsgOp op;
|
CGALEvaluator::CsgOp op;
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case MINKOWSKI:
|
case MINKOWSKI:
|
||||||
|
@ -282,9 +285,11 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
|
||||||
N = applyHull(node);
|
N = applyHull(node);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
CGALCache::instance()->insert(this->tree.getIdString(node), N);
|
|
||||||
}
|
}
|
||||||
addToParent(state, node);
|
else {
|
||||||
|
N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||||
|
}
|
||||||
|
addToParent(state, node, N);
|
||||||
}
|
}
|
||||||
return ContinueTraversal;
|
return ContinueTraversal;
|
||||||
}
|
}
|
||||||
|
@ -293,12 +298,18 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
|
||||||
Adds ourself to out parent's list of traversed children.
|
Adds ourself to out parent's list of traversed children.
|
||||||
Call this for _every_ node which affects output during the postfix traversal.
|
Call this for _every_ node which affects output during the postfix traversal.
|
||||||
*/
|
*/
|
||||||
void CGALEvaluator::addToParent(const State &state, const AbstractNode &node)
|
void CGALEvaluator::addToParent(const State &state, const AbstractNode &node, const CGAL_Nef_polyhedron &N)
|
||||||
{
|
{
|
||||||
assert(state.isPostfix());
|
assert(state.isPostfix());
|
||||||
this->visitedchildren.erase(node.index());
|
this->visitedchildren.erase(node.index());
|
||||||
if (state.parent()) {
|
if (state.parent()) {
|
||||||
this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, this->tree.getIdString(node)));
|
this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, N));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Root node, insert into cache
|
||||||
|
if (!isCached(node)) {
|
||||||
|
CGALCache::instance()->insert(this->tree.getIdString(node), N);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,9 +531,12 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps)
|
||||||
};
|
};
|
||||||
|
|
||||||
PolyReducer pr(ps);
|
PolyReducer pr(ps);
|
||||||
PRINTF("Number of polygons before reduction: %d\n", pr.polygons.size());
|
int numpolygons_before = pr.polygons.size();
|
||||||
pr.reduce();
|
pr.reduce();
|
||||||
PRINTF("Number of polygons after reduction: %d\n", pr.polygons.size());
|
int numpolygons_after = pr.polygons.size();
|
||||||
|
if (numpolygons_after < numpolygons_before) {
|
||||||
|
PRINTF("reduce polygons: %d -> %d", numpolygons_before, numpolygons_after);
|
||||||
|
}
|
||||||
return CGAL_Nef_polyhedron(pr.toNef());
|
return CGAL_Nef_polyhedron(pr.toNef());
|
||||||
#endif
|
#endif
|
||||||
#if 0
|
#if 0
|
||||||
|
|
|
@ -30,14 +30,15 @@ public:
|
||||||
const Tree &getTree() const { return this->tree; }
|
const Tree &getTree() const { return this->tree; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addToParent(const State &state, const AbstractNode &node);
|
void addToParent(const State &state, const AbstractNode &node, const CGAL_Nef_polyhedron &N);
|
||||||
bool isCached(const AbstractNode &node) const;
|
bool isCached(const AbstractNode &node) const;
|
||||||
void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CGALEvaluator::CsgOp op);
|
void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CGALEvaluator::CsgOp op);
|
||||||
CGAL_Nef_polyhedron applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op);
|
CGAL_Nef_polyhedron applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op);
|
||||||
CGAL_Nef_polyhedron applyHull(const CgaladvNode &node);
|
CGAL_Nef_polyhedron applyHull(const CgaladvNode &node);
|
||||||
|
|
||||||
std::string currindent;
|
std::string currindent;
|
||||||
typedef std::list<std::pair<const AbstractNode *, std::string> > ChildList;
|
typedef std::pair<const AbstractNode *, CGAL_Nef_polyhedron> ChildItem;
|
||||||
|
typedef std::list<ChildItem> ChildList;
|
||||||
std::map<int, ChildList> visitedchildren;
|
std::map<int, ChildList> visitedchildren;
|
||||||
|
|
||||||
const Tree &tree;
|
const Tree &tree;
|
||||||
|
|
|
@ -24,10 +24,12 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CGALRenderer.h"
|
// dxfdata.h must come first for Eigen SIMD alignment issues
|
||||||
#include "polyset.h"
|
|
||||||
#include "CGAL_renderer.h"
|
|
||||||
#include "dxfdata.h"
|
#include "dxfdata.h"
|
||||||
|
#include "polyset.h"
|
||||||
|
|
||||||
|
#include "CGALRenderer.h"
|
||||||
|
#include "CGAL_renderer.h"
|
||||||
#include "dxftess.h"
|
#include "dxftess.h"
|
||||||
#include "CGAL_Nef_polyhedron.h"
|
#include "CGAL_Nef_polyhedron.h"
|
||||||
#include "cgal.h"
|
#include "cgal.h"
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class CSGTermEvaluator
|
\class CSGTermEvaluator
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <cstddef>
|
||||||
#include "visitor.h"
|
#include "visitor.h"
|
||||||
|
|
||||||
class CSGTermEvaluator : public Visitor
|
class CSGTermEvaluator : public Visitor
|
||||||
|
|
|
@ -79,8 +79,8 @@ private:
|
||||||
bool maybeSave();
|
bool maybeSave();
|
||||||
bool checkModified();
|
bool checkModified();
|
||||||
QString dumpCSGTree(AbstractNode *root);
|
QString dumpCSGTree(AbstractNode *root);
|
||||||
static void consoleOutput(const QString &msg, void *userdata) {
|
static void consoleOutput(const std::string &msg, void *userdata) {
|
||||||
static_cast<MainWindow*>(userdata)->console->append(msg);
|
static_cast<MainWindow*>(userdata)->console->append(QString::fromStdString(msg));
|
||||||
}
|
}
|
||||||
void loadViewSettings();
|
void loadViewSettings();
|
||||||
void loadDesignSettings();
|
void loadDesignSettings();
|
||||||
|
@ -115,6 +115,7 @@ private slots:
|
||||||
void actionExportSTL();
|
void actionExportSTL();
|
||||||
void actionExportOFF();
|
void actionExportOFF();
|
||||||
void actionExportDXF();
|
void actionExportDXF();
|
||||||
|
void actionExportCSG();
|
||||||
void actionExportImage();
|
void actionExportImage();
|
||||||
void actionFlushCaches();
|
void actionFlushCaches();
|
||||||
|
|
||||||
|
|
|
@ -178,6 +178,7 @@
|
||||||
<addaction name="designActionExportSTL"/>
|
<addaction name="designActionExportSTL"/>
|
||||||
<addaction name="designActionExportOFF"/>
|
<addaction name="designActionExportOFF"/>
|
||||||
<addaction name="designActionExportDXF"/>
|
<addaction name="designActionExportDXF"/>
|
||||||
|
<addaction name="designActionExportCSG"/>
|
||||||
<addaction name="designActionExportImage"/>
|
<addaction name="designActionExportImage"/>
|
||||||
<addaction name="designActionFlushCaches"/>
|
<addaction name="designActionFlushCaches"/>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -657,6 +658,11 @@
|
||||||
<string>Export as Image...</string>
|
<string>Export as Image...</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="designActionExportCSG">
|
||||||
|
<property name="text">
|
||||||
|
<string>Export as CSG...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
|
|
@ -181,6 +181,7 @@ cant_project_non_simple_polyhedron:
|
||||||
|
|
||||||
static void add_slice(PolySet *ps, const DxfData &dxf, DxfData::Path &path, double rot1, double rot2, double h1, double h2)
|
static void add_slice(PolySet *ps, const DxfData &dxf, DxfData::Path &path, double rot1, double rot2, double h1, double h2)
|
||||||
{
|
{
|
||||||
|
bool splitfirst = sin(rot2 - rot1) >= 0.0;
|
||||||
for (size_t j = 1; j < path.indices.size(); j++)
|
for (size_t j = 1; j < path.indices.size(); j++)
|
||||||
{
|
{
|
||||||
int k = j - 1;
|
int k = j - 1;
|
||||||
|
@ -197,10 +198,7 @@ static void add_slice(PolySet *ps, const DxfData &dxf, DxfData::Path &path, doub
|
||||||
double kx2 = dxf.points[path.indices[k]][0] * cos(rot2*M_PI/180) + dxf.points[path.indices[k]][1] * sin(rot2*M_PI/180);
|
double kx2 = dxf.points[path.indices[k]][0] * cos(rot2*M_PI/180) + dxf.points[path.indices[k]][1] * sin(rot2*M_PI/180);
|
||||||
double ky2 = dxf.points[path.indices[k]][0] * -sin(rot2*M_PI/180) + dxf.points[path.indices[k]][1] * cos(rot2*M_PI/180);
|
double ky2 = dxf.points[path.indices[k]][0] * -sin(rot2*M_PI/180) + dxf.points[path.indices[k]][1] * cos(rot2*M_PI/180);
|
||||||
|
|
||||||
double dia1_len_sq = (jy1-ky2)*(jy1-ky2) + (jx1-kx2)*(jx1-kx2);
|
if (splitfirst)
|
||||||
double dia2_len_sq = (jy2-ky1)*(jy2-ky1) + (jx2-kx1)*(jx2-kx1);
|
|
||||||
|
|
||||||
if (dia1_len_sq > dia2_len_sq)
|
|
||||||
{
|
{
|
||||||
ps->append_poly();
|
ps->append_poly();
|
||||||
if (path.is_inner) {
|
if (path.is_inner) {
|
||||||
|
|
|
@ -17,5 +17,5 @@ void PolySetCache::print()
|
||||||
|
|
||||||
PolySetCache::cache_entry::cache_entry(const shared_ptr<PolySet> &ps) : ps(ps)
|
PolySetCache::cache_entry::cache_entry(const shared_ptr<PolySet> &ps) : ps(ps)
|
||||||
{
|
{
|
||||||
if (print_messages_stack.size() > 0) this->msg = print_messages_stack.last();
|
if (print_messages_stack.size() > 0) this->msg = print_messages_stack.back();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ private:
|
||||||
|
|
||||||
struct cache_entry {
|
struct cache_entry {
|
||||||
shared_ptr<class PolySet> ps;
|
shared_ptr<class PolySet> ps;
|
||||||
QString msg;
|
std::string msg;
|
||||||
cache_entry(const shared_ptr<PolySet> &ps);
|
cache_entry(const shared_ptr<PolySet> &ps);
|
||||||
~cache_entry() { }
|
~cache_entry() { }
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
#include "nodecache.h"
|
#include "nodecache.h"
|
||||||
|
|
||||||
using std::string;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
For now, just an abstraction of the node tree which keeps a dump
|
For now, just an abstraction of the node tree which keeps a dump
|
||||||
cache based on node indices around.
|
cache based on node indices around.
|
||||||
|
@ -20,8 +18,8 @@ public:
|
||||||
void setRoot(const AbstractNode *root);
|
void setRoot(const AbstractNode *root);
|
||||||
const AbstractNode *root() const { return this->root_node; }
|
const AbstractNode *root() const { return this->root_node; }
|
||||||
|
|
||||||
const string &getString(const AbstractNode &node) const;
|
const std::string &getString(const AbstractNode &node) const;
|
||||||
const string &getIdString(const AbstractNode &node) const;
|
const std::string &getIdString(const AbstractNode &node) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const AbstractNode *root_node;
|
const AbstractNode *root_node;
|
||||||
|
|
|
@ -42,8 +42,6 @@ public:
|
||||||
virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
|
virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
using std::string;
|
|
||||||
|
|
||||||
AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
|
AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
|
||||||
{
|
{
|
||||||
ColorNode *node = new ColorNode(inst);
|
ColorNode *node = new ColorNode(inst);
|
||||||
|
@ -87,7 +85,7 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
string ColorNode::toString() const
|
std::string ColorNode::toString() const
|
||||||
{
|
{
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
|
|
||||||
|
@ -96,7 +94,7 @@ string ColorNode::toString() const
|
||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
string ColorNode::name() const
|
std::string ColorNode::name() const
|
||||||
{
|
{
|
||||||
return "color";
|
return "color";
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,8 @@
|
||||||
#define EIGEN_DONT_ALIGN
|
#define EIGEN_DONT_ALIGN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "linalg.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <Eigen/Dense>
|
|
||||||
|
|
||||||
using Eigen::Vector2d;
|
|
||||||
|
|
||||||
class DxfData
|
class DxfData
|
||||||
{
|
{
|
||||||
|
@ -33,7 +31,11 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
std::vector<Vector2d, Eigen::aligned_allocator<Vector2d> > points;
|
||||||
|
#else
|
||||||
std::vector<Vector2d> points;
|
std::vector<Vector2d> points;
|
||||||
|
#endif
|
||||||
std::vector<Path> paths;
|
std::vector<Path> paths;
|
||||||
std::vector<Dim> dims;
|
std::vector<Dim> dims;
|
||||||
|
|
||||||
|
|
|
@ -75,9 +75,7 @@ Value Expression::evaluate(const Context *context) const
|
||||||
return this->children[0]->evaluate(context) > this->children[1]->evaluate(context);
|
return this->children[0]->evaluate(context) > this->children[1]->evaluate(context);
|
||||||
if (this->type == "?:") {
|
if (this->type == "?:") {
|
||||||
Value v = this->children[0]->evaluate(context);
|
Value v = this->children[0]->evaluate(context);
|
||||||
if (v.type == Value::BOOL)
|
return this->children[v.toBool() ? 1 : 2]->evaluate(context);
|
||||||
return this->children[v.b ? 1 : 2]->evaluate(context);
|
|
||||||
return Value();
|
|
||||||
}
|
}
|
||||||
if (this->type == "[]") {
|
if (this->type == "[]") {
|
||||||
Value v1 = this->children[0]->evaluate(context);
|
Value v1 = this->children[0]->evaluate(context);
|
||||||
|
|
|
@ -35,8 +35,11 @@
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
//isatty for visual c++
|
//isatty for visual c++ and mingw-cross-env
|
||||||
#ifdef _MSC_VER
|
#if defined __WIN32__ && ! defined _MSC_VER
|
||||||
|
#include "unistd.h"
|
||||||
|
#endif
|
||||||
|
#if defined __WIN32__ || defined _MSC_VER
|
||||||
extern "C" int __cdecl _isatty(int _FileHandle);
|
extern "C" int __cdecl _isatty(int _FileHandle);
|
||||||
#define isatty _isatty
|
#define isatty _isatty
|
||||||
#endif
|
#endif
|
||||||
|
@ -97,7 +100,7 @@ include[ \t\r\n>]*"<" { BEGIN(include); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
use[ \t\r\n>]*"<"[^ \t\r\n>]+">" {
|
use[ \t\r\n>]*"<"[^\t\r\n>]+">" {
|
||||||
QString filename(yytext);
|
QString filename(yytext);
|
||||||
filename.remove(QRegExp("^use[ \t\r\n>]*<"));
|
filename.remove(QRegExp("^use[ \t\r\n>]*<"));
|
||||||
filename.remove(QRegExp(">$"));
|
filename.remove(QRegExp(">$"));
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
#endif
|
#endif
|
||||||
#include <Eigen/Core>
|
#include <Eigen/Core>
|
||||||
#include <Eigen/Geometry>
|
#include <Eigen/Geometry>
|
||||||
|
#include <Eigen/Dense>
|
||||||
|
|
||||||
|
using Eigen::Vector2d;
|
||||||
using Eigen::Vector3d;
|
using Eigen::Vector3d;
|
||||||
typedef Eigen::AlignedBox<double, 3> BoundingBox;
|
typedef Eigen::AlignedBox<double, 3> BoundingBox;
|
||||||
using Eigen::Matrix3f;
|
using Eigen::Matrix3f;
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "PolySetEvaluator.h"
|
#include "PolySetEvaluator.h"
|
||||||
#include "openscad.h" // get_fragments_from_r()
|
#include "openscad.h" // get_fragments_from_r()
|
||||||
|
#include "mathc99.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <boost/assign/std/vector.hpp>
|
#include <boost/assign/std/vector.hpp>
|
||||||
|
|
|
@ -218,8 +218,12 @@ MainWindow::MainWindow(const QString &filename)
|
||||||
connect(this->fileActionReload, SIGNAL(triggered()), this, SLOT(actionReload()));
|
connect(this->fileActionReload, SIGNAL(triggered()), this, SLOT(actionReload()));
|
||||||
connect(this->fileActionQuit, SIGNAL(triggered()), this, SLOT(quit()));
|
connect(this->fileActionQuit, SIGNAL(triggered()), this, SLOT(quit()));
|
||||||
#ifndef __APPLE__
|
#ifndef __APPLE__
|
||||||
this->fileActionSave->setShortcut(QKeySequence(Qt::Key_F2));
|
QList<QKeySequence> shortcuts = this->fileActionSave->shortcuts();
|
||||||
this->fileActionReload->setShortcut(QKeySequence(Qt::Key_F3));
|
shortcuts.push_back(QKeySequence(Qt::Key_F2));
|
||||||
|
this->fileActionSave->setShortcuts(shortcuts);
|
||||||
|
shortcuts = this->fileActionReload->shortcuts();
|
||||||
|
shortcuts.push_back(QKeySequence(Qt::Key_F3));
|
||||||
|
this->fileActionReload->setShortcuts(shortcuts);
|
||||||
#endif
|
#endif
|
||||||
// Open Recent
|
// Open Recent
|
||||||
for (int i = 0;i<maxRecentFiles; i++) {
|
for (int i = 0;i<maxRecentFiles; i++) {
|
||||||
|
@ -283,6 +287,7 @@ MainWindow::MainWindow(const QString &filename)
|
||||||
connect(this->designActionExportSTL, SIGNAL(triggered()), this, SLOT(actionExportSTL()));
|
connect(this->designActionExportSTL, SIGNAL(triggered()), this, SLOT(actionExportSTL()));
|
||||||
connect(this->designActionExportOFF, SIGNAL(triggered()), this, SLOT(actionExportOFF()));
|
connect(this->designActionExportOFF, SIGNAL(triggered()), this, SLOT(actionExportOFF()));
|
||||||
connect(this->designActionExportDXF, SIGNAL(triggered()), this, SLOT(actionExportDXF()));
|
connect(this->designActionExportDXF, SIGNAL(triggered()), this, SLOT(actionExportDXF()));
|
||||||
|
connect(this->designActionExportCSG, SIGNAL(triggered()), this, SLOT(actionExportCSG()));
|
||||||
connect(this->designActionExportImage, SIGNAL(triggered()), this, SLOT(actionExportImage()));
|
connect(this->designActionExportImage, SIGNAL(triggered()), this, SLOT(actionExportImage()));
|
||||||
connect(this->designActionFlushCaches, SIGNAL(triggered()), this, SLOT(actionFlushCaches()));
|
connect(this->designActionFlushCaches, SIGNAL(triggered()), this, SLOT(actionFlushCaches()));
|
||||||
|
|
||||||
|
@ -871,7 +876,6 @@ void MainWindow::compileCSG(bool procevents)
|
||||||
this->thrownTogetherRenderer = new ThrownTogetherRenderer(this->root_chain,
|
this->thrownTogetherRenderer = new ThrownTogetherRenderer(this->root_chain,
|
||||||
this->highlights_chain,
|
this->highlights_chain,
|
||||||
this->background_chain);
|
this->background_chain);
|
||||||
|
|
||||||
PRINT("CSG generation finished.");
|
PRINT("CSG generation finished.");
|
||||||
int s = t.elapsed() / 1000;
|
int s = t.elapsed() / 1000;
|
||||||
PRINTF("Total rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60);
|
PRINTF("Total rendering time: %d hours, %d minutes, %d seconds", s / (60*60), (s / 60) % 60, s % 60);
|
||||||
|
@ -1474,6 +1478,38 @@ void MainWindow::actionExportDXF()
|
||||||
#endif /* ENABLE_CGAL */
|
#endif /* ENABLE_CGAL */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::actionExportCSG()
|
||||||
|
{
|
||||||
|
setCurrentOutput();
|
||||||
|
|
||||||
|
if (!this->root_node) {
|
||||||
|
PRINT("Nothing to export. Please try compiling first...");
|
||||||
|
clearCurrentOutput();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString csg_filename = QFileDialog::getSaveFileName(this, "Export CSG File",
|
||||||
|
this->fileName.isEmpty() ? "Untitled.csg" : QFileInfo(this->fileName).baseName()+".csg",
|
||||||
|
"CSG Files (*.csg)");
|
||||||
|
if (csg_filename.isEmpty()) {
|
||||||
|
PRINTF("No filename specified. CSG export aborted.");
|
||||||
|
clearCurrentOutput();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream fstream(csg_filename.toUtf8());
|
||||||
|
if (!fstream.is_open()) {
|
||||||
|
PRINTA("Can't open file \"%s\" for export", csg_filename);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fstream << this->tree.getString(*this->root_node) << "\n";
|
||||||
|
fstream.close();
|
||||||
|
PRINTF("CSG export finished.");
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCurrentOutput();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::actionExportImage()
|
void MainWindow::actionExportImage()
|
||||||
{
|
{
|
||||||
QImage img = this->glview->grabFrameBuffer();
|
QImage img = this->glview->grabFrameBuffer();
|
||||||
|
|
|
@ -7,10 +7,6 @@
|
||||||
#include "visitor.h"
|
#include "visitor.h"
|
||||||
#include "nodecache.h"
|
#include "nodecache.h"
|
||||||
|
|
||||||
using std::string;
|
|
||||||
using std::map;
|
|
||||||
using std::list;
|
|
||||||
|
|
||||||
class NodeDumper : public Visitor
|
class NodeDumper : public Visitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -26,15 +22,15 @@ private:
|
||||||
void handleVisitedChildren(const State &state, const AbstractNode &node);
|
void handleVisitedChildren(const State &state, const AbstractNode &node);
|
||||||
bool isCached(const AbstractNode &node) const;
|
bool isCached(const AbstractNode &node) const;
|
||||||
void handleIndent(const State &state);
|
void handleIndent(const State &state);
|
||||||
string dumpChildren(const AbstractNode &node);
|
std::string dumpChildren(const AbstractNode &node);
|
||||||
|
|
||||||
NodeCache &cache;
|
NodeCache &cache;
|
||||||
bool idprefix;
|
bool idprefix;
|
||||||
|
|
||||||
string currindent;
|
std::string currindent;
|
||||||
const AbstractNode *root;
|
const AbstractNode *root;
|
||||||
typedef list<const AbstractNode *> ChildList;
|
typedef std::list<const AbstractNode *> ChildList;
|
||||||
map<int, ChildList> visitedchildren;
|
std::map<int, ChildList> visitedchildren;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
157
src/openscad.cc
|
@ -70,7 +70,7 @@ namespace po = boost::program_options;
|
||||||
|
|
||||||
static void help(const char *progname)
|
static void help(const char *progname)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: %s [ { -s stl_file | -o off_file | -x dxf_file } [ -d deps_file ] ]\\\n"
|
fprintf(stderr, "Usage: %s [ { -o output_file } [ -d deps_file ] ]\\\n"
|
||||||
"%*s[ -m make_command ] [ -D var=val [..] ] filename\n",
|
"%*s[ -m make_command ] [ -D var=val [..] ] filename\n",
|
||||||
progname, int(strlen(progname))+8, "");
|
progname, int(strlen(progname))+8, "");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -126,18 +126,14 @@ int main(int argc, char **argv)
|
||||||
QCoreApplication::setApplicationName("OpenSCAD");
|
QCoreApplication::setApplicationName("OpenSCAD");
|
||||||
|
|
||||||
const char *filename = NULL;
|
const char *filename = NULL;
|
||||||
const char *stl_output_file = NULL;
|
const char *output_file = NULL;
|
||||||
const char *off_output_file = NULL;
|
|
||||||
const char *dxf_output_file = NULL;
|
|
||||||
const char *deps_output_file = NULL;
|
const char *deps_output_file = NULL;
|
||||||
|
|
||||||
po::options_description desc("Allowed options");
|
po::options_description desc("Allowed options");
|
||||||
desc.add_options()
|
desc.add_options()
|
||||||
("help,h", "help message")
|
("help,h", "help message")
|
||||||
("version,v", "print the version")
|
("version,v", "print the version")
|
||||||
("s,s", po::value<string>(), "stl-file")
|
("o,o", po::value<string>(), "out-file")
|
||||||
("o,o", po::value<string>(), "off-file")
|
|
||||||
("x,x", po::value<string>(), "dxf-file")
|
|
||||||
("d,d", po::value<string>(), "deps-file")
|
("d,d", po::value<string>(), "deps-file")
|
||||||
("m,m", po::value<string>(), "makefile")
|
("m,m", po::value<string>(), "makefile")
|
||||||
("D,D", po::value<vector<string> >(), "var=val");
|
("D,D", po::value<vector<string> >(), "var=val");
|
||||||
|
@ -159,20 +155,10 @@ int main(int argc, char **argv)
|
||||||
if (vm.count("help")) help(argv[0]);
|
if (vm.count("help")) help(argv[0]);
|
||||||
if (vm.count("version")) version();
|
if (vm.count("version")) version();
|
||||||
|
|
||||||
if (vm.count("s")) {
|
|
||||||
if (stl_output_file || off_output_file || dxf_output_file)
|
|
||||||
help(argv[0]);
|
|
||||||
stl_output_file = vm["s"].as<string>().c_str();
|
|
||||||
}
|
|
||||||
if (vm.count("o")) {
|
if (vm.count("o")) {
|
||||||
if (stl_output_file || off_output_file || dxf_output_file)
|
// FIXME: Allow for multiple output files?
|
||||||
help(argv[0]);
|
if (output_file) help(argv[0]);
|
||||||
off_output_file = vm["o"].as<string>().c_str();
|
output_file = vm["o"].as<string>().c_str();
|
||||||
}
|
|
||||||
if (vm.count("x")) {
|
|
||||||
if (stl_output_file || off_output_file || dxf_output_file)
|
|
||||||
help(argv[0]);
|
|
||||||
dxf_output_file = vm["x"].as<string>().c_str();
|
|
||||||
}
|
}
|
||||||
if (vm.count("d")) {
|
if (vm.count("d")) {
|
||||||
if (deps_output_file)
|
if (deps_output_file)
|
||||||
|
@ -253,10 +239,24 @@ int main(int argc, char **argv)
|
||||||
PolySetCGALEvaluator psevaluator(cgalevaluator);
|
PolySetCGALEvaluator psevaluator(cgalevaluator);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (stl_output_file || off_output_file || dxf_output_file)
|
if (output_file)
|
||||||
{
|
{
|
||||||
if (!filename)
|
const char *stl_output_file = NULL;
|
||||||
help(argv[0]);
|
const char *off_output_file = NULL;
|
||||||
|
const char *dxf_output_file = NULL;
|
||||||
|
const char *csg_output_file = NULL;
|
||||||
|
|
||||||
|
QString suffix = QFileInfo(output_file).suffix().toLower();
|
||||||
|
if (suffix == "stl") stl_output_file = output_file;
|
||||||
|
else if (suffix == "off") off_output_file = output_file;
|
||||||
|
else if (suffix == "dxf") dxf_output_file = output_file;
|
||||||
|
else if (suffix == "csg") csg_output_file = output_file;
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Unknown suffix for output file %s\n", output_file);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filename) help(argv[0]);
|
||||||
|
|
||||||
#ifdef ENABLE_CGAL
|
#ifdef ENABLE_CGAL
|
||||||
Context root_ctx;
|
Context root_ctx;
|
||||||
|
@ -304,68 +304,80 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
AbstractNode::resetIndexCounter();
|
AbstractNode::resetIndexCounter();
|
||||||
root_node = root_module->evaluate(&root_ctx, &root_inst);
|
root_node = root_module->evaluate(&root_ctx, &root_inst);
|
||||||
|
|
||||||
tree.setRoot(root_node);
|
tree.setRoot(root_node);
|
||||||
CGAL_Nef_polyhedron root_N = cgalevaluator.evaluateCGALMesh(*tree.root());
|
|
||||||
|
|
||||||
QDir::setCurrent(original_path.absolutePath());
|
if (csg_output_file) {
|
||||||
|
QDir::setCurrent(original_path.absolutePath());
|
||||||
if (deps_output_file) {
|
std::ofstream fstream(csg_output_file);
|
||||||
if (!write_deps(deps_output_file,
|
|
||||||
stl_output_file ? stl_output_file : off_output_file)) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stl_output_file) {
|
|
||||||
if (root_N.dim != 3) {
|
|
||||||
fprintf(stderr, "Current top level object is not a 3D object.\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if (!root_N.p3->is_simple()) {
|
|
||||||
fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
std::ofstream fstream(stl_output_file);
|
|
||||||
if (!fstream.is_open()) {
|
if (!fstream.is_open()) {
|
||||||
PRINTF("Can't open file \"%s\" for export", stl_output_file);
|
PRINTF("Can't open file \"%s\" for export", csg_output_file);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
export_stl(&root_N, fstream, NULL);
|
fstream << tree.getString(*root_node) << "\n";
|
||||||
fstream.close();
|
fstream.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
CGAL_Nef_polyhedron root_N = cgalevaluator.evaluateCGALMesh(*tree.root());
|
||||||
|
|
||||||
|
QDir::setCurrent(original_path.absolutePath());
|
||||||
|
|
||||||
|
if (deps_output_file) {
|
||||||
|
if (!write_deps(deps_output_file,
|
||||||
|
stl_output_file ? stl_output_file : off_output_file)) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (off_output_file) {
|
if (stl_output_file) {
|
||||||
if (root_N.dim != 3) {
|
if (root_N.dim != 3) {
|
||||||
fprintf(stderr, "Current top level object is not a 3D object.\n");
|
fprintf(stderr, "Current top level object is not a 3D object.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!root_N.p3->is_simple()) {
|
||||||
|
fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
std::ofstream fstream(stl_output_file);
|
||||||
|
if (!fstream.is_open()) {
|
||||||
|
PRINTF("Can't open file \"%s\" for export", stl_output_file);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
export_stl(&root_N, fstream, NULL);
|
||||||
|
fstream.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!root_N.p3->is_simple()) {
|
|
||||||
fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
|
if (off_output_file) {
|
||||||
exit(1);
|
if (root_N.dim != 3) {
|
||||||
|
fprintf(stderr, "Current top level object is not a 3D object.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!root_N.p3->is_simple()) {
|
||||||
|
fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
std::ofstream fstream(off_output_file);
|
||||||
|
if (!fstream.is_open()) {
|
||||||
|
PRINTF("Can't open file \"%s\" for export", off_output_file);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
export_off(&root_N, fstream, NULL);
|
||||||
|
fstream.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::ofstream fstream(off_output_file);
|
|
||||||
if (!fstream.is_open()) {
|
if (dxf_output_file) {
|
||||||
PRINTF("Can't open file \"%s\" for export", off_output_file);
|
std::ofstream fstream(dxf_output_file);
|
||||||
}
|
if (!fstream.is_open()) {
|
||||||
else {
|
PRINTF("Can't open file \"%s\" for export", dxf_output_file);
|
||||||
export_off(&root_N, fstream, NULL);
|
}
|
||||||
fstream.close();
|
else {
|
||||||
|
export_dxf(&root_N, fstream, NULL);
|
||||||
|
fstream.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dxf_output_file) {
|
|
||||||
std::ofstream fstream(dxf_output_file);
|
|
||||||
if (!fstream.is_open()) {
|
|
||||||
PRINTF("Can't open file \"%s\" for export", dxf_output_file);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
export_dxf(&root_N, fstream, NULL);
|
|
||||||
fstream.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete root_node;
|
delete root_node;
|
||||||
#else
|
#else
|
||||||
fprintf(stderr, "OpenSCAD has been compiled without CGAL support!\n");
|
fprintf(stderr, "OpenSCAD has been compiled without CGAL support!\n");
|
||||||
|
@ -415,3 +427,4 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,6 @@
|
||||||
#ifndef OPENSCAD_H
|
#ifndef OPENSCAD_H
|
||||||
#define OPENSCAD_H
|
#define OPENSCAD_H
|
||||||
|
|
||||||
// for win32 and maybe others..
|
|
||||||
#ifndef M_PI
|
|
||||||
# define M_PI 3.14159265358979323846
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
extern class AbstractModule *parse(const char *text, const char *path, int debug);
|
extern class AbstractModule *parse(const char *text, const char *path, int debug);
|
||||||
extern int get_fragments_from_r(double r, double fn, double fs, double fa);
|
extern int get_fragments_from_r(double r, double fn, double fs, double fa);
|
||||||
|
|
||||||
|
|
|
@ -649,7 +649,7 @@ Module *Module::compile_library(std::string filename)
|
||||||
|
|
||||||
if (lib_mod) {
|
if (lib_mod) {
|
||||||
libs_cache[filename].mod = lib_mod;
|
libs_cache[filename].mod = lib_mod;
|
||||||
libs_cache[filename].msg = print_messages_stack.last().toStdString();
|
libs_cache[filename].msg = print_messages_stack.back();
|
||||||
} else {
|
} else {
|
||||||
libs_cache.erase(filename);
|
libs_cache.erase(filename);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <QDate>
|
#include <QDate>
|
||||||
|
|
||||||
QList<QString> print_messages_stack;
|
std::list<std::string> print_messages_stack;
|
||||||
OutputHandlerFunc *outputhandler = NULL;
|
OutputHandlerFunc *outputhandler = NULL;
|
||||||
void *outputhandler_data = NULL;
|
void *outputhandler_data = NULL;
|
||||||
|
|
||||||
|
@ -14,37 +14,38 @@ void set_output_handler(OutputHandlerFunc *newhandler, void *userdata)
|
||||||
|
|
||||||
void print_messages_push()
|
void print_messages_push()
|
||||||
{
|
{
|
||||||
print_messages_stack.append(QString());
|
print_messages_stack.push_back(std::string());
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_messages_pop()
|
void print_messages_pop()
|
||||||
{
|
{
|
||||||
QString msg = print_messages_stack.takeLast();
|
std::string msg = print_messages_stack.back();
|
||||||
if (print_messages_stack.size() > 0 && !msg.isNull()) {
|
print_messages_stack.pop_back();
|
||||||
if (!print_messages_stack.last().isEmpty())
|
if (print_messages_stack.size() > 0 && !msg.empty()) {
|
||||||
print_messages_stack.last() += "\n";
|
if (!print_messages_stack.back().empty()) {
|
||||||
print_messages_stack.last() += msg;
|
print_messages_stack.back() += "\n";
|
||||||
|
}
|
||||||
|
print_messages_stack.back() += msg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PRINT(const QString &msg)
|
void PRINT(const std::string &msg)
|
||||||
{
|
{
|
||||||
if (msg.isNull())
|
if (msg.empty()) return;
|
||||||
return;
|
|
||||||
if (print_messages_stack.size() > 0) {
|
if (print_messages_stack.size() > 0) {
|
||||||
if (!print_messages_stack.last().isEmpty())
|
if (!print_messages_stack.back().empty()) {
|
||||||
print_messages_stack.last() += "\n";
|
print_messages_stack.back() += "\n";
|
||||||
print_messages_stack.last() += msg;
|
}
|
||||||
|
print_messages_stack.back() += msg;
|
||||||
}
|
}
|
||||||
PRINT_NOCACHE(msg);
|
PRINT_NOCACHE(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PRINT_NOCACHE(const QString &msg)
|
void PRINT_NOCACHE(const std::string &msg)
|
||||||
{
|
{
|
||||||
if (msg.isNull())
|
if (msg.empty()) return;
|
||||||
return;
|
|
||||||
if (!outputhandler) {
|
if (!outputhandler) {
|
||||||
fprintf(stderr, "%s\n", msg.toUtf8().data());
|
fprintf(stderr, "%s\n", msg.c_str());
|
||||||
} else {
|
} else {
|
||||||
outputhandler(msg, outputhandler_data);
|
outputhandler(msg, outputhandler_data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
#ifndef PRINTUTILS_H_
|
#ifndef PRINTUTILS_H_
|
||||||
#define PRINTUTILS_H_
|
#define PRINTUTILS_H_
|
||||||
|
|
||||||
#include <QString>
|
#include <string>
|
||||||
#include <QList>
|
#include <list>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|
||||||
typedef void (OutputHandlerFunc)(const QString &msg, void *userdata);
|
typedef void (OutputHandlerFunc)(const std::string &msg, void *userdata);
|
||||||
extern OutputHandlerFunc *outputhandler;
|
extern OutputHandlerFunc *outputhandler;
|
||||||
extern void *outputhandler_data;
|
extern void *outputhandler_data;
|
||||||
|
|
||||||
void set_output_handler(OutputHandlerFunc *newhandler, void *userdata);
|
void set_output_handler(OutputHandlerFunc *newhandler, void *userdata);
|
||||||
|
|
||||||
extern QList<QString> print_messages_stack;
|
extern std::list<std::string> print_messages_stack;
|
||||||
void print_messages_push();
|
void print_messages_push();
|
||||||
void print_messages_pop();
|
void print_messages_pop();
|
||||||
|
|
||||||
void PRINT(const QString &msg);
|
void PRINT(const std::string &msg);
|
||||||
#define PRINTF(_fmt, ...) do { QString _m; _m.sprintf(_fmt, ##__VA_ARGS__); PRINT(_m); } while (0)
|
#define PRINTF(_fmt, ...) do { QString _m; _m.sprintf(_fmt, ##__VA_ARGS__); PRINT(_m.toStdString()); } while (0)
|
||||||
#define PRINTA(_fmt, ...) do { QString _m = QString(_fmt).arg(__VA_ARGS__); PRINT(_m); } while (0)
|
#define PRINTA(_fmt, ...) do { QString _m = QString(_fmt).arg(__VA_ARGS__); PRINT(_m.toStdString()); } while (0)
|
||||||
|
|
||||||
void PRINT_NOCACHE(const QString &msg);
|
void PRINT_NOCACHE(const std::string &msg);
|
||||||
#define PRINTF_NOCACHE(_fmt, ...) do { QString _m; _m.sprintf(_fmt, ##__VA_ARGS__); PRINT_NOCACHE(_m); } while (0)
|
#define PRINTF_NOCACHE(_fmt, ...) do { QString _m; _m.sprintf(_fmt, ##__VA_ARGS__); PRINT_NOCACHE(_m.toStdString()); } while (0)
|
||||||
#define PRINTA_NOCACHE(_fmt, ...) do { QString _m = QString(_fmt).arg(__VA_ARGS__); PRINT_NOCACHE(_m); } while (0)
|
#define PRINTA_NOCACHE(_fmt, ...) do { QString _m = QString(_fmt).arg(__VA_ARGS__); PRINT_NOCACHE(_m.toStdString()); } while (0)
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &os, const QFileInfo &fi);
|
std::ostream &operator<<(std::ostream &os, const QFileInfo &fi);
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import_dxf();
|
import();
|
||||||
translate([-210,0,0]) import_dxf(file="../../dxf/polygons.dxf");
|
translate([-210,0,0]) import(file="../../dxf/polygons.dxf");
|
||||||
translate([-210,0,0]) import_dxf(file="../../dxf/polygons.dxf", origin=[0,110]);
|
translate([-210,0,0]) import(file="../../dxf/polygons.dxf", origin=[0,110]);
|
||||||
translate([-210,0,0]) import_dxf(file="../../dxf/polygons.dxf", origin=[110,110], scale=0.5);
|
translate([-210,0,0]) import(file="../../dxf/polygons.dxf", origin=[110,110], scale=0.5);
|
||||||
import_dxf(file="../../dxf/multiple-layers.dxf");
|
import(file="../../dxf/multiple-layers.dxf");
|
||||||
translate([-200,200,0]) import_dxf(file="../../dxf/multiple-layers.dxf", layer="0");
|
translate([-200,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="0");
|
||||||
translate([0,200,0]) import_dxf(file="../../dxf/multiple-layers.dxf", layer="0");
|
translate([0,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="0");
|
||||||
translate([200,200,0]) import_dxf(file="../../dxf/multiple-layers.dxf", layer="noname");
|
translate([200,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="noname");
|
||||||
translate([0,200,0]) import_dxf(file="../../dxf/multiple-layers.dxf", layer="Layer with a pretty long name including \\ \"special\" /'\\\\ characters");
|
translate([0,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="Layer with a pretty long name including \\ \"special\" /'\\\\ characters");
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
// These are tests which are not yet possible to express with the
|
||||||
|
// non-deprecated functionality
|
||||||
|
|
||||||
|
rotate_extrude(file = "../../dxf/open-polyline.dxf");
|
|
@ -1,4 +1,9 @@
|
||||||
cmake_minimum_required(VERSION 2.8)
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3)
|
||||||
|
# Explicitly use new include policy to avoid globally shadowing included modules
|
||||||
|
# http://www.cmake.org/cmake/help/cmake-2-8-docs.html#policy:CMP0017
|
||||||
|
cmake_policy(SET CMP0017 NEW)
|
||||||
|
endif()
|
||||||
project(tests)
|
project(tests)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}")
|
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}")
|
||||||
|
@ -8,6 +13,51 @@ if(NOT CMAKE_BUILD_TYPE)
|
||||||
set(CMAKE_BUILD_TYPE Debug)
|
set(CMAKE_BUILD_TYPE Debug)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Windows
|
||||||
|
#
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(WIN32_STATIC_BUILD "True")
|
||||||
|
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 ..")
|
||||||
|
message(FATAL_ERROR ${EMSG})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Disable warnings
|
||||||
|
if(WIN32)
|
||||||
|
# too long decorated names
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4503")
|
||||||
|
# int cast to bool in CGAL
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4800")
|
||||||
|
# unreferenced parameters in CGAL
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4100")
|
||||||
|
# fopen_s advertisement
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_CRT_SECURE_NO_DEPRECATE")
|
||||||
|
# lexer uses strdup & other POSIX stuff
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_CRT_NONSTDC_NO_DEPRECATE")
|
||||||
|
# M_PI
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_USE_MATH_DEFINES")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Debugging - if you uncomment, use nmake -f Makefile > log.txt (the log is big)
|
||||||
|
if(WIN32)
|
||||||
|
# Linker debugging
|
||||||
|
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -VERBOSE")
|
||||||
|
|
||||||
|
# Compiler debugging
|
||||||
|
# you have to pass -DCMAKE_VERBOSE_MAKEFILE=ON to cmake when you run it.
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Build test apps
|
# Build test apps
|
||||||
#
|
#
|
||||||
|
@ -23,10 +73,23 @@ find_package(Qt4 COMPONENTS QtCore QtGui QtOpenGL REQUIRED)
|
||||||
include(${QT_USE_FILE})
|
include(${QT_USE_FILE})
|
||||||
|
|
||||||
# Eigen2
|
# Eigen2
|
||||||
|
|
||||||
|
# Turn off Eigen SIMD optimization
|
||||||
|
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
|
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEIGEN_DONT_ALIGN")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
if (NOT EIGEN2_INCLUDE_DIR)
|
if (NOT EIGEN2_INCLUDE_DIR)
|
||||||
find_path(EIGEN2_INCLUDE_DIR
|
find_path(EIGEN2_INCLUDE_DIR
|
||||||
Eigen/Core
|
Eigen/Core
|
||||||
PATHS ENV EIGEN2DIR /opt/local/include/eigen2 /usr/include/eigen2)
|
PATHS ENV EIGEN2DIR /opt/local/include/eigen2 /usr/include/eigen2)
|
||||||
|
if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||||
|
find_path(EIGEN2_INCLUDE_DIR
|
||||||
|
Eigen/Core
|
||||||
|
PATHS ENV EIGEN2DIR /usr/local/include/eigen2 )
|
||||||
|
endif()
|
||||||
if (NOT EIGEN2_INCLUDE_DIR)
|
if (NOT EIGEN2_INCLUDE_DIR)
|
||||||
message(FATAL_ERROR "Eigen2 not found")
|
message(FATAL_ERROR "Eigen2 not found")
|
||||||
else()
|
else()
|
||||||
|
@ -57,17 +120,33 @@ if (NOT OPENCSG_INCLUDE_DIR)
|
||||||
endif()
|
endif()
|
||||||
include_directories(${OPENCSG_INCLUDE_DIR})
|
include_directories(${OPENCSG_INCLUDE_DIR})
|
||||||
|
|
||||||
|
# GLEW
|
||||||
|
|
||||||
if (NOT $ENV{MACOSX_DEPLOY_DIR} STREQUAL "")
|
if (NOT $ENV{MACOSX_DEPLOY_DIR} STREQUAL "")
|
||||||
set(GLEW_DIR "$ENV{MACOSX_DEPLOY_DIR}")
|
set(GLEW_DIR "$ENV{MACOSX_DEPLOY_DIR}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(GLEW REQUIRED)
|
find_package(GLEW REQUIRED)
|
||||||
include_directories(${GLEW_INCLUDE_PATH})
|
include_directories(${GLEW_INCLUDE_PATH})
|
||||||
|
|
||||||
|
if(WIN32_STATIC_BUILD)
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGLEW_STATIC")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Flex/Bison
|
# Flex/Bison
|
||||||
find_package(BISON)
|
find_package(BISON)
|
||||||
|
|
||||||
|
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||||
|
# FreeBSD has an old flex in /usr/bin and a new flex in /usr/local/bin
|
||||||
|
set(FLEX_EXECUTABLE /usr/local/bin/flex)
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(FLEX)
|
find_package(FLEX)
|
||||||
# The COMPILE_FLAGS and forced C++ compiler is just to be compatible with qmake
|
# The COMPILE_FLAGS and forced C++ compiler is just to be compatible with qmake
|
||||||
FLEX_TARGET(OpenSCADlexer ../src/lexer.l ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp COMPILE_FLAGS "-Plexer")
|
if (WIN32)
|
||||||
|
set(FLEX_UNISTD_FLAG "-DYY_NO_UNISTD_H")
|
||||||
|
endif()
|
||||||
|
FLEX_TARGET(OpenSCADlexer ../src/lexer.l ${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp COMPILE_FLAGS "-Plexer ${FLEX_UNISTD_FLAG}")
|
||||||
BISON_TARGET(OpenSCADparser ../src/parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser_yacc.c COMPILE_FLAGS "-p parser")
|
BISON_TARGET(OpenSCADparser ../src/parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser_yacc.c COMPILE_FLAGS "-p parser")
|
||||||
ADD_FLEX_BISON_DEPENDENCY(OpenSCADlexer OpenSCADparser)
|
ADD_FLEX_BISON_DEPENDENCY(OpenSCADlexer OpenSCADparser)
|
||||||
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/parser_yacc.c PROPERTIES LANGUAGE "CXX")
|
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/parser_yacc.c PROPERTIES LANGUAGE "CXX")
|
||||||
|
@ -78,8 +157,8 @@ include_directories(../src)
|
||||||
|
|
||||||
add_definitions(-DOPENSCAD_VERSION=test -DOPENSCAD_YEAR=2011 -DOPENSCAD_MONTH=10)
|
add_definitions(-DOPENSCAD_VERSION=test -DOPENSCAD_YEAR=2011 -DOPENSCAD_MONTH=10)
|
||||||
|
|
||||||
|
|
||||||
set(CORE_SOURCES
|
set(CORE_SOURCES
|
||||||
|
../src/mathc99.cc
|
||||||
../src/handle_dep.cc
|
../src/handle_dep.cc
|
||||||
../src/qhash.cc
|
../src/qhash.cc
|
||||||
../src/value.cc
|
../src/value.cc
|
||||||
|
@ -118,7 +197,9 @@ set(COMMON_SOURCES
|
||||||
../src/PolySetEvaluator.cc
|
../src/PolySetEvaluator.cc
|
||||||
../src/PolySetCache.cc
|
../src/PolySetCache.cc
|
||||||
../src/Tree.cc
|
../src/Tree.cc
|
||||||
)
|
lodepng.cpp
|
||||||
|
${FLEX_OpenSCADlexer_OUTPUTS}
|
||||||
|
${BISON_OpenSCADparser_OUTPUTS})
|
||||||
|
|
||||||
#
|
#
|
||||||
# echotest
|
# echotest
|
||||||
|
@ -126,6 +207,26 @@ set(COMMON_SOURCES
|
||||||
add_executable(echotest echotest.cc ${CORE_SOURCES})
|
add_executable(echotest echotest.cc ${CORE_SOURCES})
|
||||||
target_link_libraries(echotest ${QT_LIBRARIES} ${OPENGL_LIBRARY})
|
target_link_libraries(echotest ${QT_LIBRARIES} ${OPENGL_LIBRARY})
|
||||||
|
|
||||||
|
#
|
||||||
|
# Offscreen OpenGL context source code
|
||||||
|
#
|
||||||
|
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
|
message(STATUS "Offscreen OpenGL Context - using Apple CGL")
|
||||||
|
set(OFFSCREEN_CTX_SOURCE "OffscreenContext.mm")
|
||||||
|
elseif(UNIX)
|
||||||
|
message(STATUS "Offscreen OpenGL Context - using Unix GLX")
|
||||||
|
set(OFFSCREEN_CTX_SOURCE "OffscreenContext.cc")
|
||||||
|
elseif(WIN32)
|
||||||
|
message(STATUS "Offscreen OpenGL Context - using Microsoft WGL")
|
||||||
|
set(OFFSCREEN_CTX_SOURCE "OffscreenContextWGL.cc")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Yangli Hector Yee's PerceptualDiff code
|
||||||
|
#
|
||||||
|
|
||||||
|
add_executable(yee_compare yee_compare.cpp lodepng.cpp)
|
||||||
|
|
||||||
#
|
#
|
||||||
# dumptest
|
# dumptest
|
||||||
#
|
#
|
||||||
|
@ -154,7 +255,7 @@ include_directories(${CGAL_INCLUDE_DIRS})
|
||||||
#
|
#
|
||||||
# cgaltest
|
# cgaltest
|
||||||
#
|
#
|
||||||
add_executable(cgaltest cgaltest.cc ../src/CGAL_Nef_polyhedron.cc ../src/cgalutils.cc ../src/CSGTermEvaluator.cc
|
add_executable(cgaltest cgaltest.cc ../src/CGAL_Nef_polyhedron.cc ../src/cgalutils.cc ../src/CSGTermEvaluator.cc
|
||||||
../src/CGALEvaluator.cc ../src/CGALCache.cc ../src/PolySetCGALEvaluator.cc ../src/qhash.cc
|
../src/CGALEvaluator.cc ../src/CGALCache.cc ../src/PolySetCGALEvaluator.cc ../src/qhash.cc
|
||||||
../src/CGAL_Nef_polyhedron_DxfData.cc ../src/cgaladv_minkowski2.cc ../src/cgaladv_convexhull2.cc
|
../src/CGAL_Nef_polyhedron_DxfData.cc ../src/cgaladv_minkowski2.cc ../src/cgaladv_convexhull2.cc
|
||||||
${COMMON_SOURCES})
|
${COMMON_SOURCES})
|
||||||
|
@ -164,7 +265,7 @@ target_link_libraries(cgaltest ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${QT_
|
||||||
#
|
#
|
||||||
# cgalpngtest
|
# cgalpngtest
|
||||||
#
|
#
|
||||||
add_executable(cgalpngtest cgalpngtest.cc OffscreenView.cc OffscreenContext.mm
|
add_executable(cgalpngtest cgalpngtest.cc OffscreenView.cc bboxhelp.cc ${OFFSCREEN_CTX_SOURCE} imageutils.cc fbo.cc system-gl.cc
|
||||||
../src/CGALRenderer.cc ../src/CGAL_Nef_polyhedron.cc ../src/cgalutils.cc
|
../src/CGALRenderer.cc ../src/CGAL_Nef_polyhedron.cc ../src/cgalutils.cc
|
||||||
../src/CSGTermEvaluator.cc ../src/CGALEvaluator.cc ../src/CGALCache.cc
|
../src/CSGTermEvaluator.cc ../src/CGALEvaluator.cc ../src/CGALCache.cc
|
||||||
../src/PolySetCGALEvaluator.cc ../src/qhash.cc
|
../src/PolySetCGALEvaluator.cc ../src/qhash.cc
|
||||||
|
@ -176,7 +277,8 @@ target_link_libraries(cgalpngtest ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${
|
||||||
#
|
#
|
||||||
# opencsgtest
|
# opencsgtest
|
||||||
#
|
#
|
||||||
add_executable(opencsgtest opencsgtest.cc OffscreenView.cc OffscreenContext.mm
|
|
||||||
|
add_executable(opencsgtest opencsgtest.cc csgtestcore.cc OffscreenView.cc ${OFFSCREEN_CTX_SOURCE} imageutils.cc fbo.cc system-gl.cc
|
||||||
../src/OpenCSGRenderer.cc ../src/ThrownTogetherRenderer.cc
|
../src/OpenCSGRenderer.cc ../src/ThrownTogetherRenderer.cc
|
||||||
../src/CSGTermEvaluator.cc ../src/CGAL_Nef_polyhedron.cc ../src/cgalutils.cc
|
../src/CSGTermEvaluator.cc ../src/CGAL_Nef_polyhedron.cc ../src/cgalutils.cc
|
||||||
../src/CGALEvaluator.cc ../src/CGALCache.cc ../src/PolySetCGALEvaluator.cc ../src/qhash.cc
|
../src/CGALEvaluator.cc ../src/CGALCache.cc ../src/PolySetCGALEvaluator.cc ../src/qhash.cc
|
||||||
|
@ -185,16 +287,31 @@ add_executable(opencsgtest opencsgtest.cc OffscreenView.cc OffscreenContext.mm
|
||||||
set_target_properties(opencsgtest PROPERTIES COMPILE_FLAGS "-DENABLE_OPENCSG -DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
|
set_target_properties(opencsgtest PROPERTIES COMPILE_FLAGS "-DENABLE_OPENCSG -DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
|
||||||
target_link_libraries(opencsgtest ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${QT_LIBRARIES} ${OPENCSG_LIBRARY} ${GLEW_LIBRARY} ${COCOA_LIBRARY} ${OPENGL_LIBRARY})
|
target_link_libraries(opencsgtest ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${QT_LIBRARIES} ${OPENCSG_LIBRARY} ${GLEW_LIBRARY} ${COCOA_LIBRARY} ${OPENGL_LIBRARY})
|
||||||
|
|
||||||
|
#
|
||||||
|
# throwntogethertest
|
||||||
|
#
|
||||||
|
|
||||||
|
add_executable(throwntogethertest throwntogethertest.cc csgtestcore.cc OffscreenView.cc ${OFFSCREEN_CTX_SOURCE} imageutils.cc fbo.cc system-gl.cc
|
||||||
|
../src/OpenCSGRenderer.cc ../src/ThrownTogetherRenderer.cc
|
||||||
|
../src/CSGTermEvaluator.cc ../src/CGAL_Nef_polyhedron.cc ../src/cgalutils.cc
|
||||||
|
../src/CGALEvaluator.cc ../src/CGALCache.cc ../src/PolySetCGALEvaluator.cc ../src/qhash.cc
|
||||||
|
../src/CGAL_Nef_polyhedron_DxfData.cc ../src/cgaladv_minkowski2.cc ../src/cgaladv_convexhull2.cc
|
||||||
|
${COMMON_SOURCES})
|
||||||
|
set_target_properties(throwntogethertest PROPERTIES COMPILE_FLAGS "-DENABLE_OPENCSG -DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
|
||||||
|
target_link_libraries(throwntogethertest ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${QT_LIBRARIES} ${OPENCSG_LIBRARY} ${GLEW_LIBRARY} ${COCOA_LIBRARY} ${OPENGL_LIBRARY})
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# This functions adds cmd-line tests given files.
|
# This functions adds cmd-line tests given files.
|
||||||
# Files are sent as the parameters following TESTSUFFIX
|
# Files are sent as the parameters following TESTSUFFIX
|
||||||
#
|
#
|
||||||
|
find_package(PythonInterp)
|
||||||
function(add_cmdline_test TESTCMD TESTSUFFIX)
|
function(add_cmdline_test TESTCMD TESTSUFFIX)
|
||||||
get_filename_component(TESTCMD_NAME ${TESTCMD} NAME_WE)
|
get_filename_component(TESTCMD_NAME ${TESTCMD} NAME_WE)
|
||||||
foreach (SCADFILE ${ARGN})
|
foreach (SCADFILE ${ARGN})
|
||||||
get_filename_component(TESTNAME ${SCADFILE} NAME_WE)
|
get_filename_component(TESTNAME ${SCADFILE} NAME_WE)
|
||||||
string(REPLACE " " "_" TESTNAME ${TESTNAME}) # Test names cannot include spaces
|
string(REPLACE " " "_" TESTNAME ${TESTNAME}) # Test names cannot include spaces
|
||||||
add_test("${TESTCMD_NAME}_${TESTNAME}" ${tests_SOURCE_DIR}/test_cmdline_tool.py -s ${TESTSUFFIX} ${CMAKE_BINARY_DIR}/${TESTCMD} "${SCADFILE}")
|
add_test("${TESTCMD_NAME}_${TESTNAME}" ${PYTHON_EXECUTABLE} ${tests_SOURCE_DIR}/test_cmdline_tool.py -s ${TESTSUFFIX} ${CMAKE_BINARY_DIR}/${TESTCMD} "${SCADFILE}")
|
||||||
endforeach()
|
endforeach()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
@ -256,7 +373,8 @@ LIST(APPEND CGALPNGTEST_FILES
|
||||||
${CMAKE_SOURCE_DIR}/../testdata/scad/features/assign-tests.scad
|
${CMAKE_SOURCE_DIR}/../testdata/scad/features/assign-tests.scad
|
||||||
${CMAKE_SOURCE_DIR}/../testdata/scad/features/include-tests.scad
|
${CMAKE_SOURCE_DIR}/../testdata/scad/features/include-tests.scad
|
||||||
${CMAKE_SOURCE_DIR}/../testdata/scad/features/child-tests.scad
|
${CMAKE_SOURCE_DIR}/../testdata/scad/features/child-tests.scad
|
||||||
${CMAKE_SOURCE_DIR}/../testdata/scad/features/ifelse-tests.scad)
|
${CMAKE_SOURCE_DIR}/../testdata/scad/features/ifelse-tests.scad
|
||||||
|
${CMAKE_SOURCE_DIR}/../testdata/scad/features/rotate_extrude_dxf-tests.scad)
|
||||||
LIST(APPEND CGALPNGTEST_FILES ${SCAD_DXF_FILES})
|
LIST(APPEND CGALPNGTEST_FILES ${SCAD_DXF_FILES})
|
||||||
#LIST(APPEND CGALPNGTEST_FILES ${CMAKE_SOURCE_DIR}/../examples/example001.scad)
|
#LIST(APPEND CGALPNGTEST_FILES ${CMAKE_SOURCE_DIR}/../examples/example001.scad)
|
||||||
add_cmdline_test(cgalpngtest png ${CGALPNGTEST_FILES})
|
add_cmdline_test(cgalpngtest png ${CGALPNGTEST_FILES})
|
||||||
|
@ -269,5 +387,9 @@ LIST(APPEND OPENCSGTEST_FILES
|
||||||
LIST(APPEND OPENCSGTEST_FILES ${SCAD_DXF_FILES})
|
LIST(APPEND OPENCSGTEST_FILES ${SCAD_DXF_FILES})
|
||||||
add_cmdline_test(opencsgtest png ${OPENCSGTEST_FILES})
|
add_cmdline_test(opencsgtest png ${OPENCSGTEST_FILES})
|
||||||
|
|
||||||
|
# Add throwntogether tests to CTest
|
||||||
|
LIST(APPEND THROWNTOGETHERTEST_FILES ${CGALPNGTEST_FILES})
|
||||||
|
add_cmdline_test(throwntogethertest png ${THROWNTOGETHERTEST_FILES})
|
||||||
|
|
||||||
# Add dxfexport tests to CTest
|
# Add dxfexport tests to CTest
|
||||||
#add_cmdline_test(${CMAKE_SOURCE_DIR}/../test-code/exportdxf dxf ${SCAD_FILES})
|
add_cmdline_test(${CMAKE_SOURCE_DIR}/../test-code/exportdxf dxf ${SCAD_FILES})
|
||||||
|
|
|
@ -7,20 +7,30 @@
|
||||||
# GLEW_LIBRARY
|
# GLEW_LIBRARY
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# a few lines of this file are based on the LGPL code found at
|
||||||
|
# http://openlibraries.org/browser/trunk/FindGLEW.cmake?rev=1383
|
||||||
|
|
||||||
|
|
||||||
IF (WIN32)
|
IF (WIN32)
|
||||||
|
IF (WIN32_STATIC_BUILD) # passed from caller
|
||||||
|
SET(GLEW_LIB_SEARCH_NAME glew32s.lib) # static, non-debug (Release)
|
||||||
|
ELSE ()
|
||||||
|
SET(GLEW_LIB_SEARCH_NAME glew32.lib) # other. untested with OpenSCAD
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
FIND_PATH( GLEW_INCLUDE_PATH GL/glew.h
|
FIND_PATH( GLEW_INCLUDE_PATH GL/glew.h
|
||||||
$ENV{PROGRAMFILES}/GLEW/include
|
$ENV{PROGRAMFILES}/GLEW/include
|
||||||
${PROJECT_SOURCE_DIR}/src/nvgl/glew/include
|
${PROJECT_SOURCE_DIR}/src/nvgl/glew/include
|
||||||
DOC "The directory where GL/glew.h resides")
|
DOC "The directory where GL/glew.h resides")
|
||||||
FIND_LIBRARY( GLEW_LIBRARY
|
FIND_LIBRARY( GLEW_LIBRARY
|
||||||
NAMES glew GLEW glew32 glew32s
|
NAMES ${GLEW_LIB_SEARCH_NAME}
|
||||||
PATHS
|
PATHS
|
||||||
$ENV{PROGRAMFILES}/GLEW/lib
|
$ENV{PROGRAMFILES}/GLEW/lib
|
||||||
${PROJECT_SOURCE_DIR}/src/nvgl/glew/bin
|
${PROJECT_SOURCE_DIR}/src/nvgl/glew/bin
|
||||||
${PROJECT_SOURCE_DIR}/src/nvgl/glew/lib
|
${PROJECT_SOURCE_DIR}/src/nvgl/glew/lib
|
||||||
DOC "The GLEW library")
|
DOC "The GLEW library")
|
||||||
ELSE (WIN32)
|
ELSE (WIN32)
|
||||||
message("GLEW_DIR: " ${GLEW_DIR})
|
message("-- GLEW_DIR: " ${GLEW_DIR})
|
||||||
FIND_PATH( GLEW_INCLUDE_PATH GL/glew.h
|
FIND_PATH( GLEW_INCLUDE_PATH GL/glew.h
|
||||||
PATHS ${GLEW_DIR}/include /usr/include /usr/local/include
|
PATHS ${GLEW_DIR}/include /usr/include /usr/local/include
|
||||||
NO_DEFAULT_PATH
|
NO_DEFAULT_PATH
|
||||||
|
|
|
@ -0,0 +1,244 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Create an OpenGL context without creating an OpenGL Window. for Linux.
|
||||||
|
|
||||||
|
See Also
|
||||||
|
|
||||||
|
glxgears.c by Brian Paul from mesa-demos (mesa3d.org)
|
||||||
|
http://cgit.freedesktop.org/mesa/demos/tree/src/xdemos?id=mesa-demos-8.0.1
|
||||||
|
http://www.opengl.org/sdk/docs/man/xhtml/glXIntro.xml
|
||||||
|
http://www.mesa3d.org/brianp/sig97/offscrn.htm
|
||||||
|
http://glprogramming.com/blue/ch07.html
|
||||||
|
OffscreenContext.mm (Mac OSX version)
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "OffscreenContext.h"
|
||||||
|
#include "printutils.h"
|
||||||
|
#include "imageutils.h"
|
||||||
|
#include "system-gl.h"
|
||||||
|
#include "fbo.h"
|
||||||
|
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glx.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
struct OffscreenContext
|
||||||
|
{
|
||||||
|
GLXContext openGLContext;
|
||||||
|
Display *xdisplay;
|
||||||
|
Window xwindow;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
fbo_t *fbo;
|
||||||
|
};
|
||||||
|
|
||||||
|
void offscreen_context_init(OffscreenContext &ctx, int width, int height)
|
||||||
|
{
|
||||||
|
ctx.width = width;
|
||||||
|
ctx.height = height;
|
||||||
|
ctx.openGLContext = NULL;
|
||||||
|
ctx.xdisplay = NULL;
|
||||||
|
ctx.xwindow = (Window)NULL;
|
||||||
|
ctx.fbo = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static XErrorHandler original_xlib_handler = (XErrorHandler) NULL;
|
||||||
|
static bool XCreateWindow_failed = false;
|
||||||
|
static int XCreateWindow_error(Display *dpy, XErrorEvent *event)
|
||||||
|
{
|
||||||
|
cerr << "XCreateWindow failed: XID: " << event->resourceid
|
||||||
|
<< " request: " << (int)event->request_code
|
||||||
|
<< " minor: " << (int)event->minor_code << "\n";
|
||||||
|
char description[1024];
|
||||||
|
XGetErrorText( dpy, event->error_code, description, 1023 );
|
||||||
|
cerr << " error message: " << description << "\n";
|
||||||
|
XCreateWindow_failed = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool create_glx_dummy_window(OffscreenContext &ctx)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
create a dummy X window without showing it. (without 'mapping' it)
|
||||||
|
and save information to the ctx.
|
||||||
|
|
||||||
|
This purposely does not use glxCreateWindow, to avoid crashes,
|
||||||
|
"failed to create drawable" errors, and Mesa "WARNING: Application calling
|
||||||
|
GLX 1.3 function when GLX 1.3 is not supported! This is an application bug!"
|
||||||
|
|
||||||
|
This function will alter ctx.openGLContext and ctx.xwindow if successfull
|
||||||
|
*/
|
||||||
|
|
||||||
|
int attributes[] = {
|
||||||
|
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
||||||
|
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||||
|
GLX_RED_SIZE, 1,
|
||||||
|
GLX_GREEN_SIZE, 1,
|
||||||
|
GLX_BLUE_SIZE, 1,
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Display *dpy = ctx.xdisplay;
|
||||||
|
|
||||||
|
int num_returned = 0;
|
||||||
|
GLXFBConfig *fbconfigs = glXChooseFBConfig( dpy, DefaultScreen(dpy), attributes, &num_returned );
|
||||||
|
if ( fbconfigs == NULL ) {
|
||||||
|
cerr << "glXChooseFBConfig failed\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
XVisualInfo *visinfo = glXGetVisualFromFBConfig( dpy, fbconfigs[0] );
|
||||||
|
if ( visinfo == NULL ) {
|
||||||
|
cerr << "glXGetVisualFromFBConfig failed\n";
|
||||||
|
XFree( fbconfigs );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// can't depend on xWin==NULL at failure. use a custom Xlib error handler instead.
|
||||||
|
original_xlib_handler = XSetErrorHandler( XCreateWindow_error );
|
||||||
|
Window xWin = XCreateSimpleWindow( dpy, DefaultRootWindow(dpy), 0,0,10,10, 0,0,0 );
|
||||||
|
XSync( dpy, false );
|
||||||
|
if ( XCreateWindow_failed ) {
|
||||||
|
XFree( visinfo );
|
||||||
|
XFree( fbconfigs );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
XSetErrorHandler( original_xlib_handler );
|
||||||
|
|
||||||
|
// Most programs would call XMapWindow here. But we don't, to keep the window hidden
|
||||||
|
// XMapWindow( dpy, xWin );
|
||||||
|
|
||||||
|
GLXContext context = glXCreateNewContext( dpy, fbconfigs[0], GLX_RGBA_TYPE, NULL, True );
|
||||||
|
if ( context == NULL ) {
|
||||||
|
cerr << "glXCreateNewContext failed\n";
|
||||||
|
XDestroyWindow( dpy, xWin );
|
||||||
|
XFree( visinfo );
|
||||||
|
XFree( fbconfigs );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//GLXWindow glxWin = glXCreateWindow( dpy, fbconfigs[0], xWin, NULL );
|
||||||
|
|
||||||
|
if (!glXMakeContextCurrent( dpy, xWin, xWin, context )) {
|
||||||
|
//if (!glXMakeContextCurrent( dpy, glxWin, glxWin, context )) {
|
||||||
|
cerr << "glXMakeContextCurrent failed\n";
|
||||||
|
glXDestroyContext( dpy, context );
|
||||||
|
XDestroyWindow( dpy, xWin );
|
||||||
|
XFree( visinfo );
|
||||||
|
XFree( fbconfigs );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.openGLContext = context;
|
||||||
|
ctx.xwindow = xWin;
|
||||||
|
|
||||||
|
XFree( visinfo );
|
||||||
|
XFree( fbconfigs );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Bool create_glx_dummy_context(OffscreenContext &ctx)
|
||||||
|
{
|
||||||
|
// This will alter ctx.openGLContext and ctx.xdisplay and ctx.xwindow if successfull
|
||||||
|
int major;
|
||||||
|
int minor;
|
||||||
|
Bool result = False;
|
||||||
|
|
||||||
|
ctx.xdisplay = XOpenDisplay( NULL );
|
||||||
|
if ( ctx.xdisplay == NULL ) {
|
||||||
|
cerr << "Unable to open a connection to the X server\n";
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
|
||||||
|
// glxQueryVersion is not always reliable. Use it, but then
|
||||||
|
// also check to see if GLX 1.3 functions exist
|
||||||
|
|
||||||
|
glXQueryVersion(ctx.xdisplay, &major, &minor);
|
||||||
|
|
||||||
|
if ( major==1 && minor<=2 && glXGetVisualFromFBConfig==NULL ) {
|
||||||
|
cerr << "Error: GLX version 1.3 functions missing. "
|
||||||
|
<< "Your GLX version: " << major << "." << minor << endl;
|
||||||
|
} else {
|
||||||
|
result = create_glx_dummy_window(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result) XCloseDisplay( ctx.xdisplay );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
OffscreenContext *create_offscreen_context(int w, int h)
|
||||||
|
{
|
||||||
|
OffscreenContext *ctx = new OffscreenContext;
|
||||||
|
offscreen_context_init( *ctx, w, h );
|
||||||
|
|
||||||
|
// before an FBO can be setup, a GLX context must be created
|
||||||
|
// this call alters ctx->xDisplay and ctx->openGLContext
|
||||||
|
// and ctx->xwindow if successfull
|
||||||
|
if (!create_glx_dummy_context( *ctx )) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// glewInit must come after Context creation and before FBO calls.
|
||||||
|
GLenum err = glewInit();
|
||||||
|
if (GLEW_OK != err) {
|
||||||
|
cerr << "Unable to init GLEW: " << glewGetErrorString(err) << endl;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
glew_dump();
|
||||||
|
|
||||||
|
ctx->fbo = fbo_new();
|
||||||
|
if (!fbo_init(ctx->fbo, w, h)) {
|
||||||
|
cerr << "GL Framebuffer Object init failed; dumping GLEW info" << endl;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool teardown_offscreen_context(OffscreenContext *ctx)
|
||||||
|
{
|
||||||
|
if (ctx) {
|
||||||
|
fbo_unbind(ctx->fbo);
|
||||||
|
fbo_delete(ctx->fbo);
|
||||||
|
XDestroyWindow( ctx->xdisplay, ctx->xwindow );
|
||||||
|
glXDestroyContext( ctx->xdisplay, ctx->openGLContext );
|
||||||
|
XCloseDisplay( ctx->xdisplay );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Capture framebuffer from OpenGL and write it to the given filename as PNG.
|
||||||
|
*/
|
||||||
|
bool save_framebuffer(OffscreenContext *ctx, const char *filename)
|
||||||
|
{
|
||||||
|
if (!ctx || !filename) return false;
|
||||||
|
int samplesPerPixel = 4; // R, G, B and A
|
||||||
|
GLubyte pixels[ctx->width * ctx->height * samplesPerPixel];
|
||||||
|
glReadPixels(0, 0, ctx->width, ctx->height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||||
|
|
||||||
|
// Flip it vertically - images read from OpenGL buffers are upside-down
|
||||||
|
int rowBytes = samplesPerPixel * ctx->width;
|
||||||
|
unsigned char *flippedBuffer = (unsigned char *)malloc(rowBytes * ctx->height);
|
||||||
|
if (!flippedBuffer) {
|
||||||
|
std::cerr << "Unable to allocate flipped buffer for corrected image.";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
flip_image(pixels, flippedBuffer, samplesPerPixel, ctx->width, ctx->height);
|
||||||
|
|
||||||
|
bool writeok = write_png(filename, flippedBuffer, ctx->width, ctx->height);
|
||||||
|
|
||||||
|
free(flippedBuffer);
|
||||||
|
|
||||||
|
return writeok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind_offscreen_context(OffscreenContext *ctx)
|
||||||
|
{
|
||||||
|
if (ctx) fbo_bind(ctx->fbo);
|
||||||
|
}
|
|
@ -1,11 +1,8 @@
|
||||||
#ifndef OFFSCREENCONTEXT_H_
|
#ifndef OFFSCREENCONTEXT_H_
|
||||||
#define OFFSCREENCONTEXT_H_
|
#define OFFSCREENCONTEXT_H_
|
||||||
|
|
||||||
#include <OpenGL/OpenGL.h>
|
|
||||||
#include <iostream> // for error output
|
#include <iostream> // for error output
|
||||||
|
|
||||||
#define REPORTGLERROR(task) { GLenum tGLErr = glGetError(); if (tGLErr != GL_NO_ERROR) { std::cout << "OpenGL error " << tGLErr << " while " << task << "\n"; } }
|
|
||||||
|
|
||||||
struct OffscreenContext *create_offscreen_context(int w, int h);
|
struct OffscreenContext *create_offscreen_context(int w, int h);
|
||||||
void bind_offscreen_context(OffscreenContext *ctx);
|
void bind_offscreen_context(OffscreenContext *ctx);
|
||||||
bool teardown_offscreen_context(OffscreenContext *ctx);
|
bool teardown_offscreen_context(OffscreenContext *ctx);
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
#include "OffscreenContext.h"
|
#include "OffscreenContext.h"
|
||||||
|
#include "imageutils.h"
|
||||||
|
#include "fbo.h"
|
||||||
|
|
||||||
#import <OpenGL/OpenGL.h>
|
|
||||||
#import <OpenGL/glu.h> // for gluCheckExtension
|
|
||||||
#import <AppKit/AppKit.h> // for NSOpenGL...
|
#import <AppKit/AppKit.h> // for NSOpenGL...
|
||||||
|
|
||||||
// Simple error reporting macros to help keep the sample code clean
|
|
||||||
#define REPORT_ERROR_AND_EXIT(desc) { std::cout << desc << "\n"; return false; }
|
#define REPORTGLERROR(task) { GLenum tGLErr = glGetError(); if (tGLErr != GL_NO_ERROR) { std::cout << "OpenGL error " << tGLErr << " while " << task << "\n"; } }
|
||||||
#define NULL_ERROR_EXIT(test, desc) { if (!test) REPORT_ERROR_AND_EXIT(desc); }
|
|
||||||
|
|
||||||
struct OffscreenContext
|
struct OffscreenContext
|
||||||
{
|
{
|
||||||
|
@ -14,7 +13,7 @@ struct OffscreenContext
|
||||||
NSAutoreleasePool *pool;
|
NSAutoreleasePool *pool;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
GLuint fbo;
|
fbo_t *fbo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,78 +25,58 @@ OffscreenContext *create_offscreen_context(int w, int h)
|
||||||
|
|
||||||
ctx->pool = [NSAutoreleasePool new];
|
ctx->pool = [NSAutoreleasePool new];
|
||||||
|
|
||||||
/*
|
// Create an OpenGL context just so that OpenGL calls will work.
|
||||||
* Create an OpenGL context just so that OpenGL calls will work. I'm not
|
// Will not be used for actual rendering.
|
||||||
using it for actual rendering.
|
|
||||||
*/
|
|
||||||
|
|
||||||
NSOpenGLPixelFormatAttribute attributes[] = {
|
NSOpenGLPixelFormatAttribute attributes[] = {
|
||||||
NSOpenGLPFAPixelBuffer,
|
NSOpenGLPFAPixelBuffer,
|
||||||
NSOpenGLPFANoRecovery,
|
NSOpenGLPFANoRecovery,
|
||||||
NSOpenGLPFAAccelerated,
|
NSOpenGLPFAAccelerated,
|
||||||
NSOpenGLPFADepthSize, 24,
|
NSOpenGLPFADepthSize, 24,
|
||||||
(NSOpenGLPixelFormatAttribute) 0
|
(NSOpenGLPixelFormatAttribute) 0
|
||||||
};
|
};
|
||||||
NSOpenGLPixelFormat* pixFormat = [[[NSOpenGLPixelFormat
|
NSOpenGLPixelFormat *pixFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes] autorelease];
|
||||||
alloc] initWithAttributes:attributes] autorelease];
|
|
||||||
// Create the OpenGL context to render with (with color and depth buffers)
|
// Create and make current the OpenGL context to render with (with color and depth buffers)
|
||||||
ctx->openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixFormat
|
ctx->openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixFormat shareContext:nil];
|
||||||
shareContext:nil];
|
if (!ctx->openGLContext) {
|
||||||
NULL_ERROR_EXIT(ctx->openGLContext, "Unable to create NSOpenGLContext");
|
std::cerr << "Unable to create NSOpenGLContext\n";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
[ctx->openGLContext makeCurrentContext];
|
[ctx->openGLContext makeCurrentContext];
|
||||||
|
|
||||||
|
glewInit();
|
||||||
|
#ifdef DEBUG
|
||||||
|
cout << "GLEW version " << glewGetString(GLEW_VERSION) << "\n";
|
||||||
|
cout << (const char *)glGetString(GL_RENDERER) << "(" << (const char *)glGetString(GL_VENDOR) << ")\n"
|
||||||
|
<< "OpenGL version " << (const char *)glGetString(GL_VERSION) << "\n";
|
||||||
|
cout << "Extensions: " << (const char *)glGetString(GL_EXTENSIONS) << "\n";
|
||||||
|
|
||||||
|
|
||||||
|
if (GLEW_ARB_framebuffer_object) {
|
||||||
|
cout << "ARB_FBO supported\n";
|
||||||
|
}
|
||||||
|
if (GLEW_EXT_framebuffer_object) {
|
||||||
|
cout << "EXT_FBO supported\n";
|
||||||
|
}
|
||||||
|
if (GLEW_EXT_packed_depth_stencil) {
|
||||||
|
cout << "EXT_packed_depth_stencil\n";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
ctx->fbo = fbo_new();
|
||||||
* Test if framebuffer objects are supported
|
if (!fbo_init(ctx->fbo, w, h)) {
|
||||||
*/
|
return NULL;
|
||||||
const GLubyte* strExt = glGetString(GL_EXTENSIONS);
|
}
|
||||||
GLboolean fboSupported = gluCheckExtension((const GLubyte*)"GL_EXT_framebuffer_object", strExt);
|
|
||||||
if (!fboSupported)
|
|
||||||
REPORT_ERROR_AND_EXIT("Your system does not support framebuffer extension - unable to render scene");
|
|
||||||
/*
|
|
||||||
* Create an FBO
|
|
||||||
*/
|
|
||||||
GLuint renderBuffer = 0;
|
|
||||||
GLuint depthBuffer = 0;
|
|
||||||
// Depth buffer to use for depth testing - optional if you're not using depth testing
|
|
||||||
glGenRenderbuffersEXT(1, &depthBuffer);
|
|
||||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthBuffer);
|
|
||||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, w, h);
|
|
||||||
REPORTGLERROR("creating depth render buffer");
|
|
||||||
|
|
||||||
// Render buffer to use for imaging
|
|
||||||
glGenRenderbuffersEXT(1, &renderBuffer);
|
|
||||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderBuffer);
|
|
||||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, w, h);
|
|
||||||
REPORTGLERROR("creating color render buffer");
|
|
||||||
ctx->fbo = 0;
|
|
||||||
glGenFramebuffersEXT(1, &ctx->fbo);
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->fbo);
|
|
||||||
REPORTGLERROR("binding framebuffer");
|
|
||||||
|
|
||||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
|
||||||
GL_RENDERBUFFER_EXT, renderBuffer);
|
|
||||||
REPORTGLERROR("specifying color render buffer");
|
|
||||||
|
|
||||||
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) !=
|
|
||||||
GL_FRAMEBUFFER_COMPLETE_EXT)
|
|
||||||
REPORT_ERROR_AND_EXIT("Problem with OpenGL framebuffer after specifying color render buffer.");
|
|
||||||
|
|
||||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
|
|
||||||
GL_RENDERBUFFER_EXT, depthBuffer);
|
|
||||||
REPORTGLERROR("specifying depth render buffer");
|
|
||||||
|
|
||||||
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) !=
|
|
||||||
GL_FRAMEBUFFER_COMPLETE_EXT)
|
|
||||||
REPORT_ERROR_AND_EXIT("Problem with OpenGL framebuffer after specifying depth render buffer.");
|
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool teardown_offscreen_context(OffscreenContext *ctx)
|
bool teardown_offscreen_context(OffscreenContext *ctx)
|
||||||
{
|
{
|
||||||
// "un"bind my FBO
|
fbo_unbind(ctx->fbo);
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
fbo_delete(ctx->fbo);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cleanup
|
* Cleanup
|
||||||
|
@ -109,99 +88,40 @@ bool teardown_offscreen_context(OffscreenContext *ctx)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Capture framebuffer from OpenGL and write it to the given filename as PNG.
|
||||||
|
*/
|
||||||
bool save_framebuffer(OffscreenContext *ctx, const char *filename)
|
bool save_framebuffer(OffscreenContext *ctx, const char *filename)
|
||||||
{
|
{
|
||||||
/*
|
// Read pixels from OpenGL
|
||||||
* Extract the resulting rendering as an image
|
|
||||||
*/
|
|
||||||
|
|
||||||
int samplesPerPixel = 4; // R, G, B and A
|
int samplesPerPixel = 4; // R, G, B and A
|
||||||
int rowBytes = samplesPerPixel * ctx->width;
|
int rowBytes = samplesPerPixel * ctx->width;
|
||||||
char* bufferData = (char*)malloc(rowBytes * ctx->height);
|
unsigned char *bufferData = (unsigned char *)malloc(rowBytes * ctx->height);
|
||||||
if (!bufferData) {
|
if (!bufferData) {
|
||||||
std::cerr << "Unable to allocate buffer for image extraction.";
|
std::cerr << "Unable to allocate buffer for image extraction.";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
glReadPixels(0, 0, ctx->width, ctx->height, GL_BGRA, GL_UNSIGNED_BYTE,
|
glReadPixels(0, 0, ctx->width, ctx->height, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||||
bufferData);
|
bufferData);
|
||||||
REPORTGLERROR("reading pixels from framebuffer");
|
REPORTGLERROR("reading pixels from framebuffer");
|
||||||
|
|
||||||
// Flip it vertically - images read from OpenGL buffers are upside-down
|
// Flip it vertically - images read from OpenGL buffers are upside-down
|
||||||
char* flippedBuffer = (char*)malloc(rowBytes * ctx->height);
|
unsigned char *flippedBuffer = (unsigned char *)malloc(rowBytes * ctx->height);
|
||||||
if (!flippedBuffer) {
|
if (!flippedBuffer) {
|
||||||
std::cout << "Unable to allocate flipped buffer for corrected image.";
|
std::cout << "Unable to allocate flipped buffer for corrected image.";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
for (int i = 0 ; i < ctx->height ; i++) {
|
flip_image(bufferData, flippedBuffer, samplesPerPixel, ctx->width, ctx->height);
|
||||||
bcopy(bufferData + i * rowBytes, flippedBuffer + (ctx->height - i - 1) *
|
|
||||||
rowBytes, rowBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
bool writeok = write_png(filename, flippedBuffer, ctx->width, ctx->height);
|
||||||
* Output the image to a file
|
|
||||||
*/
|
|
||||||
CGColorSpaceRef colorSpace =
|
|
||||||
CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
|
|
||||||
CGBitmapInfo bitmapInfo = kCGImageAlphaNoneSkipFirst |
|
|
||||||
kCGBitmapByteOrder32Little; // XRGB Little Endian
|
|
||||||
int bitsPerComponent = 8;
|
|
||||||
CGContextRef contextRef = CGBitmapContextCreate(flippedBuffer,
|
|
||||||
ctx->width, ctx->height, bitsPerComponent, rowBytes,
|
|
||||||
colorSpace, bitmapInfo);
|
|
||||||
if (!contextRef) {
|
|
||||||
std::cerr << "Unable to create CGContextRef.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
CGImageRef imageRef = CGBitmapContextCreateImage(contextRef);
|
|
||||||
if (!imageRef) {
|
|
||||||
std::cerr << "Unable to create CGImageRef.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Boolean isDirectory = false;
|
|
||||||
CFStringRef fname = CFStringCreateWithCString(kCFAllocatorDefault, filename, kCFStringEncodingUTF8);
|
|
||||||
CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
|
|
||||||
fname, kCFURLPOSIXPathStyle, isDirectory);
|
|
||||||
if (!fileURL) {
|
|
||||||
std::cerr << "Unable to create file URL ref.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
CGDataConsumerRef dataconsumer = CGDataConsumerCreateWithURL(fileURL);
|
|
||||||
|
|
||||||
CFIndex fileImageIndex = 1;
|
|
||||||
CFMutableDictionaryRef fileDict = NULL;
|
|
||||||
CFStringRef fileUTType = kUTTypePNG;
|
|
||||||
// Create an image destination opaque reference for authoring an image file
|
|
||||||
CGImageDestinationRef imageDest = CGImageDestinationCreateWithDataConsumer(dataconsumer,
|
|
||||||
fileUTType,
|
|
||||||
fileImageIndex,
|
|
||||||
fileDict);
|
|
||||||
if (!imageDest) {
|
|
||||||
std::cerr << "Unable to create CGImageDestinationRef.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
CFIndex capacity = 1;
|
|
||||||
CFMutableDictionaryRef imageProps =
|
|
||||||
CFDictionaryCreateMutable(kCFAllocatorDefault,
|
|
||||||
capacity,
|
|
||||||
&kCFTypeDictionaryKeyCallBacks,
|
|
||||||
&kCFTypeDictionaryValueCallBacks);
|
|
||||||
CGImageDestinationAddImage(imageDest, imageRef, imageProps);
|
|
||||||
CGImageDestinationFinalize(imageDest);
|
|
||||||
|
|
||||||
free(flippedBuffer);
|
free(flippedBuffer);
|
||||||
free(bufferData);
|
free(bufferData);
|
||||||
CFRelease(imageDest);
|
|
||||||
CFRelease(dataconsumer);
|
return writeok;
|
||||||
CFRelease(fileURL);
|
|
||||||
CFRelease(fname);
|
|
||||||
CFRelease(imageProps);
|
|
||||||
CGColorSpaceRelease(colorSpace);
|
|
||||||
CGImageRelease(imageRef);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bind_offscreen_context(OffscreenContext *ctx)
|
void bind_offscreen_context(OffscreenContext *ctx)
|
||||||
{
|
{
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->fbo);
|
fbo_bind(ctx->fbo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Create an OpenGL context without creating an OpenGL Window. for Windows.
|
||||||
|
|
||||||
|
For more info:
|
||||||
|
|
||||||
|
http://www.nullterminator.net/opengl32.html by Blaine Hodge
|
||||||
|
http://msdn.microsoft.com/en-us/library/ee418815(v=vs.85).aspx
|
||||||
|
http://www.cprogramming.com/tutorial/wgl_wiggle_functions.html by RoD
|
||||||
|
( which includes robot.cc by Steven Billington )
|
||||||
|
http://blogs.msdn.com/b/oldnewthing/archive/2006/12/04/1205831.aspx by Tom
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "OffscreenContext.h"
|
||||||
|
#include "printutils.h"
|
||||||
|
#include "imageutils.h"
|
||||||
|
#include "system-gl.h"
|
||||||
|
#include "fbo.h"
|
||||||
|
|
||||||
|
#include <GL/gl.h> // must be included after glew.h
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
struct OffscreenContext
|
||||||
|
{
|
||||||
|
HWND window;
|
||||||
|
HDC dev_context;
|
||||||
|
HGLRC openGLContext;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
fbo_t *fbo;
|
||||||
|
};
|
||||||
|
|
||||||
|
void offscreen_context_init(OffscreenContext &ctx, int width, int height)
|
||||||
|
{
|
||||||
|
ctx.window = (HWND)NULL;
|
||||||
|
ctx.dev_context = (HDC)NULL;
|
||||||
|
ctx.openGLContext = (HGLRC)NULL;
|
||||||
|
ctx.width = width;
|
||||||
|
ctx.height = height;
|
||||||
|
ctx.fbo = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
|
||||||
|
{
|
||||||
|
return DefWindowProc( hwnd, message, wparam, lparam );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool create_wgl_dummy_context(OffscreenContext &ctx)
|
||||||
|
{
|
||||||
|
// this function alters ctx->window and ctx->openGLContext
|
||||||
|
// and ctx->dev_context if successfull
|
||||||
|
|
||||||
|
// create window
|
||||||
|
|
||||||
|
HINSTANCE inst = GetModuleHandle(0);
|
||||||
|
WNDCLASS wc;
|
||||||
|
ZeroMemory( &wc, sizeof( wc ) );
|
||||||
|
wc.style = CS_OWNDC;
|
||||||
|
wc.lpfnWndProc = WndProc;
|
||||||
|
wc.hInstance = inst;
|
||||||
|
wc.lpszClassName = "OpenSCAD";
|
||||||
|
RegisterClass( &wc );
|
||||||
|
|
||||||
|
HWND window = CreateWindow( "OpenSCAD", "OpenSCAD",
|
||||||
|
WS_CAPTION | WS_POPUPWINDOW, //| WS_VISIBLE,
|
||||||
|
0, 0, ctx.width, ctx.height, NULL, NULL, inst, NULL );
|
||||||
|
|
||||||
|
if ( window==NULL ) {
|
||||||
|
cerr << "MS GDI - CreateWindow failed\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create WGL context, make current
|
||||||
|
|
||||||
|
PIXELFORMATDESCRIPTOR pixformat;
|
||||||
|
int chosenformat;
|
||||||
|
HDC dev_context = GetDC( window );
|
||||||
|
if ( dev_context == NULL ) {
|
||||||
|
cerr << "MS GDI - GetDC failed\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZeroMemory( &pixformat, sizeof( pixformat ) );
|
||||||
|
pixformat.nSize = sizeof( pixformat );
|
||||||
|
pixformat.nVersion = 1;
|
||||||
|
pixformat.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
|
||||||
|
pixformat.iPixelType = PFD_TYPE_RGBA;
|
||||||
|
pixformat.cColorBits = 24;
|
||||||
|
pixformat.cDepthBits = 16;
|
||||||
|
pixformat.iLayerType = PFD_MAIN_PLANE;
|
||||||
|
chosenformat = ChoosePixelFormat( dev_context, &pixformat );
|
||||||
|
if (chosenformat==0) {
|
||||||
|
cerr << "MS GDI - ChoosePixelFormat failed\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool spfok = SetPixelFormat( dev_context, chosenformat, &pixformat );
|
||||||
|
if (!spfok) {
|
||||||
|
cerr << "MS GDI - SetPixelFormat failed\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HGLRC gl_render_context = wglCreateContext( dev_context );
|
||||||
|
if ( gl_render_context == NULL ) {
|
||||||
|
cerr << "MS WGL - wglCreateContext failed\n";
|
||||||
|
ReleaseDC( ctx.window, ctx.dev_context );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mcok = wglMakeCurrent( dev_context, gl_render_context );
|
||||||
|
if (!mcok) {
|
||||||
|
cerr << "MS WGL - wglMakeCurrent failed\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.window = window;
|
||||||
|
ctx.dev_context = dev_context;
|
||||||
|
ctx.openGLContext = gl_render_context;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OffscreenContext *create_offscreen_context(int w, int h)
|
||||||
|
{
|
||||||
|
OffscreenContext *ctx = new OffscreenContext;
|
||||||
|
offscreen_context_init( *ctx, w, h );
|
||||||
|
|
||||||
|
// Before an FBO can be setup, a WGL context must be created.
|
||||||
|
// This call alters ctx->window and ctx->openGLContext
|
||||||
|
// and ctx->dev_context if successfull
|
||||||
|
if (!create_wgl_dummy_context( *ctx )) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLenum err = glewInit(); // must come after Context creation and before FBO calls.
|
||||||
|
if (GLEW_OK != err) {
|
||||||
|
cerr << "Unable to init GLEW: " << glewGetErrorString(err) << "\n";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
glew_dump();
|
||||||
|
|
||||||
|
ctx->fbo = fbo_new();
|
||||||
|
if (!fbo_init(ctx->fbo, w, h)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool teardown_offscreen_context(OffscreenContext *ctx)
|
||||||
|
{
|
||||||
|
if (ctx) {
|
||||||
|
fbo_unbind(ctx->fbo);
|
||||||
|
fbo_delete(ctx->fbo);
|
||||||
|
|
||||||
|
wglMakeCurrent( NULL, NULL );
|
||||||
|
wglDeleteContext( ctx->openGLContext );
|
||||||
|
ReleaseDC( ctx->window, ctx->dev_context );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Capture framebuffer from OpenGL and write it to the given filename as PNG.
|
||||||
|
*/
|
||||||
|
bool save_framebuffer(OffscreenContext *ctx, const char *filename)
|
||||||
|
{
|
||||||
|
if (!ctx || !filename) return false;
|
||||||
|
int samplesPerPixel = 4; // R, G, B and A
|
||||||
|
vector<GLubyte> pixels(ctx->width * ctx->height * samplesPerPixel);
|
||||||
|
glReadPixels(0, 0, ctx->width, ctx->height, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
|
||||||
|
|
||||||
|
// Flip it vertically - images read from OpenGL buffers are upside-down
|
||||||
|
int rowBytes = samplesPerPixel * ctx->width;
|
||||||
|
unsigned char *flippedBuffer = (unsigned char *)malloc(rowBytes * ctx->height);
|
||||||
|
if (!flippedBuffer) {
|
||||||
|
std::cerr << "Unable to allocate flipped buffer for corrected image.";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
flip_image(&pixels[0], flippedBuffer, samplesPerPixel, ctx->width, ctx->height);
|
||||||
|
|
||||||
|
bool writeok = write_png(filename, flippedBuffer, ctx->width, ctx->height);
|
||||||
|
|
||||||
|
free(flippedBuffer);
|
||||||
|
|
||||||
|
return writeok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind_offscreen_context(OffscreenContext *ctx)
|
||||||
|
{
|
||||||
|
if (ctx) fbo_bind(ctx->fbo);
|
||||||
|
}
|
|
@ -1,8 +1,11 @@
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include "OffscreenView.h"
|
#include "OffscreenView.h"
|
||||||
#include <opencsg.h>
|
#include <opencsg.h>
|
||||||
#include "Renderer.h"
|
#include "renderer.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
#define FAR_FAR_AWAY 100000.0
|
#define FAR_FAR_AWAY 100000.0
|
||||||
|
|
||||||
|
@ -11,7 +14,8 @@ OffscreenView::OffscreenView(size_t width, size_t height)
|
||||||
object_rot(35, 0, 25), camera_eye(0, 0, 0), camera_center(0, 0, 0)
|
object_rot(35, 0, 25), camera_eye(0, 0, 0), camera_center(0, 0, 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 10; i++) this->shaderinfo[i] = 0;
|
for (int i = 0; i < 10; i++) this->shaderinfo[i] = 0;
|
||||||
this->ctx = create_offscreen_context(width, height);
|
this->ctx = create_offscreen_context(width, height);
|
||||||
|
if ( this->ctx == NULL ) throw -1;
|
||||||
initializeGL();
|
initializeGL();
|
||||||
resizeGL(width, height);
|
resizeGL(width, height);
|
||||||
}
|
}
|
||||||
|
@ -182,7 +186,7 @@ void OffscreenView::paintGL()
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
|
|
||||||
glClearColor(1.0, 1.0, 0.92, 0.0);
|
glClearColor(1.0f, 1.0f, 0.92f, 1.0f);
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
#include "OffscreenContext.h"
|
#include "OffscreenContext.h"
|
||||||
#include <Eigen/Core>
|
#include <Eigen/Core>
|
||||||
#include <Eigen/Geometry>
|
#include <Eigen/Geometry>
|
||||||
|
#ifndef _MSC_VER
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
class OffscreenView
|
class OffscreenView
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
Work around bugs in MSVC compiler with Eigen AlignmentBox
|
||||||
|
bbox.min and bbox.max will fail with Syntax Errors if placed inside
|
||||||
|
of cgalpngtest.cc
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "linalg.h"
|
||||||
|
|
||||||
|
Vector3d getBoundingCenter(BoundingBox bbox)
|
||||||
|
{
|
||||||
|
Vector3d center = (bbox.min() + bbox.max()) / 2;
|
||||||
|
return center; // Vector3d(0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double getBoundingRadius(BoundingBox bbox)
|
||||||
|
{
|
||||||
|
double radius = (bbox.max() - bbox.min()).norm() / 2;
|
||||||
|
return radius; // 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,9 @@
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
#ifndef _MSC_VER
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#endif
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -82,14 +84,20 @@ struct CsgInfo
|
||||||
OffscreenView *glview;
|
OffscreenView *glview;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern Vector3d getBoundingCenter(BoundingBox bbox);
|
||||||
|
extern double getBoundingRadius(BoundingBox bbox);
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if (argc != 2) {
|
if (argc != 3) {
|
||||||
fprintf(stderr, "Usage: %s <file.scad>\n", argv[0]);
|
fprintf(stderr, "Usage: %s <file.scad> <output.png>\n", argv[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *filename = argv[1];
|
const char *filename = argv[1];
|
||||||
|
const char *outfile = argv[2];
|
||||||
|
|
||||||
initialize_builtin_functions();
|
initialize_builtin_functions();
|
||||||
initialize_builtin_modules();
|
initialize_builtin_modules();
|
||||||
|
@ -178,9 +186,19 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
QDir::setCurrent(original_path.absolutePath());
|
QDir::setCurrent(original_path.absolutePath());
|
||||||
|
|
||||||
csgInfo.glview = new OffscreenView(512,512);
|
// match with csgtest ends
|
||||||
|
try {
|
||||||
|
csgInfo.glview = new OffscreenView(512,512);
|
||||||
|
} catch (int error) {
|
||||||
|
fprintf(stderr,"Can't create OpenGL OffscreenView. Code: %i. Exiting.\n", error);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
glewInit();
|
GLenum err = glewInit();
|
||||||
|
if (GLEW_OK != err) {
|
||||||
|
fprintf(stderr, "Unable to init GLEW: %s\n", glewGetErrorString(err));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
cout << "GLEW version " << glewGetString(GLEW_VERSION) << "\n";
|
cout << "GLEW version " << glewGetString(GLEW_VERSION) << "\n";
|
||||||
cout << (const char *)glGetString(GL_RENDERER) << "(" << (const char *)glGetString(GL_VENDOR) << ")\n"
|
cout << (const char *)glGetString(GL_RENDERER) << "(" << (const char *)glGetString(GL_VENDOR) << ")\n"
|
||||||
|
@ -205,14 +223,14 @@ int main(int argc, char **argv)
|
||||||
if (cgalRenderer.polyhedron) {
|
if (cgalRenderer.polyhedron) {
|
||||||
CGAL::Bbox_3 cgalbbox = cgalRenderer.polyhedron->bbox();
|
CGAL::Bbox_3 cgalbbox = cgalRenderer.polyhedron->bbox();
|
||||||
bbox = BoundingBox(Vector3d(cgalbbox.xmin(), cgalbbox.ymin(), cgalbbox.zmin()),
|
bbox = BoundingBox(Vector3d(cgalbbox.xmin(), cgalbbox.ymin(), cgalbbox.zmin()),
|
||||||
Vector3d(cgalbbox.xmax(), cgalbbox.ymax(), cgalbbox.zmax()));
|
Vector3d(cgalbbox.xmax(), cgalbbox.ymax(), cgalbbox.zmax()));
|
||||||
}
|
}
|
||||||
else if (cgalRenderer.polyset) {
|
else if (cgalRenderer.polyset) {
|
||||||
bbox = cgalRenderer.polyset->getBoundingBox();
|
bbox = cgalRenderer.polyset->getBoundingBox();
|
||||||
}
|
}
|
||||||
Vector3d center = (bbox.min() + bbox.max()) / 2;
|
|
||||||
double radius = (bbox.max() - bbox.min()).norm() / 2;
|
|
||||||
|
|
||||||
|
Vector3d center = getBoundingCenter(bbox);
|
||||||
|
double radius = getBoundingRadius(bbox);
|
||||||
|
|
||||||
Vector3d cameradir(1, 1, -0.5);
|
Vector3d cameradir(1, 1, -0.5);
|
||||||
Vector3d camerapos = center - radius*2*cameradir;
|
Vector3d camerapos = center - radius*2*cameradir;
|
||||||
|
@ -221,7 +239,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
csgInfo.glview->setRenderer(&cgalRenderer);
|
csgInfo.glview->setRenderer(&cgalRenderer);
|
||||||
csgInfo.glview->paintGL();
|
csgInfo.glview->paintGL();
|
||||||
csgInfo.glview->save("/dev/stdout");
|
csgInfo.glview->save(outfile);
|
||||||
|
|
||||||
destroy_builtin_functions();
|
destroy_builtin_functions();
|
||||||
destroy_builtin_modules();
|
destroy_builtin_modules();
|
||||||
|
|
|
@ -42,7 +42,9 @@
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
|
#ifndef _MSC_VER
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#endif
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
|
@ -41,10 +41,13 @@
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#ifndef _MSC_VER
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#endif
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
using std::cout;
|
using std::cout;
|
||||||
|
|
||||||
|
@ -55,12 +58,13 @@ QString librarydir;
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if (argc != 2) {
|
if (argc != 3) {
|
||||||
fprintf(stderr, "Usage: %s <file.scad>\n", argv[0]);
|
fprintf(stderr, "Usage: %s <file.scad> <output.txt>\n", argv[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *filename = argv[1];
|
const char *filename = argv[1];
|
||||||
|
const char *outfilename = argv[2];
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
@ -110,7 +114,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
AbstractModule *root_module;
|
AbstractModule *root_module;
|
||||||
ModuleInstantiation root_inst;
|
ModuleInstantiation root_inst;
|
||||||
AbstractNode *root_node;
|
const AbstractNode *root_node;
|
||||||
|
|
||||||
QFileInfo fileInfo(filename);
|
QFileInfo fileInfo(filename);
|
||||||
handle_dep(filename);
|
handle_dep(filename);
|
||||||
|
@ -159,12 +163,15 @@ int main(int argc, char **argv)
|
||||||
// if (evaluator.background) cout << "Background terms: " << evaluator.background->size() << "\n";
|
// if (evaluator.background) cout << "Background terms: " << evaluator.background->size() << "\n";
|
||||||
// if (evaluator.highlights) cout << "Highlights terms: " << evaluator.highlights->size() << "\n";
|
// if (evaluator.highlights) cout << "Highlights terms: " << evaluator.highlights->size() << "\n";
|
||||||
|
|
||||||
|
std::ofstream outfile;
|
||||||
|
outfile.open(outfilename);
|
||||||
if (root_term) {
|
if (root_term) {
|
||||||
cout << root_term->dump() << "\n";
|
outfile << root_term->dump() << "\n";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cout << "No top-level CSG object\n";
|
outfile << "No top-level CSG object\n";
|
||||||
}
|
}
|
||||||
|
outfile.close();
|
||||||
|
|
||||||
destroy_builtin_functions();
|
destroy_builtin_functions();
|
||||||
destroy_builtin_modules();
|
destroy_builtin_modules();
|
||||||
|
|
|
@ -0,0 +1,254 @@
|
||||||
|
// csg test core, used by throwntegether test and opencsg test
|
||||||
|
#include "csgtestcore.h"
|
||||||
|
|
||||||
|
#include "system-gl.h"
|
||||||
|
#include "openscad.h"
|
||||||
|
#include "handle_dep.h"
|
||||||
|
#include "builtin.h"
|
||||||
|
#include "context.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "module.h"
|
||||||
|
#include "polyset.h"
|
||||||
|
#include "Tree.h"
|
||||||
|
#include "CSGTermEvaluator.h"
|
||||||
|
#include "CGALEvaluator.h"
|
||||||
|
#include "PolySetCGALEvaluator.h"
|
||||||
|
|
||||||
|
#include "OpenCSGRenderer.h"
|
||||||
|
#include "ThrownTogetherRenderer.h"
|
||||||
|
|
||||||
|
#include "csgterm.h"
|
||||||
|
#include "OffscreenView.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QSet>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using std::cerr;
|
||||||
|
using std::cout;
|
||||||
|
|
||||||
|
std::string commandline_commands;
|
||||||
|
QString librarydir;
|
||||||
|
|
||||||
|
//#define DEBUG
|
||||||
|
|
||||||
|
class CsgInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CsgInfo();
|
||||||
|
CSGTerm *root_norm_term; // Normalized CSG products
|
||||||
|
class CSGChain *root_chain;
|
||||||
|
std::vector<CSGTerm*> highlight_terms;
|
||||||
|
CSGChain *highlights_chain;
|
||||||
|
std::vector<CSGTerm*> background_terms;
|
||||||
|
CSGChain *background_chain;
|
||||||
|
OffscreenView *glview;
|
||||||
|
};
|
||||||
|
|
||||||
|
CsgInfo::CsgInfo() {
|
||||||
|
root_norm_term = NULL;
|
||||||
|
root_chain = NULL;
|
||||||
|
highlight_terms = std::vector<CSGTerm*>();
|
||||||
|
highlights_chain = NULL;
|
||||||
|
background_terms = std::vector<CSGTerm*>();
|
||||||
|
background_chain = NULL;
|
||||||
|
glview = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractNode *find_root_tag(AbstractNode *n)
|
||||||
|
{
|
||||||
|
foreach(AbstractNode *v, n->children) {
|
||||||
|
if (v->modinst->tag_root) return v;
|
||||||
|
if (AbstractNode *vroot = find_root_tag(v)) return vroot;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int csgtestcore(int argc, char *argv[], test_type_e test_type)
|
||||||
|
{
|
||||||
|
if (argc != 3) {
|
||||||
|
fprintf(stderr, "Usage: %s <file.scad> <output.png>\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string filename(argv[1]);
|
||||||
|
std::string outfile(argv[2]);
|
||||||
|
|
||||||
|
initialize_builtin_functions();
|
||||||
|
initialize_builtin_modules();
|
||||||
|
|
||||||
|
QApplication app(argc, argv, false);
|
||||||
|
|
||||||
|
QDir original_path = QDir::current();
|
||||||
|
|
||||||
|
QString currentdir = QDir::currentPath();
|
||||||
|
|
||||||
|
QDir libdir(QApplication::instance()->applicationDirPath());
|
||||||
|
#ifdef Q_WS_MAC
|
||||||
|
libdir.cd("../Resources"); // Libraries can be bundled
|
||||||
|
if (!libdir.exists("libraries")) libdir.cd("../../..");
|
||||||
|
#elif defined(Q_OS_UNIX)
|
||||||
|
if (libdir.cd("../share/openscad/libraries")) {
|
||||||
|
librarydir = libdir.path();
|
||||||
|
} else
|
||||||
|
if (libdir.cd("../../share/openscad/libraries")) {
|
||||||
|
librarydir = libdir.path();
|
||||||
|
} else
|
||||||
|
if (libdir.cd("../../libraries")) {
|
||||||
|
librarydir = libdir.path();
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
if (libdir.cd("libraries")) {
|
||||||
|
librarydir = libdir.path();
|
||||||
|
}
|
||||||
|
|
||||||
|
Context root_ctx;
|
||||||
|
root_ctx.functions_p = &builtin_functions;
|
||||||
|
root_ctx.modules_p = &builtin_modules;
|
||||||
|
root_ctx.set_variable("$fn", Value(0.0));
|
||||||
|
root_ctx.set_variable("$fs", Value(1.0));
|
||||||
|
root_ctx.set_variable("$fa", Value(12.0));
|
||||||
|
root_ctx.set_variable("$t", Value(0.0));
|
||||||
|
|
||||||
|
Value zero3;
|
||||||
|
zero3.type = Value::VECTOR;
|
||||||
|
zero3.append(new Value(0.0));
|
||||||
|
zero3.append(new Value(0.0));
|
||||||
|
zero3.append(new Value(0.0));
|
||||||
|
root_ctx.set_variable("$vpt", zero3);
|
||||||
|
root_ctx.set_variable("$vpr", zero3);
|
||||||
|
|
||||||
|
|
||||||
|
AbstractModule *root_module;
|
||||||
|
ModuleInstantiation root_inst;
|
||||||
|
|
||||||
|
QFileInfo fileInfo(filename.c_str());
|
||||||
|
handle_dep(filename);
|
||||||
|
FILE *fp = fopen(filename.c_str(), "rt");
|
||||||
|
if (!fp) {
|
||||||
|
fprintf(stderr, "Can't open input file `%s'!\n", filename.c_str());
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
std::stringstream text;
|
||||||
|
char buffer[513];
|
||||||
|
int ret;
|
||||||
|
while ((ret = fread(buffer, 1, 512, fp)) > 0) {
|
||||||
|
buffer[ret] = 0;
|
||||||
|
text << buffer;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
text << commandline_commands;
|
||||||
|
root_module = parse(text.str().c_str(), fileInfo.absolutePath().toLocal8Bit(), false);
|
||||||
|
if (!root_module) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QDir::setCurrent(fileInfo.absolutePath());
|
||||||
|
|
||||||
|
AbstractNode::resetIndexCounter();
|
||||||
|
AbstractNode *absolute_root_node = root_module->evaluate(&root_ctx, &root_inst);
|
||||||
|
AbstractNode *root_node;
|
||||||
|
// Do we have an explicit root node (! modifier)?
|
||||||
|
if (!(root_node = find_root_tag(absolute_root_node))) root_node = absolute_root_node;
|
||||||
|
|
||||||
|
Tree tree(root_node);
|
||||||
|
|
||||||
|
CsgInfo csgInfo = CsgInfo();
|
||||||
|
CGALEvaluator cgalevaluator(tree);
|
||||||
|
CSGTermEvaluator evaluator(tree, &cgalevaluator.psevaluator);
|
||||||
|
CSGTerm *root_raw_term = evaluator.evaluateCSGTerm(*root_node,
|
||||||
|
csgInfo.highlight_terms,
|
||||||
|
csgInfo.background_terms);
|
||||||
|
|
||||||
|
if (!root_raw_term) {
|
||||||
|
cerr << "Error: CSG generation failed! (no top level object found)\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CSG normalization
|
||||||
|
csgInfo.root_norm_term = root_raw_term->link();
|
||||||
|
while (1) {
|
||||||
|
CSGTerm *n = csgInfo.root_norm_term->normalize();
|
||||||
|
csgInfo.root_norm_term->unlink();
|
||||||
|
if (csgInfo.root_norm_term == n)
|
||||||
|
break;
|
||||||
|
csgInfo.root_norm_term = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(csgInfo.root_norm_term);
|
||||||
|
|
||||||
|
csgInfo.root_chain = new CSGChain();
|
||||||
|
csgInfo.root_chain->import(csgInfo.root_norm_term);
|
||||||
|
fprintf(stderr, "Normalized CSG tree has %d elements\n", csgInfo.root_chain->polysets.size());
|
||||||
|
|
||||||
|
if (csgInfo.highlight_terms.size() > 0) {
|
||||||
|
cerr << "Compiling highlights (" << csgInfo.highlight_terms.size() << " CSG Trees)...\n";
|
||||||
|
|
||||||
|
csgInfo.highlights_chain = new CSGChain();
|
||||||
|
for (unsigned int i = 0; i < csgInfo.highlight_terms.size(); i++) {
|
||||||
|
while (1) {
|
||||||
|
CSGTerm *n = csgInfo.highlight_terms[i]->normalize();
|
||||||
|
csgInfo.highlight_terms[i]->unlink();
|
||||||
|
if (csgInfo.highlight_terms[i] == n)
|
||||||
|
break;
|
||||||
|
csgInfo.highlight_terms[i] = n;
|
||||||
|
}
|
||||||
|
csgInfo.highlights_chain->import(csgInfo.highlight_terms[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (csgInfo.background_terms.size() > 0) {
|
||||||
|
cerr << "Compiling background (" << csgInfo.background_terms.size() << " CSG Trees)...\n";
|
||||||
|
|
||||||
|
csgInfo.background_chain = new CSGChain();
|
||||||
|
for (unsigned int i = 0; i < csgInfo.background_terms.size(); i++) {
|
||||||
|
while (1) {
|
||||||
|
CSGTerm *n = csgInfo.background_terms[i]->normalize();
|
||||||
|
csgInfo.background_terms[i]->unlink();
|
||||||
|
if (csgInfo.background_terms[i] == n)
|
||||||
|
break;
|
||||||
|
csgInfo.background_terms[i] = n;
|
||||||
|
}
|
||||||
|
csgInfo.background_chain->import(csgInfo.background_terms[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QDir::setCurrent(original_path.absolutePath());
|
||||||
|
|
||||||
|
try {
|
||||||
|
csgInfo.glview = new OffscreenView(512,512);
|
||||||
|
} catch (int error) {
|
||||||
|
fprintf(stderr,"Can't create OpenGL OffscreenView. Code: %i. Exiting.\n", error);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
BoundingBox bbox = csgInfo.root_chain->getBoundingBox();
|
||||||
|
|
||||||
|
Vector3d center = (bbox.min() + bbox.max()) / 2;
|
||||||
|
double radius = (bbox.max() - bbox.min()).norm() / 2;
|
||||||
|
|
||||||
|
|
||||||
|
Vector3d cameradir(1, 1, -0.5);
|
||||||
|
Vector3d camerapos = center - radius*1.8*cameradir;
|
||||||
|
csgInfo.glview->setCamera(camerapos, center);
|
||||||
|
|
||||||
|
OpenCSGRenderer opencsgRenderer(csgInfo.root_chain, csgInfo.highlights_chain, csgInfo.background_chain, csgInfo.glview->shaderinfo);
|
||||||
|
ThrownTogetherRenderer thrownTogetherRenderer(csgInfo.root_chain, csgInfo.highlights_chain, csgInfo.background_chain);
|
||||||
|
|
||||||
|
if (test_type == TEST_THROWNTOGETHER)
|
||||||
|
csgInfo.glview->setRenderer(&thrownTogetherRenderer);
|
||||||
|
else
|
||||||
|
csgInfo.glview->setRenderer(&opencsgRenderer);
|
||||||
|
|
||||||
|
csgInfo.glview->paintGL();
|
||||||
|
|
||||||
|
csgInfo.glview->save(outfile.c_str());
|
||||||
|
|
||||||
|
destroy_builtin_functions();
|
||||||
|
destroy_builtin_modules();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
#ifndef CSGTESTCORE_H_
|
||||||
|
#define CSGTESTCORE_H_
|
||||||
|
|
||||||
|
enum test_type_e {
|
||||||
|
TEST_THROWNTOGETHER,
|
||||||
|
TEST_OPENCSG
|
||||||
|
};
|
||||||
|
|
||||||
|
int csgtestcore(int argc, char *argv[], test_type_e test_type);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -39,10 +39,13 @@
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#ifndef _MSC_VER
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#endif
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
std::string commandline_commands;
|
std::string commandline_commands;
|
||||||
QString currentdir;
|
QString currentdir;
|
||||||
|
@ -58,12 +61,13 @@ void csgTree(CSGTextCache &cache, const AbstractNode &root)
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if (argc != 2) {
|
if (argc != 3) {
|
||||||
fprintf(stderr, "Usage: %s <file.scad>\n", argv[0]);
|
fprintf(stderr, "Usage: %s <file.scad> <output.txt>\n", argv[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *filename = argv[1];
|
const char *filename = argv[1];
|
||||||
|
const char *outfilename = argv[2];
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
@ -149,7 +153,10 @@ int main(int argc, char **argv)
|
||||||
csgTree(csgcache, *root_node);
|
csgTree(csgcache, *root_node);
|
||||||
// std::cout << tree.getString(*root_node) << "\n";
|
// std::cout << tree.getString(*root_node) << "\n";
|
||||||
|
|
||||||
std::cout << csgcache[*root_node] << "\n";
|
std::ofstream outfile;
|
||||||
|
outfile.open(outfilename);
|
||||||
|
outfile << csgcache[*root_node] << "\n";
|
||||||
|
outfile.close();
|
||||||
|
|
||||||
destroy_builtin_functions();
|
destroy_builtin_functions();
|
||||||
destroy_builtin_modules();
|
destroy_builtin_modules();
|
||||||
|
|
|
@ -39,10 +39,13 @@
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#ifndef _MSC_VER
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#endif
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
|
@ -53,12 +56,13 @@ QString librarydir;
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if (argc != 2) {
|
if (argc != 3) {
|
||||||
fprintf(stderr, "Usage: %s <file.scad>\n", argv[0]);
|
fprintf(stderr, "Usage: %s <file.scad> <output.txt>\n", argv[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *filename = argv[1];
|
const char *filename = argv[1];
|
||||||
|
const char *outfilename = argv[2];
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
@ -146,7 +150,10 @@ int main(int argc, char **argv)
|
||||||
string dumpstdstr_cached = tree.getString(*root_node);
|
string dumpstdstr_cached = tree.getString(*root_node);
|
||||||
assert(dumpstdstr == dumpstdstr_cached);
|
assert(dumpstdstr == dumpstdstr_cached);
|
||||||
|
|
||||||
std::cout << dumpstdstr << "\n";
|
std::ofstream outfile;
|
||||||
|
outfile.open(outfilename);
|
||||||
|
outfile << dumpstdstr << "\n";
|
||||||
|
outfile.close();
|
||||||
|
|
||||||
destroy_builtin_functions();
|
destroy_builtin_functions();
|
||||||
destroy_builtin_modules();
|
destroy_builtin_modules();
|
||||||
|
|
|
@ -37,10 +37,13 @@
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#ifndef _MSC_VER
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#endif
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
|
@ -49,22 +52,29 @@ QString currentdir;
|
||||||
QString examplesdir;
|
QString examplesdir;
|
||||||
QString librarydir;
|
QString librarydir;
|
||||||
|
|
||||||
static void stdout_handler(const QString &msg, void *userdata) {
|
static void outfile_handler(const std::string &msg, void *userdata) {
|
||||||
std::cout << msg.toUtf8().data() << std::endl;
|
std::ostream *str = static_cast<std::ostream*>(userdata);
|
||||||
|
*str << msg << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if (argc != 2) {
|
if (argc != 3) {
|
||||||
fprintf(stderr, "Usage: %s <file.scad>\n", argv[0]);
|
fprintf(stderr, "Usage: %s <file.scad> <output.txt>\n", argv[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *filename = argv[1];
|
const char *filename = argv[1];
|
||||||
|
const char *outfile = argv[2];
|
||||||
|
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
set_output_handler(&stdout_handler, NULL);
|
std::ofstream ofile(outfile);
|
||||||
|
if (!ofile.good()) {
|
||||||
|
std::cerr << "Unable to open output file\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
set_output_handler(&outfile_handler, &ofile);
|
||||||
|
|
||||||
initialize_builtin_functions();
|
initialize_builtin_functions();
|
||||||
initialize_builtin_modules();
|
initialize_builtin_modules();
|
||||||
|
@ -144,5 +154,6 @@ int main(int argc, char **argv)
|
||||||
destroy_builtin_functions();
|
destroy_builtin_functions();
|
||||||
destroy_builtin_modules();
|
destroy_builtin_modules();
|
||||||
|
|
||||||
|
ofile.close();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,208 @@
|
||||||
|
#include "fbo.h"
|
||||||
|
#include "system-gl.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <iostream>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
fbo_t *fbo_new()
|
||||||
|
{
|
||||||
|
fbo_t *fbo = new fbo_t;
|
||||||
|
fbo->fbo_id = 0;
|
||||||
|
fbo->old_fbo_id = 0;
|
||||||
|
fbo->renderbuf_id = 0;
|
||||||
|
fbo->depthbuf_id = 0;
|
||||||
|
|
||||||
|
return fbo;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool use_ext()
|
||||||
|
{
|
||||||
|
// do we need to use the EXT or ARB version?
|
||||||
|
if (!glewIsSupported("GL_ARB_framebuffer_object") &&
|
||||||
|
glewIsSupported("GL_EXT_framebuffer_object")) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_fbo_status()
|
||||||
|
{
|
||||||
|
/* This code is based on user V-man code from
|
||||||
|
http://www.opengl.org/wiki/GL_EXT_framebuffer_multisample
|
||||||
|
See also: http://www.songho.ca/opengl/gl_fbo.html */
|
||||||
|
GLenum status;
|
||||||
|
bool result = false;
|
||||||
|
if (use_ext())
|
||||||
|
status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||||||
|
else
|
||||||
|
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||||
|
|
||||||
|
if (report_glerror("checking framebuffer status")) return false;
|
||||||
|
|
||||||
|
if (status == GL_FRAMEBUFFER_COMPLETE)
|
||||||
|
result = true;
|
||||||
|
else if (status == GL_FRAMEBUFFER_UNSUPPORTED)
|
||||||
|
cerr << "GL_FRAMEBUFFER_UNSUPPORTED\n";
|
||||||
|
else if (status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)
|
||||||
|
cerr << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT\n";
|
||||||
|
else if (status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT)
|
||||||
|
cerr << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT\n";
|
||||||
|
else if (status == GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT)
|
||||||
|
cerr << "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT\n";
|
||||||
|
else if (status == GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT)
|
||||||
|
cerr << "GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT\n";
|
||||||
|
else if (status == GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT)
|
||||||
|
cerr << "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT\n";
|
||||||
|
else if (status == GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT)
|
||||||
|
cerr << "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT\n";
|
||||||
|
else if (status == GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT)
|
||||||
|
cerr << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT\n";
|
||||||
|
else
|
||||||
|
cerr << "Unknown Code: glCheckFramebufferStatusEXT returned %i\n",status;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fbo_ext_init(fbo_t *fbo, size_t width, size_t height)
|
||||||
|
{
|
||||||
|
// Generate and bind FBO
|
||||||
|
glGenFramebuffersEXT(1, &fbo->fbo_id);
|
||||||
|
if (report_glerror("glGenFramebuffersEXT")) return false;
|
||||||
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->fbo_id);
|
||||||
|
if (report_glerror("glBindFramebufferEXT")) return false;
|
||||||
|
|
||||||
|
// Generate depth and render buffers
|
||||||
|
glGenRenderbuffersEXT(1, &fbo->depthbuf_id);
|
||||||
|
glGenRenderbuffersEXT(1, &fbo->renderbuf_id);
|
||||||
|
|
||||||
|
// Create buffers with correct size
|
||||||
|
if (!fbo_resize(fbo, width, height)) return false;
|
||||||
|
|
||||||
|
// Attach render and depth buffers
|
||||||
|
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
||||||
|
GL_RENDERBUFFER_EXT, fbo->renderbuf_id);
|
||||||
|
if (report_glerror("specifying color render buffer EXT")) return false;
|
||||||
|
|
||||||
|
|
||||||
|
if (!check_fbo_status()) {
|
||||||
|
cerr << "Problem with OpenGL EXT framebuffer after specifying color render buffer.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
|
||||||
|
GL_RENDERBUFFER_EXT, fbo->depthbuf_id);
|
||||||
|
if (report_glerror("specifying depth render buffer EXT")) return false;
|
||||||
|
|
||||||
|
if (!check_fbo_status()) {
|
||||||
|
cerr << "Problem with OpenGL EXT framebuffer after specifying depth render buffer.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fbo_arb_init(fbo_t *fbo, size_t width, size_t height)
|
||||||
|
{
|
||||||
|
// Generate and bind FBO
|
||||||
|
glGenFramebuffers(1, &fbo->fbo_id);
|
||||||
|
if (report_glerror("glGenFramebuffers")) return false;
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo->fbo_id);
|
||||||
|
if (report_glerror("glBindFramebuffer")) return false;
|
||||||
|
|
||||||
|
// Generate depth and render buffers
|
||||||
|
glGenRenderbuffers(1, &fbo->depthbuf_id);
|
||||||
|
glGenRenderbuffers(1, &fbo->renderbuf_id);
|
||||||
|
|
||||||
|
// Create buffers with correct size
|
||||||
|
if (!fbo_resize(fbo, width, height)) return false;
|
||||||
|
|
||||||
|
// Attach render and depth buffers
|
||||||
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||||
|
GL_RENDERBUFFER, fbo->renderbuf_id);
|
||||||
|
if (report_glerror("specifying color render buffer")) return false;
|
||||||
|
|
||||||
|
if (!check_fbo_status()) {
|
||||||
|
cerr << "Problem with OpenGL framebuffer after specifying color render buffer.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
|
||||||
|
GL_RENDERBUFFER, fbo->depthbuf_id);
|
||||||
|
if (report_glerror("specifying depth render buffer")) return false;
|
||||||
|
|
||||||
|
if (!check_fbo_status()) {
|
||||||
|
cerr << "Problem with OpenGL framebuffer after specifying depth render buffer.\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool fbo_init(fbo_t *fbo, size_t width, size_t height)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Some OpenGL drivers include the framebuffer functions but not with
|
||||||
|
core or ARB names, only with the EXT name. This has been worked-around
|
||||||
|
by deciding at runtime, using GLEW, which version needs to be used. See also:
|
||||||
|
|
||||||
|
http://www.opengl.org/wiki/Framebuffer_Object
|
||||||
|
http://stackoverflow.com/questions/6912988/glgenframebuffers-or-glgenframebuffersex
|
||||||
|
http://www.devmaster.net/forums/showthread.php?t=10967
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
if (glewIsSupported("GL_ARB_framebuffer_object"))
|
||||||
|
result = fbo_arb_init(fbo, width, height);
|
||||||
|
else if (use_ext())
|
||||||
|
result = fbo_ext_init(fbo, width, height);
|
||||||
|
else
|
||||||
|
cerr << "Framebuffer Object extension not found by GLEW\n";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fbo_resize(fbo_t *fbo, size_t width, size_t height)
|
||||||
|
{
|
||||||
|
if (use_ext()) {
|
||||||
|
glBindRenderbufferEXT(GL_RENDERBUFFER, fbo->depthbuf_id);
|
||||||
|
glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
||||||
|
if (report_glerror("creating depth render buffer")) return false;
|
||||||
|
|
||||||
|
glBindRenderbufferEXT(GL_RENDERBUFFER, fbo->renderbuf_id);
|
||||||
|
glRenderbufferStorageEXT(GL_RENDERBUFFER, GL_RGBA8, width, height);
|
||||||
|
if (report_glerror("creating color render buffer")) return false;
|
||||||
|
} else {
|
||||||
|
glBindRenderbuffer(GL_RENDERBUFFER, fbo->depthbuf_id);
|
||||||
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
|
||||||
|
if (report_glerror("creating depth render buffer")) return false;
|
||||||
|
|
||||||
|
glBindRenderbuffer(GL_RENDERBUFFER, fbo->renderbuf_id);
|
||||||
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
|
||||||
|
if (report_glerror("creating color render buffer")) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fbo_delete(fbo_t *fbo)
|
||||||
|
{
|
||||||
|
delete fbo;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint fbo_bind(fbo_t *fbo)
|
||||||
|
{
|
||||||
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *)&fbo->old_fbo_id);
|
||||||
|
if (use_ext())
|
||||||
|
glBindFramebufferEXT(GL_FRAMEBUFFER, fbo->fbo_id);
|
||||||
|
else
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo->fbo_id);
|
||||||
|
return fbo->old_fbo_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fbo_unbind(fbo_t *fbo)
|
||||||
|
{
|
||||||
|
if (use_ext())
|
||||||
|
glBindFramebufferEXT(GL_FRAMEBUFFER, fbo->old_fbo_id);
|
||||||
|
else
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, fbo->old_fbo_id);
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef FBO_H_
|
||||||
|
#define FBO_H_
|
||||||
|
|
||||||
|
#include "system-gl.h"
|
||||||
|
#include <stddef.h> // size_t
|
||||||
|
|
||||||
|
struct fbo_t
|
||||||
|
{
|
||||||
|
GLuint fbo_id;
|
||||||
|
GLuint old_fbo_id;
|
||||||
|
|
||||||
|
GLuint renderbuf_id;
|
||||||
|
GLuint depthbuf_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
fbo_t *fbo_new();
|
||||||
|
bool fbo_init(fbo_t *fbo, size_t width, size_t height);
|
||||||
|
bool fbo_resize(fbo_t *fbo, size_t width, size_t height);
|
||||||
|
void fbo_delete(fbo_t *fbo);
|
||||||
|
GLuint fbo_bind(fbo_t *fbo);
|
||||||
|
void fbo_unbind(fbo_t *fbo);
|
||||||
|
|
||||||
|
bool REPORTGLERROR(const char * task);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,24 @@
|
||||||
|
#include "lodepng.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
bool write_png(const char *filename, unsigned char *pixels, int width, int height)
|
||||||
|
{
|
||||||
|
//encoder.settings.zlibsettings.windowSize = 2048;
|
||||||
|
//LodePNG_Text_add(&encoder.infoPng.text, "Comment", "Created with LodePNG");
|
||||||
|
|
||||||
|
size_t dataout_size = -1;
|
||||||
|
unsigned char *dataout = (unsigned char *)malloc(width*height*4);
|
||||||
|
LodePNG_encode(&dataout, &dataout_size, pixels, width, height, LCT_RGBA, 8);
|
||||||
|
//LodePNG_saveFile(dataout, dataout_size, "blah2.png");
|
||||||
|
|
||||||
|
FILE *f = fopen(filename, "wb");
|
||||||
|
if (!f) {
|
||||||
|
free(dataout);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(dataout, 1, dataout_size, f);
|
||||||
|
fclose(f);
|
||||||
|
free(dataout);
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
bool write_png(const char *filename, unsigned char *pixels, int width, int height)
|
||||||
|
{
|
||||||
|
size_t rowBytes = width * 4;
|
||||||
|
// CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
|
||||||
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||||
|
CGBitmapInfo bitmapInfo = kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big; // BGRA
|
||||||
|
int bitsPerComponent = 8;
|
||||||
|
CGContextRef contextRef = CGBitmapContextCreate(pixels, width, height,
|
||||||
|
bitsPerComponent, rowBytes,
|
||||||
|
colorSpace, bitmapInfo);
|
||||||
|
if (!contextRef) {
|
||||||
|
std::cerr << "Unable to create CGContextRef.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGImageRef imageRef = CGBitmapContextCreateImage(contextRef);
|
||||||
|
if (!imageRef) {
|
||||||
|
std::cerr << "Unable to create CGImageRef.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFStringRef fname = CFStringCreateWithCString(kCFAllocatorDefault, filename, kCFStringEncodingUTF8);
|
||||||
|
CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
|
||||||
|
fname, kCFURLPOSIXPathStyle, false);
|
||||||
|
if (!fileURL) {
|
||||||
|
std::cerr << "Unable to create file URL ref.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGDataConsumerRef dataconsumer = CGDataConsumerCreateWithURL(fileURL);
|
||||||
|
CFIndex fileImageIndex = 1;
|
||||||
|
CFMutableDictionaryRef fileDict = NULL;
|
||||||
|
CFStringRef fileUTType = kUTTypePNG;
|
||||||
|
// Create an image destination opaque reference for authoring an image file
|
||||||
|
CGImageDestinationRef imageDest = CGImageDestinationCreateWithDataConsumer(dataconsumer,
|
||||||
|
fileUTType,
|
||||||
|
fileImageIndex,
|
||||||
|
fileDict);
|
||||||
|
if (!imageDest) {
|
||||||
|
std::cerr << "Unable to create CGImageDestinationRef.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFIndex capacity = 1;
|
||||||
|
CFMutableDictionaryRef imageProps =
|
||||||
|
CFDictionaryCreateMutable(kCFAllocatorDefault,
|
||||||
|
capacity,
|
||||||
|
&kCFTypeDictionaryKeyCallBacks,
|
||||||
|
&kCFTypeDictionaryValueCallBacks);
|
||||||
|
CGImageDestinationAddImage(imageDest, imageRef, imageProps);
|
||||||
|
CGImageDestinationFinalize(imageDest);
|
||||||
|
|
||||||
|
CFRelease(imageDest);
|
||||||
|
CFRelease(dataconsumer);
|
||||||
|
CFRelease(fileURL);
|
||||||
|
CFRelease(fname);
|
||||||
|
CFRelease(imageProps);
|
||||||
|
CGColorSpaceRelease(colorSpace);
|
||||||
|
CGImageRelease(imageRef);
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
#include "imageutils.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void flip_image(const unsigned char *src, unsigned char *dst, size_t pixelsize, size_t width, size_t height)
|
||||||
|
{
|
||||||
|
size_t rowBytes = pixelsize * width;
|
||||||
|
for (size_t i = 0 ; i < height ; i++) {
|
||||||
|
memmove(dst + (height - i - 1) * rowBytes, src + i * rowBytes, rowBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include "imageutils-macosx.cc"
|
||||||
|
#else
|
||||||
|
#include "imageutils-lodepng.cc"
|
||||||
|
#endif
|
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef IMAGEUTILS_H_
|
||||||
|
#define IMAGEUTILS_H_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
bool write_png(const char *filename, unsigned char *pixels, int width, int height);
|
||||||
|
void flip_image(const unsigned char *src, unsigned char *dst, size_t pixelsize, size_t width, size_t height);
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,249 +1,5 @@
|
||||||
#include <GL/glew.h>
|
#include "csgtestcore.h"
|
||||||
#include "openscad.h"
|
|
||||||
#include "handle_dep.h"
|
|
||||||
#include "builtin.h"
|
|
||||||
#include "context.h"
|
|
||||||
#include "node.h"
|
|
||||||
#include "module.h"
|
|
||||||
#include "polyset.h"
|
|
||||||
#include "Tree.h"
|
|
||||||
#include "CSGTermEvaluator.h"
|
|
||||||
#include "CGALEvaluator.h"
|
|
||||||
#include "PolySetCGALEvaluator.h"
|
|
||||||
|
|
||||||
#include "OpenCSGRenderer.h"
|
int main(int argc, char* argv[]) {
|
||||||
#include "ThrownTogetherRenderer.h"
|
return csgtestcore(argc, argv, TEST_OPENCSG);
|
||||||
|
|
||||||
#include "csgterm.h"
|
|
||||||
#include "OffscreenView.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QSet>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
using std::cerr;
|
|
||||||
using std::cout;
|
|
||||||
|
|
||||||
std::string commandline_commands;
|
|
||||||
QString librarydir;
|
|
||||||
|
|
||||||
//#define DEBUG
|
|
||||||
|
|
||||||
struct CsgInfo
|
|
||||||
{
|
|
||||||
CSGTerm *root_norm_term; // Normalized CSG products
|
|
||||||
class CSGChain *root_chain;
|
|
||||||
std::vector<CSGTerm*> highlight_terms;
|
|
||||||
CSGChain *highlights_chain;
|
|
||||||
std::vector<CSGTerm*> background_terms;
|
|
||||||
CSGChain *background_chain;
|
|
||||||
OffscreenView *glview;
|
|
||||||
};
|
|
||||||
|
|
||||||
AbstractNode *find_root_tag(AbstractNode *n)
|
|
||||||
{
|
|
||||||
foreach(AbstractNode *v, n->children) {
|
|
||||||
if (v->modinst->tag_root) return v;
|
|
||||||
if (AbstractNode *vroot = find_root_tag(v)) return vroot;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
if (argc != 2) {
|
|
||||||
fprintf(stderr, "Usage: %s <file.scad>\n", argv[0]);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *filename = argv[1];
|
|
||||||
|
|
||||||
initialize_builtin_functions();
|
|
||||||
initialize_builtin_modules();
|
|
||||||
|
|
||||||
QApplication app(argc, argv);
|
|
||||||
|
|
||||||
QDir original_path = QDir::current();
|
|
||||||
|
|
||||||
QString currentdir = QDir::currentPath();
|
|
||||||
|
|
||||||
QDir libdir(QApplication::instance()->applicationDirPath());
|
|
||||||
#ifdef Q_WS_MAC
|
|
||||||
libdir.cd("../Resources"); // Libraries can be bundled
|
|
||||||
if (!libdir.exists("libraries")) libdir.cd("../../..");
|
|
||||||
#elif defined(Q_OS_UNIX)
|
|
||||||
if (libdir.cd("../share/openscad/libraries")) {
|
|
||||||
librarydir = libdir.path();
|
|
||||||
} else
|
|
||||||
if (libdir.cd("../../share/openscad/libraries")) {
|
|
||||||
librarydir = libdir.path();
|
|
||||||
} else
|
|
||||||
if (libdir.cd("../../libraries")) {
|
|
||||||
librarydir = libdir.path();
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
if (libdir.cd("libraries")) {
|
|
||||||
librarydir = libdir.path();
|
|
||||||
}
|
|
||||||
|
|
||||||
Context root_ctx;
|
|
||||||
root_ctx.functions_p = &builtin_functions;
|
|
||||||
root_ctx.modules_p = &builtin_modules;
|
|
||||||
root_ctx.set_variable("$fn", Value(0.0));
|
|
||||||
root_ctx.set_variable("$fs", Value(1.0));
|
|
||||||
root_ctx.set_variable("$fa", Value(12.0));
|
|
||||||
root_ctx.set_variable("$t", Value(0.0));
|
|
||||||
|
|
||||||
Value zero3;
|
|
||||||
zero3.type = Value::VECTOR;
|
|
||||||
zero3.append(new Value(0.0));
|
|
||||||
zero3.append(new Value(0.0));
|
|
||||||
zero3.append(new Value(0.0));
|
|
||||||
root_ctx.set_variable("$vpt", zero3);
|
|
||||||
root_ctx.set_variable("$vpr", zero3);
|
|
||||||
|
|
||||||
|
|
||||||
AbstractModule *root_module;
|
|
||||||
ModuleInstantiation root_inst;
|
|
||||||
|
|
||||||
QFileInfo fileInfo(filename);
|
|
||||||
handle_dep(filename);
|
|
||||||
FILE *fp = fopen(filename, "rt");
|
|
||||||
if (!fp) {
|
|
||||||
fprintf(stderr, "Can't open input file `%s'!\n", filename);
|
|
||||||
exit(1);
|
|
||||||
} else {
|
|
||||||
std::stringstream text;
|
|
||||||
char buffer[513];
|
|
||||||
int ret;
|
|
||||||
while ((ret = fread(buffer, 1, 512, fp)) > 0) {
|
|
||||||
buffer[ret] = 0;
|
|
||||||
text << buffer;
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
text << commandline_commands;
|
|
||||||
root_module = parse(text.str().c_str(), fileInfo.absolutePath().toLocal8Bit(), false);
|
|
||||||
if (!root_module) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QDir::setCurrent(fileInfo.absolutePath());
|
|
||||||
|
|
||||||
AbstractNode::resetIndexCounter();
|
|
||||||
AbstractNode *absolute_root_node = root_module->evaluate(&root_ctx, &root_inst);
|
|
||||||
AbstractNode *root_node;
|
|
||||||
// Do we have an explicit root node (! modifier)?
|
|
||||||
if (!(root_node = find_root_tag(absolute_root_node))) root_node = absolute_root_node;
|
|
||||||
|
|
||||||
Tree tree(root_node);
|
|
||||||
|
|
||||||
CsgInfo csgInfo;
|
|
||||||
CGALEvaluator cgalevaluator(tree);
|
|
||||||
CSGTermEvaluator evaluator(tree, &cgalevaluator.psevaluator);
|
|
||||||
CSGTerm *root_raw_term = evaluator.evaluateCSGTerm(*root_node,
|
|
||||||
csgInfo.highlight_terms,
|
|
||||||
csgInfo.background_terms);
|
|
||||||
|
|
||||||
if (!root_raw_term) {
|
|
||||||
cerr << "Error: CSG generation failed! (no top level object found)\n";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CSG normalization
|
|
||||||
csgInfo.root_norm_term = root_raw_term->link();
|
|
||||||
while (1) {
|
|
||||||
CSGTerm *n = csgInfo.root_norm_term->normalize();
|
|
||||||
csgInfo.root_norm_term->unlink();
|
|
||||||
if (csgInfo.root_norm_term == n)
|
|
||||||
break;
|
|
||||||
csgInfo.root_norm_term = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(csgInfo.root_norm_term);
|
|
||||||
|
|
||||||
csgInfo.root_chain = new CSGChain();
|
|
||||||
csgInfo.root_chain->import(csgInfo.root_norm_term);
|
|
||||||
fprintf(stderr, "Normalized CSG tree has %d elements\n", csgInfo.root_chain->polysets.size());
|
|
||||||
|
|
||||||
if (csgInfo.highlight_terms.size() > 0) {
|
|
||||||
cerr << "Compiling highlights (" << csgInfo.highlight_terms.size() << " CSG Trees)...\n";
|
|
||||||
|
|
||||||
csgInfo.highlights_chain = new CSGChain();
|
|
||||||
for (unsigned int i = 0; i < csgInfo.highlight_terms.size(); i++) {
|
|
||||||
while (1) {
|
|
||||||
CSGTerm *n = csgInfo.highlight_terms[i]->normalize();
|
|
||||||
csgInfo.highlight_terms[i]->unlink();
|
|
||||||
if (csgInfo.highlight_terms[i] == n)
|
|
||||||
break;
|
|
||||||
csgInfo.highlight_terms[i] = n;
|
|
||||||
}
|
|
||||||
csgInfo.highlights_chain->import(csgInfo.highlight_terms[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (csgInfo.background_terms.size() > 0) {
|
|
||||||
cerr << "Compiling background (" << csgInfo.background_terms.size() << " CSG Trees)...\n";
|
|
||||||
|
|
||||||
csgInfo.background_chain = new CSGChain();
|
|
||||||
for (unsigned int i = 0; i < csgInfo.background_terms.size(); i++) {
|
|
||||||
while (1) {
|
|
||||||
CSGTerm *n = csgInfo.background_terms[i]->normalize();
|
|
||||||
csgInfo.background_terms[i]->unlink();
|
|
||||||
if (csgInfo.background_terms[i] == n)
|
|
||||||
break;
|
|
||||||
csgInfo.background_terms[i] = n;
|
|
||||||
}
|
|
||||||
csgInfo.background_chain->import(csgInfo.background_terms[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QDir::setCurrent(original_path.absolutePath());
|
|
||||||
|
|
||||||
csgInfo.glview = new OffscreenView(512,512);
|
|
||||||
BoundingBox bbox = csgInfo.root_chain->getBoundingBox();
|
|
||||||
|
|
||||||
Vector3d center = (bbox.min() + bbox.max()) / 2;
|
|
||||||
double radius = (bbox.max() - bbox.min()).norm() / 2;
|
|
||||||
|
|
||||||
|
|
||||||
Vector3d cameradir(1, 1, -0.5);
|
|
||||||
Vector3d camerapos = center - radius*1.8*cameradir;
|
|
||||||
csgInfo.glview->setCamera(camerapos, center);
|
|
||||||
|
|
||||||
glewInit();
|
|
||||||
#ifdef DEBUG
|
|
||||||
cout << "GLEW version " << glewGetString(GLEW_VERSION) << "\n";
|
|
||||||
cout << (const char *)glGetString(GL_RENDERER) << "(" << (const char *)glGetString(GL_VENDOR) << ")\n"
|
|
||||||
<< "OpenGL version " << (const char *)glGetString(GL_VERSION) << "\n";
|
|
||||||
cout << "Extensions: " << (const char *)glGetString(GL_EXTENSIONS) << "\n";
|
|
||||||
|
|
||||||
|
|
||||||
if (GLEW_ARB_framebuffer_object) {
|
|
||||||
cout << "ARB_FBO supported\n";
|
|
||||||
}
|
|
||||||
if (GLEW_EXT_framebuffer_object) {
|
|
||||||
cout << "EXT_FBO supported\n";
|
|
||||||
}
|
|
||||||
if (GLEW_EXT_packed_depth_stencil) {
|
|
||||||
cout << "EXT_packed_depth_stencil\n";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
OpenCSGRenderer opencsgRenderer(csgInfo.root_chain, csgInfo.highlights_chain, csgInfo.background_chain, csgInfo.glview->shaderinfo);
|
|
||||||
ThrownTogetherRenderer thrownTogetherRenderer(csgInfo.root_chain, csgInfo.highlights_chain, csgInfo.background_chain);
|
|
||||||
// csgInfo.glview->setRenderer(&thrownTogetherRenderer);
|
|
||||||
csgInfo.glview->setRenderer(&opencsgRenderer);
|
|
||||||
|
|
||||||
csgInfo.glview->paintGL();
|
|
||||||
|
|
||||||
csgInfo.glview->save("/dev/stdout");
|
|
||||||
|
|
||||||
destroy_builtin_functions();
|
|
||||||
destroy_builtin_modules();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 8.9 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 8.5 KiB |
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 7.8 KiB |
After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 4.4 KiB |