merge master

stl_dim
Brad Pitcher 2011-11-01 10:15:35 -07:00
commit e2caf3726d
134 changed files with 12305 additions and 669 deletions

View File

@ -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
================

View File

@ -1,4 +1,5 @@
boost {
isEmpty(DEPLOYDIR) {
# Optionally specify location of boost using the
# BOOSTDIR env. variable
@ -10,9 +11,16 @@ boost {
}
}
win32 {
LIBS += -llibboost_thread-vc90-mt-s-1_46_1 -llibboost_program_options-vc90-mt-s-1_46_1
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 {
LIBS += -lboost_thread -lboost_program_options
win32 {
LIBS += -llibboost_thread-vc90-mt-s-1_46_1 -llibboost_program_options-vc90-mt-s-1_46_1
} else {
LIBS += -lboost_thread -lboost_program_options
}
}
}

View File

@ -13,10 +13,19 @@ cgal {
}
}
win32 {
LIBS += $$CGAL_DIR/auxiliary/gmp/lib/libmpfr-4.lib -lCGAL-vc90-mt-s
} else {
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
}
}
QMAKE_CXXFLAGS += -frounding-math
}

View File

@ -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:

View File

@ -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

View File

@ -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
}
}

View File

@ -16,4 +16,6 @@ glew {
unix:LIBS += -lGLEW
win32:LIBS += -lglew32s
CONFIG(mingw-cross-env):DEFINES += GLEW_STATIC
}

View File

@ -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

View File

