diff options
-rw-r--r-- | src/CsgInfo.h | 3 | ||||
-rw-r--r-- | src/GLView.cc | 10 | ||||
-rw-r--r-- | src/OpenCSGRenderer.cc | 57 | ||||
-rw-r--r-- | src/OpenCSGRenderer.h | 5 | ||||
-rw-r--r-- | src/export.h | 3 | ||||
-rw-r--r-- | src/export_png.cc | 39 | ||||
-rw-r--r-- | src/openscad.cc | 15 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 11 | ||||
-rw-r--r-- | tests/csgtestcore.cc | 48 | ||||
-rw-r--r-- | tests/guiopencsgtest.cc | 27 | ||||
-rwxr-xr-x | tests/test_cmdline_tool.py | 1 |
11 files changed, 148 insertions, 71 deletions
diff --git a/src/CsgInfo.h b/src/CsgInfo.h index 889eefe..4107b1a 100644 --- a/src/CsgInfo.h +++ b/src/CsgInfo.h @@ -13,10 +13,7 @@ public: #ifdef ENABLE_OPENCSG -#include <opencsg.h> -#include "OpenCSGRenderer.h" #include "csgterm.h" -#include "csgtermnormalizer.h" class CsgInfo_OpenCSG : public CsgInfo { diff --git a/src/GLView.cc b/src/GLView.cc index 0507492..bec3a31 100644 --- a/src/GLView.cc +++ b/src/GLView.cc @@ -393,13 +393,3 @@ void GLView::showCrosshairs() glEnd(); } -/* - - - void paintGL(); // - bool save(const char *filename); // - //bool save(std::ostream &output); // not implemented in qgl? - - GLint shaderinfo[11]; // - -*/ diff --git a/src/OpenCSGRenderer.cc b/src/OpenCSGRenderer.cc index eb66687..e4ed928 100644 --- a/src/OpenCSGRenderer.cc +++ b/src/OpenCSGRenderer.cc @@ -38,7 +38,7 @@ class OpenCSGPrim : public OpenCSG::Primitive public: OpenCSGPrim(OpenCSG::Operation operation, unsigned int convexity) : OpenCSG::Primitive(operation, convexity) { } - shared_ptr<PolySet> ps; + boost::shared_ptr<PolySet> ps; Transform3d m; PolySet::csgmode_e csgmode; virtual void render() { @@ -71,6 +71,10 @@ void OpenCSGRenderer::draw(bool /*showfaces*/, bool showedges) const } } +#include "CGALEvaluator.h" +#include "CSGTermEvaluator.h" +#include "csgtermnormalizer.h" + void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo, bool highlight, bool background) const { @@ -129,3 +133,54 @@ void OpenCSGRenderer::renderCSGChain(CSGChain *chain, GLint *shaderinfo, } std::for_each(primitives.begin(), primitives.end(), del_fun<OpenCSG::Primitive>()); } + +// miscellaneous code to prep OpenCSG render. +// returns 0 on success, 1 on failure +// csgInfo gets modified +int opencsg_prep( const Tree &tree, const AbstractNode *root_node, CsgInfo_OpenCSG &csgInfo ) +{ + CGALEvaluator cgalevaluator(tree); + CSGTermEvaluator evaluator(tree, &cgalevaluator.psevaluator); + boost::shared_ptr<CSGTerm> root_raw_term = evaluator.evaluateCSGTerm(*root_node, + csgInfo.highlight_terms, + csgInfo.background_terms); + + if (!root_raw_term) { + std::cerr << "Error: CSG generation failed! (no top level object found)\n"; + return 1; + } + + // CSG normalization + CSGTermNormalizer normalizer(5000); + csgInfo.root_norm_term = normalizer.normalize(root_raw_term); + if (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", int(csgInfo.root_chain->polysets.size())); + } + else { + csgInfo.root_chain = NULL; + fprintf(stderr, "WARNING: CSG normalization resulted in an empty tree\n"); + } + + if (csgInfo.highlight_terms.size() > 0) { + std::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++) { + csgInfo.highlight_terms[i] = normalizer.normalize(csgInfo.highlight_terms[i]); + csgInfo.highlights_chain->import(csgInfo.highlight_terms[i]); + } + } + + if (csgInfo.background_terms.size() > 0) { + std::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++) { + csgInfo.background_terms[i] = normalizer.normalize(csgInfo.background_terms[i]); + csgInfo.background_chain->import(csgInfo.background_terms[i]); + } + } + return 0; +} diff --git a/src/OpenCSGRenderer.h b/src/OpenCSGRenderer.h index e6091aa..9a24c1c 100644 --- a/src/OpenCSGRenderer.h +++ b/src/OpenCSGRenderer.h @@ -20,4 +20,9 @@ private: GLint *shaderinfo; }; +#include "Tree.h" +#include "CsgInfo.h" +// should we refactor this into the renderer class? +int opencsg_prep( const Tree &tree, const AbstractNode *root_node, CsgInfo_OpenCSG &csgInfo ); + #endif diff --git a/src/export.h b/src/export.h index b140db6..77359c1 100644 --- a/src/export.h +++ b/src/export.h @@ -2,6 +2,7 @@ #define EXPORT_H_ #include <iostream> +#include "Tree.h" #ifdef ENABLE_CGAL @@ -9,7 +10,7 @@ void export_stl(class CGAL_Nef_polyhedron *root_N, std::ostream &output); void export_off(CGAL_Nef_polyhedron *root_N, std::ostream &output); void export_dxf(CGAL_Nef_polyhedron *root_N, std::ostream &output); void export_png_with_cgal(CGAL_Nef_polyhedron *root_N, std::ostream &output); -void export_png_with_opencsg(CGAL_Nef_polyhedron *root_N, std::ostream &output); +void export_png_with_opencsg(Tree &tree, std::ostream &output); #endif diff --git a/src/export_png.cc b/src/export_png.cc index 179278a..0626c71 100644 --- a/src/export_png.cc +++ b/src/export_png.cc @@ -46,15 +46,50 @@ void export_png_with_cgal(CGAL_Nef_polyhedron *root_N, std::ostream &output) csgInfo.glview->save(output); } -void export_png_with_opencsg(CGAL_Nef_polyhedron *root_N, std::ostream &output) +#ifdef ENABLE_OPENCSG +#include "OpenCSGRenderer.h" +#include <opencsg.h> +#endif + +void export_png_with_opencsg(Tree &tree, std::ostream &output) { - CsgInfo csgInfo; +#ifdef ENABLE_OPENCSG + CsgInfo_OpenCSG csgInfo = CsgInfo_OpenCSG(); + AbstractNode const *root_node = tree.root(); + int result = opencsg_prep( tree, root_node, csgInfo ); + if ( result == 1 ) { + return; + fprintf(stderr,"Couldn't init OpenCSG chainsn"); + } + try { csgInfo.glview = new OffscreenView(512,512); } catch (int error) { fprintf(stderr,"Can't create OpenGL OffscreenView. Code: %i.\n", error); return; } + + OpenCSGRenderer opencsgRenderer(csgInfo.root_chain, csgInfo.highlights_chain, csgInfo.background_chain, csgInfo.glview->shaderinfo); + + Vector3d center(0,0,0); + double radius = 1.0; + if (csgInfo.root_chain) { + BoundingBox bbox = csgInfo.root_chain->getBoundingBox(); + center = (bbox.min() + bbox.max()) / 2; + 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); + csgInfo.glview->setRenderer(&opencsgRenderer); + OpenCSG::setContext(0); + OpenCSG::setOption(OpenCSG::OffscreenSetting, OpenCSG::FrameBufferObject); + csgInfo.glview->paintGL(); + csgInfo.glview->save(output); +#else + fprintf(stderr,"This openscad was built without OpenCSG support\n"); +#endif } diff --git a/src/openscad.cc b/src/openscad.cc index 0b5466e..1bbe049 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -133,7 +133,7 @@ int main(int argc, char **argv) desc.add_options() ("help,h", "help message") ("version,v", "print the version") - ("render", "if exporting an image, do a full CGAL render") + ("render", "if exporting a png image, do a full CGAL render") ("o,o", po::value<string>(), "out-file") ("s,s", po::value<string>(), "stl-file") ("x,x", po::value<string>(), "dxf-file") @@ -266,6 +266,7 @@ int main(int argc, char **argv) ModuleInstantiation root_inst; AbstractNode *root_node; AbstractNode *absolute_root_node; + CGAL_Nef_polyhedron root_N; handle_dep(filename); @@ -310,10 +311,14 @@ int main(int argc, char **argv) } else { #ifdef ENABLE_CGAL - CGAL_Nef_polyhedron root_N = cgalevaluator.evaluateCGALMesh(*tree.root()); - + if (png_output_file && !vm.count("render")) { + // OpenCSG png -> don't necessarily need CGALMesh evaluation + } else { + root_N = cgalevaluator.evaluateCGALMesh(*tree.root()); + } + fs::current_path(original_path); - + if (deps_output_file) { std::string deps_out( deps_output_file ); std::string geom_out; @@ -395,7 +400,7 @@ int main(int argc, char **argv) if (vm.count("render")) { export_png_with_cgal(&root_N, fstream); } else { - export_png_with_opencsg(&root_N, fstream); + export_png_with_opencsg(tree, fstream); } fstream.close(); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 733a87a..b3d5a54 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -603,6 +603,8 @@ endif() if(EXISTS "${GUI_BINPATH}") add_executable(guicgalpngtest guicgalpngtest.cc) set_target_properties(guicgalpngtest PROPERTIES COMPILE_FLAGS "-DBINPATH=${GUI_BINPATH}") + add_executable(guiopencsgtest guiopencsgtest.cc) + set_target_properties(guiopencsgtest PROPERTIES COMPILE_FLAGS "-DBINPATH=${GUI_BINPATH}") message(STATUS "Found OpenSCAD GUI binary: ${GUI_BINPATH}") else() message(STATUS "Couldn't find the OpenSCAD GUI binary: ${GUI_BINPATH}") @@ -762,6 +764,7 @@ list(APPEND THROWNTOGETHERTEST_FILES ${OPENCSGTEST_FILES}) list(APPEND CGALSTLSANITYTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/normal-nan.scad) list(APPEND GUICGALPNGTEST_FILES ${CGALPNGTEST_FILES}) +list(APPEND GUIOPENCSGTEST_FILES ${OPENCSGTEST_FILES}) # Disable tests which are known to cause floating point comparison issues # Once we're capable of comparing these across platforms, we can put these back in @@ -787,10 +790,11 @@ disable_tests(dumptest_transform-tests # FIXME: This test illustrates a weakness in child() combined with modifiers. # Reenable it when this is improved disable_tests(opencsgtest_child-background) +disable_tests(guiopencsgtest_child-background) # FIXME: This single test takes over an hour to run on a 2.7 GHz P4 disable_tests(opencsgtest_example006 cgalpngtest_example006) -disable_tests(opencsgtest_example006 guicgalpngtest_example006) +disable_tests(guiopencsgtest_example006 guicgalpngtest_example006) # These tests only makes sense in OpenCSG mode disable_tests(cgalpngtest_child-background @@ -807,6 +811,8 @@ disable_tests(cgalpngtest_child-background set_test_config(Heavy opencsgtest_minkowski3-tests opencsgtest_projection-tests + guiopencsgtest_minkowski3-tests + guiopencsgtest_projection-tests throwntogethertest_minkowski3-tests throwntogethertest_projection-tests cgalpngtest_projection-tests @@ -835,6 +841,8 @@ foreach(FILE ${EXAMPLE_FILES}) set_test_config(Examples ${TEST_FULLNAME}) get_test_fullname(guicgalpngtest ${FILE} TEST_FULLNAME) set_test_config(Examples ${TEST_FULLNAME}) + get_test_fullname(guiopencsgtest ${FILE} TEST_FULLNAME) + set_test_config(Examples ${TEST_FULLNAME}) endforeach() # Workaround Gallium bugs @@ -888,6 +896,7 @@ add_cmdline_test(cgalpngtest png ${CGALPNGTEST_FILES}) add_cmdline_test(opencsgtest png ${OPENCSGTEST_FILES}) add_cmdline_test(throwntogethertest png ${THROWNTOGETHERTEST_FILES}) add_cmdline_test(guicgalpngtest png ${GUICGALPNGTEST_FILES}) +add_cmdline_test(guiopencsgtest png ${GUIOPENCSGTEST_FILES}) # FIXME: We don't actually need to compare the output of cgalstlsanitytest # with anything. It's self-contained and returns != 0 on error diff --git a/tests/csgtestcore.cc b/tests/csgtestcore.cc index a4a036d..a3a0b4d 100644 --- a/tests/csgtestcore.cc +++ b/tests/csgtestcore.cc @@ -105,54 +105,6 @@ po::variables_map parse_options(int argc, char *argv[]) return vm; } -int opencsg_prep( Tree &tree, AbstractNode *root_node, CsgInfo_OpenCSG &csgInfo ) -{ - CGALEvaluator cgalevaluator(tree); - CSGTermEvaluator evaluator(tree, &cgalevaluator.psevaluator); - shared_ptr<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 - CSGTermNormalizer normalizer(5000); - csgInfo.root_norm_term = normalizer.normalize(root_raw_term); - if (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", int(csgInfo.root_chain->polysets.size())); - } - else { - csgInfo.root_chain = NULL; - fprintf(stderr, "WARNING: CSG normalization resulted in an empty tree\n"); - } - - 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++) { - csgInfo.highlight_terms[i] = normalizer.normalize(csgInfo.highlight_terms[i]); - 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++) { - csgInfo.background_terms[i] = normalizer.normalize(csgInfo.background_terms[i]); - csgInfo.background_chain->import(csgInfo.background_terms[i]); - } - } - return 0; -} - int csgtestcore(int argc, char *argv[], test_type_e test_type) { bool sysinfo_dump = false; diff --git a/tests/guiopencsgtest.cc b/tests/guiopencsgtest.cc new file mode 100644 index 0000000..75e6abd --- /dev/null +++ b/tests/guiopencsgtest.cc @@ -0,0 +1,27 @@ +// Wrapper around openscad gui binary, so it can act like a 'test' + +#include <unistd.h> +#include <stdio.h> +#ifndef BINPATH +#error please define BINPATH=/some/path/openscad when compiling +#endif +#define PREQUOTE(x) #x +#define QUOTE(x) PREQUOTE(x) +int main( int argc, char * argv[] ) +{ + fprintf(stderr,"%s: wrapper for OpenSCAD at %s\n", argv[0], QUOTE( BINPATH ) ); + if ( argc != 3 ) { + fprintf(stderr,"%s: bad number of arguments: %i\n", argv[0], argc); + return 1; + } + char *newargs[6]; + char *scadfilename = argv[1]; + char *pngfilename = argv[2]; + newargs[0] = const_cast<char *>(QUOTE( BINPATH )); + newargs[1] = scadfilename; + newargs[2] = const_cast<char *>("-o"); + newargs[3] = pngfilename; + newargs[4] = NULL; + return execv( newargs[0], newargs ); +} + diff --git a/tests/test_cmdline_tool.py b/tests/test_cmdline_tool.py index ebe60df..5314921 100755 --- a/tests/test_cmdline_tool.py +++ b/tests/test_cmdline_tool.py @@ -30,6 +30,7 @@ import string share_expected_imgs = {} share_expected_imgs["guicgalpngtest"] = "cgalpngtest" +share_expected_imgs["guiopencsgtest"] = "opencsgtest" def initialize_environment(): if not options.generate: options.generate = bool(os.getenv("TEST_GENERATE")) |