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)
|
||||
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 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 The version() function will return the OpenSCAD version as a vector, e.g. [2011, 09]
|
||||
o The version_num() function will return the OpenSCAD version as a number, e.g. 20110923
|
||||
o Added PI constant.
|
||||
o Now uses standard shortcuts for save and reload on Linux and Windows. F2/F3 will still work but is deprecated.
|
||||
|
||||
Bugfixes:
|
||||
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()
|
||||
are now deprecated. Use an import() child 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
|
||||
================
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
boost {
|
||||
|
||||
isEmpty(DEPLOYDIR) {
|
||||
# Optionally specify location of boost using the
|
||||
# BOOSTDIR env. variable
|
||||
|
@ -10,9 +11,16 @@ boost {
|
|||
}
|
||||
}
|
||||
|
||||
CONFIG(mingw-cross-env) {
|
||||
DEFINES += BOOST_STATIC
|
||||
DEFINES += BOOST_THREAD_USE_LIB
|
||||
DEFINES += Boost_USE_STATIC_LIBS
|
||||
LIBS += -lboost_thread_win32-mt -lboost_program_options-mt
|
||||
} else {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
13
cgal.pri
|
@ -13,10 +13,19 @@ cgal {
|
|||
}
|
||||
}
|
||||
|
||||
win32 {
|
||||
CONFIG(mingw-cross-env) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -217,7 +217,6 @@ TESTING
|
|||
o Caching and MDI looks suspicious when the code relies on external resources
|
||||
which might be loaded from difference locations in different documents
|
||||
-> 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
|
||||
tests on them all
|
||||
o dumptest tests:
|
||||
|
|
|
@ -10,6 +10,20 @@ cmake ..
|
|||
make
|
||||
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:
|
||||
------------------------------
|
||||
|
@ -27,3 +41,21 @@ Adding a new regression test:
|
|||
|
||||
Note that test files which don't have an *-expected.<suffix> file will
|
||||
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
|
||||
}
|
||||
else {
|
||||
macx {
|
||||
INCLUDEPATH += /opt/local/include/eigen2
|
||||
}
|
||||
else {
|
||||
INCLUDEPATH += /usr/include/eigen2
|
||||
CONFIG(mingw-cross-env) {
|
||||
INCLUDEPATH += mingw-cross-env/include/eigen2
|
||||
} else {
|
||||
freebsd-g++: INCLUDEPATH += /usr/local/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
|
||||
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 {
|
||||
isEmpty(VERSION) VERSION = $$system(date /t)
|
||||
} else {
|
||||
isEmpty(VERSION) VERSION = $$system(date "+%Y.%m.%d")
|
||||
# QMAKE_LFLAGS += -VERBOSE
|
||||
}
|
||||
|
||||
# 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
|
||||
unix:freebsd-g++ {
|
||||
QMAKE_LEX = /usr/local/bin/flex
|
||||
QMAKE_YACC = /usr/local/bin/bison
|
||||
}
|
||||
win32 {
|
||||
include(flex.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
|
||||
win32:DEFINES += _USE_MATH_DEFINES NOMINMAX _CRT_SECURE_NO_WARNINGS YY_NO_UNISTD_H
|
||||
|
||||
#disable warning about too long decorated names
|
||||
win32:QMAKE_CXXFLAGS += -wd4503
|
||||
# disable MSVC warnings that are of very low importance
|
||||
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
|
||||
RESOURCES = openscad.qrc
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <assert.h>
|
||||
#include <QRegExp>
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const AbstractNode &node)
|
||||
{
|
||||
if (!isCached(node)) {
|
||||
|
@ -75,23 +77,24 @@ 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 N;
|
||||
if (this->visitedchildren[node.index()].size() > 0) {
|
||||
for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin();
|
||||
iter != this->visitedchildren[node.index()].end();
|
||||
iter++) {
|
||||
const AbstractNode *chnode = iter->first;
|
||||
const string &chcacheid = iter->second;
|
||||
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
const AbstractNode *chnode = item.first;
|
||||
const CGAL_Nef_polyhedron &chN = item.second;
|
||||
// FIXME: Don't use deep access to modinst members
|
||||
if (chnode->modinst->tag_background) continue;
|
||||
assert(isCached(*chnode));
|
||||
if (N.empty()) {
|
||||
N = CGALCache::instance()->get(chcacheid).copy();
|
||||
} else {
|
||||
process(N, CGALCache::instance()->get(chcacheid), op);
|
||||
|
||||
// NB! We insert into the cache here to ensure that all children of
|
||||
// a node is a valid object. If we inserted as we created them, the
|
||||
// cache could have been modified before we reach this point due to a large
|
||||
// sibling object.
|
||||
if (!isCached(*chnode)) {
|
||||
CGALCache::instance()->insert(this->tree.getIdString(*chnode), chN);
|
||||
}
|
||||
if (N.empty()) N = chN.copy();
|
||||
else process(N, chN, op);
|
||||
|
||||
chnode->progress_report();
|
||||
}
|
||||
}
|
||||
return N;
|
||||
}
|
||||
|
||||
|
@ -100,22 +103,17 @@ extern CGAL_Nef_polyhedron2 *convexhull2(std::list<CGAL_Nef_polyhedron2*> a);
|
|||
CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
|
||||
{
|
||||
CGAL_Nef_polyhedron N;
|
||||
if (this->visitedchildren[node.index()].size() > 0) {
|
||||
std::list<CGAL_Nef_polyhedron2*> polys;
|
||||
bool all2d = true;
|
||||
for (ChildList::const_iterator iter = this->visitedchildren[node.index()].begin();
|
||||
iter != this->visitedchildren[node.index()].end();
|
||||
iter++) {
|
||||
const AbstractNode *chnode = iter->first;
|
||||
const string &chcacheid = iter->second;
|
||||
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
const AbstractNode *chnode = item.first;
|
||||
const CGAL_Nef_polyhedron &chN = item.second;
|
||||
// FIXME: Don't use deep access to modinst members
|
||||
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());
|
||||
if (chN.dim == 2) {
|
||||
polys.push_back(chN.p2.get());
|
||||
}
|
||||
else if (ch.dim == 3) {
|
||||
else if (chN.dim == 3) {
|
||||
PRINT("WARNING: hull() is not implemented yet for 3D objects!");
|
||||
all2d = false;
|
||||
}
|
||||
|
@ -125,7 +123,6 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
|
|||
if (all2d) {
|
||||
N = CGAL_Nef_polyhedron(convexhull2(polys));
|
||||
}
|
||||
}
|
||||
return N;
|
||||
}
|
||||
|
||||
|
@ -140,11 +137,10 @@ Response CGALEvaluator::visit(State &state, const AbstractNode &node)
|
|||
{
|
||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||
if (state.isPostfix()) {
|
||||
if (!isCached(node)) {
|
||||
CGAL_Nef_polyhedron N = applyToChildren(node, CGE_UNION);
|
||||
CGALCache::instance()->insert(this->tree.getIdString(node), N);
|
||||
}
|
||||
addToParent(state, node);
|
||||
CGAL_Nef_polyhedron N;
|
||||
if (!isCached(node)) N = applyToChildren(node, CGE_UNION);
|
||||
else N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||
addToParent(state, node, N);
|
||||
}
|
||||
return ContinueTraversal;
|
||||
}
|
||||
|
@ -153,11 +149,10 @@ Response CGALEvaluator::visit(State &state, const AbstractIntersectionNode &node
|
|||
{
|
||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||
if (state.isPostfix()) {
|
||||
if (!isCached(node)) {
|
||||
CGAL_Nef_polyhedron N = applyToChildren(node, CGE_INTERSECTION);
|
||||
CGALCache::instance()->insert(this->tree.getIdString(node), N);
|
||||
}
|
||||
addToParent(state, node);
|
||||
CGAL_Nef_polyhedron N;
|
||||
if (!isCached(node)) N = applyToChildren(node, CGE_INTERSECTION);
|
||||
else N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||
addToParent(state, node, N);
|
||||
}
|
||||
return ContinueTraversal;
|
||||
}
|
||||
|
@ -166,6 +161,7 @@ Response CGALEvaluator::visit(State &state, const CsgNode &node)
|
|||
{
|
||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||
if (state.isPostfix()) {
|
||||
CGAL_Nef_polyhedron N;
|
||||
if (!isCached(node)) {
|
||||
CGALEvaluator::CsgOp op;
|
||||
switch (node.type) {
|
||||
|
@ -181,10 +177,12 @@ Response CGALEvaluator::visit(State &state, const CsgNode &node)
|
|||
default:
|
||||
assert(false);
|
||||
}
|
||||
CGAL_Nef_polyhedron N = applyToChildren(node, op);
|
||||
CGALCache::instance()->insert(this->tree.getIdString(node), N);
|
||||
N = applyToChildren(node, op);
|
||||
}
|
||||
addToParent(state, node);
|
||||
else {
|
||||
N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||
}
|
||||
addToParent(state, node, N);
|
||||
}
|
||||
return ContinueTraversal;
|
||||
}
|
||||
|
@ -193,9 +191,10 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node)
|
|||
{
|
||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||
if (state.isPostfix()) {
|
||||
CGAL_Nef_polyhedron N;
|
||||
if (!isCached(node)) {
|
||||
// First union all children
|
||||
CGAL_Nef_polyhedron N = applyToChildren(node, CGE_UNION);
|
||||
N = applyToChildren(node, CGE_UNION);
|
||||
|
||||
// Then apply transform
|
||||
// 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));
|
||||
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;
|
||||
}
|
||||
|
@ -242,18 +243,20 @@ Response CGALEvaluator::visit(State &state, const AbstractPolyNode &node)
|
|||
{
|
||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||
if (state.isPostfix()) {
|
||||
CGAL_Nef_polyhedron N;
|
||||
if (!isCached(node)) {
|
||||
// Apply polyset operation
|
||||
shared_ptr<PolySet> ps = this->psevaluator.getPolySet(node, false);
|
||||
CGAL_Nef_polyhedron N;
|
||||
if (ps) {
|
||||
N = evaluateCGALMesh(*ps);
|
||||
// print_messages_pop();
|
||||
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;
|
||||
}
|
||||
|
@ -262,8 +265,8 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
|
|||
{
|
||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||
if (state.isPostfix()) {
|
||||
if (!isCached(node)) {
|
||||
CGAL_Nef_polyhedron N;
|
||||
if (!isCached(node)) {
|
||||
CGALEvaluator::CsgOp op;
|
||||
switch (node.type) {
|
||||
case MINKOWSKI:
|
||||
|
@ -282,9 +285,11 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
|
|||
N = applyHull(node);
|
||||
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;
|
||||
}
|
||||
|
@ -293,12 +298,18 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
|
|||
Adds ourself to out parent's list of traversed children.
|
||||
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());
|
||||
this->visitedchildren.erase(node.index());
|
||||
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);
|
||||
PRINTF("Number of polygons before reduction: %d\n", pr.polygons.size());
|
||||
int numpolygons_before = pr.polygons.size();
|
||||
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());
|
||||
#endif
|
||||
#if 0
|
||||
|
|
|
@ -30,14 +30,15 @@ public:
|
|||
const Tree &getTree() const { return this->tree; }
|
||||
|
||||
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;
|
||||
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 applyHull(const CgaladvNode &node);
|
||||
|
||||
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;
|
||||
|
||||
const Tree &tree;
|
||||
|
|
|
@ -24,10 +24,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "CGALRenderer.h"
|
||||
#include "polyset.h"
|
||||
#include "CGAL_renderer.h"
|
||||
// dxfdata.h must come first for Eigen SIMD alignment issues
|
||||
#include "dxfdata.h"
|
||||
#include "polyset.h"
|
||||
|
||||
#include "CGALRenderer.h"
|
||||
#include "CGAL_renderer.h"
|
||||
#include "dxftess.h"
|
||||
#include "CGAL_Nef_polyhedron.h"
|
||||
#include "cgal.h"
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
#include <cstddef>
|
||||
|
||||
/*!
|
||||
\class CSGTermEvaluator
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <map>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
#include "visitor.h"
|
||||
|
||||
class CSGTermEvaluator : public Visitor
|
||||
|
|
|
@ -79,8 +79,8 @@ private:
|
|||
bool maybeSave();
|
||||
bool checkModified();
|
||||
QString dumpCSGTree(AbstractNode *root);
|
||||
static void consoleOutput(const QString &msg, void *userdata) {
|
||||
static_cast<MainWindow*>(userdata)->console->append(msg);
|
||||
static void consoleOutput(const std::string &msg, void *userdata) {
|
||||
static_cast<MainWindow*>(userdata)->console->append(QString::fromStdString(msg));
|
||||
}
|
||||
void loadViewSettings();
|
||||
void loadDesignSettings();
|
||||
|
@ -115,6 +115,7 @@ private slots:
|
|||
void actionExportSTL();
|
||||
void actionExportOFF();
|
||||
void actionExportDXF();
|
||||
void actionExportCSG();
|
||||
void actionExportImage();
|
||||
void actionFlushCaches();
|
||||
|
||||
|
|
|
@ -178,6 +178,7 @@
|
|||
<addaction name="designActionExportSTL"/>
|
||||
<addaction name="designActionExportOFF"/>
|
||||
<addaction name="designActionExportDXF"/>
|
||||
<addaction name="designActionExportCSG"/>
|
||||
<addaction name="designActionExportImage"/>
|
||||
<addaction name="designActionFlushCaches"/>
|
||||
</widget>
|
||||
|
@ -657,6 +658,11 @@
|
|||
<string>Export as Image...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="designActionExportCSG">
|
||||
<property name="text">
|
||||
<string>Export as CSG...</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<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)
|
||||
{
|
||||
bool splitfirst = sin(rot2 - rot1) >= 0.0;
|
||||
for (size_t j = 1; j < path.indices.size(); j++)
|
||||
{
|
||||
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 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);
|
||||
double dia2_len_sq = (jy2-ky1)*(jy2-ky1) + (jx2-kx1)*(jx2-kx1);
|
||||
|
||||
if (dia1_len_sq > dia2_len_sq)
|
||||
if (splitfirst)
|
||||
{
|
||||
ps->append_poly();
|
||||
if (path.is_inner) {
|
||||
|
|
|
@ -17,5 +17,5 @@ void PolySetCache::print()
|
|||
|
||||
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 {
|
||||
shared_ptr<class PolySet> ps;
|
||||
QString msg;
|
||||
std::string msg;
|
||||
cache_entry(const shared_ptr<PolySet> &ps);
|
||||
~cache_entry() { }
|
||||
};
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
#include "nodecache.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
/*!
|
||||
For now, just an abstraction of the node tree which keeps a dump
|
||||
cache based on node indices around.
|
||||
|
@ -20,8 +18,8 @@ public:
|
|||
void setRoot(const AbstractNode *root);
|
||||
const AbstractNode *root() const { return this->root_node; }
|
||||
|
||||
const string &getString(const AbstractNode &node) const;
|
||||
const string &getIdString(const AbstractNode &node) const;
|
||||
const std::string &getString(const AbstractNode &node) const;
|
||||
const std::string &getIdString(const AbstractNode &node) const;
|
||||
|
||||
private:
|
||||
const AbstractNode *root_node;
|
||||
|
|
|
@ -42,8 +42,6 @@ public:
|
|||
virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
|
||||
};
|
||||
|
||||
using std::string;
|
||||
|
||||
AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const
|
||||
{
|
||||
ColorNode *node = new ColorNode(inst);
|
||||
|
@ -87,7 +85,7 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio
|
|||
return node;
|
||||
}
|
||||
|
||||
string ColorNode::toString() const
|
||||
std::string ColorNode::toString() const
|
||||
{
|
||||
std::stringstream stream;
|
||||
|
||||
|
@ -96,7 +94,7 @@ string ColorNode::toString() const
|
|||
return stream.str();
|
||||
}
|
||||
|
||||
string ColorNode::name() const
|
||||
std::string ColorNode::name() const
|
||||
{
|
||||
return "color";
|
||||
}
|
||||
|
|
|
@ -4,10 +4,8 @@
|
|||
#define EIGEN_DONT_ALIGN
|
||||
#endif
|
||||
|
||||
#include "linalg.h"
|
||||
#include <vector>
|
||||
#include <Eigen/Dense>
|
||||
|
||||
using Eigen::Vector2d;
|
||||
|
||||
class DxfData
|
||||
{
|
||||
|
@ -33,7 +31,11 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
#ifdef __APPLE__
|
||||
std::vector<Vector2d, Eigen::aligned_allocator<Vector2d> > points;
|
||||
#else
|
||||
std::vector<Vector2d> points;
|
||||
#endif
|
||||
std::vector<Path> paths;
|
||||
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);
|
||||
if (this->type == "?:") {
|
||||
Value v = this->children[0]->evaluate(context);
|
||||
if (v.type == Value::BOOL)
|
||||
return this->children[v.b ? 1 : 2]->evaluate(context);
|
||||
return Value();
|
||||
return this->children[v.toBool() ? 1 : 2]->evaluate(context);
|
||||
}
|
||||
if (this->type == "[]") {
|
||||
Value v1 = this->children[0]->evaluate(context);
|
||||
|
|
|
@ -35,8 +35,11 @@
|
|||
#include <QDir>
|
||||
#include <assert.h>
|
||||
|
||||
//isatty for visual c++
|
||||
#ifdef _MSC_VER
|
||||
//isatty for visual c++ and mingw-cross-env
|
||||
#if defined __WIN32__ && ! defined _MSC_VER
|
||||
#include "unistd.h"
|
||||
#endif
|
||||
#if defined __WIN32__ || defined _MSC_VER
|
||||
extern "C" int __cdecl _isatty(int _FileHandle);
|
||||
#define isatty _isatty
|
||||
#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);
|
||||
filename.remove(QRegExp("^use[ \t\r\n>]*<"));
|
||||
filename.remove(QRegExp(">$"));
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
#endif
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
#include <Eigen/Dense>
|
||||
|
||||
using Eigen::Vector2d;
|
||||
using Eigen::Vector3d;
|
||||
typedef Eigen::AlignedBox<double, 3> BoundingBox;
|
||||
using Eigen::Matrix3f;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "builtin.h"
|
||||
#include "PolySetEvaluator.h"
|
||||
#include "openscad.h" // get_fragments_from_r()
|
||||
#include "mathc99.h"
|
||||
|
||||
#include <sstream>
|
||||
#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->fileActionQuit, SIGNAL(triggered()), this, SLOT(quit()));
|
||||
#ifndef __APPLE__
|
||||
this->fileActionSave->setShortcut(QKeySequence(Qt::Key_F2));
|
||||
this->fileActionReload->setShortcut(QKeySequence(Qt::Key_F3));
|
||||
QList<QKeySequence> shortcuts = this->fileActionSave->shortcuts();
|
||||
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
|
||||
// Open Recent
|
||||
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->designActionExportOFF, SIGNAL(triggered()), this, SLOT(actionExportOFF()));
|
||||
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->designActionFlushCaches, SIGNAL(triggered()), this, SLOT(actionFlushCaches()));
|
||||
|
||||
|
@ -871,7 +876,6 @@ void MainWindow::compileCSG(bool procevents)
|
|||
this->thrownTogetherRenderer = new ThrownTogetherRenderer(this->root_chain,
|
||||
this->highlights_chain,
|
||||
this->background_chain);
|
||||
|
||||
PRINT("CSG generation finished.");
|
||||
int s = t.elapsed() / 1000;
|
||||
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 */
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
QImage img = this->glview->grabFrameBuffer();
|
||||
|
|
|
@ -7,10 +7,6 @@
|
|||
#include "visitor.h"
|
||||
#include "nodecache.h"
|
||||
|
||||
using std::string;
|
||||
using std::map;
|
||||
using std::list;
|
||||
|
||||
class NodeDumper : public Visitor
|
||||
{
|
||||
public:
|
||||
|
@ -26,15 +22,15 @@ private:
|
|||
void handleVisitedChildren(const State &state, const AbstractNode &node);
|
||||
bool isCached(const AbstractNode &node) const;
|
||||
void handleIndent(const State &state);
|
||||
string dumpChildren(const AbstractNode &node);
|
||||
std::string dumpChildren(const AbstractNode &node);
|
||||
|
||||
NodeCache &cache;
|
||||
bool idprefix;
|
||||
|
||||
string currindent;
|
||||
std::string currindent;
|
||||
const AbstractNode *root;
|
||||
typedef list<const AbstractNode *> ChildList;
|
||||
map<int, ChildList> visitedchildren;
|
||||
typedef std::list<const AbstractNode *> ChildList;
|
||||
std::map<int, ChildList> visitedchildren;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace po = boost::program_options;
|
|||
|
||||
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",
|
||||
progname, int(strlen(progname))+8, "");
|
||||
exit(1);
|
||||
|
@ -126,18 +126,14 @@ int main(int argc, char **argv)
|
|||
QCoreApplication::setApplicationName("OpenSCAD");
|
||||
|
||||
const char *filename = NULL;
|
||||
const char *stl_output_file = NULL;
|
||||
const char *off_output_file = NULL;
|
||||
const char *dxf_output_file = NULL;
|
||||
const char *output_file = NULL;
|
||||
const char *deps_output_file = NULL;
|
||||
|
||||
po::options_description desc("Allowed options");
|
||||
desc.add_options()
|
||||
("help,h", "help message")
|
||||
("version,v", "print the version")
|
||||
("s,s", po::value<string>(), "stl-file")
|
||||
("o,o", po::value<string>(), "off-file")
|
||||
("x,x", po::value<string>(), "dxf-file")
|
||||
("o,o", po::value<string>(), "out-file")
|
||||
("d,d", po::value<string>(), "deps-file")
|
||||
("m,m", po::value<string>(), "makefile")
|
||||
("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("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 (stl_output_file || off_output_file || dxf_output_file)
|
||||
help(argv[0]);
|
||||
off_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();
|
||||
// FIXME: Allow for multiple output files?
|
||||
if (output_file) help(argv[0]);
|
||||
output_file = vm["o"].as<string>().c_str();
|
||||
}
|
||||
if (vm.count("d")) {
|
||||
if (deps_output_file)
|
||||
|
@ -253,10 +239,24 @@ int main(int argc, char **argv)
|
|||
PolySetCGALEvaluator psevaluator(cgalevaluator);
|
||||
#endif
|
||||
|
||||
if (stl_output_file || off_output_file || dxf_output_file)
|
||||
if (output_file)
|
||||
{
|
||||
if (!filename)
|
||||
help(argv[0]);
|
||||
const char *stl_output_file = NULL;
|
||||
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
|
||||
Context root_ctx;
|
||||
|
@ -304,8 +304,20 @@ int main(int argc, char **argv)
|
|||
|
||||
AbstractNode::resetIndexCounter();
|
||||
root_node = root_module->evaluate(&root_ctx, &root_inst);
|
||||
|
||||
tree.setRoot(root_node);
|
||||
|
||||
if (csg_output_file) {
|
||||
QDir::setCurrent(original_path.absolutePath());
|
||||
std::ofstream fstream(csg_output_file);
|
||||
if (!fstream.is_open()) {
|
||||
PRINTF("Can't open file \"%s\" for export", csg_output_file);
|
||||
}
|
||||
else {
|
||||
fstream << tree.getString(*root_node) << "\n";
|
||||
fstream.close();
|
||||
}
|
||||
}
|
||||
else {
|
||||
CGAL_Nef_polyhedron root_N = cgalevaluator.evaluateCGALMesh(*tree.root());
|
||||
|
||||
QDir::setCurrent(original_path.absolutePath());
|
||||
|
@ -365,7 +377,7 @@ int main(int argc, char **argv)
|
|||
fstream.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
delete root_node;
|
||||
#else
|
||||
fprintf(stderr, "OpenSCAD has been compiled without CGAL support!\n");
|
||||
|
@ -415,3 +427,4 @@ int main(int argc, char **argv)
|
|||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,12 +27,6 @@
|
|||
#ifndef 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 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) {
|
||||
libs_cache[filename].mod = lib_mod;
|
||||
libs_cache[filename].msg = print_messages_stack.last().toStdString();
|
||||
libs_cache[filename].msg = print_messages_stack.back();
|
||||
} else {
|
||||
libs_cache.erase(filename);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include <stdio.h>
|
||||
#include <QDate>
|
||||
|
||||
QList<QString> print_messages_stack;
|
||||
std::list<std::string> print_messages_stack;
|
||||
OutputHandlerFunc *outputhandler = NULL;
|
||||
void *outputhandler_data = NULL;
|
||||
|
||||
|
@ -14,37 +14,38 @@ void set_output_handler(OutputHandlerFunc *newhandler, void *userdata)
|
|||
|
||||
void print_messages_push()
|
||||
{
|
||||
print_messages_stack.append(QString());
|
||||
print_messages_stack.push_back(std::string());
|
||||
}
|
||||
|
||||
void print_messages_pop()
|
||||
{
|
||||
QString msg = print_messages_stack.takeLast();
|
||||
if (print_messages_stack.size() > 0 && !msg.isNull()) {
|
||||
if (!print_messages_stack.last().isEmpty())
|
||||
print_messages_stack.last() += "\n";
|
||||
print_messages_stack.last() += msg;
|
||||
std::string msg = print_messages_stack.back();
|
||||
print_messages_stack.pop_back();
|
||||
if (print_messages_stack.size() > 0 && !msg.empty()) {
|
||||
if (!print_messages_stack.back().empty()) {
|
||||
print_messages_stack.back() += "\n";
|
||||
}
|
||||
print_messages_stack.back() += msg;
|
||||
}
|
||||
}
|
||||
|
||||
void PRINT(const QString &msg)
|
||||
void PRINT(const std::string &msg)
|
||||
{
|
||||
if (msg.isNull())
|
||||
return;
|
||||
if (msg.empty()) return;
|
||||
if (print_messages_stack.size() > 0) {
|
||||
if (!print_messages_stack.last().isEmpty())
|
||||
print_messages_stack.last() += "\n";
|
||||
print_messages_stack.last() += msg;
|
||||
if (!print_messages_stack.back().empty()) {
|
||||
print_messages_stack.back() += "\n";
|
||||
}
|
||||
print_messages_stack.back() += msg;
|
||||
}
|
||||
PRINT_NOCACHE(msg);
|
||||
}
|
||||
|
||||
void PRINT_NOCACHE(const QString &msg)
|
||||
void PRINT_NOCACHE(const std::string &msg)
|
||||
{
|
||||
if (msg.isNull())
|
||||
return;
|
||||
if (msg.empty()) return;
|
||||
if (!outputhandler) {
|
||||
fprintf(stderr, "%s\n", msg.toUtf8().data());
|
||||
fprintf(stderr, "%s\n", msg.c_str());
|
||||
} else {
|
||||
outputhandler(msg, outputhandler_data);
|
||||
}
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
#ifndef PRINTUTILS_H_
|
||||
#define PRINTUTILS_H_
|
||||
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <QFileInfo>
|
||||
|
||||
typedef void (OutputHandlerFunc)(const QString &msg, void *userdata);
|
||||
typedef void (OutputHandlerFunc)(const std::string &msg, void *userdata);
|
||||
extern OutputHandlerFunc *outputhandler;
|
||||
extern void *outputhandler_data;
|
||||
|
||||
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_pop();
|
||||
|
||||
void PRINT(const QString &msg);
|
||||
#define PRINTF(_fmt, ...) do { QString _m; _m.sprintf(_fmt, ##__VA_ARGS__); PRINT(_m); } while (0)
|
||||
#define PRINTA(_fmt, ...) do { QString _m = QString(_fmt).arg(__VA_ARGS__); PRINT(_m); } while (0)
|
||||
void PRINT(const std::string &msg);
|
||||
#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.toStdString()); } while (0)
|
||||
|
||||
void PRINT_NOCACHE(const QString &msg);
|
||||
#define PRINTF_NOCACHE(_fmt, ...) do { QString _m; _m.sprintf(_fmt, ##__VA_ARGS__); PRINT_NOCACHE(_m); } while (0)
|
||||
#define PRINTA_NOCACHE(_fmt, ...) do { QString _m = QString(_fmt).arg(__VA_ARGS__); PRINT_NOCACHE(_m); } while (0)
|
||||
void PRINT_NOCACHE(const std::string &msg);
|
||||
#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.toStdString()); } while (0)
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const QFileInfo &fi);
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import_dxf();
|
||||
translate([-210,0,0]) import_dxf(file="../../dxf/polygons.dxf");
|
||||
translate([-210,0,0]) import_dxf(file="../../dxf/polygons.dxf", origin=[0,110]);
|
||||
translate([-210,0,0]) import_dxf(file="../../dxf/polygons.dxf", origin=[110,110], scale=0.5);
|
||||
import_dxf(file="../../dxf/multiple-layers.dxf");
|
||||
translate([-200,200,0]) import_dxf(file="../../dxf/multiple-layers.dxf", layer="0");
|
||||
translate([0,200,0]) import_dxf(file="../../dxf/multiple-layers.dxf", layer="0");
|
||||
translate([200,200,0]) import_dxf(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");
|
||||
import();
|
||||
translate([-210,0,0]) import(file="../../dxf/polygons.dxf");
|
||||
translate([-210,0,0]) import(file="../../dxf/polygons.dxf", origin=[0,110]);
|
||||
translate([-210,0,0]) import(file="../../dxf/polygons.dxf", origin=[110,110], scale=0.5);
|
||||
import(file="../../dxf/multiple-layers.dxf");
|
||||
translate([-200,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="0");
|
||||
translate([0,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="0");
|
||||
translate([200,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="noname");
|
||||
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)
|
||||
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)
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}")
|
||||
|
@ -8,6 +13,51 @@ if(NOT CMAKE_BUILD_TYPE)
|
|||
set(CMAKE_BUILD_TYPE Debug)
|
||||
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
|
||||
#
|
||||
|
@ -23,10 +73,23 @@ find_package(Qt4 COMPONENTS QtCore QtGui QtOpenGL REQUIRED)
|
|||
include(${QT_USE_FILE})
|
||||
|
||||
# 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)
|
||||
find_path(EIGEN2_INCLUDE_DIR
|
||||
Eigen/Core
|
||||
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)
|
||||
message(FATAL_ERROR "Eigen2 not found")
|
||||
else()
|
||||
|
@ -57,17 +120,33 @@ if (NOT OPENCSG_INCLUDE_DIR)
|
|||
endif()
|
||||
include_directories(${OPENCSG_INCLUDE_DIR})
|
||||
|
||||
# GLEW
|
||||
|
||||
if (NOT $ENV{MACOSX_DEPLOY_DIR} STREQUAL "")
|
||||
set(GLEW_DIR "$ENV{MACOSX_DEPLOY_DIR}")
|
||||
endif()
|
||||
|
||||
find_package(GLEW REQUIRED)
|
||||
include_directories(${GLEW_INCLUDE_PATH})
|
||||
|
||||
if(WIN32_STATIC_BUILD)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGLEW_STATIC")
|
||||
endif()
|
||||
|
||||
# Flex/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)
|
||||
# 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")
|
||||
ADD_FLEX_BISON_DEPENDENCY(OpenSCADlexer OpenSCADparser)
|
||||
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)
|
||||
|
||||
|
||||
set(CORE_SOURCES
|
||||
../src/mathc99.cc
|
||||
../src/handle_dep.cc
|
||||
../src/qhash.cc
|
||||
../src/value.cc
|
||||
|
@ -118,7 +197,9 @@ set(COMMON_SOURCES
|
|||
../src/PolySetEvaluator.cc
|
||||
../src/PolySetCache.cc
|
||||
../src/Tree.cc
|
||||
)
|
||||
lodepng.cpp
|
||||
${FLEX_OpenSCADlexer_OUTPUTS}
|
||||
${BISON_OpenSCADparser_OUTPUTS})
|
||||
|
||||
#
|
||||
# echotest
|
||||
|
@ -126,6 +207,26 @@ set(COMMON_SOURCES
|
|||
add_executable(echotest echotest.cc ${CORE_SOURCES})
|
||||
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
|
||||
#
|
||||
|
@ -164,7 +265,7 @@ target_link_libraries(cgaltest ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${QT_
|
|||
#
|
||||
# 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/CSGTermEvaluator.cc ../src/CGALEvaluator.cc ../src/CGALCache.cc
|
||||
../src/PolySetCGALEvaluator.cc ../src/qhash.cc
|
||||
|
@ -176,7 +277,8 @@ target_link_libraries(cgalpngtest ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${
|
|||
#
|
||||
# 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/CSGTermEvaluator.cc ../src/CGAL_Nef_polyhedron.cc ../src/cgalutils.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}")
|
||||
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.
|
||||
# Files are sent as the parameters following TESTSUFFIX
|
||||
#
|
||||
find_package(PythonInterp)
|
||||
function(add_cmdline_test TESTCMD TESTSUFFIX)
|
||||
get_filename_component(TESTCMD_NAME ${TESTCMD} NAME_WE)
|
||||
foreach (SCADFILE ${ARGN})
|
||||
get_filename_component(TESTNAME ${SCADFILE} NAME_WE)
|
||||
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()
|
||||
endfunction()
|
||||
|
||||
|
@ -256,7 +373,8 @@ LIST(APPEND CGALPNGTEST_FILES
|
|||
${CMAKE_SOURCE_DIR}/../testdata/scad/features/assign-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/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 ${CMAKE_SOURCE_DIR}/../examples/example001.scad)
|
||||
add_cmdline_test(cgalpngtest png ${CGALPNGTEST_FILES})
|
||||
|
@ -269,5 +387,9 @@ LIST(APPEND OPENCSGTEST_FILES
|
|||
LIST(APPEND OPENCSGTEST_FILES ${SCAD_DXF_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_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
|
||||
#
|
||||
|
||||
# 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_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
|
||||
$ENV{PROGRAMFILES}/GLEW/include
|
||||
${PROJECT_SOURCE_DIR}/src/nvgl/glew/include
|
||||
DOC "The directory where GL/glew.h resides")
|
||||
FIND_LIBRARY( GLEW_LIBRARY
|
||||
NAMES glew GLEW glew32 glew32s
|
||||
NAMES ${GLEW_LIB_SEARCH_NAME}
|
||||
PATHS
|
||||
$ENV{PROGRAMFILES}/GLEW/lib
|
||||
${PROJECT_SOURCE_DIR}/src/nvgl/glew/bin
|
||||
${PROJECT_SOURCE_DIR}/src/nvgl/glew/lib
|
||||
DOC "The GLEW library")
|
||||
ELSE (WIN32)
|
||||
message("GLEW_DIR: " ${GLEW_DIR})
|
||||
message("-- GLEW_DIR: " ${GLEW_DIR})
|
||||
FIND_PATH( GLEW_INCLUDE_PATH GL/glew.h
|
||||
PATHS ${GLEW_DIR}/include /usr/include /usr/local/include
|
||||
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_
|
||||
#define OFFSCREENCONTEXT_H_
|
||||
|
||||
#include <OpenGL/OpenGL.h>
|
||||
#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);
|
||||
void bind_offscreen_context(OffscreenContext *ctx);
|
||||
bool teardown_offscreen_context(OffscreenContext *ctx);
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
#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...
|
||||
|
||||
// Simple error reporting macros to help keep the sample code clean
|
||||
#define REPORT_ERROR_AND_EXIT(desc) { std::cout << desc << "\n"; return false; }
|
||||
#define NULL_ERROR_EXIT(test, desc) { if (!test) REPORT_ERROR_AND_EXIT(desc); }
|
||||
|
||||
#define REPORTGLERROR(task) { GLenum tGLErr = glGetError(); if (tGLErr != GL_NO_ERROR) { std::cout << "OpenGL error " << tGLErr << " while " << task << "\n"; } }
|
||||
|
||||
struct OffscreenContext
|
||||
{
|
||||
|
@ -14,7 +13,7 @@ struct OffscreenContext
|
|||
NSAutoreleasePool *pool;
|
||||
int width;
|
||||
int height;
|
||||
GLuint fbo;
|
||||
fbo_t *fbo;
|
||||
};
|
||||
|
||||
|
||||
|
@ -26,10 +25,8 @@ OffscreenContext *create_offscreen_context(int w, int h)
|
|||
|
||||
ctx->pool = [NSAutoreleasePool new];
|
||||
|
||||
/*
|
||||
* Create an OpenGL context just so that OpenGL calls will work. I'm not
|
||||
using it for actual rendering.
|
||||
*/
|
||||
// Create an OpenGL context just so that OpenGL calls will work.
|
||||
// Will not be used for actual rendering.
|
||||
|
||||
NSOpenGLPixelFormatAttribute attributes[] = {
|
||||
NSOpenGLPFAPixelBuffer,
|
||||
|
@ -38,66 +35,48 @@ OffscreenContext *create_offscreen_context(int w, int h)
|
|||
NSOpenGLPFADepthSize, 24,
|
||||
(NSOpenGLPixelFormatAttribute) 0
|
||||
};
|
||||
NSOpenGLPixelFormat* pixFormat = [[[NSOpenGLPixelFormat
|
||||
alloc] initWithAttributes:attributes] autorelease];
|
||||
// Create the OpenGL context to render with (with color and depth buffers)
|
||||
ctx->openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixFormat
|
||||
shareContext:nil];
|
||||
NULL_ERROR_EXIT(ctx->openGLContext, "Unable to create NSOpenGLContext");
|
||||
NSOpenGLPixelFormat *pixFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes] autorelease];
|
||||
|
||||
// Create and make current the OpenGL context to render with (with color and depth buffers)
|
||||
ctx->openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixFormat shareContext:nil];
|
||||
if (!ctx->openGLContext) {
|
||||
std::cerr << "Unable to create NSOpenGLContext\n";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
[ctx->openGLContext makeCurrentContext];
|
||||
|
||||
/*
|
||||
* Test if framebuffer objects are supported
|
||||
*/
|
||||
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");
|
||||
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";
|
||||
|
||||
// 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 (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
|
||||
|
||||
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.");
|
||||
ctx->fbo = fbo_new();
|
||||
if (!fbo_init(ctx->fbo, w, h)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
bool teardown_offscreen_context(OffscreenContext *ctx)
|
||||
{
|
||||
// "un"bind my FBO
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
fbo_unbind(ctx->fbo);
|
||||
fbo_delete(ctx->fbo);
|
||||
|
||||
/*
|
||||
* Cleanup
|
||||
|
@ -109,99 +88,40 @@ bool teardown_offscreen_context(OffscreenContext *ctx)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Capture framebuffer from OpenGL and write it to the given filename as PNG.
|
||||
*/
|
||||
bool save_framebuffer(OffscreenContext *ctx, const char *filename)
|
||||
{
|
||||
/*
|
||||
* Extract the resulting rendering as an image
|
||||
*/
|
||||
|
||||
// Read pixels from OpenGL
|
||||
int samplesPerPixel = 4; // R, G, B and A
|
||||
int rowBytes = samplesPerPixel * ctx->width;
|
||||
char* bufferData = (char*)malloc(rowBytes * ctx->height);
|
||||
unsigned char *bufferData = (unsigned char *)malloc(rowBytes * ctx->height);
|
||||
if (!bufferData) {
|
||||
std::cerr << "Unable to allocate buffer for image extraction.";
|
||||
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);
|
||||
REPORTGLERROR("reading pixels from framebuffer");
|
||||
|
||||
// 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) {
|
||||
std::cout << "Unable to allocate flipped buffer for corrected image.";
|
||||
return 1;
|
||||
}
|
||||
for (int i = 0 ; i < ctx->height ; i++) {
|
||||
bcopy(bufferData + i * rowBytes, flippedBuffer + (ctx->height - i - 1) *
|
||||
rowBytes, rowBytes);
|
||||
}
|
||||
flip_image(bufferData, flippedBuffer, samplesPerPixel, 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);
|
||||
bool writeok = write_png(filename, flippedBuffer, ctx->width, ctx->height);
|
||||
|
||||
free(flippedBuffer);
|
||||
free(bufferData);
|
||||
CFRelease(imageDest);
|
||||
CFRelease(dataconsumer);
|
||||
CFRelease(fileURL);
|
||||
CFRelease(fname);
|
||||
CFRelease(imageProps);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
CGImageRelease(imageRef);
|
||||
return true;
|
||||
|
||||
return writeok;
|
||||
}
|
||||
|
||||
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 "OffscreenView.h"
|
||||
#include <opencsg.h>
|
||||
#include "Renderer.h"
|
||||
#include "renderer.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <cstdlib>
|
||||
|
||||
#define FAR_FAR_AWAY 100000.0
|
||||
|
||||
|
@ -12,6 +15,7 @@ OffscreenView::OffscreenView(size_t width, size_t height)
|
|||
{
|
||||
for (int i = 0; i < 10; i++) this->shaderinfo[i] = 0;
|
||||
this->ctx = create_offscreen_context(width, height);
|
||||
if ( this->ctx == NULL ) throw -1;
|
||||
initializeGL();
|
||||
resizeGL(width, height);
|
||||
}
|
||||
|
@ -182,7 +186,7 @@ void OffscreenView::paintGL()
|
|||
glMatrixMode(GL_MODELVIEW);
|
||||
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);
|
||||
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
#include "OffscreenContext.h"
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Geometry>
|
||||
#ifndef _MSC_VER
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
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 <QSet>
|
||||
#include <QTextStream>
|
||||
#ifndef _MSC_VER
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
#include <sstream>
|
||||
|
@ -82,14 +84,20 @@ struct CsgInfo
|
|||
OffscreenView *glview;
|
||||
};
|
||||
|
||||
|
||||
extern Vector3d getBoundingCenter(BoundingBox bbox);
|
||||
extern double getBoundingRadius(BoundingBox bbox);
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <file.scad>\n", argv[0]);
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <file.scad> <output.png>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const char *filename = argv[1];
|
||||
const char *outfile = argv[2];
|
||||
|
||||
initialize_builtin_functions();
|
||||
initialize_builtin_modules();
|
||||
|
@ -178,9 +186,19 @@ int main(int argc, char **argv)
|
|||
|
||||
QDir::setCurrent(original_path.absolutePath());
|
||||
|
||||
// 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
|
||||
cout << "GLEW version " << glewGetString(GLEW_VERSION) << "\n";
|
||||
cout << (const char *)glGetString(GL_RENDERER) << "(" << (const char *)glGetString(GL_VENDOR) << ")\n"
|
||||
|
@ -210,9 +228,9 @@ int main(int argc, char **argv)
|
|||
else if (cgalRenderer.polyset) {
|
||||
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 camerapos = center - radius*2*cameradir;
|
||||
|
@ -221,7 +239,7 @@ int main(int argc, char **argv)
|
|||
|
||||
csgInfo.glview->setRenderer(&cgalRenderer);
|
||||
csgInfo.glview->paintGL();
|
||||
csgInfo.glview->save("/dev/stdout");
|
||||
csgInfo.glview->save(outfile);
|
||||
|
||||
destroy_builtin_functions();
|
||||
destroy_builtin_modules();
|
||||
|
|
|
@ -42,7 +42,9 @@
|
|||
#include <QDir>
|
||||
#include <QSet>
|
||||
#include <QTextStream>
|
||||
#ifndef _MSC_VER
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
#include <sstream>
|
||||
|
|
|
@ -41,10 +41,13 @@
|
|||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QSet>
|
||||
#ifndef _MSC_VER
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
using std::cout;
|
||||
|
||||
|
@ -55,12 +58,13 @@ QString librarydir;
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <file.scad>\n", argv[0]);
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <file.scad> <output.txt>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const char *filename = argv[1];
|
||||
const char *outfilename = argv[2];
|
||||
|
||||
int rc = 0;
|
||||
|
||||
|
@ -110,7 +114,7 @@ int main(int argc, char **argv)
|
|||
|
||||
AbstractModule *root_module;
|
||||
ModuleInstantiation root_inst;
|
||||
AbstractNode *root_node;
|
||||
const AbstractNode *root_node;
|
||||
|
||||
QFileInfo fileInfo(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.highlights) cout << "Highlights terms: " << evaluator.highlights->size() << "\n";
|
||||
|
||||
std::ofstream outfile;
|
||||
outfile.open(outfilename);
|
||||
if (root_term) {
|
||||
cout << root_term->dump() << "\n";
|
||||
outfile << root_term->dump() << "\n";
|
||||
}
|
||||
else {
|
||||
cout << "No top-level CSG object\n";
|
||||
outfile << "No top-level CSG object\n";
|
||||
}
|
||||
outfile.close();
|
||||
|
||||
destroy_builtin_functions();
|
||||
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 <QDir>
|
||||
#include <QSet>
|
||||
#ifndef _MSC_VER
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
std::string commandline_commands;
|
||||
QString currentdir;
|
||||
|
@ -58,12 +61,13 @@ void csgTree(CSGTextCache &cache, const AbstractNode &root)
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <file.scad>\n", argv[0]);
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <file.scad> <output.txt>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const char *filename = argv[1];
|
||||
const char *outfilename = argv[2];
|
||||
|
||||
int rc = 0;
|
||||
|
||||
|
@ -149,7 +153,10 @@ int main(int argc, char **argv)
|
|||
csgTree(csgcache, *root_node);
|
||||
// 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_modules();
|
||||
|
|
|
@ -39,10 +39,13 @@
|
|||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QSet>
|
||||
#ifndef _MSC_VER
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -53,12 +56,13 @@ QString librarydir;
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <file.scad>\n", argv[0]);
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <file.scad> <output.txt>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const char *filename = argv[1];
|
||||
const char *outfilename = argv[2];
|
||||
|
||||
int rc = 0;
|
||||
|
||||
|
@ -146,7 +150,10 @@ int main(int argc, char **argv)
|
|||
string dumpstdstr_cached = tree.getString(*root_node);
|
||||
assert(dumpstdstr == dumpstdstr_cached);
|
||||
|
||||
std::cout << dumpstdstr << "\n";
|
||||
std::ofstream outfile;
|
||||
outfile.open(outfilename);
|
||||
outfile << dumpstdstr << "\n";
|
||||
outfile.close();
|
||||
|
||||
destroy_builtin_functions();
|
||||
destroy_builtin_modules();
|
||||
|
|
|
@ -37,10 +37,13 @@
|
|||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QSet>
|
||||
#ifndef _MSC_VER
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -49,22 +52,29 @@ QString currentdir;
|
|||
QString examplesdir;
|
||||
QString librarydir;
|
||||
|
||||
static void stdout_handler(const QString &msg, void *userdata) {
|
||||
std::cout << msg.toUtf8().data() << std::endl;
|
||||
static void outfile_handler(const std::string &msg, void *userdata) {
|
||||
std::ostream *str = static_cast<std::ostream*>(userdata);
|
||||
*str << msg << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <file.scad>\n", argv[0]);
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <file.scad> <output.txt>\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
const char *filename = argv[1];
|
||||
const char *outfile = argv[2];
|
||||
|
||||
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_modules();
|
||||
|
@ -144,5 +154,6 @@ int main(int argc, char **argv)
|
|||
destroy_builtin_functions();
|
||||
destroy_builtin_modules();
|
||||
|
||||
ofile.close();
|
||||
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 "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 "csgtestcore.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
|
||||
|
||||
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;
|
||||
int main(int argc, char* argv[]) {
|
||||
return csgtestcore(argc, argv, TEST_OPENCSG);
|
||||
}
|
||||
|
|
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 |