@ -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,22 +77,23 @@ void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedr
CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op)
{
CGAL_Nef_polyhedron 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;
// 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);
}
chnode->progress_report();
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;
// 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,31 +103,25 @@ extern CGAL_Nef_polyhedron2 *convexhull2(std::list<CGAL_Nef_polyhedron2*> a);
CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
{
CGAL_Nef_polyhedron 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;
// 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());
}
else if (ch.dim == 3) {
PRINT("WARNING: hull() is not implemented yet for 3D objects!");
all2d = false;
}
chnode->progress_report();
std::list<CGAL_Nef_polyhedron2*> polys;
bool all2d = true;
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;
if (chN.dim == 2) {
polys.push_back(chN.p2.get());
}
if (all2d) {
N = CGAL_Nef_polyhedron(convexhull2(polys));
else if (chN.dim == 3) {
PRINT("WARNING: hull() is not implemented yet for 3D objects!");
all2d = false;
}
chnode->progress_report();
}
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()) {
CGAL_Nef_polyhedron N;
if (!isCached(node)) {
CGAL_Nef_polyhedron N;
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

View File

@ -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;

View File

@ -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"

View File

@ -17,6 +17,7 @@
#include <sstream>
#include <iostream>
#include <assert.h>
#include <cstddef>
/*!
\class CSGTermEvaluator

View File

@ -4,6 +4,7 @@
#include <map>
#include <list>
#include <vector>
#include <cstddef>
#include "visitor.h"
class CSGTermEvaluator : public Visitor

View File

@ -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();

View File

@ -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>

View File

@ -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) {

View File

@ -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();
}

View File

@ -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() { }
};

View File

@ -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;

View File

@ -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";
}

View File

@ -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;

View File

@ -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);

View File

@ -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(">$"));

View File

@ -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;

View File

@ -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>

View File

@ -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();

View File

@ -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

View File

@ -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,68 +304,80 @@ int main(int argc, char **argv)
AbstractNode::resetIndexCounter();
root_node = root_module->evaluate(&root_ctx, &root_inst);
tree.setRoot(root_node);
CGAL_Nef_polyhedron root_N = cgalevaluator.evaluateCGALMesh(*tree.root());
QDir::setCurrent(original_path.absolutePath());
if (deps_output_file) {
if (!write_deps(deps_output_file,
stl_output_file ? stl_output_file : off_output_file)) {
exit(1);
}
}
if (stl_output_file) {
if (root_N.dim != 3) {
fprintf(stderr, "Current top level object is not a 3D object.\n");
exit(1);
}
if (!root_N.p3->is_simple()) {
fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
exit(1);
}
std::ofstream fstream(stl_output_file);
if (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", stl_output_file);
PRINTF("Can't open file \"%s\" for export", csg_output_file);
}
else {
export_stl(&root_N, fstream, NULL);
fstream << tree.getString(*root_node) << "\n";
fstream.close();
}
}
else {
CGAL_Nef_polyhedron root_N = cgalevaluator.evaluateCGALMesh(*tree.root());
QDir::setCurrent(original_path.absolutePath());
if (deps_output_file) {
if (!write_deps(deps_output_file,
stl_output_file ? stl_output_file : off_output_file)) {
exit(1);
}
}
if (off_output_file) {
if (root_N.dim != 3) {
fprintf(stderr, "Current top level object is not a 3D object.\n");
exit(1);
if (stl_output_file) {
if (root_N.dim != 3) {
fprintf(stderr, "Current top level object is not a 3D object.\n");
exit(1);
}
if (!root_N.p3->is_simple()) {
fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
exit(1);
}
std::ofstream fstream(stl_output_file);
if (!fstream.is_open()) {
PRINTF("Can't open file \"%s\" for export", stl_output_file);
}
else {
export_stl(&root_N, fstream, NULL);
fstream.close();
}
}
if (!root_N.p3->is_simple()) {
fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
exit(1);
if (off_output_file) {
if (root_N.dim != 3) {
fprintf(stderr, "Current top level object is not a 3D object.\n");
exit(1);
}
if (!root_N.p3->is_simple()) {
fprintf(stderr, "Object isn't a valid 2-manifold! Modify your design.\n");
exit(1);
}
std::ofstream fstream(off_output_file);
if (!fstream.is_open()) {
PRINTF("Can't open file \"%s\" for export", off_output_file);
}
else {
export_off(&root_N, fstream, NULL);
fstream.close();
}
}
std::ofstream fstream(off_output_file);
if (!fstream.is_open()) {
PRINTF("Can't open file \"%s\" for export", off_output_file);
}
else {
export_off(&root_N, fstream, NULL);
fstream.close();
if (dxf_output_file) {
std::ofstream fstream(dxf_output_file);
if (!fstream.is_open()) {
PRINTF("Can't open file \"%s\" for export", dxf_output_file);
}
else {
export_dxf(&root_N, fstream, NULL);
fstream.close();
}
}
}
if (dxf_output_file) {
std::ofstream fstream(dxf_output_file);
if (!fstream.is_open()) {
PRINTF("Can't open file \"%s\" for export", dxf_output_file);
}
else {
export_dxf(&root_N, fstream, NULL);
fstream.close();
}
}
delete root_node;
#else
fprintf(stderr, "OpenSCAD has been compiled without CGAL support!\n");
@ -415,3 +427,4 @@ int main(int argc, char **argv)
return rc;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

1904
testdata/dxf/open-polyline.dxf vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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");

View File

@ -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");

View File

@ -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
#
@ -154,7 +255,7 @@ include_directories(${CGAL_INCLUDE_DIRS})
#
# cgaltest
#
add_executable(cgaltest cgaltest.cc ../src/CGAL_Nef_polyhedron.cc ../src/cgalutils.cc ../src/CSGTermEvaluator.cc
add_executable(cgaltest cgaltest.cc ../src/CGAL_Nef_polyhedron.cc ../src/cgalutils.cc ../src/CSGTermEvaluator.cc
../src/CGALEvaluator.cc ../src/CGALCache.cc ../src/PolySetCGALEvaluator.cc ../src/qhash.cc
../src/CGAL_Nef_polyhedron_DxfData.cc ../src/cgaladv_minkowski2.cc ../src/cgaladv_convexhull2.cc
${COMMON_SOURCES})
@ -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})

View File

@ -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

244
tests/OffscreenContext.cc Normal file
View File

@ -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);
}

View File

@ -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);

View File

@ -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,78 +25,58 @@ 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[] = {
NSOpenGLPixelFormatAttribute attributes[] = {
NSOpenGLPFAPixelBuffer,
NSOpenGLPFANoRecovery,
NSOpenGLPFAAccelerated,
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];
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
/*
* 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");
// Render buffer to use for imaging
glGenRenderbuffersEXT(1, &renderBuffer);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderBuffer);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, w, h);
REPORTGLERROR("creating color render buffer");
ctx->fbo = 0;
glGenFramebuffersEXT(1, &ctx->fbo);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->fbo);
REPORTGLERROR("binding framebuffer");
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_RENDERBUFFER_EXT, renderBuffer);
REPORTGLERROR("specifying color render buffer");
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) !=
GL_FRAMEBUFFER_COMPLETE_EXT)
REPORT_ERROR_AND_EXIT("Problem with OpenGL framebuffer after specifying color render buffer.");
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, depthBuffer);
REPORTGLERROR("specifying depth render buffer");
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) !=
GL_FRAMEBUFFER_COMPLETE_EXT)
REPORT_ERROR_AND_EXIT("Problem with OpenGL framebuffer after specifying depth render buffer.");
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);
}

View File

@ -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);
}

View File

@ -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
@ -11,7 +14,8 @@ OffscreenView::OffscreenView(size_t width, size_t height)
object_rot(35, 0, 25), camera_eye(0, 0, 0), camera_center(0, 0, 0)
{
for (int i = 0; i < 10; i++) this->shaderinfo[i] = 0;
this->ctx = create_offscreen_context(width, height);
this->ctx = create_offscreen_context(width, height);
if ( this->ctx == NULL ) throw -1;
initializeGL();
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);

View File

@ -4,7 +4,9 @@
#include "OffscreenContext.h"
#include <Eigen/Core>
#include <Eigen/Geometry>
#ifndef _MSC_VER
#include <stdint.h>
#endif
class OffscreenView
{

21
tests/bboxhelp.cc Normal file
View File

@ -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;
}

View File

@ -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());
csgInfo.glview = new OffscreenView(512,512);
// match with csgtest ends
try {
csgInfo.glview = new OffscreenView(512,512);
} catch (int error) {
fprintf(stderr,"Can't create OpenGL OffscreenView. Code: %i. Exiting.\n", error);
exit(1);
}
glewInit();
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "Unable to init GLEW: %s\n", glewGetErrorString(err));
exit(1);
}
#ifdef DEBUG
cout << "GLEW version " << glewGetString(GLEW_VERSION) << "\n";
cout << (const char *)glGetString(GL_RENDERER) << "(" << (const char *)glGetString(GL_VENDOR) << ")\n"
@ -205,14 +223,14 @@ int main(int argc, char **argv)
if (cgalRenderer.polyhedron) {
CGAL::Bbox_3 cgalbbox = cgalRenderer.polyhedron->bbox();
bbox = BoundingBox(Vector3d(cgalbbox.xmin(), cgalbbox.ymin(), cgalbbox.zmin()),
Vector3d(cgalbbox.xmax(), cgalbbox.ymax(), cgalbbox.zmax()));
Vector3d(cgalbbox.xmax(), cgalbbox.ymax(), cgalbbox.zmax()));
}
else if (cgalRenderer.polyset) {
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();

View File

@ -42,7 +42,9 @@
#include <QDir>
#include <QSet>
#include <QTextStream>
#ifndef _MSC_VER
#include <getopt.h>
#endif
#include <iostream>
#include <assert.h>
#include <sstream>

View File

@ -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();

254
tests/csgtestcore.cc Normal file
View File

@ -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;
}

12
tests/csgtestcore.h Normal file
View File

@ -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

View File

@ -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();

View File

@ -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();

View File

@ -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;
}

208
tests/fbo.cc Normal file
View File

@ -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);
}

25
tests/fbo.h Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

16
tests/imageutils.cc Normal file
View File

@ -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

9
tests/imageutils.h Normal file
View File

@ -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

5797
tests/lodepng.cpp Normal file

File diff suppressed because it is too large Load Diff

1899
tests/lodepng.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Some files were not shown because too many files have changed in this diff Show More