Merge branch 'master' of https://github.com/prusa3d/Slic3r
|  | @ -34,6 +34,8 @@ option(SLIC3R_PERL_XS           "Compile XS Perl module and enable Perl unit and | |||
| option(SLIC3R_ASAN              "Enable ASan on Clang and GCC" 0) | ||||
| option(SLIC3R_SYNTAXONLY        "Only perform source code correctness checking, no binary output (UNIX only)" 0) | ||||
| 
 | ||||
| set(SLIC3R_GTK "2" CACHE STRING "GTK version to use with wxWidgets on Linux") | ||||
| 
 | ||||
| # Proposal for C++ unit tests and sandboxes | ||||
| option(SLIC3R_BUILD_SANDBOXES   "Build development sandboxes" OFF) | ||||
| option(SLIC3R_BUILD_TESTS       "Build unit tests" OFF) | ||||
|  |  | |||
							
								
								
									
										55
									
								
								README.md
									
										
									
									
									
								
							
							
						
						|  | @ -1,26 +1,24 @@ | |||
| _Q: Oh cool, a new RepRap slicer?_ | ||||
| 
 | ||||
| A: Yes. | ||||
|  | ||||
| 
 | ||||
| # Slic3r Prusa Edition | ||||
| 
 | ||||
| Slic3r | ||||
| ====== | ||||
| Prebuilt Windows, OSX and Linux binaries are available through the [git releases page](https://github.com/prusa3d/Slic3r/releases). | ||||
| 
 | ||||
| <img width=256 src=https://cloud.githubusercontent.com/assets/31754/22719818/09998c92-ed6d-11e6-9fa0-09de638f3a36.png /> | ||||
| 
 | ||||
| Slic3r takes 3D models (STL, OBJ, AMF) and converts them into G-code instructions for  | ||||
| 3D printers. It's compatible with any modern printer based on the RepRap toolchain, | ||||
| including all those based on the Marlin, Sprinter and Repetier firmware. It also works | ||||
| Slic3r takes 3D models (STL, OBJ, AMF) and converts them into G-code | ||||
| instructions for FFF printers or PNG layers for mSLA 3D printers. It's | ||||
| compatible with any modern printer based on the RepRap toolchain, including all | ||||
| those based on the Marlin, Prusa, Sprinter and Repetier firmware. It also works | ||||
| with Mach3, LinuxCNC and Machinekit controllers. | ||||
| 
 | ||||
| See the [project homepage](http://slic3r.org/) at slic3r.org and the | ||||
| [manual](http://manual.slic3r.org/) for more information. | ||||
| See the [project homepage](https://www.prusa3d.com/slic3r-prusa-edition/) and | ||||
| the [documentation directory](doc/) for more information. | ||||
| 
 | ||||
| ### What language is it written in? | ||||
| 
 | ||||
| The core geometric algorithms and data structures are written in C++, | ||||
| and Perl is used for high-level flow abstraction, GUI and testing. | ||||
| If you're wondering why Perl, see https://xkcd.com/224/ | ||||
| All user facing code is written in C++, and some legacy code as well as unit | ||||
| tests are written in Perl. Perl is not required for either development or use | ||||
| of Slic3r. | ||||
| 
 | ||||
| The C++ API is public and its use in other projects is encouraged. | ||||
| The goal is to make Slic3r fully modular so that any part of its logic | ||||
|  | @ -49,34 +47,23 @@ Other major features are: | |||
| * several infill patterns including honeycomb, spirals, Hilbert curves | ||||
| * support material, raft, brim, skirt | ||||
| * **standby temperature** and automatic wiping for multi-extruder printing | ||||
| * customizable **G-code macros** and output filename with variable placeholders | ||||
| * [customizable **G-code macros**](https://github.com/prusa3d/Slic3r/wiki/Slic3r-Prusa-Edition-Macro-Language) and output filename with variable placeholders | ||||
| * support for **post-processing scripts** | ||||
| * **cooling logic** controlling fan speed and dynamic print speed | ||||
| 
 | ||||
| ### How to install? | ||||
| ### Development | ||||
| 
 | ||||
| You can download a precompiled package from [slic3r.org](http://slic3r.org/); | ||||
| it will run without the need for any dependency. | ||||
| 
 | ||||
| If you want to compile the source yourself follow the instructions on one of these wiki pages:  | ||||
| * [Linux](https://github.com/alexrj/Slic3r/wiki/Running-Slic3r-from-git-on-GNU-Linux) | ||||
| * [Windows](https://github.com/prusa3d/Slic3r/wiki/How-to-compile-Slic3r-Prusa-Edition-on-MS-Windows) | ||||
| * [Mac OSX](https://github.com/alexrj/Slic3r/wiki/Running-Slic3r-from-git-on-OS-X) | ||||
| If you want to compile the source yourself, follow the instructions on one of | ||||
| these documentation pages: | ||||
| * [Linux](doc/How%20to%20build%20-%20Linux%20et%20al.md) | ||||
| * [macOS](doc/How%20to%20build%20-%20Mac%20OS.md) | ||||
| * [Windows](doc/How%20to%20build%20-%20Windows.md) | ||||
| 
 | ||||
| ### Can I help? | ||||
| 
 | ||||
| Sure! You can do the following to find things that are available to help with: | ||||
| * [Pull Request Milestone](https://github.com/alexrj/Slic3r/milestone/31) | ||||
|     * Please comment in the related github issue that you are working on it so that other people know.  | ||||
| * Items in the [TODO](https://github.com/alexrj/Slic3r/wiki/TODO) wiki page. | ||||
|     * Please comment in the related github issue that you are working on it so that other people know.  | ||||
| * Drop me a line at aar@cpan.org. | ||||
| * You can also find me (rarely) in #reprap and in #slic3r on [FreeNode](https://webchat.freenode.net) with the nickname _Sound_. Another contributor, _LoH_, is also in both channels. | ||||
| * Add an [issue](https://github.com/alexrj/Slic3r/issues) to the github tracker if it isn't already present. | ||||
| 
 | ||||
| Before sending patches and pull requests contact me (preferably through opening a github issue or commenting on an existing, related, issue) to discuss your proposed | ||||
| changes: this way we'll ensure nobody wastes their time and no conflicts arise | ||||
| in development. | ||||
| * Add an [issue](https://github.com/prusa3d/Slic3r/issues) to the github tracker if it isn't already present. | ||||
| * Look at [issues labeled "volunteer needed"](https://github.com/prusa3d/Slic3r/issues?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue+label%3A%22volunteer+needed%22) | ||||
| 
 | ||||
| ### What's Slic3r license? | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										23
									
								
								deps/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							
							
						
						|  | @ -32,6 +32,7 @@ if (NPROC EQUAL 0) | |||
| endif () | ||||
| 
 | ||||
| set(DESTDIR "${CMAKE_CURRENT_BINARY_DIR}/destdir" CACHE PATH "Destination directory") | ||||
| 
 | ||||
| option(DEP_DEBUG "Build debug variants (only applicable on Windows)" ON) | ||||
| option(DEP_WX_STABLE "Build against wxWidgets stable 3.0 as opposed to default 3.1 (Linux only)" OFF) | ||||
| 
 | ||||
|  | @ -73,7 +74,9 @@ else () | |||
|     include("deps-linux.cmake") | ||||
| endif() | ||||
| 
 | ||||
| add_custom_target(deps ALL | ||||
| if (MSVC) | ||||
| 
 | ||||
|     add_custom_target(deps ALL | ||||
|     DEPENDS | ||||
|         dep_boost | ||||
|         dep_tbb | ||||
|  | @ -81,8 +84,22 @@ add_custom_target(deps ALL | |||
|         dep_wxwidgets | ||||
|         dep_gtest | ||||
|         dep_nlopt | ||||
|         dep_libpng | ||||
| ) | ||||
|         dep_zlib    # on Windows we still need zlib | ||||
|     ) | ||||
| 
 | ||||
| else() | ||||
| 
 | ||||
|     add_custom_target(deps ALL | ||||
|     DEPENDS | ||||
|         dep_boost | ||||
|         dep_tbb | ||||
|         dep_libcurl | ||||
|         dep_wxwidgets | ||||
|         dep_gtest | ||||
|         dep_nlopt | ||||
|     ) | ||||
| 
 | ||||
| endif() | ||||
| 
 | ||||
| # Note: I'm not using any of the LOG_xxx options in ExternalProject_Add() commands | ||||
| # because they seem to generate bogus build files (possibly a bug in ExternalProject). | ||||
|  |  | |||
							
								
								
									
										18
									
								
								deps/deps-linux.cmake
									
										
									
									
										vendored
									
									
								
							
							
						
						|  | @ -3,7 +3,6 @@ set(DEP_CMAKE_OPTS "-DCMAKE_POSITION_INDEPENDENT_CODE=ON") | |||
| 
 | ||||
| include("deps-unix-common.cmake") | ||||
| 
 | ||||
| 
 | ||||
| ExternalProject_Add(dep_boost | ||||
|     EXCLUDE_FROM_ALL 1 | ||||
|     URL "https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.gz" | ||||
|  | @ -25,19 +24,6 @@ ExternalProject_Add(dep_boost | |||
|     INSTALL_COMMAND ""   # b2 does that already | ||||
| ) | ||||
| 
 | ||||
| ExternalProject_Add(dep_libpng | ||||
|     EXCLUDE_FROM_ALL 1 | ||||
|     URL "https://github.com/glennrp/libpng/archive/v1.6.36.tar.gz" | ||||
|     URL_HASH SHA256=5bef5a850a9255365a2dc344671b7e9ef810de491bd479c2506ac3c337e2d84f | ||||
|     CMAKE_GENERATOR "${DEP_MSVC_GEN}" | ||||
|     CMAKE_ARGS | ||||
|         -DPNG_SHARED=OFF | ||||
|         -DPNG_TESTS=OFF | ||||
|         ${DEP_CMAKE_OPTS} | ||||
|     INSTALL_COMMAND make install "DESTDIR=${DESTDIR}" | ||||
|     INSTALL_COMMAND "" | ||||
| ) | ||||
| 
 | ||||
| ExternalProject_Add(dep_libopenssl | ||||
|     EXCLUDE_FROM_ALL 1 | ||||
|     URL "https://github.com/openssl/openssl/archive/OpenSSL_1_1_0g.tar.gz" | ||||
|  | @ -55,7 +41,7 @@ ExternalProject_Add(dep_libopenssl | |||
| 
 | ||||
| ExternalProject_Add(dep_libcurl | ||||
|     EXCLUDE_FROM_ALL 1 | ||||
|    DEPENDS dep_libopenssl | ||||
|     DEPENDS dep_libopenssl | ||||
|     URL "https://curl.haxx.se/download/curl-7.58.0.tar.gz" | ||||
|     URL_HASH SHA256=cc245bf9a1a42a45df491501d97d5593392a03f7b4f07b952793518d97666115 | ||||
|     BUILD_IN_SOURCE 1 | ||||
|  | @ -127,7 +113,7 @@ ExternalProject_Add(dep_wxwidgets | |||
|         --with-libxpm=builtin | ||||
|         --with-libjpeg=builtin | ||||
|         --with-libtiff=builtin | ||||
|         --with-zlib=builtin | ||||
|         --with-zlib | ||||
|         --with-expat=builtin | ||||
|         --disable-precomp-headers | ||||
|         --enable-debug_info | ||||
|  |  | |||
							
								
								
									
										16
									
								
								deps/deps-macos.cmake
									
										
									
									
										vendored
									
									
								
							
							
						
						|  | @ -87,20 +87,6 @@ ExternalProject_Add(dep_libcurl | |||
|     INSTALL_COMMAND make install "DESTDIR=${DESTDIR}" | ||||
| ) | ||||
| 
 | ||||
| ExternalProject_Add(dep_libpng | ||||
|     EXCLUDE_FROM_ALL 1 | ||||
|     URL "https://github.com/glennrp/libpng/archive/v1.6.36.tar.gz" | ||||
|     URL_HASH SHA256=5bef5a850a9255365a2dc344671b7e9ef810de491bd479c2506ac3c337e2d84f | ||||
|     CMAKE_GENERATOR "${DEP_MSVC_GEN}" | ||||
|     CMAKE_ARGS | ||||
|         -DPNG_SHARED=OFF | ||||
|         -DPNG_TESTS=OFF | ||||
|         ${DEP_CMAKE_OPTS} | ||||
|     INSTALL_COMMAND make install "DESTDIR=${DESTDIR}" | ||||
|     INSTALL_COMMAND "" | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| ExternalProject_Add(dep_wxwidgets | ||||
|     EXCLUDE_FROM_ALL 1 | ||||
|     URL "https://github.com/wxWidgets/wxWidgets/releases/download/v3.1.2/wxWidgets-3.1.2.tar.bz2" | ||||
|  | @ -119,7 +105,7 @@ ExternalProject_Add(dep_wxwidgets | |||
|         --with-libxpm=builtin | ||||
|         --with-libjpeg=builtin | ||||
|         --with-libtiff=builtin | ||||
|         --with-zlib=builtin | ||||
|         --with-zlib | ||||
|         --with-expat=builtin | ||||
|         --disable-debug | ||||
|         --disable-debug_flag | ||||
|  |  | |||
							
								
								
									
										9
									
								
								deps/deps-unix-common.cmake
									
										
									
									
										vendored
									
									
								
							
							
						
						|  | @ -8,30 +8,27 @@ ExternalProject_Add(dep_tbb | |||
|     CMAKE_ARGS | ||||
|         -DTBB_BUILD_SHARED=OFF | ||||
|         -DTBB_BUILD_TESTS=OFF | ||||
|         -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local | ||||
|         ${DEP_CMAKE_OPTS} | ||||
|     INSTALL_COMMAND make install "DESTDIR=${DESTDIR}" | ||||
| ) | ||||
| 
 | ||||
| ExternalProject_Add(dep_gtest | ||||
|     EXCLUDE_FROM_ALL 1 | ||||
|     URL "https://github.com/google/googletest/archive/release-1.8.1.tar.gz" | ||||
|     URL_HASH SHA256=9bf1fe5182a604b4135edc1a425ae356c9ad15e9b23f9f12a02e80184c3a249c | ||||
|     CMAKE_ARGS -DBUILD_GMOCK=OFF ${DEP_CMAKE_OPTS} | ||||
|     INSTALL_COMMAND make install "DESTDIR=${DESTDIR}" | ||||
|     CMAKE_ARGS -DBUILD_GMOCK=OFF ${DEP_CMAKE_OPTS} -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local | ||||
| ) | ||||
| 
 | ||||
| ExternalProject_Add(dep_nlopt | ||||
|     EXCLUDE_FROM_ALL 1 | ||||
|     URL "https://github.com/stevengj/nlopt/archive/v2.5.0.tar.gz" | ||||
|     URL_HASH SHA256=c6dd7a5701fff8ad5ebb45a3dc8e757e61d52658de3918e38bab233e7fd3b4ae | ||||
|     CMAKE_GENERATOR "${DEP_MSVC_GEN}" | ||||
|     CMAKE_ARGS | ||||
|         -DBUILD_SHARED_LIBS=OFF | ||||
|         -DNLOPT_PYTHON=OFF | ||||
|         -DNLOPT_OCTAVE=OFF | ||||
|         -DNLOPT_MATLAB=OFF | ||||
|         -DNLOPT_GUILE=OFF | ||||
|         -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local | ||||
|         ${DEP_CMAKE_OPTS} | ||||
|     INSTALL_COMMAND make install "DESTDIR=${DESTDIR}" | ||||
|     INSTALL_COMMAND "" | ||||
| ) | ||||
|  |  | |||
							
								
								
									
										56
									
								
								deps/deps-windows.cmake
									
										
									
									
										vendored
									
									
								
							
							
						
						|  | @ -62,7 +62,7 @@ ExternalProject_Add(dep_tbb | |||
|         -DTBB_BUILD_SHARED=OFF | ||||
|         -DTBB_BUILD_TESTS=OFF | ||||
|         "-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local" | ||||
|     BUILD_COMMAND msbuild /P:Configuration=Release INSTALL.vcxproj | ||||
|     BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj | ||||
|     INSTALL_COMMAND "" | ||||
| ) | ||||
| if (${DEP_DEBUG}) | ||||
|  | @ -70,7 +70,7 @@ if (${DEP_DEBUG}) | |||
|     ExternalProject_Add_Step(dep_tbb build_debug | ||||
|         DEPENDEES build | ||||
|         DEPENDERS install | ||||
|         COMMAND msbuild /P:Configuration=Debug INSTALL.vcxproj | ||||
|         COMMAND msbuild /m /P:Configuration=Debug INSTALL.vcxproj | ||||
|         WORKING_DIRECTORY "${BINARY_DIR}" | ||||
|     ) | ||||
| endif () | ||||
|  | @ -86,7 +86,7 @@ ExternalProject_Add(dep_gtest | |||
|         -Dgtest_force_shared_crt=ON | ||||
|         -DCMAKE_POSITION_INDEPENDENT_CODE=ON | ||||
|         "-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local" | ||||
|     BUILD_COMMAND msbuild /P:Configuration=Release INSTALL.vcxproj | ||||
|     BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj | ||||
|     INSTALL_COMMAND "" | ||||
| ) | ||||
| if (${DEP_DEBUG}) | ||||
|  | @ -94,7 +94,7 @@ if (${DEP_DEBUG}) | |||
|     ExternalProject_Add_Step(dep_gtest build_debug | ||||
|         DEPENDEES build | ||||
|         DEPENDERS install | ||||
|         COMMAND msbuild /P:Configuration=Debug INSTALL.vcxproj | ||||
|         COMMAND msbuild /m /P:Configuration=Debug INSTALL.vcxproj | ||||
|         WORKING_DIRECTORY "${BINARY_DIR}" | ||||
|     ) | ||||
| endif () | ||||
|  | @ -114,7 +114,7 @@ ExternalProject_Add(dep_nlopt | |||
|         -DCMAKE_POSITION_INDEPENDENT_CODE=ON | ||||
|         -DCMAKE_DEBUG_POSTFIX=d | ||||
|         "-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local" | ||||
|     BUILD_COMMAND msbuild /P:Configuration=Release INSTALL.vcxproj | ||||
|     BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj | ||||
|     INSTALL_COMMAND "" | ||||
| ) | ||||
| if (${DEP_DEBUG}) | ||||
|  | @ -122,7 +122,7 @@ if (${DEP_DEBUG}) | |||
|     ExternalProject_Add_Step(dep_nlopt build_debug | ||||
|         DEPENDEES build | ||||
|         DEPENDERS install | ||||
|         COMMAND msbuild /P:Configuration=Debug INSTALL.vcxproj | ||||
|         COMMAND msbuild /m /P:Configuration=Debug INSTALL.vcxproj | ||||
|         WORKING_DIRECTORY "${BINARY_DIR}" | ||||
|     ) | ||||
| endif () | ||||
|  | @ -138,7 +138,7 @@ ExternalProject_Add(dep_zlib | |||
|         "-DINSTALL_BIN_DIR=${CMAKE_CURRENT_BINARY_DIR}\\fallout"   # I found no better way of preventing zlib from creating & installing DLLs :-/ | ||||
|         -DCMAKE_POSITION_INDEPENDENT_CODE=ON | ||||
|         "-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local" | ||||
|     BUILD_COMMAND msbuild /P:Configuration=Release INSTALL.vcxproj | ||||
|     BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj | ||||
|     INSTALL_COMMAND "" | ||||
| ) | ||||
| if (${DEP_DEBUG}) | ||||
|  | @ -146,7 +146,7 @@ if (${DEP_DEBUG}) | |||
|     ExternalProject_Add_Step(dep_zlib build_debug | ||||
|         DEPENDEES build | ||||
|         DEPENDERS install | ||||
|         COMMAND msbuild /P:Configuration=Debug INSTALL.vcxproj | ||||
|         COMMAND msbuild /m /P:Configuration=Debug INSTALL.vcxproj | ||||
|         WORKING_DIRECTORY "${BINARY_DIR}" | ||||
|     ) | ||||
| endif () | ||||
|  | @ -165,46 +165,6 @@ if (${DEP_DEBUG}) | |||
| endif () | ||||
| 
 | ||||
| 
 | ||||
| ExternalProject_Add(dep_libpng | ||||
|     DEPENDS dep_zlib | ||||
|     EXCLUDE_FROM_ALL 1 | ||||
|     URL "https://github.com/glennrp/libpng/archive/v1.6.36.tar.gz" | ||||
|     URL_HASH SHA256=5bef5a850a9255365a2dc344671b7e9ef810de491bd479c2506ac3c337e2d84f | ||||
|     CMAKE_GENERATOR "${DEP_MSVC_GEN}" | ||||
|     CMAKE_ARGS | ||||
|         -DPNG_SHARED=OFF | ||||
|         -DPNG_TESTS=OFF | ||||
|         -DSKIP_INSTALL_FILES=ON                                   # Prevent installation of man pages et al. | ||||
|         -DCMAKE_POSITION_INDEPENDENT_CODE=ON | ||||
|         "-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local" | ||||
|     BUILD_COMMAND msbuild /P:Configuration=Release INSTALL.vcxproj | ||||
|     INSTALL_COMMAND "" | ||||
| ) | ||||
| if (${DEP_DEBUG}) | ||||
|     ExternalProject_Get_Property(dep_libpng BINARY_DIR) | ||||
|     ExternalProject_Add_Step(dep_libpng build_debug | ||||
|         DEPENDEES build | ||||
|         DEPENDERS install | ||||
|         COMMAND msbuild /P:Configuration=Debug INSTALL.vcxproj | ||||
|         WORKING_DIRECTORY "${BINARY_DIR}" | ||||
|     ) | ||||
| endif () | ||||
| # The following steps are unfortunately needed to remove the _static suffix on libraries | ||||
| # (And also overwrite the dynamic .lib) | ||||
| ExternalProject_Add_Step(dep_libpng fix_static | ||||
|     DEPENDEES install | ||||
|     COMMAND "${CMAKE_COMMAND}" -E rename libpng16_static.lib libpng16.lib | ||||
|     WORKING_DIRECTORY "${DESTDIR}\\usr\\local\\lib\\" | ||||
| ) | ||||
| if (${DEP_DEBUG}) | ||||
|     ExternalProject_Add_Step(dep_libpng fix_static_debug | ||||
|         DEPENDEES install | ||||
|         COMMAND "${CMAKE_COMMAND}" -E rename libpng16_staticd.lib libpng16d.lib | ||||
|         WORKING_DIRECTORY "${DESTDIR}\\usr\\local\\lib\\" | ||||
|     ) | ||||
| endif () | ||||
| 
 | ||||
| 
 | ||||
| if (${DEPS_BITS} EQUAL 32) | ||||
|     set(DEP_LIBCURL_TARGET "x86") | ||||
| else () | ||||
|  |  | |||
|  | @ -58,11 +58,20 @@ Note that Slic3r PE is tested with wxWidgets 3.0 somewhat sporadically and so th | |||
| 
 | ||||
| ### Build variant | ||||
| 
 | ||||
| By default Scli3r builds the release variant. | ||||
| By default Slic3r builds the release variant. | ||||
| To create a debug build, use the following CMake flag: | ||||
| 
 | ||||
|     -DCMAKE_BUILD_TYPE=Debug | ||||
| 
 | ||||
| ### Enabling address sanitizer | ||||
| 
 | ||||
| If you're using GCC/Clang compiler, it is possible to build Slic3r with the built-in address sanitizer enabled to help detect memory-corruption issues. | ||||
| To enable it, simply use the following CMake flag: | ||||
| 
 | ||||
|     -DSLIC3R_ASAN=1 | ||||
| 
 | ||||
| This requires GCC>4.8 or Clang>3.1. | ||||
| 
 | ||||
| ### Installation | ||||
| 
 | ||||
| At runtime, Slic3r needs a way to access its resource files. By default, it looks for a `resources` directory relative to its binary. | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ _Note:_ Thanks to [**@supermerill**](https://github.com/supermerill) for testing | |||
| ### Dependencies | ||||
| 
 | ||||
| On Windows Slic3r is built against statically built libraries. | ||||
| We provide a prebuilt package of all the needed dependencies. | ||||
| We provide a prebuilt package of all the needed dependencies. This package only works on Visual Studio 2013, so if you are using a newer version of Visual Studio, you need to compile the dependencies yourself as per [below](#building-the-dependencies-package-yourself). | ||||
| The package comes in a several variants: | ||||
| 
 | ||||
|   - [64 bit, Release mode only](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=destdir-64.7z) (41 MB, 578 MB unpacked) | ||||
|  | @ -28,7 +28,7 @@ Alternatively you can also compile the dependencies yourself, see below. | |||
| 
 | ||||
| ### Building Slic3r PE with Visual Studio | ||||
| 
 | ||||
| First obtain the Slic3 PE sources via either git or by extracting the source archive. | ||||
| First obtain the Slic3r PE sources via either git or by extracting the source archive. | ||||
| 
 | ||||
| Then you will need to note down the so-called 'prefix path' to the dependencies, this is the location of the dependencies packages + `\usr\local` appended. | ||||
| For example on 64 bits this would be `C:\local\destdir-64\usr\local`. The prefix path will need to be passed to CMake. | ||||
|  | @ -66,7 +66,7 @@ There are several options for building from the command line: | |||
| 
 | ||||
| To build with msbuild, use the same CMake command as in previous paragraph and then build using | ||||
| 
 | ||||
|     msbuild /P:Configuration=Release ALL_BUILD.vcxproj | ||||
|     msbuild /m /P:Configuration=Release ALL_BUILD.vcxproj | ||||
| 
 | ||||
| To build with Ninja or nmake, replace the `-G` option in the CMake call with `-G Ninja` or `-G "NMake Makefiles"` , respectively. | ||||
| Then use either `ninja` or `nmake` to start the build. | ||||
|  | @ -84,15 +84,26 @@ Then `cd` into the `deps` directory and use these commands to build: | |||
|     mkdir build | ||||
|     cd build | ||||
|     cmake .. -G "Visual Studio 12 Win64" -DDESTDIR="C:\local\destdir-custom" | ||||
|     msbuild ALL_BUILD.vcxproj | ||||
|     msbuild /m ALL_BUILD.vcxproj | ||||
| 
 | ||||
| You can also use the Visual Studio GUI or other generators as mentioned above. | ||||
| 
 | ||||
| The `DESTDIR` option is the location where the bundle will be installed. | ||||
| This may be customized. If you leave it empty, the `DESTDIR` will be places inside the same `build` directory. | ||||
| This may be customized. If you leave it empty, the `DESTDIR` will be placed inside the same `build` directory. | ||||
| 
 | ||||
| Warning: If the `build` directory is nested too deep inside other folders, various file paths during the build | ||||
| become too long and the build might fail due to file writing errors (\*). For this reason, it is recommended to | ||||
| place the `build` directory relatively close to the drive root. | ||||
| 
 | ||||
| Note that the build variant that you may choose using Visual Studio (i.e. _Release_ or _Debug_ etc.) when building the dependency package is **not relevant**. | ||||
| The dependency build will by default build _both_ the _Release_ and _Debug_ variants regardless of what you choose in Visual Studio. | ||||
| You can disable building of the debug variant by passing the `-DDEP_DEBUG=OFF` option to CMake, this will only produce a _Release_ build. | ||||
| You can disable building of the debug variant by passing the | ||||
| 
 | ||||
|     -DDEP_DEBUG=OFF | ||||
| 
 | ||||
| option to CMake, this will only produce a _Release_ build. | ||||
| 
 | ||||
| Refer to the CMake scripts inside the `deps` directory to see which dependencies are built in what versions and how this is done. | ||||
| 
 | ||||
| \*) Specifically, the problem arises when building boost. Boost build tool appends all build options into paths of | ||||
| intermediate files, which are not handled correctly by either `b2.exe` or possibly `ninja` (?). | ||||
|  |  | |||
| Before Width: | Height: | Size: 144 KiB | 
| Before Width: | Height: | Size: 364 KiB | 
| Before Width: | Height: | Size: 398 KiB | 
| Before Width: | Height: | Size: 794 KiB | 
| Before Width: | Height: | Size: 63 KiB | 
| Before Width: | Height: | Size: 159 KiB | 
| Before Width: | Height: | Size: 143 KiB | 
| Before Width: | Height: | Size: 361 KiB | 
| Before Width: | Height: | Size: 396 KiB | 
| Before Width: | Height: | Size: 790 KiB | 
| Before Width: | Height: | Size: 63 KiB | 
| Before Width: | Height: | Size: 159 KiB | 
| Before Width: | Height: | Size: 105 KiB | 
| Before Width: | Height: | Size: 277 KiB | 
| Before Width: | Height: | Size: 324 KiB | 
| Before Width: | Height: | Size: 674 KiB | 
| Before Width: | Height: | Size: 29 KiB | 
| Before Width: | Height: | Size: 20 KiB | 
							
								
								
									
										17
									
								
								resources/icons/cog.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,17 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="machine_x2B_cog"> | ||||
| 	<path fill="#808080" d="M13.77,6.39c-0.13-0.47-0.32-0.92-0.55-1.33l0.43-1.3l-1.41-1.41l-1.3,0.43c-0.42-0.23-0.86-0.42-1.33-0.55 | ||||
| 		L9,1H7L6.39,2.23C5.92,2.36,5.47,2.54,5.06,2.78l-1.3-0.43L2.34,3.76l0.43,1.3C2.54,5.47,2.36,5.92,2.23,6.39L1,7v2l1.23,0.61 | ||||
| 		c0.13,0.47,0.32,0.92,0.55,1.33l-0.43,1.3l1.41,1.41l1.3-0.43c0.42,0.23,0.86,0.42,1.33,0.55L7,15h2l0.61-1.23 | ||||
| 		c0.47-0.13,0.92-0.32,1.33-0.55l1.3,0.43l1.41-1.41l-0.43-1.3c0.23-0.42,0.42-0.86,0.55-1.33L15,9V7L13.77,6.39z M8,13 | ||||
| 		c-2.76,0-5-2.24-5-5s2.24-5,5-5s5,2.24,5,5S10.76,13,8,13z"/> | ||||
| 	<path fill="#ED6B21" d="M11.3,7.08c-0.07-0.27-0.18-0.52-0.31-0.76l0.25-0.74l-0.81-0.81L9.68,5.01C9.45,4.88,9.19,4.78,8.92,4.7 | ||||
| 		L8.57,4H7.43L7.08,4.7C6.81,4.78,6.55,4.88,6.32,5.01L5.58,4.77L4.77,5.58l0.25,0.74C4.88,6.55,4.78,6.81,4.7,7.08L4,7.43v1.14 | ||||
| 		l0.7,0.35c0.07,0.27,0.18,0.52,0.31,0.76l-0.25,0.74l0.81,0.81l0.74-0.25c0.24,0.13,0.49,0.24,0.76,0.31L7.43,12h1.14l0.35-0.7 | ||||
| 		c0.27-0.07,0.52-0.18,0.76-0.31l0.74,0.25l0.81-0.81l-0.25-0.74c0.13-0.24,0.24-0.49,0.31-0.76L12,8.57V7.43L11.3,7.08z M8,10.86 | ||||
| 		c-1.58,0-2.86-1.28-2.86-2.86S6.42,5.14,8,5.14S10.86,6.42,10.86,8S9.58,10.86,8,10.86z"/> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.5 KiB | 
							
								
								
									
										25
									
								
								resources/icons/cooling.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,25 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="cooling"> | ||||
| 	<path fill="#808080" d="M14,1H2C1.45,1,1,1.45,1,2v12c0,0.55,0.45,1,1,1h12c0.55,0,1-0.45,1-1V2C15,1.45,14.55,1,14,1z M8,14 | ||||
| 		c-3.31,0-6-2.69-6-6s2.69-6,6-6s6,2.69,6,6S11.31,14,8,14z"/> | ||||
| 	<g> | ||||
| 		<path fill="#ED6B21" d="M7.86,7.14C7.94,7.41,8,7.7,8,8c0,1.66-1.34,3-3,3c-0.3,0-0.59-0.06-0.86-0.14C4.51,12.09,5.64,13,7,13 | ||||
| 			c1.66,0,3-1.34,3-3C10,8.64,9.09,7.51,7.86,7.14z"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<path fill="#ED6B21" d="M8,8C6.34,8,5,6.66,5,5c0-0.3,0.06-0.59,0.14-0.86C3.91,4.51,3,5.64,3,7c0,1.66,1.34,3,3,3 | ||||
| 			c1.36,0,2.49-0.91,2.86-2.14C8.59,7.94,8.3,8,8,8z"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<path fill="#ED6B21" d="M10,6C8.64,6,7.51,6.91,7.14,8.14C7.41,8.06,7.7,8,8,8c1.66,0,3,1.34,3,3c0,0.3-0.06,0.59-0.14,0.86 | ||||
| 			C12.09,11.49,13,10.36,13,9C13,7.34,11.66,6,10,6z"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<path fill="#ED6B21" d="M8,8c0-1.66,1.34-3,3-3c0.3,0,0.59,0.06,0.86,0.14C11.49,3.91,10.36,3,9,3C7.34,3,6,4.34,6,6 | ||||
| 			c0,1.36,0.91,2.49,2.14,2.86C8.06,8.59,8,8.3,8,8z"/> | ||||
| 	</g> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								resources/icons/empty_icon.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 893 B | 
							
								
								
									
										15
									
								
								resources/icons/funnel.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,15 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="extruder_x2B_funnel"> | ||||
| 	<rect x="1" y="1" display="none" fill="#808080" width="14" height="6"/> | ||||
| 	<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="9.37" x2="8" y2="15"/> | ||||
| 	<polygon display="none" fill="#808080" points="5,7 5,8 8,10 11,8 11,7 	"/> | ||||
| 	<g> | ||||
| 		<path fill="#808080" d="M14,2l0,4h-3c-0.55,0-1,0.45-1,1v0.47L8,8.8L6,7.46V7c0-0.55-0.45-1-1-1L2,6l0-4H14 M14,1H2 | ||||
| 			C1.45,1,1,1.45,1,2v4c0,0.55,0.45,1,1,1h3v1l2.45,1.63C7.61,9.74,7.81,9.8,8,9.8c0.19,0,0.39-0.06,0.55-0.17L11,8V7h3 | ||||
| 			c0.55,0,1-0.45,1-1V2C15,1.45,14.55,1,14,1L14,1z"/> | ||||
| 	</g> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 941 B | 
							
								
								
									
										33
									
								
								resources/icons/infill.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,33 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="infill"> | ||||
| 	<g> | ||||
| 		<defs> | ||||
| 			<polygon id="SVGID_1_" points="8,1.03 2,5.03 2,7.03 2,11.03 8,15.03 14,11.03 14,7.03 14,5.03 			"/> | ||||
| 		</defs> | ||||
| 		<clipPath id="SVGID_2_"> | ||||
| 			<use xlink:href="#SVGID_1_"  overflow="visible"/> | ||||
| 		</clipPath> | ||||
| 		<g clip-path="url(#SVGID_2_)"> | ||||
| 			 | ||||
| 				<line fill="none" stroke="#ED6B21" stroke-width="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="2.32" y1="11.59" x2="8.56" y2="1.34"/> | ||||
| 			 | ||||
| 				<line fill="none" stroke="#ED6B21" stroke-width="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="4.88" y1="13.15" x2="11.12" y2="2.9"/> | ||||
| 			 | ||||
| 				<line fill="none" stroke="#ED6B21" stroke-width="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="7.44" y1="14.71" x2="13.68" y2="4.46"/> | ||||
| 			 | ||||
| 				<line fill="none" stroke="#ED6B21" stroke-width="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="4.44" y1="2.34" x2="14.68" y2="8.59"/> | ||||
| 			 | ||||
| 				<line fill="none" stroke="#ED6B21" stroke-width="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="2.88" y1="4.91" x2="13.12" y2="11.15"/> | ||||
| 			 | ||||
| 				<line fill="none" stroke="#ED6B21" stroke-width="0.7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="1.32" y1="7.47" x2="11.56" y2="13.71"/> | ||||
| 		</g> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<path fill="#808080" d="M8,2.23l5,3.33v1.46v3.46l-5,3.33l-5-3.33V7.03V5.56L8,2.23 M8,1.03l-6,4v2v4l6,4l6-4v-4v-2L8,1.03L8,1.03 | ||||
| 			z"/> | ||||
| 	</g> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.8 KiB | 
|  | @ -1,25 +1,27 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 128 128" enable-background="new 0 0 128 128" xml:space="preserve"> | ||||
| <g> | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="layers"> | ||||
| 	<g> | ||||
| 		<rect x="7.98" y="105" fill="#FFFFFF" width="112.04" height="15"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<rect x="7.98" y="85.67" fill="#FFFFFF" width="112.04" height="13"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<rect x="7.98" y="66.33" fill="#FFFFFF" width="112.04" height="11"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<rect x="7.98" y="47" fill="#ED6B21" width="112.04" height="9"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<rect x="7.98" y="27.67" fill="#ED6B21" width="112.04" height="7"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<rect x="7.98" y="8.33" fill="#ED6B21" width="112.04" height="5"/> | ||||
| 		<g> | ||||
| 			<rect x="1" y="13" fill="#FFFFFF" width="14" height="2"/> | ||||
| 		</g> | ||||
| 		<g> | ||||
| 			<rect x="1" y="10.6" fill="#FFFFFF" width="14" height="1.74"/> | ||||
| 		</g> | ||||
| 		<g> | ||||
| 			<rect x="1" y="8.19" fill="#FFFFFF" width="14" height="1.47"/> | ||||
| 		</g> | ||||
| 		<g> | ||||
| 			<rect x="1" y="5.79" fill="#ED6B21" width="14" height="1.2"/> | ||||
| 		</g> | ||||
| 		<g> | ||||
| 			<rect x="1" y="3.39" fill="#ED6B21" width="14" height="0.93"/> | ||||
| 		</g> | ||||
| 		<g> | ||||
| 			<rect x="1" y="0.99" fill="#FFFFFF" width="14" height="0.67"/> | ||||
| 		</g> | ||||
| 	</g> | ||||
| </g> | ||||
| </svg> | ||||
|  |  | |||
| Before Width: | Height: | Size: 841 B After Width: | Height: | Size: 845 B | 
							
								
								
									
										25
									
								
								resources/icons/note.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,25 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="notes"> | ||||
| 	<g> | ||||
| 		<path fill="#808080" d="M11,2l0,12l-9,0L2,2H11 M11,1H2C1.45,1,1,1.45,1,2V14c0,0.55,0.45,1,1,1H11c0.55,0,1-0.45,1-1V2 | ||||
| 			C12,1.45,11.55,1,11,1L11,1z"/> | ||||
| 	</g> | ||||
| 	<path fill="#ED6B21" d="M14,3L14,3c-0.55,0-1,0.45-1,1v10c0,0.55,0.45,1,1,1h0c0.55,0,1-0.45,1-1V4C15,3.45,14.55,3,14,3z"/> | ||||
| 	<polygon fill="#ED6B21" points="15,4 13,4 14,1 	"/> | ||||
| 	<g> | ||||
| 		<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" x1="3" y1="4" x2="10" y2="4"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" x1="3" y1="6" x2="10" y2="6"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" x1="3" y1="8" x2="10" y2="8"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" x1="3" y1="10" x2="7" y2="10"/> | ||||
| 	</g> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										21
									
								
								resources/icons/output+page_white.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,21 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="output_x2B_page_x5F_white"> | ||||
| 	<g> | ||||
| 		<path fill="#808080" d="M14.5,10c-0.27,0-0.5,0.23-0.5,0.5v3c0,0.27-0.23,0.5-0.5,0.5h-11C2.22,14,2,13.77,2,13.5v-11 | ||||
| 			C2,2.22,2.22,2,2.5,2h11C13.77,2,14,2.22,14,2.5v3C14,5.78,14.23,6,14.5,6l0,0C14.77,6,15,5.78,15,5.5v-4C15,1.23,14.77,1,14.5,1 | ||||
| 			h-13C1.23,1,1,1.23,1,1.5v13C1,14.77,1.23,15,1.5,15h13c0.27,0,0.5-0.23,0.5-0.5v-4C15,10.23,14.77,10,14.5,10L14.5,10z"/> | ||||
| 	</g> | ||||
| 	<path fill="#808080" d="M11,10h-0.04c-0.39,0.57-0.94,1.04-1.63,1.32c-1.83,0.73-3.91-0.16-4.64-1.99s0.16-3.91,1.99-4.64 | ||||
| 		C8.26,4.05,10.03,4.64,10.96,6H11V4.99c-0.11-0.11-0.2-0.23-0.32-0.33l-0.06-0.98L9.31,3.12L8.57,3.75 | ||||
| 		C8.23,3.71,7.88,3.7,7.54,3.74L6.81,3.09L5.48,3.62L5.4,4.6C5.12,4.81,4.87,5.05,4.66,5.32L3.69,5.37L3.12,6.69l0.63,0.75 | ||||
| 		C3.71,7.77,3.7,8.12,3.74,8.46L3.09,9.19l0.53,1.33L4.6,10.6c0.21,0.28,0.45,0.52,0.72,0.74l0.06,0.98l1.31,0.56l0.75-0.63 | ||||
| 		c0.34,0.05,0.68,0.05,1.03,0.01l0.73,0.65l1.33-0.53l0.08-0.98c0.15-0.11,0.27-0.26,0.4-0.39V10z"/> | ||||
| 	<g> | ||||
| 		<path fill="#ED6B21" d="M14.65,8.35c0.19-0.19,0.19-0.51,0-0.71l-2.29-2.29C12.16,5.16,12,5.22,12,5.5v1C12,6.78,11.77,7,11.5,7 | ||||
| 			h-3C8.23,7,8,7.22,8,7.5v1C8,8.77,8.23,9,8.5,9h3C11.77,9,12,9.23,12,9.5v1c0,0.27,0.16,0.34,0.35,0.15L14.65,8.35z"/> | ||||
| 	</g> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.5 KiB | 
							
								
								
									
										14
									
								
								resources/icons/printer.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,14 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="printer"> | ||||
| 	<rect x="1" y="1" fill="#808080" width="1" height="14"/> | ||||
| 	<rect x="14" y="1" fill="#808080" width="1" height="14"/> | ||||
| 	<rect x="7.5" y="-1.5" transform="matrix(-1.836970e-16 1 -1 -1.836970e-16 13.5 -2.5)" fill="#808080" width="1" height="14"/> | ||||
| 	<rect x="7.5" y="-5.5" transform="matrix(-1.836970e-16 1 -1 -1.836970e-16 9.5 -6.5)" fill="#808080" width="1" height="14"/> | ||||
| 	<rect x="7" y="7" transform="matrix(-1.836970e-16 1 -1 -1.836970e-16 22 6)" fill="#808080" width="2" height="14"/> | ||||
| 	<rect x="3" y="4" fill="#ED6B21" width="4" height="4"/> | ||||
| 	<polygon fill="#ED6B21" points="5,9 4,8 6,8 	"/> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 958 B | 
							
								
								
									
										19
									
								
								resources/icons/skirt+brim.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,19 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="skirt_x2B_brim"> | ||||
| 	<g id="skirt_x2B_brim_-_box"> | ||||
| 		<g> | ||||
| 			<path fill="#808080" d="M8,3.26L12.12,6v1.17v2.88L8,12.8l-4.12-2.74V7.17V6L8,3.26 M8,2.06L2.88,5.47v1.71v3.41L8,14l5.12-3.41 | ||||
| 				V7.17V5.47L8,2.06L8,2.06z"/> | ||||
| 		</g> | ||||
| 	</g> | ||||
| 	<g id="skirt_x2B_brim_-_box_1_"> | ||||
| 		<g> | ||||
| 			<path fill="#ED6B21" d="M8,1.63l5.5,3.67v1.73v3.73L8,14.43l-5.5-3.67V7.03V5.3L8,1.63 M8,1.03l-6,4v2v4l6,4l6-4v-4v-2L8,1.03 | ||||
| 				L8,1.03z"/> | ||||
| 		</g> | ||||
| 	</g> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 780 B | 
							
								
								
									
										21
									
								
								resources/icons/spool.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,21 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="spool"> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="2" x2="2" y2="14"/> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="14" y1="2" x2="14" y2="14"/> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-width="1.5" stroke-linecap="round" stroke-miterlimit="10" x1="4" y1="3" x2="4" y2="13"/> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-width="1.5" stroke-linecap="round" stroke-miterlimit="10" x1="6" y1="3" x2="6" y2="13"/> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-width="1.5" stroke-linecap="round" stroke-miterlimit="10" x1="8" y1="3" x2="8" y2="13"/> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-width="1.5" stroke-linecap="round" stroke-miterlimit="10" x1="10" y1="3" x2="10" y2="13"/> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-width="1.5" stroke-linecap="round" stroke-miterlimit="10" x1="12" y1="3" x2="12" y2="13"/> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.3 KiB | 
							
								
								
									
										25
									
								
								resources/icons/support.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,25 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="support"> | ||||
| 	<polygon fill="none" stroke="#808080" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="8,1  | ||||
| 		2.31,4.79 2.31,8.57 2.31,8.79 2.31,10.47 8,14.25 13.69,10.47 13.69,8.79 13.69,8.57 13.69,4.79 	"/> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="12.69" y1="15" x2="12.69" y2="12.44"/> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="13.87" y1="15" x2="13.87" y2="11.64"/> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="2.13" y1="15" x2="2.13" y2="11.64"/> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="3.33" y1="15" x2="3.33" y2="12.44"/> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="4.51" y1="15" x2="4.51" y2="13.22"/> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="5.66" y1="15" x2="5.66" y2="14"/> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="10.34" y1="15" x2="10.34" y2="14"/> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="11.5" y1="15" x2="11.5" y2="13.22"/> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										16
									
								
								resources/icons/time.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,16 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="time"> | ||||
| 	<g> | ||||
| 		<path fill="#808080" d="M8,2c3.31,0,6,2.69,6,6s-2.69,6-6,6s-6-2.69-6-6S4.69,2,8,2 M8,1C4.13,1,1,4.13,1,8s3.13,7,7,7s7-3.13,7-7 | ||||
| 			S11.87,1,8,1L8,1z"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-miterlimit="10" x1="5" y1="4" x2="8" y2="8"/> | ||||
| 	</g> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#ED6B21" stroke-width="1.5" stroke-linecap="round" stroke-miterlimit="10" x1="11.5" y1="8" x2="8" y2="8"/> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 789 B | 
							
								
								
									
										24
									
								
								resources/icons/wrench.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,24 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="advanced_x2B_wrench"> | ||||
| 	<path fill="#808080" d="M7.39,3.69C7.32,3.46,7.23,3.24,7.11,3.03l0.22-0.65L6.62,1.67L5.97,1.89C5.76,1.77,5.54,1.68,5.31,1.61 | ||||
| 		L5,1H4L3.69,1.61C3.46,1.68,3.24,1.77,3.03,1.89L2.38,1.67L1.67,2.38l0.22,0.65C1.77,3.24,1.68,3.46,1.61,3.69L1,4v1l0.61,0.31 | ||||
| 		c0.07,0.23,0.16,0.46,0.27,0.67L1.67,6.62l0.71,0.71l0.65-0.22c0.21,0.12,0.43,0.21,0.67,0.28L4,8h1l0.31-0.61 | ||||
| 		c0.23-0.07,0.46-0.16,0.67-0.28l0.65,0.22l0.71-0.71L7.11,5.97c0.12-0.21,0.21-0.43,0.27-0.67L8,5V4L7.39,3.69z"/> | ||||
| 	<path fill="#808080" d="M12.4,2.49c-0.05-0.17-0.11-0.33-0.2-0.48l0.15-0.46l-0.51-0.51L11.39,1.2c-0.15-0.08-0.31-0.15-0.48-0.2 | ||||
| 		l-0.22-0.44H9.98L9.76,1C9.59,1.05,9.43,1.11,9.28,1.2L8.82,1.04L8.31,1.55l0.15,0.46c-0.08,0.15-0.15,0.31-0.2,0.48L7.83,2.71 | ||||
| 		v0.71l0.44,0.22c0.05,0.17,0.11,0.33,0.2,0.48L8.31,4.58l0.51,0.51l0.46-0.15c0.15,0.08,0.31,0.15,0.48,0.2l0.22,0.44h0.71 | ||||
| 		l0.22-0.44c0.17-0.05,0.33-0.11,0.48-0.2l0.46,0.15l0.51-0.51L12.2,4.12c0.08-0.15,0.15-0.31,0.2-0.48l0.44-0.22V2.71L12.4,2.49z" | ||||
| 		/> | ||||
| 	<path fill="#ED6B21" d="M14.36,10.66c0.04-0.34,0.04-0.68,0-1.02L15,8.91L14.46,7.6l-0.97-0.07c-0.21-0.27-0.45-0.51-0.72-0.72 | ||||
| 		L12.7,5.84L11.39,5.3l-0.73,0.64c-0.34-0.04-0.68-0.04-1.02,0L8.91,5.3L7.6,5.84L7.53,6.81C7.26,7.02,7.02,7.26,6.81,7.53L5.84,7.6 | ||||
| 		L5.3,8.91l0.64,0.73c-0.04,0.34-0.04,0.68,0,1.02L5.3,11.39l0.54,1.31l0.97,0.07c0.21,0.27,0.45,0.51,0.72,0.72l0.07,0.97L8.91,15 | ||||
| 		l0.73-0.64c0.34,0.04,0.68,0.04,1.02,0L11.39,15l1.31-0.54l0.07-0.97c0.27-0.21,0.51-0.45,0.72-0.72l0.97-0.07L15,11.39 | ||||
| 		L14.36,10.66z"/> | ||||
| 	<circle fill="#FFFFFF" cx="4.5" cy="4.5" r="1.92"/> | ||||
| 	<circle fill="#FFFFFF" cx="10.33" cy="3.06" r="1.11"/> | ||||
| 	<circle fill="#FFFFFF" cx="10.15" cy="10.15" r="2.85"/> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 2 KiB | 
|  | @ -21,30 +21,6 @@ add_subdirectory(libnest2d) | |||
| include_directories(${LIBDIR}/qhull/src) | ||||
| #message(STATUS ${LIBDIR}/qhull/src) | ||||
| 
 | ||||
| # ############################################################################## | ||||
| # Configure rasterizer target | ||||
| # ############################################################################## | ||||
| 
 | ||||
| find_package(PNG QUIET) | ||||
| 
 | ||||
| option(RASTERIZER_FORCE_BUILTIN_LIBPNG "Force the usage of builting libpng instead of the system version." OFF) | ||||
| 
 | ||||
| if(PNG_FOUND AND NOT RASTERIZER_FORCE_BUILTIN_LIBPNG) | ||||
|     message(STATUS "Using system libpng.") | ||||
| else() | ||||
|     set(ZLIB_LIBRARY "") | ||||
|     message(WARNING "Using builtin libpng. This can cause crashes on some platforms.") | ||||
|     set(SKIP_INSTALL_ALL 1)   # Prevent png+zlib from creating install targets | ||||
|     add_subdirectory(png/zlib) | ||||
|     set(ZLIB_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/png/zlib ${CMAKE_CURRENT_BINARY_DIR}/png/zlib) | ||||
|     include_directories(${ZLIB_INCLUDE_DIR}) | ||||
|     add_subdirectory(png/libpng) | ||||
|     set_target_properties(zlibstatic PROPERTIES POSITION_INDEPENDENT_CODE ON) | ||||
|     set_target_properties(png_static PROPERTIES POSITION_INDEPENDENT_CODE ON) | ||||
|     set(PNG_LIBRARIES png_static zlibstatic) | ||||
|     set(PNG_INCLUDE_DIRS ${ZLIB_INCLUDE_DIR} ${PROJECT_SOURCE_DIR}/png/libpng ${CMAKE_CURRENT_BINARY_DIR}/png/libpng) | ||||
| endif() | ||||
| 
 | ||||
| add_subdirectory(libslic3r) | ||||
| 
 | ||||
| if (SLIC3R_GUI) | ||||
|  | @ -60,10 +36,12 @@ if (SLIC3R_GUI) | |||
|     endif() | ||||
| 
 | ||||
|     if (CMAKE_SYSTEM_NAME STREQUAL "Linux") | ||||
|         set (wxWidgets_CONFIG_OPTIONS "--toolkit=gtk${SLIC3R_GTK}") | ||||
|         if (SLIC3R_WX_STABLE) | ||||
|             find_package(wxWidgets 3.0 REQUIRED COMPONENTS base core adv html gl) | ||||
|         else () | ||||
|             find_package(wxWidgets 3.1 QUIET COMPONENTS base core adv html gl) | ||||
| 
 | ||||
|             if (NOT wxWidgets_FOUND) | ||||
|                 message(FATAL_ERROR "\nCould not find wxWidgets 3.1.\n" | ||||
|                     "Hint: On Linux you can set -DSLIC3R_WX_STABLE=1 to use wxWidgets 3.0\n") | ||||
|  | @ -115,12 +93,16 @@ endif () | |||
| 
 | ||||
| # Add the Slic3r GUI library, libcurl, OpenGL and GLU libraries. | ||||
| if (SLIC3R_GUI) | ||||
|     target_link_libraries(slic3r libslic3r_gui ${wxWidgets_LIBRARIES}) | ||||
|     target_link_libraries(slic3r  libslic3r_gui ${wxWidgets_LIBRARIES}) | ||||
| 
 | ||||
|     # Configure libcurl & OpenSSL | ||||
|     # Configure libcurl and its dependencies OpenSSL & zlib | ||||
|     find_package(CURL REQUIRED) | ||||
|     if (NOT MSVC) | ||||
|         # Required by libcurl | ||||
|         find_package(ZLIB REQUIRED) | ||||
|     endif() | ||||
|     target_include_directories(slic3r PRIVATE ${CURL_INCLUDE_DIRS}) | ||||
|     target_link_libraries(slic3r CURL::libcurl) | ||||
|     target_link_libraries(slic3r ${CURL_LIBRARIES} ${ZLIB_LIBRARIES}) | ||||
|     if (SLIC3R_STATIC) | ||||
|         if (NOT APPLE) | ||||
|             # libcurl is always linked dynamically to the system libcurl on OSX. | ||||
|  | @ -155,7 +137,7 @@ if (MSVC) | |||
|     add_executable(slic3r_app_gui WIN32 slic3r_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/slic3r.rc) | ||||
|     target_compile_definitions(slic3r_app_gui PRIVATE -DSLIC3R_WRAPPER_NOCONSOLE) | ||||
|     add_dependencies(slic3r_app_gui slic3r) | ||||
|     set_target_properties(slic3r_app_gui PROPERTIES OUTPUT_NAME "slic3r") | ||||
|     set_target_properties(slic3r_app_gui PROPERTIES OUTPUT_NAME "slic3r" PDB_NAME "slic3r_gui") | ||||
| 
 | ||||
|     add_executable(slic3r_app_console slic3r_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/slic3r.rc) | ||||
|     target_compile_definitions(slic3r_app_console PRIVATE -DSLIC3R_WRAPPER_CONSOLE) | ||||
|  | @ -188,7 +170,7 @@ if (MSVC) | |||
|         ) | ||||
|     endif () | ||||
| elseif (XCODE) | ||||
|     # Because of Debug/Release/etc. configurations (similar to MSVC) the slic3r binary is located in an extra level | ||||
|     # Because of Debug/Release/etc. configurations (similar to MSVC) the slic3r binary is located in an extra level | ||||
|     add_custom_command(TARGET slic3r POST_BUILD | ||||
|         COMMAND ln -sf "${SLIC3R_RESOURCES_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/resources" | ||||
|         COMMENT "Symlinking the resources directory into the build tree" | ||||
|  |  | |||
|  | @ -39,8 +39,7 @@ static void stl_record_neighbors(stl_file *stl, | |||
|                                  stl_hash_edge *edge_a, stl_hash_edge *edge_b); | ||||
| static void stl_initialize_facet_check_exact(stl_file *stl); | ||||
| static void stl_initialize_facet_check_nearby(stl_file *stl); | ||||
| static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, | ||||
|                                 stl_vertex *a, stl_vertex *b); | ||||
| static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, const stl_vertex *a, const stl_vertex *b); | ||||
| static int stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge, | ||||
|                                 stl_vertex *a, stl_vertex *b, float tolerance); | ||||
| static void insert_hash_edge(stl_file *stl, stl_hash_edge edge, | ||||
|  | @ -60,41 +59,40 @@ extern int stl_check_normal_vector(stl_file *stl, | |||
|                                    int facet_num, int normal_fix_flag); | ||||
| static void stl_update_connects_remove_1(stl_file *stl, int facet_num); | ||||
| 
 | ||||
| 
 | ||||
| void | ||||
| stl_check_facets_exact(stl_file *stl) { | ||||
|   /* This function builds the neighbors list.  No modifications are made
 | ||||
|    *  to any of the facets.  The edges are said to match only if all six | ||||
|    *  floats of the first edge matches all six floats of the second edge. | ||||
|    */ | ||||
| 
 | ||||
|   stl_hash_edge  edge; | ||||
|   stl_facet      facet; | ||||
|   int            i; | ||||
|   int            j; | ||||
| 
 | ||||
|   if (stl->error) return; | ||||
| // This function builds the neighbors list.  No modifications are made
 | ||||
| // to any of the facets.  The edges are said to match only if all six
 | ||||
| // floats of the first edge matches all six floats of the second edge.
 | ||||
| void stl_check_facets_exact(stl_file *stl) | ||||
| { | ||||
|   if (stl->error) | ||||
| 	  return; | ||||
| 
 | ||||
|   stl->stats.connected_edges = 0; | ||||
|   stl->stats.connected_facets_1_edge = 0; | ||||
|   stl->stats.connected_facets_2_edge = 0; | ||||
|   stl->stats.connected_facets_3_edge = 0; | ||||
| 
 | ||||
|   stl_initialize_facet_check_exact(stl); | ||||
|   // If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet.
 | ||||
|   // Do it before the next step, as the next step stores references to the face indices in the hash tables and removing a facet
 | ||||
|   // will break the references.
 | ||||
|   for (int i = 0; i < stl->stats.number_of_facets;) { | ||||
| 	  stl_facet &facet = stl->facet_start[i]; | ||||
| 	  if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) { | ||||
| 		  // Remove the degenerate facet.
 | ||||
| 		  facet = stl->facet_start[--stl->stats.number_of_facets]; | ||||
| 		  stl->stats.facets_removed += 1; | ||||
| 		  stl->stats.degenerate_facets += 1; | ||||
| 	  } else | ||||
| 		  ++ i; | ||||
|   } | ||||
| 
 | ||||
|   for(i = 0; i < stl->stats.number_of_facets; i++) { | ||||
|     facet = stl->facet_start[i]; | ||||
|     // If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet.
 | ||||
|     if (facet.vertex[0] == facet.vertex[1] || | ||||
|         facet.vertex[1] == facet.vertex[2] || | ||||
|         facet.vertex[0] == facet.vertex[2]) { | ||||
|       stl->stats.degenerate_facets += 1; | ||||
|       stl_remove_facet(stl, i); | ||||
|       -- i; | ||||
|       continue; | ||||
|     } | ||||
|     for(j = 0; j < 3; j++) { | ||||
|       edge.facet_number = i; | ||||
|   // Connect neighbor edges.
 | ||||
|   stl_initialize_facet_check_exact(stl); | ||||
|   for (int i = 0; i < stl->stats.number_of_facets; i++) { | ||||
| 	const stl_facet &facet = stl->facet_start[i]; | ||||
|     for (int j = 0; j < 3; j++) { | ||||
| 	  stl_hash_edge  edge; | ||||
| 	  edge.facet_number = i; | ||||
|       edge.which_edge = j; | ||||
|       stl_load_edge_exact(stl, &edge, &facet.vertex[j], &facet.vertex[(j + 1) % 3]); | ||||
|       insert_hash_edge(stl, edge, stl_record_neighbors); | ||||
|  | @ -109,9 +107,7 @@ stl_check_facets_exact(stl_file *stl) { | |||
| #endif | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, | ||||
|                     stl_vertex *a, stl_vertex *b) { | ||||
| static void stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, const stl_vertex *a, const stl_vertex *b) { | ||||
| 
 | ||||
|   if (stl->error) return; | ||||
| 
 | ||||
|  | @ -333,7 +329,9 @@ static void stl_free_edges(stl_file *stl) | |||
|     } | ||||
|   } | ||||
|   free(stl->heads); | ||||
|   stl->heads = nullptr; | ||||
|   free(stl->tail); | ||||
|   stl->tail = nullptr; | ||||
| } | ||||
| 
 | ||||
| static void stl_initialize_facet_check_nearby(stl_file *stl) | ||||
|  |  | |||
|  | @ -127,7 +127,6 @@ typedef struct { | |||
| typedef struct { | ||||
|   FILE          *fp; | ||||
|   stl_facet     *facet_start; | ||||
|   stl_edge      *edge_start; | ||||
|   stl_hash_edge **heads; | ||||
|   stl_hash_edge *tail; | ||||
|   int           M; | ||||
|  | @ -142,7 +141,6 @@ typedef struct { | |||
| extern void stl_open(stl_file *stl, const char *file); | ||||
| extern void stl_close(stl_file *stl); | ||||
| extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file); | ||||
| extern void stl_print_edges(stl_file *stl, FILE *file); | ||||
| extern void stl_print_neighbors(stl_file *stl, char *file); | ||||
| extern void stl_put_little_int(FILE *fp, int value_in); | ||||
| extern void stl_put_little_float(FILE *fp, float value_in); | ||||
|  |  | |||
|  | @ -33,24 +33,6 @@ | |||
| #define SEEK_END 2 | ||||
| #endif | ||||
| 
 | ||||
| void | ||||
| stl_print_edges(stl_file *stl, FILE *file) { | ||||
|   int i; | ||||
|   int edges_allocated; | ||||
| 
 | ||||
|   if (stl->error) return; | ||||
| 
 | ||||
|   edges_allocated = stl->stats.number_of_facets * 3; | ||||
|   for(i = 0; i < edges_allocated; i++) { | ||||
|     fprintf(file, "%d, %f, %f, %f, %f, %f, %f\n", | ||||
|             stl->edge_start[i].facet_number, | ||||
|             stl->edge_start[i].p1(0), stl->edge_start[i].p1(1), | ||||
|             stl->edge_start[i].p1(2), stl->edge_start[i].p2(0), | ||||
|             stl->edge_start[i].p2(1), stl->edge_start[i].p2(2)); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void | ||||
| stl_stats_out(stl_file *stl, FILE *file, char *input_file) { | ||||
|   if (stl->error) return; | ||||
|  |  | |||
|  | @ -64,6 +64,7 @@ endif() | |||
| target_include_directories(ClipperBackend INTERFACE ${Boost_INCLUDE_DIRS} ) | ||||
| target_sources(ClipperBackend INTERFACE | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/geometries.hpp | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/clipper_polygon.hpp | ||||
|     ${SRC_DIR}/libnest2d/utils/boost_alg.hpp ) | ||||
| 
 | ||||
| target_compile_definitions(ClipperBackend INTERFACE LIBNEST2D_BACKEND_CLIPPER) | ||||
|  |  | |||
|  | @ -0,0 +1,72 @@ | |||
| #ifndef CLIPPER_POLYGON_HPP | ||||
| #define CLIPPER_POLYGON_HPP | ||||
| 
 | ||||
| #include <clipper.hpp> | ||||
| 
 | ||||
| namespace ClipperLib { | ||||
| 
 | ||||
| struct Polygon { | ||||
|     Path Contour; | ||||
|     Paths Holes; | ||||
| 
 | ||||
|     inline Polygon() = default; | ||||
| 
 | ||||
|     inline explicit Polygon(const Path& cont): Contour(cont) {} | ||||
|     inline explicit Polygon(const Paths& holes): | ||||
|         Holes(holes) {} | ||||
|     inline Polygon(const Path& cont, const Paths& holes): | ||||
|         Contour(cont), Holes(holes) {} | ||||
| 
 | ||||
|     inline explicit Polygon(Path&& cont): Contour(std::move(cont)) {} | ||||
|     inline explicit Polygon(Paths&& holes): Holes(std::move(holes)) {} | ||||
|     inline Polygon(Path&& cont, Paths&& holes): | ||||
|         Contour(std::move(cont)), Holes(std::move(holes)) {} | ||||
| }; | ||||
| 
 | ||||
| inline IntPoint& operator +=(IntPoint& p, const IntPoint& pa ) { | ||||
|     // This could be done with SIMD
 | ||||
|     p.X += pa.X; | ||||
|     p.Y += pa.Y; | ||||
|     return p; | ||||
| } | ||||
| 
 | ||||
| inline IntPoint operator+(const IntPoint& p1, const IntPoint& p2) { | ||||
|     IntPoint ret = p1; | ||||
|     ret += p2; | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| inline IntPoint& operator -=(IntPoint& p, const IntPoint& pa ) { | ||||
|     p.X -= pa.X; | ||||
|     p.Y -= pa.Y; | ||||
|     return p; | ||||
| } | ||||
| 
 | ||||
| inline IntPoint operator -(IntPoint& p ) { | ||||
|     IntPoint ret = p; | ||||
|     ret.X = -ret.X; | ||||
|     ret.Y = -ret.Y; | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| inline IntPoint operator-(const IntPoint& p1, const IntPoint& p2) { | ||||
|     IntPoint ret = p1; | ||||
|     ret -= p2; | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| inline IntPoint& operator *=(IntPoint& p, const IntPoint& pa ) { | ||||
|     p.X *= pa.X; | ||||
|     p.Y *= pa.Y; | ||||
|     return p; | ||||
| } | ||||
| 
 | ||||
| inline IntPoint operator*(const IntPoint& p1, const IntPoint& p2) { | ||||
|     IntPoint ret = p1; | ||||
|     ret *= p2; | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // CLIPPER_POLYGON_HPP
 | ||||
|  | @ -10,84 +10,15 @@ | |||
| #include <libnest2d/geometry_traits.hpp> | ||||
| #include <libnest2d/geometry_traits_nfp.hpp> | ||||
| 
 | ||||
| #include <clipper.hpp> | ||||
| 
 | ||||
| namespace ClipperLib { | ||||
| using PointImpl = IntPoint; | ||||
| using PathImpl = Path; | ||||
| using HoleStore = std::vector<PathImpl>; | ||||
| 
 | ||||
| struct PolygonImpl { | ||||
|     PathImpl Contour; | ||||
|     HoleStore Holes; | ||||
| 
 | ||||
|     inline PolygonImpl() = default; | ||||
| 
 | ||||
|     inline explicit PolygonImpl(const PathImpl& cont): Contour(cont) {} | ||||
|     inline explicit PolygonImpl(const HoleStore& holes): | ||||
|         Holes(holes) {} | ||||
|     inline PolygonImpl(const Path& cont, const HoleStore& holes): | ||||
|         Contour(cont), Holes(holes) {} | ||||
| 
 | ||||
|     inline explicit PolygonImpl(PathImpl&& cont): Contour(std::move(cont)) {} | ||||
|     inline explicit PolygonImpl(HoleStore&& holes): Holes(std::move(holes)) {} | ||||
|     inline PolygonImpl(Path&& cont, HoleStore&& holes): | ||||
|         Contour(std::move(cont)), Holes(std::move(holes)) {} | ||||
| }; | ||||
| 
 | ||||
| inline PointImpl& operator +=(PointImpl& p, const PointImpl& pa ) { | ||||
|     // This could be done with SIMD
 | ||||
|     p.X += pa.X; | ||||
|     p.Y += pa.Y; | ||||
|     return p; | ||||
| } | ||||
| 
 | ||||
| inline PointImpl operator+(const PointImpl& p1, const PointImpl& p2) { | ||||
|     PointImpl ret = p1; | ||||
|     ret += p2; | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| inline PointImpl& operator -=(PointImpl& p, const PointImpl& pa ) { | ||||
|     p.X -= pa.X; | ||||
|     p.Y -= pa.Y; | ||||
|     return p; | ||||
| } | ||||
| 
 | ||||
| inline PointImpl operator -(PointImpl& p ) { | ||||
|     PointImpl ret = p; | ||||
|     ret.X = -ret.X; | ||||
|     ret.Y = -ret.Y; | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| inline PointImpl operator-(const PointImpl& p1, const PointImpl& p2) { | ||||
|     PointImpl ret = p1; | ||||
|     ret -= p2; | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| inline PointImpl& operator *=(PointImpl& p, const PointImpl& pa ) { | ||||
|     p.X *= pa.X; | ||||
|     p.Y *= pa.Y; | ||||
|     return p; | ||||
| } | ||||
| 
 | ||||
| inline PointImpl operator*(const PointImpl& p1, const PointImpl& p2) { | ||||
|     PointImpl ret = p1; | ||||
|     ret *= p2; | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| } | ||||
| #include "clipper_polygon.hpp" | ||||
| 
 | ||||
| namespace libnest2d { | ||||
| 
 | ||||
| // Aliases for convinience
 | ||||
| using ClipperLib::PointImpl; | ||||
| using ClipperLib::PathImpl; | ||||
| using ClipperLib::PolygonImpl; | ||||
| using ClipperLib::HoleStore; | ||||
| using PointImpl = ClipperLib::IntPoint; | ||||
| using PathImpl  = ClipperLib::Path; | ||||
| using HoleStore = ClipperLib::Paths; | ||||
| using PolygonImpl = ClipperLib::Polygon; | ||||
| 
 | ||||
| // Type of coordinate units used by Clipper
 | ||||
| template<> struct CoordType<PointImpl> { | ||||
|  | @ -158,33 +89,24 @@ template<> inline TCoord<PointImpl>& y(PointImpl& p) | |||
| #define DISABLE_BOOST_AREA | ||||
| 
 | ||||
| namespace _smartarea { | ||||
| 
 | ||||
| template<Orientation o> | ||||
| inline double area(const PolygonImpl& /*sh*/) { | ||||
|     return std::nan(""); | ||||
| } | ||||
| 
 | ||||
| template<> | ||||
| inline double area<Orientation::CLOCKWISE>(const PolygonImpl& sh) { | ||||
|     double a = 0; | ||||
| 
 | ||||
|     std::for_each(sh.Holes.begin(), sh.Holes.end(), [&a](const PathImpl& h) | ||||
|     { | ||||
|         a -= ClipperLib::Area(h); | ||||
| inline double area<Orientation::COUNTER_CLOCKWISE>(const PolygonImpl& sh) { | ||||
|     return std::accumulate(sh.Holes.begin(), sh.Holes.end(), | ||||
|                            ClipperLib::Area(sh.Contour), | ||||
|                            [](double a, const ClipperLib::Path& pt){ | ||||
|         return a + ClipperLib::Area(pt); | ||||
|     }); | ||||
| 
 | ||||
|     return -ClipperLib::Area(sh.Contour) + a; | ||||
| } | ||||
| 
 | ||||
| template<> | ||||
| inline double area<Orientation::COUNTER_CLOCKWISE>(const PolygonImpl& sh) { | ||||
|     double a = 0; | ||||
| 
 | ||||
|     std::for_each(sh.Holes.begin(), sh.Holes.end(), [&a](const PathImpl& h) | ||||
|     { | ||||
|         a += ClipperLib::Area(h); | ||||
|     }); | ||||
| 
 | ||||
|     return ClipperLib::Area(sh.Contour) + a; | ||||
| inline double area<Orientation::CLOCKWISE>(const PolygonImpl& sh) { | ||||
|     return -area<Orientation::COUNTER_CLOCKWISE>(sh); | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  | @ -228,9 +150,10 @@ template<> inline void offset(PolygonImpl& sh, TCoord<PointImpl> distance) | |||
|             // but throwing would be an overkill. Instead, we should warn the
 | ||||
|             // caller about the inability to create correct geometries
 | ||||
|             if(!found_the_contour) { | ||||
|                 sh.Contour = r; | ||||
|                 sh.Contour = std::move(r); | ||||
|                 ClipperLib::ReversePath(sh.Contour); | ||||
|                 sh.Contour.push_back(sh.Contour.front()); | ||||
|                 auto front_p = sh.Contour.front(); | ||||
|                 sh.Contour.emplace_back(std::move(front_p)); | ||||
|                 found_the_contour = true; | ||||
|             } else { | ||||
|                 dout() << "Warning: offsetting result is invalid!"; | ||||
|  | @ -240,9 +163,10 @@ template<> inline void offset(PolygonImpl& sh, TCoord<PointImpl> distance) | |||
|             // TODO If there are multiple contours we can't be sure which hole
 | ||||
|             // belongs to the first contour. (But in this case the situation is
 | ||||
|             // bad enough to let it go...)
 | ||||
|             sh.Holes.push_back(r); | ||||
|             sh.Holes.emplace_back(std::move(r)); | ||||
|             ClipperLib::ReversePath(sh.Holes.back()); | ||||
|             sh.Holes.back().push_back(sh.Holes.back().front()); | ||||
|             auto front_p = sh.Holes.back().front(); | ||||
|             sh.Holes.back().emplace_back(std::move(front_p)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -390,34 +314,53 @@ inline void rotate(PolygonImpl& sh, const Radians& rads) | |||
| } // namespace shapelike
 | ||||
| 
 | ||||
| #define DISABLE_BOOST_NFP_MERGE | ||||
| inline std::vector<PolygonImpl> _merge(ClipperLib::Clipper& clipper) { | ||||
| inline std::vector<PolygonImpl> clipper_execute( | ||||
|         ClipperLib::Clipper& clipper, | ||||
|         ClipperLib::ClipType clipType, | ||||
|         ClipperLib::PolyFillType subjFillType = ClipperLib::pftEvenOdd, | ||||
|         ClipperLib::PolyFillType clipFillType = ClipperLib::pftEvenOdd) | ||||
| { | ||||
|     shapelike::Shapes<PolygonImpl> retv; | ||||
| 
 | ||||
|     ClipperLib::PolyTree result; | ||||
|     clipper.Execute(ClipperLib::ctUnion, result, ClipperLib::pftNegative); | ||||
|     clipper.Execute(clipType, result, subjFillType, clipFillType); | ||||
| 
 | ||||
|     retv.reserve(static_cast<size_t>(result.Total())); | ||||
| 
 | ||||
|     std::function<void(ClipperLib::PolyNode*, PolygonImpl&)> processHole; | ||||
| 
 | ||||
|     auto processPoly = [&retv, &processHole](ClipperLib::PolyNode *pptr) { | ||||
|         PolygonImpl poly(pptr->Contour); | ||||
|         poly.Contour.push_back(poly.Contour.front()); | ||||
|         PolygonImpl poly; | ||||
|         poly.Contour.swap(pptr->Contour); | ||||
| 
 | ||||
|         assert(!pptr->IsHole()); | ||||
| 
 | ||||
|         if(pptr->IsOpen()) { | ||||
|             auto front_p = poly.Contour.front(); | ||||
|             poly.Contour.emplace_back(front_p); | ||||
|         } | ||||
| 
 | ||||
|         for(auto h : pptr->Childs) { processHole(h, poly); } | ||||
|         retv.push_back(poly); | ||||
|     }; | ||||
| 
 | ||||
|     processHole = [&processPoly](ClipperLib::PolyNode *pptr, PolygonImpl& poly) | ||||
|     { | ||||
|         poly.Holes.push_back(pptr->Contour); | ||||
|         poly.Holes.back().push_back(poly.Holes.back().front()); | ||||
|         poly.Holes.emplace_back(std::move(pptr->Contour)); | ||||
| 
 | ||||
|         assert(pptr->IsHole()); | ||||
| 
 | ||||
|         if(pptr->IsOpen()) { | ||||
|             auto front_p = poly.Holes.back().front(); | ||||
|             poly.Holes.back().emplace_back(front_p); | ||||
|         } | ||||
| 
 | ||||
|         for(auto c : pptr->Childs) processPoly(c); | ||||
|     }; | ||||
| 
 | ||||
|     auto traverse = [&processPoly] (ClipperLib::PolyNode *node) | ||||
|     { | ||||
|         for(auto ch : node->Childs) { | ||||
|             processPoly(ch); | ||||
|         } | ||||
|         for(auto ch : node->Childs) processPoly(ch); | ||||
|     }; | ||||
| 
 | ||||
|     traverse(&result); | ||||
|  | @ -438,14 +381,13 @@ merge(const std::vector<PolygonImpl>& shapes) | |||
|     for(auto& path : shapes) { | ||||
|         valid &= clipper.AddPath(path.Contour, ClipperLib::ptSubject, closed); | ||||
| 
 | ||||
|         for(auto& hole : path.Holes) { | ||||
|             valid &= clipper.AddPath(hole, ClipperLib::ptSubject, closed); | ||||
|         } | ||||
|         for(auto& h : path.Holes) | ||||
|             valid &= clipper.AddPath(h, ClipperLib::ptSubject, closed); | ||||
|     } | ||||
| 
 | ||||
|     if(!valid) throw GeometryException(GeomErr::MERGE); | ||||
| 
 | ||||
|     return _merge(clipper); | ||||
|     return clipper_execute(clipper, ClipperLib::ctUnion, ClipperLib::pftNegative); | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -966,7 +966,7 @@ private: | |||
| 
 | ||||
|         for(size_t i = 0; i < pckgrp.size(); i++) { | ||||
|             auto items = pckgrp[i]; | ||||
|             pg.push_back({}); | ||||
|             pg.emplace_back(); | ||||
|             pg[i].reserve(items.size()); | ||||
| 
 | ||||
|             for(Item& itemA : items) { | ||||
|  |  | |||
|  | @ -261,7 +261,7 @@ template<class RawShape> class EdgeCache { | |||
|             while(next != endit) { | ||||
|                 contour_.emap.emplace_back(*(first++), *(next++)); | ||||
|                 contour_.full_distance += contour_.emap.back().length(); | ||||
|                 contour_.distances.push_back(contour_.full_distance); | ||||
|                 contour_.distances.emplace_back(contour_.full_distance); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  | @ -276,10 +276,10 @@ template<class RawShape> class EdgeCache { | |||
|             while(next != endit) { | ||||
|                 hc.emap.emplace_back(*(first++), *(next++)); | ||||
|                 hc.full_distance += hc.emap.back().length(); | ||||
|                 hc.distances.push_back(hc.full_distance); | ||||
|                 hc.distances.emplace_back(hc.full_distance); | ||||
|             } | ||||
| 
 | ||||
|             holes_.push_back(hc); | ||||
|             holes_.emplace_back(std::move(hc)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -63,7 +63,7 @@ public: | |||
|     bool pack(Item& item, const Range& rem = Range()) { | ||||
|         auto&& r = static_cast<Subclass*>(this)->trypack(item, rem); | ||||
|         if(r) { | ||||
|             items_.push_back(*(r.item_ptr_)); | ||||
|             items_.emplace_back(*(r.item_ptr_)); | ||||
|             farea_valid_ = false; | ||||
|         } | ||||
|         return r; | ||||
|  | @ -78,7 +78,7 @@ public: | |||
|         if(r) { | ||||
|             r.item_ptr_->translation(r.move_); | ||||
|             r.item_ptr_->rotation(r.rot_); | ||||
|             items_.push_back(*(r.item_ptr_)); | ||||
|             items_.emplace_back(*(r.item_ptr_)); | ||||
|             farea_valid_ = false; | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -667,7 +667,7 @@ public: | |||
|                 addBin(); | ||||
|                 ItemList& not_packed = not_packeds[b]; | ||||
|                 for(unsigned idx = b; idx < store_.size(); idx+=bincount_guess) { | ||||
|                     not_packed.push_back(store_[idx]); | ||||
|                     not_packed.emplace_back(store_[idx]); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|  |  | |||
|  | @ -463,7 +463,7 @@ template<> inline std::string serialize<libnest2d::Formats::SVG>( | |||
|             auto& v = *it; | ||||
|             hf.emplace_back(getX(v)*scale, getY(v)*scale); | ||||
|         }; | ||||
|         holes.push_back(hf); | ||||
|         holes.emplace_back(std::move(hf)); | ||||
|     } | ||||
| 
 | ||||
|     Polygonf poly; | ||||
|  |  | |||
|  | @ -2,36 +2,10 @@ | |||
| #define PRINTER_PARTS_H | ||||
| 
 | ||||
| #include <vector> | ||||
| #include <clipper.hpp> | ||||
| 
 | ||||
| #ifndef CLIPPER_BACKEND_HPP | ||||
| namespace ClipperLib { | ||||
| using PointImpl = IntPoint; | ||||
| using PathImpl = Path; | ||||
| using HoleStore = std::vector<PathImpl>; | ||||
| 
 | ||||
| struct PolygonImpl { | ||||
|     PathImpl Contour; | ||||
|     HoleStore Holes; | ||||
| 
 | ||||
|     inline PolygonImpl() {} | ||||
| 
 | ||||
|     inline explicit PolygonImpl(const PathImpl& cont): Contour(cont) {} | ||||
|     inline explicit PolygonImpl(const HoleStore& holes): | ||||
|         Holes(holes) {} | ||||
|     inline PolygonImpl(const Path& cont, const HoleStore& holes): | ||||
|         Contour(cont), Holes(holes) {} | ||||
| 
 | ||||
|     inline explicit PolygonImpl(PathImpl&& cont): Contour(std::move(cont)) {} | ||||
|     inline explicit PolygonImpl(HoleStore&& holes): Holes(std::move(holes)) {} | ||||
|     inline PolygonImpl(Path&& cont, HoleStore&& holes): | ||||
|         Contour(std::move(cont)), Holes(std::move(holes)) {} | ||||
| }; | ||||
| } | ||||
| #endif | ||||
| #include <libnest2d/backends/clipper/clipper_polygon.hpp> | ||||
| 
 | ||||
| using TestData = std::vector<ClipperLib::Path>; | ||||
| using TestDataEx = std::vector<ClipperLib::PolygonImpl>; | ||||
| using TestDataEx = std::vector<ClipperLib::Polygon>; | ||||
| 
 | ||||
| extern const TestData PRINTER_PART_POLYGONS; | ||||
| extern const TestData STEGOSAUR_POLYGONS; | ||||
|  |  | |||
|  | @ -161,6 +161,8 @@ add_library(libslic3r STATIC | |||
|     utils.cpp | ||||
|     Utils.hpp | ||||
|     MTUtils.hpp | ||||
|     Zipper.hpp | ||||
|     Zipper.cpp | ||||
|     SLA/SLABoilerPlate.hpp | ||||
|     SLA/SLABasePool.hpp | ||||
|     SLA/SLABasePool.cpp | ||||
|  | @ -177,8 +179,8 @@ if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY) | |||
|     add_precompiled_header(libslic3r pchheader.hpp FORCEINCLUDE) | ||||
| endif () | ||||
| 
 | ||||
| target_compile_definitions(libslic3r PUBLIC -DUSE_TBB ${PNG_DEFINITIONS}) | ||||
| target_include_directories(libslic3r PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${LIBNEST2D_INCLUDES} ${PNG_INCLUDE_DIRS} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) | ||||
| target_compile_definitions(libslic3r PUBLIC -DUSE_TBB) | ||||
| target_include_directories(libslic3r PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${LIBNEST2D_INCLUDES} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) | ||||
| target_link_libraries(libslic3r | ||||
|     libnest2d | ||||
|     admesh | ||||
|  | @ -188,7 +190,6 @@ target_link_libraries(libslic3r | |||
|     nowide | ||||
|     ${EXPAT_LIBRARIES} | ||||
|     ${GLEW_LIBRARIES} | ||||
|     ${PNG_LIBRARIES} | ||||
|     glu-libtess | ||||
|     polypartition | ||||
|     poly2tri | ||||
|  |  | |||
|  | @ -120,7 +120,7 @@ Slic3r::Polygon ClipperPath_to_Slic3rPolygon(const ClipperLib::Path &input) | |||
| { | ||||
|     Polygon retval; | ||||
|     for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit) | ||||
|         retval.points.push_back(Point( (*pit).X, (*pit).Y )); | ||||
|         retval.points.emplace_back(pit->X, pit->Y); | ||||
|     return retval; | ||||
| } | ||||
| 
 | ||||
|  | @ -128,7 +128,7 @@ Slic3r::Polyline ClipperPath_to_Slic3rPolyline(const ClipperLib::Path &input) | |||
| { | ||||
|     Polyline retval; | ||||
|     for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit) | ||||
|         retval.points.push_back(Point( (*pit).X, (*pit).Y )); | ||||
|         retval.points.emplace_back(pit->X, pit->Y); | ||||
|     return retval; | ||||
| } | ||||
| 
 | ||||
|  | @ -137,7 +137,7 @@ Slic3r::Polygons ClipperPaths_to_Slic3rPolygons(const ClipperLib::Paths &input) | |||
|     Slic3r::Polygons retval; | ||||
|     retval.reserve(input.size()); | ||||
|     for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it) | ||||
|         retval.push_back(ClipperPath_to_Slic3rPolygon(*it)); | ||||
|         retval.emplace_back(ClipperPath_to_Slic3rPolygon(*it)); | ||||
|     return retval; | ||||
| } | ||||
| 
 | ||||
|  | @ -146,7 +146,7 @@ Slic3r::Polylines ClipperPaths_to_Slic3rPolylines(const ClipperLib::Paths &input | |||
|     Slic3r::Polylines retval; | ||||
|     retval.reserve(input.size()); | ||||
|     for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it) | ||||
|         retval.push_back(ClipperPath_to_Slic3rPolyline(*it)); | ||||
|         retval.emplace_back(ClipperPath_to_Slic3rPolyline(*it)); | ||||
|     return retval; | ||||
| } | ||||
| 
 | ||||
|  | @ -171,7 +171,7 @@ Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input) | |||
| { | ||||
|     ClipperLib::Path retval; | ||||
|     for (Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit) | ||||
|         retval.push_back(ClipperLib::IntPoint( (*pit)(0), (*pit)(1) )); | ||||
|         retval.emplace_back((*pit)(0), (*pit)(1)); | ||||
|     return retval; | ||||
| } | ||||
| 
 | ||||
|  | @ -181,7 +181,7 @@ Slic3rMultiPoint_to_ClipperPath_reversed(const Slic3r::MultiPoint &input) | |||
|     ClipperLib::Path output; | ||||
|     output.reserve(input.points.size()); | ||||
|     for (Slic3r::Points::const_reverse_iterator pit = input.points.rbegin(); pit != input.points.rend(); ++pit) | ||||
|         output.push_back(ClipperLib::IntPoint( (*pit)(0), (*pit)(1) )); | ||||
|         output.emplace_back((*pit)(0), (*pit)(1)); | ||||
|     return output; | ||||
| } | ||||
| 
 | ||||
|  | @ -189,7 +189,7 @@ ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polygons &input) | |||
| { | ||||
|     ClipperLib::Paths retval; | ||||
|     for (Polygons::const_iterator it = input.begin(); it != input.end(); ++it) | ||||
|         retval.push_back(Slic3rMultiPoint_to_ClipperPath(*it)); | ||||
|         retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(*it)); | ||||
|     return retval; | ||||
| } | ||||
| 
 | ||||
|  | @ -197,7 +197,7 @@ ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polylines &input) | |||
| { | ||||
|     ClipperLib::Paths retval; | ||||
|     for (Polylines::const_iterator it = input.begin(); it != input.end(); ++it) | ||||
|         retval.push_back(Slic3rMultiPoint_to_ClipperPath(*it)); | ||||
|         retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(*it)); | ||||
|     return retval; | ||||
| } | ||||
| 
 | ||||
|  | @ -226,7 +226,7 @@ ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType | |||
| ClipperLib::Paths _offset(ClipperLib::Path &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit) | ||||
| { | ||||
|     ClipperLib::Paths paths; | ||||
|     paths.push_back(std::move(input)); | ||||
|     paths.emplace_back(std::move(input)); | ||||
| 	return _offset(std::move(paths), endType, delta, joinType, miterLimit); | ||||
| } | ||||
| 
 | ||||
|  | @ -585,7 +585,7 @@ Polylines _clipper_pl(ClipperLib::ClipType clipType, const Polygons &subject, co | |||
|     Polylines polylines; | ||||
|     polylines.reserve(subject.size()); | ||||
|     for (Polygons::const_iterator polygon = subject.begin(); polygon != subject.end(); ++polygon) | ||||
|         polylines.push_back(*polygon);  // implicit call to split_at_first_point()
 | ||||
|         polylines.emplace_back(polygon->operator Polyline());  // implicit call to split_at_first_point()
 | ||||
|      | ||||
|     // perform clipping
 | ||||
|     Polylines retval = _clipper_pl(clipType, polylines, clip, safety_offset_); | ||||
|  | @ -643,7 +643,7 @@ _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons | |||
|     // convert Polylines to Lines
 | ||||
|     Lines retval; | ||||
|     for (Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline) | ||||
|         retval.push_back(*polyline); | ||||
|         retval.emplace_back(polyline->operator Line()); | ||||
|     return retval; | ||||
| } | ||||
| 
 | ||||
|  | @ -673,7 +673,7 @@ void traverse_pt(ClipperLib::PolyNodes &nodes, Polygons* retval) | |||
|     ordering_points.reserve(nodes.size()); | ||||
|     for (ClipperLib::PolyNodes::const_iterator it = nodes.begin(); it != nodes.end(); ++it) { | ||||
|         Point p((*it)->Contour.front().X, (*it)->Contour.front().Y); | ||||
|         ordering_points.push_back(p); | ||||
|         ordering_points.emplace_back(p); | ||||
|     } | ||||
|      | ||||
|     // perform the ordering
 | ||||
|  | @ -684,7 +684,7 @@ void traverse_pt(ClipperLib::PolyNodes &nodes, Polygons* retval) | |||
|     for (ClipperLib::PolyNodes::iterator it = ordered_nodes.begin(); it != ordered_nodes.end(); ++it) { | ||||
|         // traverse the next depth
 | ||||
|         traverse_pt((*it)->Childs, retval); | ||||
|         retval->push_back(ClipperPath_to_Slic3rPolygon((*it)->Contour)); | ||||
|         retval->emplace_back(ClipperPath_to_Slic3rPolygon((*it)->Contour)); | ||||
|         if ((*it)->IsHole()) retval->back().reverse();  // ccw
 | ||||
|     } | ||||
| } | ||||
|  | @ -791,8 +791,8 @@ Polygons top_level_islands(const Slic3r::Polygons &polygons) | |||
|     Polygons out; | ||||
|     out.reserve(polytree.ChildCount()); | ||||
|     for (int i = 0; i < polytree.ChildCount(); ++i) | ||||
|         out.push_back(ClipperPath_to_Slic3rPolygon(polytree.Childs[i]->Contour)); | ||||
|         out.emplace_back(ClipperPath_to_Slic3rPolygon(polytree.Childs[i]->Contour)); | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -28,8 +28,8 @@ namespace Slic3r { | |||
| 
 | ||||
| //-----------------------------------------------------------
 | ||||
| // legacy code from Clipper documentation
 | ||||
| void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPolygons& expolygons); | ||||
| void PolyTreeToExPolygons(ClipperLib::PolyTree& polytree, Slic3r::ExPolygons& expolygons); | ||||
| void AddOuterPolyNodeToExPolygons(ClipperLib::PolyNode& polynode, Slic3r::ExPolygons *expolygons); | ||||
| Slic3r::ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree& polytree); | ||||
| //-----------------------------------------------------------
 | ||||
| 
 | ||||
| ClipperLib::Path   Slic3rMultiPoint_to_ClipperPath(const Slic3r::MultiPoint &input); | ||||
|  | @ -228,4 +228,4 @@ Polygons top_level_islands(const Slic3r::Polygons &polygons); | |||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| #endif | ||||
|  |  | |||
|  | @ -175,6 +175,11 @@ struct AMFParserContext | |||
|         bool  mirrory_set; | ||||
|         float mirrorz; | ||||
|         bool  mirrorz_set; | ||||
| 
 | ||||
|         bool anything_set() const { return deltax_set || deltay_set || deltaz_set || | ||||
|                                            rx_set || ry_set || rz_set || | ||||
|                                            scalex_set || scaley_set || scalez_set || | ||||
|                                            mirrorx_set || mirrory_set || mirrorz_set; } | ||||
|     }; | ||||
| 
 | ||||
|     struct Object { | ||||
|  | @ -644,11 +649,7 @@ void AMFParserContext::endDocument() | |||
|             continue; | ||||
|         } | ||||
|         for (const Instance &instance : object.second.instances) | ||||
| #if ENABLE_VOLUMES_CENTERING_FIXES | ||||
|         { | ||||
| #else | ||||
|             if (instance.deltax_set && instance.deltay_set) { | ||||
| #endif // ENABLE_VOLUMES_CENTERING_FIXES
 | ||||
|             if (instance.anything_set()) { | ||||
|                 ModelInstance *mi = m_model.objects[object.second.idx]->add_instance(); | ||||
|                 mi->set_offset(Vec3d(instance.deltax_set ? (double)instance.deltax : 0.0, instance.deltay_set ? (double)instance.deltay : 0.0, instance.deltaz_set ? (double)instance.deltaz : 0.0)); | ||||
|                 mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0)); | ||||
|  |  | |||
|  | @ -1034,6 +1034,15 @@ void GCode::_do_export(Print &print, FILE *file) | |||
|     } | ||||
|     _write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100%
 | ||||
|     _write(file, m_writer.postamble()); | ||||
| 
 | ||||
|     // adds tags for time estimators
 | ||||
|     if (print.config().remaining_times.value) | ||||
|     { | ||||
|         _writeln(file, GCodeTimeEstimator::Normal_Last_M73_Output_Placeholder_Tag); | ||||
|         if (m_silent_time_estimator_enabled) | ||||
|             _writeln(file, GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag); | ||||
|     } | ||||
| 
 | ||||
|     print.throw_if_canceled(); | ||||
| 
 | ||||
|     // calculates estimated printing time
 | ||||
|  | @ -2408,6 +2417,9 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, | |||
| { | ||||
|     std::string gcode; | ||||
|      | ||||
|     if (is_bridge(path.role())) | ||||
|         description += " (bridge)"; | ||||
|      | ||||
|     // go to first point of extrusion path
 | ||||
|     if (!m_last_pos_defined || m_last_pos != path.first_point()) { | ||||
|         gcode += this->travel_to( | ||||
|  |  | |||
|  | @ -726,7 +726,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ | |||
|     GCodePreviewData::Range volumetric_rate_range; | ||||
| 
 | ||||
|     // to avoid to call the callback too often
 | ||||
|     unsigned int cancel_callback_threshold = (unsigned int)extrude_moves->second.size() / 25; | ||||
|     unsigned int cancel_callback_threshold = (unsigned int)std::max((int)extrude_moves->second.size() / 25, 1); | ||||
|     unsigned int cancel_callback_curr = 0; | ||||
| 
 | ||||
|     // constructs the polylines while traversing the moves
 | ||||
|  | @ -776,6 +776,9 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ | |||
|     preview_data.ranges.width.update_from(width_range); | ||||
|     preview_data.ranges.feedrate.update_from(feedrate_range); | ||||
|     preview_data.ranges.volumetric_rate.update_from(volumetric_rate_range); | ||||
| 
 | ||||
|     // we need to sort the layers by their z as they can be shuffled in case of sequential prints
 | ||||
|     std::sort(preview_data.extrusion.layers.begin(), preview_data.extrusion.layers.end(), [](const GCodePreviewData::Extrusion::Layer& l1, const GCodePreviewData::Extrusion::Layer& l2)->bool { return l1.z < l2.z; }); | ||||
| } | ||||
| 
 | ||||
| void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, std::function<void()> cancel_callback) | ||||
|  | @ -807,7 +810,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s | |||
|     GCodePreviewData::Range feedrate_range; | ||||
| 
 | ||||
|     // to avoid to call the callback too often
 | ||||
|     unsigned int cancel_callback_threshold = (unsigned int)travel_moves->second.size() / 25; | ||||
|     unsigned int cancel_callback_threshold = (unsigned int)std::max((int)travel_moves->second.size() / 25, 1); | ||||
|     unsigned int cancel_callback_curr = 0; | ||||
| 
 | ||||
|     // constructs the polylines while traversing the moves
 | ||||
|  | @ -855,6 +858,11 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s | |||
|     preview_data.ranges.height.update_from(height_range); | ||||
|     preview_data.ranges.width.update_from(width_range); | ||||
|     preview_data.ranges.feedrate.update_from(feedrate_range); | ||||
| 
 | ||||
|     // we need to sort the polylines by their min z as they can be shuffled in case of sequential prints
 | ||||
|     std::sort(preview_data.travel.polylines.begin(), preview_data.travel.polylines.end(), | ||||
|         [](const GCodePreviewData::Travel::Polyline& p1, const GCodePreviewData::Travel::Polyline& p2)->bool | ||||
|     { return unscale<double>(p1.polyline.bounding_box().min(2)) < unscale<double>(p2.polyline.bounding_box().min(2)); }); | ||||
| } | ||||
| 
 | ||||
| void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_data, std::function<void()> cancel_callback) | ||||
|  | @ -864,7 +872,7 @@ void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_da | |||
|         return; | ||||
| 
 | ||||
|     // to avoid to call the callback too often
 | ||||
|     unsigned int cancel_callback_threshold = (unsigned int)retraction_moves->second.size() / 25; | ||||
|     unsigned int cancel_callback_threshold = (unsigned int)std::max((int)retraction_moves->second.size() / 25, 1); | ||||
|     unsigned int cancel_callback_curr = 0; | ||||
| 
 | ||||
|     for (const GCodeMove& move : retraction_moves->second) | ||||
|  | @ -877,6 +885,11 @@ void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_da | |||
|         Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())); | ||||
|         preview_data.retraction.positions.emplace_back(position, move.data.width, move.data.height); | ||||
|     } | ||||
| 
 | ||||
|     // we need to sort the positions by their z as they can be shuffled in case of sequential prints
 | ||||
|     std::sort(preview_data.retraction.positions.begin(), preview_data.retraction.positions.end(), | ||||
|         [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2)->bool | ||||
|     { return unscale<double>(p1.position(2)) < unscale<double>(p2.position(2)); }); | ||||
| } | ||||
| 
 | ||||
| void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_data, std::function<void()> cancel_callback) | ||||
|  | @ -886,7 +899,7 @@ void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_ | |||
|         return; | ||||
| 
 | ||||
|     // to avoid to call the callback too often
 | ||||
|     unsigned int cancel_callback_threshold = (unsigned int)unretraction_moves->second.size() / 25; | ||||
|     unsigned int cancel_callback_threshold = (unsigned int)std::max((int)unretraction_moves->second.size() / 25, 1); | ||||
|     unsigned int cancel_callback_curr = 0; | ||||
| 
 | ||||
|     for (const GCodeMove& move : unretraction_moves->second) | ||||
|  | @ -899,6 +912,11 @@ void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_ | |||
|         Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())); | ||||
|         preview_data.unretraction.positions.emplace_back(position, move.data.width, move.data.height); | ||||
|     } | ||||
| 
 | ||||
|     // we need to sort the positions by their z as they can be shuffled in case of sequential prints
 | ||||
|     std::sort(preview_data.unretraction.positions.begin(), preview_data.unretraction.positions.end(), | ||||
|         [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2)->bool | ||||
|     { return unscale<double>(p1.position(2)) < unscale<double>(p2.position(2)); }); | ||||
| } | ||||
| 
 | ||||
| // Return an estimate of the memory consumed by the time estimator.
 | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| #include <boost/log/trivial.hpp> | ||||
| #include <boost/format.hpp> | ||||
| #include <boost/filesystem.hpp> | ||||
| #include <boost/nowide/convert.hpp> | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| 
 | ||||
|  | @ -11,6 +12,7 @@ | |||
| #define WIN32_LEAN_AND_MEAN | ||||
| #define NOMINMAX | ||||
| #include <Windows.h> | ||||
| #include <shellapi.h> | ||||
| 
 | ||||
| // https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
 | ||||
| // This routine appends the given argument to a command line such that CommandLineToArgvW will return the argument string unchanged.
 | ||||
|  |  | |||
|  | @ -171,6 +171,8 @@ namespace Slic3r { | |||
| 
 | ||||
|     const std::string GCodeTimeEstimator::Normal_First_M73_Output_Placeholder_Tag = "; NORMAL_FIRST_M73_OUTPUT_PLACEHOLDER"; | ||||
|     const std::string GCodeTimeEstimator::Silent_First_M73_Output_Placeholder_Tag = "; SILENT_FIRST_M73_OUTPUT_PLACEHOLDER"; | ||||
|     const std::string GCodeTimeEstimator::Normal_Last_M73_Output_Placeholder_Tag = "; NORMAL_LAST_M73_OUTPUT_PLACEHOLDER"; | ||||
|     const std::string GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag = "; SILENT_LAST_M73_OUTPUT_PLACEHOLDER"; | ||||
| 
 | ||||
|     GCodeTimeEstimator::GCodeTimeEstimator(EMode mode) | ||||
|         : _mode(mode) | ||||
|  | @ -306,9 +308,17 @@ namespace Slic3r { | |||
|                 sprintf(time_line, time_mask.c_str(), "0", _get_time_minutes(_time).c_str()); | ||||
|                 gcode_line = time_line; | ||||
|             } | ||||
|             // replaces placeholders for final line M73 with the real lines
 | ||||
|             else if (((_mode == Normal) && (gcode_line == Normal_Last_M73_Output_Placeholder_Tag)) || | ||||
|                      ((_mode == Silent) && (gcode_line == Silent_Last_M73_Output_Placeholder_Tag))) | ||||
|             { | ||||
|                 sprintf(time_line, time_mask.c_str(), "100", "0"); | ||||
|                 gcode_line = time_line; | ||||
|             } | ||||
|             else | ||||
|                gcode_line += "\n"; | ||||
| 
 | ||||
| 
 | ||||
|             // add remaining time lines where needed
 | ||||
|             _parser.parse_line(gcode_line, | ||||
|                 [this, &it_line_id, &g1_lines_count, &last_recorded_time, &time_line, &gcode_line, time_mask, interval](GCodeReader& reader, const GCodeReader::GCodeLine& line) | ||||
|  |  | |||
|  | @ -19,6 +19,8 @@ namespace Slic3r { | |||
|     public: | ||||
|         static const std::string Normal_First_M73_Output_Placeholder_Tag; | ||||
|         static const std::string Silent_First_M73_Output_Placeholder_Tag; | ||||
|         static const std::string Normal_Last_M73_Output_Placeholder_Tag; | ||||
|         static const std::string Silent_Last_M73_Output_Placeholder_Tag; | ||||
| 
 | ||||
|         enum EMode : unsigned char | ||||
|         { | ||||
|  |  | |||
|  | @ -246,6 +246,7 @@ public: | |||
| 
 | ||||
|     const Vec3d& get_mirror() const { return m_mirror; } | ||||
|     double get_mirror(Axis axis) const { return m_mirror(axis); } | ||||
|     bool is_left_handed() const { return m_mirror.x() * m_mirror.y() * m_mirror.z() < 0.; } | ||||
| 
 | ||||
|     void set_mirror(const Vec3d& mirror); | ||||
|     void set_mirror(Axis axis, double mirror); | ||||
|  |  | |||
|  | @ -258,13 +258,18 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) | |||
|                 #ifdef SLIC3R_DEBUG | ||||
|                 printf("Processing bridge at layer " PRINTF_ZU ":\n", this->layer()->id()); | ||||
|                 #endif | ||||
|                 if (bd.detect_angle(Geometry::deg2rad(this->region()->config().bridge_angle.value))) { | ||||
| 				double custom_angle = Geometry::deg2rad(this->region()->config().bridge_angle.value); | ||||
| 				if (bd.detect_angle(custom_angle)) { | ||||
|                     bridges[idx_last].bridge_angle = bd.angle; | ||||
|                     if (this->layer()->object()->config().support_material) { | ||||
|                         polygons_append(this->bridged, bd.coverage()); | ||||
|                         this->unsupported_bridge_edges.append(bd.unsupported_edges());  | ||||
|                     } | ||||
|                 } | ||||
| 				} else if (custom_angle > 0) { | ||||
| 					// Bridge was not detected (likely it is only supported at one side). Still it is a surface filled in
 | ||||
| 					// using a bridging flow, therefore it makes sense to respect the custom bridging direction.
 | ||||
| 					bridges[idx_last].bridge_angle = custom_angle; | ||||
| 				} | ||||
|                 // without safety offset, artifacts are generated (GH #2494)
 | ||||
|                 surfaces_append(bottom, union_ex(grown, true), bridges[idx_last]); | ||||
|             } | ||||
|  |  | |||
|  | @ -56,6 +56,132 @@ public: | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| /// An std compatible random access iterator which uses indices to the source
 | ||||
| /// vector thus resistant to invalidation caused by relocations. It also "knows"
 | ||||
| /// its container. No comparison is neccesary to the container "end()" iterator.
 | ||||
| /// The template can be instantiated with a different value type than that of
 | ||||
| /// the container's but the types must be compatible. E.g. a base class of the
 | ||||
| /// contained objects is compatible.
 | ||||
| ///
 | ||||
| /// For a constant iterator, one can instantiate this template with a value
 | ||||
| /// type preceded with 'const'.
 | ||||
| template<class Vector,  // The container type, must be random access...
 | ||||
|          class Value = typename Vector::value_type // The value type
 | ||||
|          > | ||||
| class IndexBasedIterator { | ||||
|     static const size_t NONE = size_t(-1); | ||||
| 
 | ||||
|     std::reference_wrapper<Vector> m_index_ref; | ||||
|     size_t m_idx = NONE; | ||||
| public: | ||||
| 
 | ||||
|     using value_type = Value; | ||||
|     using pointer = Value *; | ||||
|     using reference = Value &; | ||||
|     using difference_type = long; | ||||
|     using iterator_category = std::random_access_iterator_tag; | ||||
| 
 | ||||
|     inline explicit | ||||
|     IndexBasedIterator(Vector& index, size_t idx): | ||||
|         m_index_ref(index), m_idx(idx) {} | ||||
| 
 | ||||
|     // Post increment
 | ||||
|     inline IndexBasedIterator operator++(int) { | ||||
|         IndexBasedIterator cpy(*this); ++m_idx; return cpy; | ||||
|     } | ||||
| 
 | ||||
|     inline IndexBasedIterator operator--(int) { | ||||
|         IndexBasedIterator cpy(*this); --m_idx; return cpy; | ||||
|     } | ||||
| 
 | ||||
|     inline IndexBasedIterator& operator++() { | ||||
|         ++m_idx; return *this; | ||||
|     } | ||||
| 
 | ||||
|     inline IndexBasedIterator& operator--() { | ||||
|         --m_idx; return *this; | ||||
|     } | ||||
| 
 | ||||
|     inline IndexBasedIterator& operator+=(difference_type l) { | ||||
|         m_idx += size_t(l); return *this; | ||||
|     } | ||||
| 
 | ||||
|     inline IndexBasedIterator operator+(difference_type l) { | ||||
|         auto cpy = *this; cpy += l; return cpy; | ||||
|     } | ||||
| 
 | ||||
|     inline IndexBasedIterator& operator-=(difference_type l) { | ||||
|         m_idx -= size_t(l); return *this; | ||||
|     } | ||||
| 
 | ||||
|     inline IndexBasedIterator operator-(difference_type l) { | ||||
|         auto cpy = *this; cpy -= l; return cpy; | ||||
|     } | ||||
| 
 | ||||
|     operator difference_type() { return difference_type(m_idx); } | ||||
| 
 | ||||
|     /// Tesing the end of the container... this is not possible with std
 | ||||
|     /// iterators.
 | ||||
|     inline bool is_end() const { return m_idx >= m_index_ref.get().size();} | ||||
| 
 | ||||
|     inline Value & operator*() const { | ||||
|         assert(m_idx < m_index_ref.get().size()); | ||||
|         return m_index_ref.get().operator[](m_idx); | ||||
|     } | ||||
| 
 | ||||
|     inline Value * operator->() const { | ||||
|         assert(m_idx < m_index_ref.get().size()); | ||||
|         return &m_index_ref.get().operator[](m_idx); | ||||
|     } | ||||
| 
 | ||||
|     /// If both iterators point past the container, they are equal...
 | ||||
|     inline bool operator ==(const IndexBasedIterator& other) { | ||||
|         size_t e = m_index_ref.get().size(); | ||||
|         return m_idx == other.m_idx || (m_idx >= e && other.m_idx >= e); | ||||
|     } | ||||
| 
 | ||||
|     inline bool operator !=(const IndexBasedIterator& other) { | ||||
|         return !(*this == other); | ||||
|     } | ||||
| 
 | ||||
|     inline bool operator <=(const IndexBasedIterator& other) { | ||||
|         return (m_idx < other.m_idx) || (*this == other); | ||||
|     } | ||||
| 
 | ||||
|     inline bool operator <(const IndexBasedIterator& other) { | ||||
|         return m_idx < other.m_idx && (*this != other); | ||||
|     } | ||||
| 
 | ||||
|     inline bool operator >=(const IndexBasedIterator& other) { | ||||
|         return m_idx > other.m_idx || *this == other; | ||||
|     } | ||||
| 
 | ||||
|     inline bool operator >(const IndexBasedIterator& other) { | ||||
|         return m_idx > other.m_idx && *this != other; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /// A very simple range concept implementation with iterator-like objects.
 | ||||
| template<class It> class Range { | ||||
|     It from, to; | ||||
| public: | ||||
| 
 | ||||
|     // The class is ready for range based for loops.
 | ||||
|     It begin() const { return from; } | ||||
|     It end() const { return to; } | ||||
| 
 | ||||
|     // The iterator type can be obtained this way.
 | ||||
|     using Type = It; | ||||
| 
 | ||||
|     Range() = default; | ||||
|     Range(It &&b, It &&e): | ||||
|         from(std::forward<It>(b)), to(std::forward<It>(e)) {} | ||||
| 
 | ||||
|     // Some useful container-like methods...
 | ||||
|     inline size_t size() const { return end() - begin(); } | ||||
|     inline bool empty() const { return size() == 0; } | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // MTUTILS_HPP
 | ||||
|  |  | |||
|  | @ -61,7 +61,7 @@ Model& Model::assign_copy(Model &&rhs) | |||
| 	this->objects = std::move(rhs.objects); | ||||
|     for (ModelObject *model_object : this->objects) | ||||
|         model_object->set_model(this); | ||||
| 	rhs.objects.clear(); | ||||
|     rhs.objects.clear(); | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
|  | @ -556,19 +556,9 @@ std::string Model::propose_export_file_name_and_path() const | |||
|     for (const ModelObject *model_object : this->objects) | ||||
|         for (ModelInstance *model_instance : model_object->instances) | ||||
|             if (model_instance->is_printable()) { | ||||
|                 input_file = model_object->input_file; | ||||
|                 if (! model_object->name.empty()) { | ||||
|                     if (input_file.empty()) | ||||
|                         // model_object->input_file was empty, just use model_object->name
 | ||||
|                         input_file = model_object->name; | ||||
|                     else { | ||||
|                         // Replace file name in input_file with model_object->name, but keep the path and file extension.
 | ||||
| 						input_file = (boost::filesystem::path(model_object->name).parent_path().empty()) ? | ||||
| 							(boost::filesystem::path(input_file).parent_path() / model_object->name).make_preferred().string() : | ||||
| 							model_object->name; | ||||
| 					} | ||||
|                 } | ||||
|                 if (! input_file.empty()) | ||||
|                 input_file = model_object->get_export_filename(); | ||||
| 
 | ||||
|                 if (!input_file.empty()) | ||||
|                     goto end; | ||||
|                 // Other instances will produce the same name, skip them.
 | ||||
|                 break; | ||||
|  | @ -651,7 +641,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs) | |||
|     for (ModelInstance *model_instance : this->instances) | ||||
|         model_instance->set_model_object(this); | ||||
| 
 | ||||
| 	return *this; | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| void ModelObject::assign_new_unique_ids_recursive() | ||||
|  | @ -970,8 +960,8 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) | |||
|                 } | ||||
|             } | ||||
|         } | ||||
| 	std::sort(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) < b(0) || (a(0) == b(0) && a(1) < b(1)); }); | ||||
| 	pts.erase(std::unique(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) == b(0) && a(1) == b(1); }), pts.end()); | ||||
|     std::sort(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) < b(0) || (a(0) == b(0) && a(1) < b(1)); }); | ||||
|     pts.erase(std::unique(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) == b(0) && a(1) == b(1); }), pts.end()); | ||||
| 
 | ||||
|     Polygon hull; | ||||
|     int n = (int)pts.size(); | ||||
|  | @ -997,12 +987,16 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) | |||
|     return hull; | ||||
| } | ||||
| 
 | ||||
| #if ENABLE_VOLUMES_CENTERING_FIXES | ||||
| void ModelObject::center_around_origin(bool include_modifiers) | ||||
| #else | ||||
| void ModelObject::center_around_origin() | ||||
| #endif // ENABLE_VOLUMES_CENTERING_FIXES
 | ||||
| { | ||||
|     // calculate the displacements needed to 
 | ||||
|     // center this object around the origin
 | ||||
| #if ENABLE_VOLUMES_CENTERING_FIXES | ||||
|     BoundingBoxf3 bb = full_raw_mesh_bounding_box(); | ||||
|     BoundingBoxf3 bb = include_modifiers ? full_raw_mesh_bounding_box() : raw_mesh_bounding_box(); | ||||
| #else | ||||
| 	BoundingBoxf3 bb; | ||||
| 	for (ModelVolume *v : this->volumes) | ||||
|  | @ -1183,8 +1177,9 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b | |||
|         else { | ||||
|             TriangleMesh upper_mesh, lower_mesh; | ||||
| 
 | ||||
|             // Transform the mesh by the combined transformation matrix
 | ||||
|             volume->mesh.transform(instance_matrix * volume_matrix); | ||||
|             // Transform the mesh by the combined transformation matrix.
 | ||||
|             // Flip the triangles in case the composite transformation is left handed.
 | ||||
|             volume->mesh.transform(instance_matrix * volume_matrix, true); | ||||
| 
 | ||||
|             // Perform cut
 | ||||
|             TriangleMeshSlicer tms(&volume->mesh); | ||||
|  | @ -1287,11 +1282,11 @@ void ModelObject::split(ModelObjectPtrs* new_objects) | |||
|          | ||||
|         // XXX: this seems to be the only real usage of m_model, maybe refactor this so that it's not needed?
 | ||||
|         ModelObject* new_object = m_model->add_object();     | ||||
| 		new_object->name   = this->name; | ||||
| 		new_object->config = this->config; | ||||
| 		new_object->instances.reserve(this->instances.size()); | ||||
| 		for (const ModelInstance *model_instance : this->instances) | ||||
| 			new_object->add_instance(*model_instance); | ||||
|         new_object->name   = this->name; | ||||
|         new_object->config = this->config; | ||||
|         new_object->instances.reserve(this->instances.size()); | ||||
|         for (const ModelInstance *model_instance : this->instances) | ||||
|             new_object->add_instance(*model_instance); | ||||
|         ModelVolume* new_vol = new_object->add_volume(*volume, std::move(*mesh)); | ||||
| #if !ENABLE_VOLUMES_CENTERING_FIXES | ||||
|         new_vol->center_geometry(); | ||||
|  | @ -1428,6 +1423,26 @@ void ModelObject::print_info() const | |||
|     cout << "volume = "           << mesh.volume()                  << endl; | ||||
| } | ||||
| 
 | ||||
| std::string ModelObject::get_export_filename() const | ||||
| { | ||||
|     std::string ret = input_file; | ||||
| 
 | ||||
|     if (!name.empty()) | ||||
|     { | ||||
|         if (ret.empty()) | ||||
|             // input_file was empty, just use name
 | ||||
|             ret = name; | ||||
|         else | ||||
|         { | ||||
|             // Replace file name in input_file with name, but keep the path and file extension.
 | ||||
|             ret = (boost::filesystem::path(name).parent_path().empty()) ? | ||||
|                 (boost::filesystem::path(ret).parent_path() / name).make_preferred().string() : name; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| void ModelVolume::set_material_id(t_model_material_id material_id) | ||||
| { | ||||
|     m_material_id = material_id; | ||||
|  | @ -1463,9 +1478,9 @@ int ModelVolume::extruder_id() const | |||
| 
 | ||||
| bool ModelVolume::is_splittable() const | ||||
| { | ||||
|     // the call mesh.has_multiple_patches() is expensive, so cache the value to calculate it only once
 | ||||
|     // the call mesh.is_splittable() is expensive, so cache the value to calculate it only once
 | ||||
|     if (m_is_splittable == -1) | ||||
|         m_is_splittable = (int)mesh.has_multiple_patches(); | ||||
|         m_is_splittable = (int)mesh.is_splittable(); | ||||
| 
 | ||||
|     return m_is_splittable == 1; | ||||
| } | ||||
|  | @ -1605,6 +1620,7 @@ void ModelVolume::rotate(double angle, Axis axis) | |||
|     case X: { rotate(angle, Vec3d::UnitX()); break; } | ||||
|     case Y: { rotate(angle, Vec3d::UnitY()); break; } | ||||
|     case Z: { rotate(angle, Vec3d::UnitZ()); break; } | ||||
|     default: break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -1621,6 +1637,7 @@ void ModelVolume::mirror(Axis axis) | |||
|     case X: { mirror(0) *= -1.0; break; } | ||||
|     case Y: { mirror(1) *= -1.0; break; } | ||||
|     case Z: { mirror(2) *= -1.0; break; } | ||||
|     default: break; | ||||
|     } | ||||
|     set_mirror(mirror); | ||||
| } | ||||
|  | @ -1707,7 +1724,6 @@ bool model_object_list_extended(const Model &model_old, const Model &model_new) | |||
| 
 | ||||
| bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolumeType type) | ||||
| { | ||||
|     bool modifiers_differ = false; | ||||
|     size_t i_old, i_new; | ||||
|     for (i_old = 0, i_new = 0; i_old < model_object_old.volumes.size() && i_new < model_object_new.volumes.size();) { | ||||
|         const ModelVolume &mv_old = *model_object_old.volumes[i_old]; | ||||
|  |  | |||
|  | @ -236,7 +236,11 @@ public: | |||
|     // This method is used by the auto arrange function.
 | ||||
|     Polygon       convex_hull_2d(const Transform3d &trafo_instance); | ||||
| 
 | ||||
| #if ENABLE_VOLUMES_CENTERING_FIXES | ||||
|     void center_around_origin(bool include_modifiers = true); | ||||
| #else | ||||
|     void center_around_origin(); | ||||
| #endif // ENABLE_VOLUMES_CENTERING_FIXES
 | ||||
|     void ensure_on_bed(); | ||||
|     void translate_instances(const Vec3d& vector); | ||||
|     void translate_instance(size_t instance_idx, const Vec3d& vector); | ||||
|  | @ -271,6 +275,8 @@ public: | |||
|     // Print object statistics to console.
 | ||||
|     void print_info() const; | ||||
| 
 | ||||
|     std::string get_export_filename() const; | ||||
| 
 | ||||
| protected: | ||||
|     friend class Print; | ||||
|     friend class SLAPrint; | ||||
|  | @ -390,6 +396,7 @@ public: | |||
| 
 | ||||
|     const Vec3d& get_mirror() const { return m_transformation.get_mirror(); } | ||||
|     double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); } | ||||
|     bool is_left_handed() const { return m_transformation.is_left_handed(); } | ||||
| 
 | ||||
|     void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); } | ||||
|     void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); } | ||||
|  | @ -494,6 +501,7 @@ public: | |||
| 
 | ||||
|     const Vec3d& get_mirror() const { return m_transformation.get_mirror(); } | ||||
|     double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); } | ||||
| 	bool is_left_handed() const { return m_transformation.is_left_handed(); } | ||||
| 
 | ||||
|     void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); } | ||||
|     void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); } | ||||
|  |  | |||
|  | @ -556,29 +556,7 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { | |||
|             // TODO export the exact 2D projection. Cannot do it as libnest2d
 | ||||
|             // does not support concave shapes (yet).
 | ||||
|             ClipperLib::Path clpath; | ||||
| //WIP Vojtech's optimization of the calculation of the convex hull is not working correctly yet.
 | ||||
| #if 1 | ||||
|             { | ||||
|                 TriangleMesh rmesh = objptr->raw_mesh(); | ||||
| 
 | ||||
|                 ModelInstance * finst = objptr->instances.front(); | ||||
| 
 | ||||
|                 // Object instances should carry the same scaling and
 | ||||
|                 // x, y rotation that is why we use the first instance.
 | ||||
|                 // The next line will apply only the full mirroring and scaling
 | ||||
|                 rmesh.transform(finst->get_matrix(true, true, false, false)); | ||||
|                 rmesh.rotate_x(float(finst->get_rotation()(X))); | ||||
|                 rmesh.rotate_y(float(finst->get_rotation()(Y))); | ||||
| 
 | ||||
|                  // TODO export the exact 2D projection. Cannot do it as libnest2d
 | ||||
|                  // does not support concave shapes (yet).
 | ||||
|                 auto p = rmesh.convex_hull(); | ||||
| 
 | ||||
|                 p.make_clockwise(); | ||||
|                 p.append(p.first_point()); | ||||
|                 clpath = Slic3rMultiPoint_to_ClipperPath(p); | ||||
|             } | ||||
| #else | ||||
|             // Object instances should carry the same scaling and
 | ||||
|             // x, y rotation that is why we use the first instance.
 | ||||
|             { | ||||
|  | @ -593,11 +571,10 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { | |||
|                 p.append(p.first_point()); | ||||
|                 clpath = Slic3rMultiPoint_to_ClipperPath(p); | ||||
|             } | ||||
| #endif | ||||
| 
 | ||||
|             for(ModelInstance* objinst : objptr->instances) { | ||||
|                 if(objinst) { | ||||
|                     ClipperLib::PolygonImpl pn; | ||||
|                     ClipperLib::Polygon pn; | ||||
|                     pn.Contour = clpath; | ||||
| 
 | ||||
|                     // Efficient conversion to item.
 | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ | |||
| #include "GCode/WipeTowerPrusaMM.hpp" | ||||
| #include "Utils.hpp" | ||||
| 
 | ||||
| #include "PrintExport.hpp" | ||||
| //#include "PrintExport.hpp"
 | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <limits> | ||||
|  |  | |||
|  | @ -208,7 +208,7 @@ void PrintConfigDef::init_fff_params() | |||
|     def->tooltip = L("Horizontal width of the brim that will be printed around each object on the first layer."); | ||||
|     def->sidetext = L("mm"); | ||||
|     def->min = 0; | ||||
|     def->mode = comAdvanced; | ||||
|     def->mode = comSimple; | ||||
|     def->default_value = new ConfigOptionFloat(0); | ||||
| 
 | ||||
|     def = this->add("clip_multipart_objects", coBool); | ||||
|  | @ -1375,6 +1375,7 @@ void PrintConfigDef::init_fff_params() | |||
|     def->sidetext = L("(minimum)"); | ||||
|     def->aliases = { "perimeter_offsets" }; | ||||
|     def->min = 0; | ||||
|     def->max = 10000; | ||||
|     def->default_value = new ConfigOptionInt(3); | ||||
| 
 | ||||
|     def = this->add("post_process", coStrings); | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ | |||
| #include <vector> | ||||
| 
 | ||||
| #include <boost/log/trivial.hpp> | ||||
| #include <boost/filesystem/path.hpp> | ||||
| 
 | ||||
| #include "Rasterizer/Rasterizer.hpp" | ||||
| //#include <tbb/parallel_for.h>
 | ||||
|  | @ -42,8 +43,9 @@ template<FilePrinterFormat format> | |||
| class FilePrinter { | ||||
| public: | ||||
| 
 | ||||
|     // Draw an ExPolygon which is a polygon inside a slice on the specified layer.
 | ||||
|     // Draw a polygon which is a polygon inside a slice on the specified layer.
 | ||||
|     void draw_polygon(const ExPolygon& p, unsigned lyr); | ||||
|     void draw_polygon(const ClipperLib::Polygon& p, unsigned lyr); | ||||
| 
 | ||||
|     // Tell the printer how many layers should it consider.
 | ||||
|     void layers(unsigned layernum); | ||||
|  | @ -71,7 +73,8 @@ public: | |||
|     void finish_layer(); | ||||
| 
 | ||||
|     // Save all the layers into the file (or dir) specified in the path argument
 | ||||
|     void save(const std::string& path); | ||||
|     // An optional project name can be added to be used for the layer file names
 | ||||
|     void save(const std::string& path, const std::string& projectname = ""); | ||||
| 
 | ||||
|     // Save only the selected layer to the file specified in path argument.
 | ||||
|     void save_layer(unsigned lyr, const std::string& path); | ||||
|  | @ -80,28 +83,35 @@ public: | |||
| // Provokes static_assert in the right way.
 | ||||
| template<class T = void> struct VeryFalse { static const bool value = false; }; | ||||
| 
 | ||||
| // This has to be explicitly implemented in the gui layer or a default zlib
 | ||||
| // based implementation is needed. I don't have time for that and I'm delegating
 | ||||
| // the implementation to the gui layer where the gui toolkit can cover this.
 | ||||
| // This can be explicitly implemented in the gui layer or the default Zipper
 | ||||
| // API in libslic3r with minz.
 | ||||
| template<class Fmt> class LayerWriter { | ||||
| public: | ||||
| 
 | ||||
|     LayerWriter(const std::string& /*zipfile_path*/) { | ||||
|     LayerWriter(const std::string& /*zipfile_path*/) | ||||
|     { | ||||
|         static_assert(VeryFalse<Fmt>::value, | ||||
|                       "No layer writer implementation provided!"); | ||||
|     } | ||||
| 
 | ||||
|     // Should create a new file within the zip with the given filename. It
 | ||||
|     // should also finish any previous entry.
 | ||||
|     void next_entry(const std::string& /*fname*/) {} | ||||
| 
 | ||||
|     std::string get_name() { return ""; } | ||||
|     // Should create a new file within the archive and write the provided data.
 | ||||
|     void binary_entry(const std::string& /*fname*/, | ||||
|                       const std::uint8_t* buf, size_t len); | ||||
| 
 | ||||
|     // Test whether the object can still be used for writing.
 | ||||
|     bool is_ok() { return false; } | ||||
| 
 | ||||
|     template<class T> LayerWriter& operator<<(const T& /*arg*/) { | ||||
|     // Write some data (text) into the current file (entry) within the archive.
 | ||||
|     template<class T> LayerWriter& operator<<(T&& /*arg*/) { | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     void close() {} | ||||
|     // Flush the current entry into the archive.
 | ||||
|     void finalize() {} | ||||
| }; | ||||
| 
 | ||||
| // Implementation for PNG raster output
 | ||||
|  | @ -110,14 +120,14 @@ public: | |||
| template<> class FilePrinter<FilePrinterFormat::SLA_PNGZIP> | ||||
| { | ||||
|     struct Layer { | ||||
|         Raster first; | ||||
|         std::stringstream second; | ||||
|         Raster raster; | ||||
|         RawBytes rawbytes; | ||||
| 
 | ||||
|         Layer() {} | ||||
| 
 | ||||
|         Layer(const Layer&) = delete; | ||||
|         Layer(Layer&& m): | ||||
|             first(std::move(m.first))/*, second(std::move(m.second))*/ {} | ||||
|             raster(std::move(m.raster)) {} | ||||
|     }; | ||||
| 
 | ||||
|     // We will save the compressed PNG data into stringstreams which can be done
 | ||||
|  | @ -135,14 +145,11 @@ template<> class FilePrinter<FilePrinterFormat::SLA_PNGZIP> | |||
|     int    m_cnt_fast_layers = 0; | ||||
| 
 | ||||
|     std::string createIniContent(const std::string& projectname) { | ||||
| //         double layer_height = m_layer_height;
 | ||||
| 
 | ||||
|         using std::string; | ||||
|         using std::to_string; | ||||
| 
 | ||||
|         auto expt_str = to_string(m_exp_time_s); | ||||
|         auto expt_first_str = to_string(m_exp_time_first_s); | ||||
| //         auto stepnum_str = to_string(static_cast<unsigned>(800*layer_height));
 | ||||
|         auto layerh_str = to_string(m_layer_height); | ||||
| 
 | ||||
|         const std::string cnt_fade_layers = to_string(m_cnt_fade_layers); | ||||
|  | @ -211,41 +218,48 @@ public: | |||
| 
 | ||||
|     inline void draw_polygon(const ExPolygon& p, unsigned lyr) { | ||||
|         assert(lyr < m_layers_rst.size()); | ||||
|         m_layers_rst[lyr].first.draw(p); | ||||
|         m_layers_rst[lyr].raster.draw(p); | ||||
|     } | ||||
| 
 | ||||
|     inline void draw_polygon(const ClipperLib::Polygon& p, unsigned lyr) { | ||||
|         assert(lyr < m_layers_rst.size()); | ||||
|         m_layers_rst[lyr].raster.draw(p); | ||||
|     } | ||||
| 
 | ||||
|     inline void begin_layer(unsigned lyr) { | ||||
|         if(m_layers_rst.size() <= lyr) m_layers_rst.resize(lyr+1); | ||||
|         m_layers_rst[lyr].first.reset(m_res, m_pxdim, m_o); | ||||
|         m_layers_rst[lyr].raster.reset(m_res, m_pxdim, m_o); | ||||
|     } | ||||
| 
 | ||||
|     inline void begin_layer() { | ||||
|         m_layers_rst.emplace_back(); | ||||
|         m_layers_rst.front().first.reset(m_res, m_pxdim, m_o); | ||||
|         m_layers_rst.front().raster.reset(m_res, m_pxdim, m_o); | ||||
|     } | ||||
| 
 | ||||
|     inline void finish_layer(unsigned lyr_id) { | ||||
|         assert(lyr_id < m_layers_rst.size()); | ||||
|         m_layers_rst[lyr_id].first.save(m_layers_rst[lyr_id].second, | ||||
|                                        Raster::Compression::PNG); | ||||
|         m_layers_rst[lyr_id].first.reset(); | ||||
|         m_layers_rst[lyr_id].rawbytes = | ||||
|                 m_layers_rst[lyr_id].raster.save(Raster::Compression::PNG); | ||||
|         m_layers_rst[lyr_id].raster.reset(); | ||||
|     } | ||||
| 
 | ||||
|     inline void finish_layer() { | ||||
|         if(!m_layers_rst.empty()) { | ||||
|             m_layers_rst.back().first.save(m_layers_rst.back().second, | ||||
|                                           Raster::Compression::PNG); | ||||
|             m_layers_rst.back().first.reset(); | ||||
|             m_layers_rst.back().rawbytes = | ||||
|                     m_layers_rst.back().raster.save(Raster::Compression::PNG); | ||||
|             m_layers_rst.back().raster.reset(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     template<class LyrFmt> | ||||
|     inline void save(const std::string& path) { | ||||
|     inline void save(const std::string& fpath, const std::string& prjname = "") | ||||
|     { | ||||
|         try { | ||||
|             LayerWriter<LyrFmt> writer(path); | ||||
|             LayerWriter<LyrFmt> writer(fpath); | ||||
|             if(!writer.is_ok()) return; | ||||
| 
 | ||||
|             std::string project = writer.get_name(); | ||||
|             std::string project = prjname.empty()? | ||||
|                        boost::filesystem::path(fpath).stem().string() : prjname; | ||||
| 
 | ||||
|             writer.next_entry("config.ini"); | ||||
|             if(!writer.is_ok()) return; | ||||
|  | @ -254,20 +268,19 @@ public: | |||
| 
 | ||||
|             for(unsigned i = 0; i < m_layers_rst.size() && writer.is_ok(); i++) | ||||
|             { | ||||
|                 if(m_layers_rst[i].second.rdbuf()->in_avail() > 0) { | ||||
|                 if(m_layers_rst[i].rawbytes.size() > 0) { | ||||
|                     char lyrnum[6]; | ||||
|                     std::sprintf(lyrnum, "%.5d", i); | ||||
|                     auto zfilename = project + lyrnum + ".png"; | ||||
|                     writer.next_entry(zfilename); | ||||
| 
 | ||||
|                     if(!writer.is_ok()) break; | ||||
| 
 | ||||
|                     writer << m_layers_rst[i].second.str(); | ||||
|                     // writer << m_layers_rst[i].second.rdbuf();
 | ||||
|                     // we can keep the date for later calls of this method
 | ||||
|                     //m_layers_rst[i].second.str("");
 | ||||
|                     writer.binary_entry(zfilename, | ||||
|                                         m_layers_rst[i].rawbytes.data(), | ||||
|                                         m_layers_rst[i].rawbytes.size()); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             writer.finalize(); | ||||
|         } catch(std::exception& e) { | ||||
|             BOOST_LOG_TRIVIAL(error) << e.what(); | ||||
|             // Rethrow the exception
 | ||||
|  | @ -285,13 +298,13 @@ public: | |||
| 
 | ||||
|         std::fstream out(loc, std::fstream::out | std::fstream::binary); | ||||
|         if(out.good()) { | ||||
|             m_layers_rst[i].first.save(out, Raster::Compression::PNG); | ||||
|             m_layers_rst[i].raster.save(out, Raster::Compression::PNG); | ||||
|         } else { | ||||
|             BOOST_LOG_TRIVIAL(error) << "Can't create file for layer"; | ||||
|         } | ||||
| 
 | ||||
|         out.close(); | ||||
|         m_layers_rst[i].first.reset(); | ||||
|         m_layers_rst[i].raster.reset(); | ||||
|     } | ||||
| 
 | ||||
|     void set_statistics(const std::vector<double> statistics) | ||||
|  |  | |||
|  | @ -1790,15 +1790,21 @@ std::vector<ExPolygons> PrintObject::_slice_volumes(const std::vector<float> &z, | |||
|     if (! volumes.empty()) { | ||||
|         // Compose mesh.
 | ||||
|         //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
 | ||||
|         TriangleMesh mesh; | ||||
|         for (const ModelVolume *v : volumes) | ||||
|         { | ||||
|             TriangleMesh vol_mesh(v->mesh); | ||||
|             vol_mesh.transform(v->get_matrix()); | ||||
| 		TriangleMesh mesh(volumes.front()->mesh); | ||||
|         mesh.transform(volumes.front()->get_matrix(), true); | ||||
| 		assert(mesh.repaired); | ||||
| 		if (volumes.size() == 1 && mesh.repaired) { | ||||
| 			//FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it.
 | ||||
| 			stl_check_facets_exact(&mesh.stl); | ||||
| 		} | ||||
|         for (size_t idx_volume = 1; idx_volume < volumes.size(); ++ idx_volume) { | ||||
|             const ModelVolume &model_volume = *volumes[idx_volume]; | ||||
|             TriangleMesh vol_mesh(model_volume.mesh); | ||||
|             vol_mesh.transform(model_volume.get_matrix(), true); | ||||
|             mesh.merge(vol_mesh); | ||||
|         } | ||||
|         if (mesh.stl.stats.number_of_facets > 0) { | ||||
|             mesh.transform(m_trafo); | ||||
|             mesh.transform(m_trafo, true); | ||||
|             // apply XY shift
 | ||||
|             mesh.translate(- unscale<float>(m_copies_shift(0)), - unscale<float>(m_copies_shift(1)), 0); | ||||
|             // perform actual slicing
 | ||||
|  | @ -1819,9 +1825,13 @@ std::vector<ExPolygons> PrintObject::_slice_volume(const std::vector<float> &z, | |||
|     // Compose mesh.
 | ||||
|     //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
 | ||||
|     TriangleMesh mesh(volume.mesh); | ||||
|     mesh.transform(volume.get_matrix()); | ||||
|     mesh.transform(volume.get_matrix(), true); | ||||
| 	if (mesh.repaired) { | ||||
| 		//FIXME The admesh repair function may break the face connectivity, rather refresh it here as the slicing code relies on it.
 | ||||
| 		stl_check_facets_exact(&mesh.stl); | ||||
| 	} | ||||
|     if (mesh.stl.stats.number_of_facets > 0) { | ||||
|         mesh.transform(m_trafo); | ||||
|         mesh.transform(m_trafo, true); | ||||
|         // apply XY shift
 | ||||
|         mesh.translate(- unscale<float>(m_copies_shift(0)), - unscale<float>(m_copies_shift(1)), 0); | ||||
|         // perform actual slicing
 | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| #include "Rasterizer.hpp" | ||||
| #include <ExPolygon.hpp> | ||||
| 
 | ||||
| #include <cstdint> | ||||
| #include <libnest2d/backends/clipper/clipper_polygon.hpp> | ||||
| 
 | ||||
| // For rasterizing
 | ||||
| #include <agg/agg_basics.h> | ||||
|  | @ -15,8 +14,8 @@ | |||
| #include <agg/agg_rasterizer_scanline_aa.h> | ||||
| #include <agg/agg_path_storage.h> | ||||
| 
 | ||||
| // For png compression
 | ||||
| #include <png/writer.hpp> | ||||
| // Experimental minz image write:
 | ||||
| #include <miniz/miniz_tdef.h> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
|  | @ -91,6 +90,25 @@ public: | |||
|         agg::render_scanlines(ras, scanlines, m_renderer); | ||||
|     } | ||||
| 
 | ||||
|     void draw(const ClipperLib::Polygon &poly) { | ||||
|         agg::rasterizer_scanline_aa<> ras; | ||||
|         agg::scanline_p8 scanlines; | ||||
| 
 | ||||
|         auto&& path = to_path(poly.Contour); | ||||
| 
 | ||||
|         if(m_o == Origin::TOP_LEFT) flipy(path); | ||||
| 
 | ||||
|         ras.add_path(path); | ||||
| 
 | ||||
|         for(auto h : poly.Holes) { | ||||
|             auto&& holepath = to_path(h); | ||||
|             if(m_o == Origin::TOP_LEFT) flipy(holepath); | ||||
|             ras.add_path(holepath); | ||||
|         } | ||||
| 
 | ||||
|         agg::render_scanlines(ras, scanlines, m_renderer); | ||||
|     } | ||||
| 
 | ||||
|     inline void clear() { | ||||
|         m_raw_renderer.clear(ColorBlack); | ||||
|     } | ||||
|  | @ -110,14 +128,36 @@ private: | |||
|         return p(1) * SCALING_FACTOR/m_pxdim.h_mm; | ||||
|     } | ||||
| 
 | ||||
|     agg::path_storage to_path(const Polygon& poly) { | ||||
|     agg::path_storage to_path(const Polygon& poly) | ||||
|     { | ||||
|         agg::path_storage path; | ||||
| 
 | ||||
|         auto it = poly.points.begin(); | ||||
|         path.move_to(getPx(*it), getPy(*it)); | ||||
|         while(++it != poly.points.end()) | ||||
|         while(++it != poly.points.end()) path.line_to(getPx(*it), getPy(*it)); | ||||
|         path.line_to(getPx(poly.points.front()), getPy(poly.points.front())); | ||||
| 
 | ||||
|         return path; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     double getPx(const ClipperLib::IntPoint& p) { | ||||
|         return p.X * SCALING_FACTOR/m_pxdim.w_mm; | ||||
|     } | ||||
| 
 | ||||
|     double getPy(const ClipperLib::IntPoint& p) { | ||||
|         return p.Y * SCALING_FACTOR/m_pxdim.h_mm; | ||||
|     } | ||||
| 
 | ||||
|     agg::path_storage to_path(const ClipperLib::Path& poly) | ||||
|     { | ||||
|         agg::path_storage path; | ||||
|         auto it = poly.begin(); | ||||
|         path.move_to(getPx(*it), getPy(*it)); | ||||
|         while(++it != poly.end()) | ||||
|             path.line_to(getPx(*it), getPy(*it)); | ||||
| 
 | ||||
|         path.line_to(getPx(poly.points.front()), getPy(poly.points.front())); | ||||
|         path.line_to(getPx(poly.front()), getPy(poly.front())); | ||||
|         return path; | ||||
|     } | ||||
| 
 | ||||
|  | @ -169,38 +209,36 @@ void Raster::clear() | |||
|     m_impl->clear(); | ||||
| } | ||||
| 
 | ||||
| void Raster::draw(const ExPolygon &poly) | ||||
| void Raster::draw(const ExPolygon &expoly) | ||||
| { | ||||
|     m_impl->draw(expoly); | ||||
| } | ||||
| 
 | ||||
| void Raster::draw(const ClipperLib::Polygon &poly) | ||||
| { | ||||
|     assert(m_impl); | ||||
|     m_impl->draw(poly); | ||||
| } | ||||
| 
 | ||||
| void Raster::save(std::ostream& stream, Compression comp) | ||||
| { | ||||
|     assert(m_impl); | ||||
|     if(!stream.good()) return; | ||||
| 
 | ||||
|     switch(comp) { | ||||
|     case Compression::PNG: { | ||||
| 
 | ||||
|         png::writer<std::ostream> wr(stream); | ||||
| 
 | ||||
|         wr.set_bit_depth(8); | ||||
|         wr.set_color_type(png::color_type_gray); | ||||
|         wr.set_width(resolution().width_px); | ||||
|         wr.set_height(resolution().height_px); | ||||
|         wr.set_compression_type(png::compression_type_default); | ||||
| 
 | ||||
|         wr.write_info(); | ||||
| 
 | ||||
|         auto& b = m_impl->buffer(); | ||||
|         auto ptr = reinterpret_cast<png::byte*>( b.data() ); | ||||
|         unsigned stride = | ||||
|                 sizeof(Impl::TBuffer::value_type) *  resolution().width_px; | ||||
|         size_t out_len = 0; | ||||
|         void * rawdata = tdefl_write_image_to_png_file_in_memory( | ||||
|                     b.data(), | ||||
|                     int(resolution().width_px), | ||||
|                     int(resolution().height_px), 1, &out_len); | ||||
| 
 | ||||
|         for(unsigned r = 0; r < resolution().height_px; r++, ptr+=stride) { | ||||
|             wr.write_row(ptr); | ||||
|         } | ||||
|         if(rawdata == nullptr) break; | ||||
| 
 | ||||
|         wr.write_end_info(); | ||||
|         stream.write(static_cast<const char*>(rawdata), | ||||
|                      std::streamsize(out_len)); | ||||
| 
 | ||||
|         MZ_FREE(rawdata); | ||||
| 
 | ||||
|         break; | ||||
|     } | ||||
|  | @ -217,4 +255,47 @@ void Raster::save(std::ostream& stream, Compression comp) | |||
|     } | ||||
| } | ||||
| 
 | ||||
| RawBytes Raster::save(Raster::Compression comp) | ||||
| { | ||||
|     assert(m_impl); | ||||
| 
 | ||||
|     std::uint8_t *ptr = nullptr; size_t s = 0; | ||||
| 
 | ||||
|     switch(comp) { | ||||
|     case Compression::PNG: { | ||||
| 
 | ||||
|         void *rawdata = tdefl_write_image_to_png_file_in_memory( | ||||
|                     m_impl->buffer().data(), | ||||
|                     int(resolution().width_px), | ||||
|                     int(resolution().height_px), 1, &s); | ||||
| 
 | ||||
|         if(rawdata == nullptr) break; | ||||
| 
 | ||||
|         ptr = static_cast<std::uint8_t*>(rawdata); | ||||
| 
 | ||||
|         break; | ||||
|     } | ||||
|     case Compression::RAW: { | ||||
|         auto header = std::string("P5 ") + | ||||
|                 std::to_string(m_impl->resolution().width_px) + " " + | ||||
|                 std::to_string(m_impl->resolution().height_px) + " " + "255 "; | ||||
| 
 | ||||
|         auto sz = m_impl->buffer().size()*sizeof(Impl::TBuffer::value_type); | ||||
| 
 | ||||
|         s = sz + header.size(); | ||||
|         ptr = static_cast<std::uint8_t*>(MZ_MALLOC(s)); | ||||
| 
 | ||||
|         auto buff = reinterpret_cast<std::uint8_t*>(m_impl->buffer().data()); | ||||
|         std::copy(buff, buff+sz, ptr + header.size()); | ||||
|     } | ||||
|     } | ||||
| 
 | ||||
|     return {ptr, s}; | ||||
| } | ||||
| 
 | ||||
| void RawBytes::MinzDeleter::operator()(uint8_t *rawptr) | ||||
| { | ||||
|     MZ_FREE(rawptr); | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -3,11 +3,52 @@ | |||
| 
 | ||||
| #include <ostream> | ||||
| #include <memory> | ||||
| #include <vector> | ||||
| #include <cstdint> | ||||
| 
 | ||||
| namespace ClipperLib { struct Polygon; } | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| class ExPolygon; | ||||
| 
 | ||||
| // Raw byte buffer paired with its size. Suitable for compressed PNG data.
 | ||||
| class RawBytes { | ||||
| 
 | ||||
|     class MinzDeleter { | ||||
|     public: | ||||
|         void operator()(std::uint8_t *rawptr); | ||||
|     }; | ||||
| 
 | ||||
|     std::unique_ptr<std::uint8_t, MinzDeleter> m_buffer = nullptr; | ||||
|     size_t m_size = 0; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     RawBytes() = default; | ||||
|     RawBytes(std::uint8_t *rawptr, size_t s): m_buffer(rawptr), m_size(s) {} | ||||
| 
 | ||||
|     size_t size() const { return m_size; } | ||||
|     const uint8_t * data() { return m_buffer.get(); } | ||||
| 
 | ||||
|     // /////////////////////////////////////////////////////////////////////////
 | ||||
|     // FIXME: the following is needed for MSVC2013 compatibility
 | ||||
|     // /////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|     RawBytes(const RawBytes&) = delete; | ||||
|     RawBytes(RawBytes&& mv): | ||||
|         m_buffer(std::move(mv.m_buffer)), m_size(mv.m_size) {} | ||||
| 
 | ||||
|     RawBytes& operator=(const RawBytes&) = delete; | ||||
|     RawBytes& operator=(RawBytes&& mv) { | ||||
|         m_buffer.swap(mv.m_buffer); | ||||
|         m_size = mv.m_size; | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     // /////////////////////////////////////////////////////////////////////////
 | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Raster captures an anti-aliased monochrome canvas where vectorial | ||||
|  * polygons can be rasterized. Fill color is always white and the background is | ||||
|  | @ -84,9 +125,12 @@ public: | |||
| 
 | ||||
|     /// Draw a polygon with holes.
 | ||||
|     void draw(const ExPolygon& poly); | ||||
|     void draw(const ClipperLib::Polygon& poly); | ||||
| 
 | ||||
|     /// Save the raster on the specified stream.
 | ||||
|     void save(std::ostream& stream, Compression comp = Compression::RAW); | ||||
| 
 | ||||
|     RawBytes save(Compression comp = Compression::RAW); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -49,8 +49,8 @@ float SLAAutoSupports::distance_limit(float angle) const | |||
| }*/ | ||||
| 
 | ||||
| SLAAutoSupports::SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector<ExPolygons>& slices, const std::vector<float>& heights, | ||||
|                                    const Config& config, std::function<void(void)> throw_on_cancel) | ||||
| : m_config(config), m_emesh(emesh), m_throw_on_cancel(throw_on_cancel) | ||||
|                                    const Config& config, std::function<void(void)> throw_on_cancel, std::function<void(int)> statusfn) | ||||
| : m_config(config), m_emesh(emesh), m_throw_on_cancel(throw_on_cancel), m_statusfn(statusfn) | ||||
| { | ||||
|     process(slices, heights); | ||||
|     project_onto_mesh(m_output); | ||||
|  | @ -197,6 +197,9 @@ void SLAAutoSupports::process(const std::vector<ExPolygons>& slices, const std:: | |||
|     PointGrid3D point_grid; | ||||
|     point_grid.cell_size = Vec3f(10.f, 10.f, 10.f); | ||||
| 
 | ||||
|     double increment = 100.0 / layers.size(); | ||||
|     double status    = 0; | ||||
| 
 | ||||
|     for (unsigned int layer_id = 0; layer_id < layers.size(); ++ layer_id) { | ||||
|         SLAAutoSupports::MyLayer *layer_top     = &layers[layer_id]; | ||||
|         SLAAutoSupports::MyLayer *layer_bottom  = (layer_id > 0) ? &layers[layer_id - 1] : nullptr; | ||||
|  | @ -252,6 +255,9 @@ void SLAAutoSupports::process(const std::vector<ExPolygons>& slices, const std:: | |||
| 
 | ||||
|         m_throw_on_cancel(); | ||||
| 
 | ||||
|         status += increment; | ||||
|         m_statusfn(int(std::round(status))); | ||||
| 
 | ||||
| #ifdef SLA_AUTOSUPPORTS_DEBUG | ||||
|         /*std::string layer_num_str = std::string((i<10 ? "0" : "")) + std::string((i<100 ? "0" : "")) + std::to_string(i);
 | ||||
|         output_expolygons(expolys_top, "top" + layer_num_str + ".svg"); | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ public: | |||
|         }; | ||||
| 
 | ||||
|     SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector<ExPolygons>& slices, | ||||
|                      const std::vector<float>& heights, const Config& config, std::function<void(void)> throw_on_cancel); | ||||
|                      const std::vector<float>& heights, const Config& config, std::function<void(void)> throw_on_cancel, std::function<void(int)> statusfn); | ||||
|     const std::vector<sla::SupportPoint>& output() { return m_output; } | ||||
| 
 | ||||
| 	struct MyLayer; | ||||
|  | @ -196,12 +196,13 @@ private: | |||
|     static void output_structures(const std::vector<Structure> &structures); | ||||
| #endif // SLA_AUTOSUPPORTS_DEBUG
 | ||||
| 
 | ||||
|     std::function<void(void)> m_throw_on_cancel; | ||||
|     const sla::EigenMesh3D& m_emesh; | ||||
|     std::function<void(void)> m_throw_on_cancel; | ||||
|     std::function<void(int)>  m_statusfn; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| } // namespace Slic3r
 | ||||
| 
 | ||||
| 
 | ||||
| #endif // SLAAUTOSUPPORTS_HPP_
 | ||||
| #endif // SLAAUTOSUPPORTS_HPP_
 | ||||
|  |  | |||
|  | @ -755,9 +755,12 @@ public: | |||
|         return m_compact_bridges; | ||||
|     } | ||||
| 
 | ||||
|     template<class T> inline | ||||
|     typename std::enable_if<std::is_integral<T>::value, const Pillar&>::type | ||||
|     pillar(T id) const { assert(id >= 0); return m_pillars.at(size_t(id)); } | ||||
|     template<class T> inline const Pillar& pillar(T id) const { | ||||
|         static_assert(std::is_integral<T>::value, "Invalid index type"); | ||||
|         assert(id >= 0 && id < m_pillars.size() && | ||||
|                id < std::numeric_limits<size_t>::max()); | ||||
|         return m_pillars[size_t(id)]; | ||||
|     } | ||||
| 
 | ||||
|     const Pad& create_pad(const TriangleMesh& object_supports, | ||||
|                           const ExPolygons& baseplate, | ||||
|  | @ -1463,7 +1466,7 @@ public: | |||
|                                   m_cfg.head_back_radius_mm, | ||||
|                                   w); | ||||
| 
 | ||||
|                 if(t <= w || (hp(Z) + nn(Z) * w) < m_result.ground_level) { | ||||
|                 if(t <= w) { | ||||
| 
 | ||||
|                     // Let's try to optimize this angle, there might be a
 | ||||
|                     // viable normal that doesn't collide with the model
 | ||||
|  | @ -1506,7 +1509,7 @@ public: | |||
|                 // save the verified and corrected normal
 | ||||
|                 m_support_nmls.row(fidx) = nn; | ||||
| 
 | ||||
|                 if(t > w && (hp(Z) + nn(Z) * w) > m_result.ground_level) { | ||||
|                 if(t > w) { | ||||
|                     // mark the point for needing a head.
 | ||||
|                     m_iheads.emplace_back(fidx); | ||||
|                 } else if( polar >= 3*PI/4 ) { | ||||
|  | @ -2237,6 +2240,18 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const | |||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| SlicedSupports SLASupportTree::slice(const std::vector<float> &heights, | ||||
|                                      float cr) const | ||||
| { | ||||
|     TriangleMesh fullmesh = m_impl->merged_mesh(); | ||||
|     fullmesh.merge(get_pad()); | ||||
|     TriangleMeshSlicer slicer(&fullmesh); | ||||
|     SlicedSupports ret; | ||||
|     slicer.slice(heights, cr, &ret, get().ctl().cancelfn); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| const TriangleMesh &SLASupportTree::add_pad(const SliceLayer& baseplate, | ||||
|                                             const PoolConfig& pcfg) const | ||||
| { | ||||
|  |  | |||
|  | @ -181,6 +181,8 @@ public: | |||
|     /// Get the sliced 2d layers of the support geometry.
 | ||||
|     SlicedSupports slice(float layerh, float init_layerh = -1.0) const; | ||||
| 
 | ||||
|     SlicedSupports slice(const std::vector<float>&, float closing_radius) const; | ||||
| 
 | ||||
|     /// Adding the "pad" (base pool) under the supports
 | ||||
|     const TriangleMesh& add_pad(const SliceLayer& baseplate, | ||||
|                                 const PoolConfig& pcfg) const; | ||||
|  |  | |||
|  | @ -6,12 +6,14 @@ | |||
| #include "PrintExport.hpp" | ||||
| #include "Point.hpp" | ||||
| #include "MTUtils.hpp" | ||||
| #include <libnest2d/backends/clipper/clipper_polygon.hpp> | ||||
| #include "Zipper.hpp" | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| enum SLAPrintStep : unsigned int { | ||||
| 	slapsRasterize, | ||||
| 	slapsValidate, | ||||
|     slapsMergeSlicesAndEval, | ||||
|     slapsRasterize, | ||||
| 	slapsCount | ||||
| }; | ||||
| 
 | ||||
|  | @ -20,8 +22,7 @@ enum SLAPrintObjectStep : unsigned int { | |||
| 	slaposSupportPoints, | ||||
| 	slaposSupportTree, | ||||
| 	slaposBasePool, | ||||
| 	slaposSliceSupports, | ||||
|     slaposIndexSlices, | ||||
|     slaposSliceSupports, | ||||
| 	slaposCount | ||||
| }; | ||||
| 
 | ||||
|  | @ -33,7 +34,9 @@ using _SLAPrintObjectBase = | |||
| 
 | ||||
| // Layers according to quantized height levels. This will be consumed by
 | ||||
| // the printer (rasterizer) in the SLAPrint class.
 | ||||
| using LevelID = long long; | ||||
| // using coord_t = long long;
 | ||||
| 
 | ||||
| enum SliceOrigin { soSupport, soModel }; | ||||
| 
 | ||||
| class SLAPrintObject : public _SLAPrintObjectBase | ||||
| { | ||||
|  | @ -41,8 +44,14 @@ private: // Prevents erroneous use by other classes. | |||
|     using Inherited = _SLAPrintObjectBase; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     // I refuse to grantee copying (Tamas)
 | ||||
|     SLAPrintObject(const SLAPrintObject&) = delete; | ||||
|     SLAPrintObject& operator=(const SLAPrintObject&) = delete; | ||||
| 
 | ||||
|     const SLAPrintObjectConfig& config() const { return m_config; } | ||||
|     const Transform3d&          trafo()  const { return m_trafo; } | ||||
|     bool                        is_left_handed() const { return m_left_handed; } | ||||
| 
 | ||||
|     struct Instance { | ||||
|     	Instance(ModelID instance_id, const Point &shift, float rotation) : instance_id(instance_id), shift(shift), rotation(rotation) {} | ||||
|  | @ -82,39 +91,145 @@ public: | |||
|     // pad is not, then without the pad, otherwise the full value is returned.
 | ||||
|     double get_current_elevation() const; | ||||
| 
 | ||||
|     // These two methods should be callable on the client side (e.g. UI thread)
 | ||||
|     // when the appropriate steps slaposObjectSlice and slaposSliceSupports
 | ||||
|     // are ready. All the print objects are processed before slapsRasterize so
 | ||||
|     // it is safe to call them during and/or after slapsRasterize.
 | ||||
|     const std::vector<ExPolygons>& get_model_slices() const; | ||||
|     const std::vector<ExPolygons>& get_support_slices() const; | ||||
| 
 | ||||
|     // This method returns the support points of this SLAPrintObject.
 | ||||
|     const std::vector<sla::SupportPoint>& get_support_points() const; | ||||
| 
 | ||||
|     // An index record referencing the slices
 | ||||
|     // (get_model_slices(), get_support_slices()) where the keys are the height
 | ||||
|     // levels of the model in scaled-clipper coordinates. The levels correspond
 | ||||
|     // to the z coordinate of the object coordinate system.
 | ||||
|     struct SliceRecord { | ||||
|         using Key = float; | ||||
|     // The public Slice record structure. It corresponds to one printable layer.
 | ||||
|     class SliceRecord { | ||||
|     public: | ||||
|         // this will be the max limit of size_t
 | ||||
|         static const size_t NONE = size_t(-1); | ||||
| 
 | ||||
|         using Idx = size_t; | ||||
|         static const Idx NONE = Idx(-1); // this will be the max limit of size_t
 | ||||
|         static const SliceRecord EMPTY; | ||||
| 
 | ||||
|         Idx model_slices_idx = NONE; | ||||
|         Idx support_slices_idx = NONE; | ||||
|     private: | ||||
|         coord_t   m_print_z = 0;      // Top of the layer
 | ||||
|         float     m_slice_z = 0.f;    // Exact level of the slice
 | ||||
|         float     m_height  = 0.f;     // Height of the sliced layer
 | ||||
| 
 | ||||
|         size_t m_model_slices_idx = NONE; | ||||
|         size_t m_support_slices_idx = NONE; | ||||
|         const SLAPrintObject *m_po = nullptr; | ||||
| 
 | ||||
|     public: | ||||
| 
 | ||||
|         SliceRecord(coord_t key, float slicez, float height): | ||||
|             m_print_z(key), m_slice_z(slicez), m_height(height) {} | ||||
| 
 | ||||
|         // The key will be the integer height level of the top of the layer.
 | ||||
|         coord_t print_level() const { return m_print_z; } | ||||
| 
 | ||||
|         // Returns the exact floating point Z coordinate of the slice
 | ||||
|         float slice_level() const { return m_slice_z; } | ||||
| 
 | ||||
|         // Returns the current layer height
 | ||||
|         float layer_height() const { return m_height; } | ||||
| 
 | ||||
|         bool is_valid() const { return ! std::isnan(m_slice_z); } | ||||
| 
 | ||||
|         const SLAPrintObject* print_obj() const { assert(m_po); return m_po; } | ||||
| 
 | ||||
|         // Methods for setting the indices into the slice vectors.
 | ||||
|         void set_model_slice_idx(const SLAPrintObject &po, size_t id) { | ||||
|             m_po = &po; m_model_slices_idx = id; | ||||
|         } | ||||
| 
 | ||||
|         void set_support_slice_idx(const SLAPrintObject& po, size_t id) { | ||||
|             m_po = &po; m_support_slices_idx = id; | ||||
|         } | ||||
| 
 | ||||
|         const ExPolygons& get_slice(SliceOrigin o) const; | ||||
|     }; | ||||
| 
 | ||||
|     using SliceIndex = std::map<SliceRecord::Key, SliceRecord>; | ||||
| private: | ||||
| 
 | ||||
|     // Retrieve the slice index which is readable only after slaposIndexSlices
 | ||||
|     // is done.
 | ||||
|     const SliceIndex& get_slice_index() const; | ||||
|     template <class T> inline static T level(const SliceRecord& sr) { | ||||
|         static_assert(std::is_arithmetic<T>::value, "Arithmetic only!"); | ||||
|         return std::is_integral<T>::value ? T(sr.print_level()) : T(sr.slice_level()); | ||||
|     } | ||||
| 
 | ||||
|     // I refuse to grantee copying (Tamas)
 | ||||
|     SLAPrintObject(const SLAPrintObject&) = delete; | ||||
|     SLAPrintObject& operator=(const SLAPrintObject&) = delete; | ||||
|     template <class T> inline static SliceRecord create_slice_record(T val) { | ||||
|         static_assert(std::is_arithmetic<T>::value, "Arithmetic only!"); | ||||
|         return std::is_integral<T>::value ? SliceRecord{ coord_t(val), 0.f, 0.f } : SliceRecord{ 0, float(val), 0.f }; | ||||
|     } | ||||
| 
 | ||||
|     // This is a template method for searching the slice index either by
 | ||||
|     // an integer key: print_level or a floating point key: slice_level.
 | ||||
|     // The eps parameter gives the max deviation in + or - direction.
 | ||||
|     //
 | ||||
|     // This method can be used in const or non-const contexts as well.
 | ||||
|     template<class Container, class T> | ||||
|     static auto closest_slice_record( | ||||
|             Container& cont, | ||||
|             T lvl, | ||||
|             T eps = std::numeric_limits<T>::max()) -> decltype (cont.begin()) | ||||
|     { | ||||
|         if(cont.empty()) return cont.end(); | ||||
|         if(cont.size() == 1 && std::abs(level<T>(cont.front()) - lvl) > eps) | ||||
|             return cont.end(); | ||||
| 
 | ||||
|         SliceRecord query = create_slice_record(lvl); | ||||
| 
 | ||||
|         auto it = std::lower_bound(cont.begin(), cont.end(), query, | ||||
|                                    [](const SliceRecord& r1, | ||||
|                                       const SliceRecord& r2) | ||||
|         { | ||||
|             return level<T>(r1) < level<T>(r2); | ||||
|         }); | ||||
| 
 | ||||
|         T diff = std::abs(level<T>(*it) - lvl); | ||||
| 
 | ||||
|         if(it != cont.begin()) { | ||||
|             auto it_prev = std::prev(it); | ||||
|             T diff_prev = std::abs(level<T>(*it_prev) - lvl); | ||||
|             if(diff_prev < diff) { diff = diff_prev; it = it_prev; } | ||||
|         } | ||||
| 
 | ||||
|         if(diff > eps) it = cont.end(); | ||||
| 
 | ||||
|         return it; | ||||
|     } | ||||
| 
 | ||||
|     const std::vector<ExPolygons>& get_model_slices() const { return m_model_slices; } | ||||
|     const std::vector<ExPolygons>& get_support_slices() const; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     // /////////////////////////////////////////////////////////////////////////
 | ||||
|     //
 | ||||
|     // These methods should be callable on the client side (e.g. UI thread)
 | ||||
|     // when the appropriate steps slaposObjectSlice and slaposSliceSupports
 | ||||
|     // are ready. All the print objects are processed before slapsRasterize so
 | ||||
|     // it is safe to call them during and/or after slapsRasterize.
 | ||||
|     //
 | ||||
|     // /////////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|     // Retrieve the slice index.
 | ||||
|     const std::vector<SliceRecord>& get_slice_index() const { | ||||
|         return m_slice_index; | ||||
|     } | ||||
| 
 | ||||
|     // Search slice index for the closest slice to given print_level.
 | ||||
|     // max_epsilon gives the allowable deviation of the returned slice record's
 | ||||
|     // level.
 | ||||
|     const SliceRecord& closest_slice_to_print_level( | ||||
|             coord_t print_level, | ||||
|             coord_t max_epsilon = std::numeric_limits<coord_t>::max()) const | ||||
|     { | ||||
|         auto it = closest_slice_record(m_slice_index, print_level, max_epsilon); | ||||
|         return it == m_slice_index.end() ? SliceRecord::EMPTY : *it; | ||||
|     } | ||||
| 
 | ||||
|     // Search slice index for the closest slice to given slice_level.
 | ||||
|     // max_epsilon gives the allowable deviation of the returned slice record's
 | ||||
|     // level. Use SliceRecord::is_valid() to check the result.
 | ||||
|     const SliceRecord& closest_slice_to_slice_level( | ||||
|             float slice_level, | ||||
|             float max_epsilon = std::numeric_limits<float>::max()) const | ||||
|     { | ||||
|         auto it = closest_slice_record(m_slice_index, slice_level, max_epsilon); | ||||
|         return it == m_slice_index.end() ? SliceRecord::EMPTY : *it; | ||||
|     } | ||||
| 
 | ||||
| protected: | ||||
|     // to be called from SLAPrint only.
 | ||||
|  | @ -127,11 +242,12 @@ protected: | |||
|     void                    config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false)  | ||||
|     	{ this->m_config.apply_only(other, keys, ignore_nonexistent); } | ||||
| 
 | ||||
|     void                    set_trafo(const Transform3d& trafo) { | ||||
|         m_transformed_rmesh.invalidate([this, &trafo](){ m_trafo = trafo; }); | ||||
|     void                    set_trafo(const Transform3d& trafo, bool left_handed) { | ||||
| 		m_transformed_rmesh.invalidate([this, &trafo, left_handed](){ m_trafo = trafo; m_left_handed = left_handed; }); | ||||
|     } | ||||
| 
 | ||||
|     void                    set_instances(const std::vector<Instance> &instances) { m_instances = instances; } | ||||
|     template<class InstVec> inline void set_instances(InstVec&& instances) { m_instances = std::forward<InstVec>(instances); } | ||||
| 
 | ||||
|     // Invalidates the step, and its depending steps in SLAPrintObject and SLAPrint.
 | ||||
|     bool                    invalidate_step(SLAPrintObjectStep step); | ||||
|     bool                    invalidate_all_steps(); | ||||
|  | @ -145,8 +261,12 @@ protected: | |||
| private: | ||||
|     // Object specific configuration, pulled from the configuration layer.
 | ||||
|     SLAPrintObjectConfig                    m_config; | ||||
| 
 | ||||
|     // Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
 | ||||
|     Transform3d                             m_trafo = Transform3d::Identity(); | ||||
|     // m_trafo is left handed -> 3x3 affine transformation has negative determinant.
 | ||||
|     bool                                    m_left_handed = false; | ||||
| 
 | ||||
|     std::vector<Instance> 					m_instances; | ||||
| 
 | ||||
|     // Individual 2d slice polygons from lower z to higher z levels
 | ||||
|  | @ -154,11 +274,9 @@ private: | |||
| 
 | ||||
|     // Exact (float) height levels mapped to the slices. Each record contains
 | ||||
|     // the index to the model and the support slice vectors.
 | ||||
|     SliceIndex                              m_slice_index; | ||||
|     std::vector<SliceRecord>                m_slice_index; | ||||
| 
 | ||||
|     // The height levels corrected and scaled up in integer values. This will
 | ||||
|     // be used at rasterization.
 | ||||
|     std::vector<LevelID>                    m_level_ids; | ||||
|     std::vector<float>                      m_model_height_levels; | ||||
| 
 | ||||
|     // Caching the transformed (m_trafo) raw mesh of the object
 | ||||
|     mutable CachedObject<TriangleMesh>      m_transformed_rmesh; | ||||
|  | @ -169,6 +287,8 @@ private: | |||
| 
 | ||||
| using PrintObjects = std::vector<SLAPrintObject*>; | ||||
| 
 | ||||
| using SliceRecord  = SLAPrintObject::SliceRecord; | ||||
| 
 | ||||
| class TriangleMesh; | ||||
| 
 | ||||
| struct SLAPrintStatistics | ||||
|  | @ -200,6 +320,37 @@ struct SLAPrintStatistics | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| // The implementation of creating zipped archives with wxWidgets
 | ||||
| template<> class LayerWriter<Zipper> { | ||||
|     Zipper m_zip; | ||||
| public: | ||||
| 
 | ||||
|     LayerWriter(const std::string& zipfile_path): m_zip(zipfile_path) {} | ||||
| 
 | ||||
|     void next_entry(const std::string& fname) { m_zip.add_entry(fname); } | ||||
| 
 | ||||
|     void binary_entry(const std::string& fname, | ||||
|                       const std::uint8_t* buf, | ||||
|                       size_t l) | ||||
|     { | ||||
|         m_zip.add_entry(fname, buf, l); | ||||
|     } | ||||
| 
 | ||||
|     template<class T> inline LayerWriter& operator<<(T&& arg) { | ||||
|         m_zip << std::forward<T>(arg); return *this; | ||||
|     } | ||||
| 
 | ||||
|     bool is_ok() const { | ||||
|         return true; // m_zip blows up if something goes wrong...
 | ||||
|     } | ||||
| 
 | ||||
|     // After finalize, no writing to the archive will have an effect. The only
 | ||||
|     // valid operation is to dispose the object calling the destructor which
 | ||||
|     // should close the file. This method can throw and signal potential errors
 | ||||
|     // when flushing the archive. This is why its present.
 | ||||
|     void finalize() { m_zip.finalize(); } | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief This class is the high level FSM for the SLA printing process. | ||||
|  * | ||||
|  | @ -214,6 +365,7 @@ private: // Prevents erroneous use by other classes. | |||
|     typedef PrintBaseWithState<SLAPrintStep, slapsCount> Inherited; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     SLAPrint(): m_stepmask(slapsCount, true) {} | ||||
| 
 | ||||
|     virtual ~SLAPrint() override { this->clear(); } | ||||
|  | @ -229,31 +381,79 @@ public: | |||
|     // Returns true if an object step is done on all objects and there's at least one object.    
 | ||||
|     bool                is_step_done(SLAPrintObjectStep step) const; | ||||
|     // Returns true if the last step was finished with success.
 | ||||
| 	bool                finished() const override { return this->is_step_done(slaposIndexSlices) && this->Inherited::is_step_done(slapsRasterize); } | ||||
|     bool                finished() const override { return this->is_step_done(slaposSliceSupports) && this->Inherited::is_step_done(slapsRasterize); } | ||||
| 
 | ||||
|     template<class Fmt> void export_raster(const std::string& fname) { | ||||
|         if(m_printer) m_printer->save<Fmt>(fname); | ||||
|     template<class Fmt = Zipper> | ||||
|     inline void export_raster(const std::string& fpath, | ||||
|                        const std::string& projectname = "") | ||||
|     { | ||||
|         if(m_printer) m_printer->save<Fmt>(fpath, projectname); | ||||
|     } | ||||
| 
 | ||||
|     const PrintObjects& objects() const { return m_objects; } | ||||
| 
 | ||||
|     const SLAPrintConfig&       print_config() const { return m_print_config; } | ||||
|     const SLAPrinterConfig&     printer_config() const { return m_printer_config; } | ||||
|     const SLAMaterialConfig&    material_config() const { return m_material_config; } | ||||
|     const SLAPrintObjectConfig& default_object_config() const { return m_default_object_config; } | ||||
| 
 | ||||
| 	std::string         output_filename() const override; | ||||
| 
 | ||||
|     const SLAPrintStatistics&      print_statistics() const { return m_print_statistics; } | ||||
| 
 | ||||
|     std::string validate() const override; | ||||
| 
 | ||||
|     // An aggregation of SliceRecord-s from all the print objects for each
 | ||||
|     // occupied layer. Slice record levels dont have to match exactly.
 | ||||
|     // They are unified if the level difference is within +/- SCALED_EPSILON
 | ||||
|     class PrintLayer { | ||||
|         coord_t m_level; | ||||
| 
 | ||||
|         // The collection of slice records for the current level.
 | ||||
|         std::vector<std::reference_wrapper<const SliceRecord>> m_slices; | ||||
| 
 | ||||
|         std::vector<ClipperLib::Polygon> m_transformed_slices; | ||||
| 
 | ||||
|         template<class Container> void transformed_slices(Container&& c) { | ||||
|             m_transformed_slices = std::forward<Container>(c); | ||||
|         } | ||||
| 
 | ||||
|         friend void SLAPrint::process(); | ||||
| 
 | ||||
|     public: | ||||
| 
 | ||||
|         explicit PrintLayer(coord_t lvl) : m_level(lvl) {} | ||||
| 
 | ||||
|         // for being sorted in their container (see m_printer_input)
 | ||||
|         bool operator<(const PrintLayer& other) const { | ||||
|             return m_level < other.m_level; | ||||
|         } | ||||
| 
 | ||||
|         void add(const SliceRecord& sr) { m_slices.emplace_back(sr); } | ||||
| 
 | ||||
|         coord_t level() const { return m_level; } | ||||
| 
 | ||||
|         auto slices() const -> const decltype (m_slices)& { return m_slices; } | ||||
| 
 | ||||
|         const std::vector<ClipperLib::Polygon> & transformed_slices() const { | ||||
|             return m_transformed_slices; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     // The aggregated and leveled print records from various objects.
 | ||||
|     // TODO: use this structure for the preview in the future.
 | ||||
|     const std::vector<PrintLayer>& print_layers() const { return m_printer_input; } | ||||
| 
 | ||||
| private: | ||||
|     using SLAPrinter = FilePrinter<FilePrinterFormat::SLA_PNGZIP>; | ||||
|     using SLAPrinterPtr = std::unique_ptr<SLAPrinter>; | ||||
| 
 | ||||
|     // Implement same logic as in SLAPrintObject
 | ||||
|     bool invalidate_step(SLAPrintStep st); | ||||
| 
 | ||||
|     // Invalidate steps based on a set of parameters changed.
 | ||||
|     bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); | ||||
| 
 | ||||
|     std::vector<float> calculate_heights(const BoundingBoxf3& bb, | ||||
|                                          float elevation, | ||||
|                                          float initial_layer_height, | ||||
|                                          float layer_height) const; | ||||
| 
 | ||||
|     void fill_statistics(); | ||||
| 
 | ||||
|     SLAPrintConfig                  m_print_config; | ||||
|     SLAPrinterConfig                m_printer_config; | ||||
|     SLAMaterialConfig               m_material_config; | ||||
|  | @ -262,23 +462,8 @@ private: | |||
|     PrintObjects                    m_objects; | ||||
|     std::vector<bool>               m_stepmask; | ||||
| 
 | ||||
|     // Definition of the print input map. It consists of the slices indexed
 | ||||
|     // with scaled (clipper) Z coordinates. Also contains the instance
 | ||||
|     // transformations in scaled and filtered version. This is enough for the
 | ||||
|     // rasterizer to be able to draw every layer in the right position
 | ||||
|     using Layer = ExPolygons; | ||||
|     using LayerCopies = std::vector<SLAPrintObject::Instance>; | ||||
|     struct LayerRef { | ||||
|         std::reference_wrapper<const Layer> lref; | ||||
|         std::reference_wrapper<const LayerCopies> copies; | ||||
|         LayerRef(const Layer& lyr, const LayerCopies& cp) : | ||||
|             lref(std::cref(lyr)), copies(std::cref(cp)) {} | ||||
|     }; | ||||
| 
 | ||||
|     // One level may contain multiple slices from multiple objects and their
 | ||||
|     // supports
 | ||||
|     using LayerRefs = std::vector<LayerRef>; | ||||
|     std::map<LevelID, LayerRefs>            m_printer_input; | ||||
|     // Ready-made data for rasterization.
 | ||||
|     std::vector<PrintLayer>                 m_printer_input; | ||||
| 
 | ||||
|     // The printer itself
 | ||||
|     SLAPrinterPtr                           m_printer; | ||||
|  | @ -286,6 +471,15 @@ private: | |||
|     // Estimated print time, material consumed.
 | ||||
|     SLAPrintStatistics                      m_print_statistics; | ||||
| 
 | ||||
|     class StatusReporter { | ||||
|         double m_st = 0; | ||||
|     public: | ||||
|         void operator() (SLAPrint& p, double st, const std::string& msg, | ||||
|                          unsigned flags = SlicingStatus::DEFAULT); | ||||
|         double status() const { return m_st; } | ||||
|     } m_report_status; | ||||
| 
 | ||||
| 
 | ||||
| 	friend SLAPrintObject; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -20,9 +20,8 @@ | |||
| 
 | ||||
| // Disable synchronization of unselected instances
 | ||||
| #define DISABLE_INSTANCES_SYNCH (0 && ENABLE_1_42_0_ALPHA1) | ||||
| // Scene's GUI made using imgui library
 | ||||
| #define ENABLE_IMGUI (1 && ENABLE_1_42_0_ALPHA1) | ||||
| #define DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI (1 && ENABLE_IMGUI) | ||||
| // Disable imgui dialog for move, rotate and scale gizmos
 | ||||
| #define DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI (1 && ENABLE_1_42_0_ALPHA1) | ||||
| // Use wxDataViewRender instead of wxDataViewCustomRenderer
 | ||||
| #define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1) | ||||
| 
 | ||||
|  | @ -34,8 +33,6 @@ | |||
| 
 | ||||
| // Changed algorithm to extract euler angles from rotation matrix
 | ||||
| #define ENABLE_NEW_EULER_ANGLES (1 && ENABLE_1_42_0_ALPHA4) | ||||
| // Added minimum threshold for click and drag movements
 | ||||
| #define ENABLE_MOVE_MIN_THRESHOLD (1 && ENABLE_1_42_0_ALPHA4) | ||||
| // Modified initial default placement of generic subparts
 | ||||
| #define ENABLE_GENERIC_SUBPARTS_PLACEMENT (1 && ENABLE_1_42_0_ALPHA4) | ||||
| // Bunch of fixes related to volumes centering
 | ||||
|  | @ -59,4 +56,5 @@ | |||
| // Toolbars and Gizmos use icons imported from svg files
 | ||||
| #define ENABLE_SVG_ICONS (1 && ENABLE_1_42_0_ALPHA8 && ENABLE_TEXTURES_FROM_SVG) | ||||
| 
 | ||||
| 
 | ||||
| #endif // _technologies_h_
 | ||||
|  |  | |||
|  | @ -55,7 +55,7 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& f | |||
|     stl.stats.original_num_facets = stl.stats.number_of_facets; | ||||
|     stl_allocate(&stl); | ||||
| 
 | ||||
|     for (int i = 0; i < stl.stats.number_of_facets; i++) { | ||||
|     for (uint32_t i = 0; i < stl.stats.number_of_facets; i++) { | ||||
|         stl_facet facet; | ||||
|         facet.vertex[0] = points[facets[i](0)].cast<float>(); | ||||
|         facet.vertex[1] = points[facets[i](1)].cast<float>(); | ||||
|  | @ -125,9 +125,9 @@ void TriangleMesh::repair() | |||
| 	float tolerance = stl.stats.shortest_edge; | ||||
|     float increment = stl.stats.bounding_diameter / 10000.0; | ||||
|     int iterations = 2; | ||||
|     if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) { | ||||
|     if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) { | ||||
|         for (int i = 0; i < iterations; i++) { | ||||
|             if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) { | ||||
|             if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) { | ||||
|                 //printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations);
 | ||||
| #ifdef SLIC3R_TRACE_REPAIR | ||||
| 				BOOST_LOG_TRIVIAL(trace) << "\tstl_check_faces_nearby"; | ||||
|  | @ -143,7 +143,7 @@ void TriangleMesh::repair() | |||
|     } | ||||
|      | ||||
|     // remove_unconnected
 | ||||
|     if (stl.stats.connected_facets_3_edge <  stl.stats.number_of_facets) { | ||||
|     if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) { | ||||
| #ifdef SLIC3R_TRACE_REPAIR | ||||
|         BOOST_LOG_TRIVIAL(trace) << "\tstl_remove_unconnected_facets"; | ||||
| #endif /* SLIC3R_TRACE_REPAIR */ | ||||
|  | @ -212,9 +212,9 @@ void TriangleMesh::check_topology() | |||
|     float tolerance = stl.stats.shortest_edge; | ||||
|     float increment = stl.stats.bounding_diameter / 10000.0; | ||||
|     int iterations = 2; | ||||
|     if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) { | ||||
|     if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) { | ||||
|         for (int i = 0; i < iterations; i++) { | ||||
|             if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) { | ||||
|             if (stl.stats.connected_facets_3_edge < (int)stl.stats.number_of_facets) { | ||||
|                 //printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations);
 | ||||
|                 stl_check_facets_nearby(&stl, tolerance); | ||||
|                 //printf("  Fixed %d edges.\n", stl.stats.edges_fixed - last_edges_fixed);
 | ||||
|  | @ -273,6 +273,11 @@ void TriangleMesh::translate(float x, float y, float z) | |||
|     stl_invalidate_shared_vertices(&this->stl); | ||||
| } | ||||
| 
 | ||||
| void TriangleMesh::translate(const Vec3f &displacement) | ||||
| { | ||||
|     translate(displacement(0), displacement(1), displacement(2)); | ||||
| } | ||||
| 
 | ||||
| void TriangleMesh::rotate(float angle, const Axis &axis) | ||||
| { | ||||
|     if (angle == 0.f) | ||||
|  | @ -314,10 +319,15 @@ void TriangleMesh::mirror(const Axis &axis) | |||
|     stl_invalidate_shared_vertices(&this->stl); | ||||
| } | ||||
| 
 | ||||
| void TriangleMesh::transform(const Transform3d& t) | ||||
| void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed) | ||||
| { | ||||
|     stl_transform(&stl, t); | ||||
|     stl_invalidate_shared_vertices(&stl); | ||||
| 	if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.) { | ||||
| 		// Left handed transformation is being applied. It is a good idea to flip the faces and their normals.
 | ||||
| 		this->repair(); | ||||
| 		stl_reverse_all_facets(&stl); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void TriangleMesh::align_to_origin() | ||||
|  | @ -338,113 +348,79 @@ void TriangleMesh::rotate(double angle, Point* center) | |||
|     this->translate(c(0), c(1), 0); | ||||
| } | ||||
| 
 | ||||
| bool TriangleMesh::has_multiple_patches() const | ||||
| /**
 | ||||
|  * Calculates whether or not the mesh is splittable. | ||||
|  */ | ||||
| bool TriangleMesh::is_splittable() const | ||||
| { | ||||
|     // we need neighbors
 | ||||
|     if (!this->repaired) | ||||
|         throw std::runtime_error("split() requires repair()"); | ||||
|      | ||||
|     if (this->stl.stats.number_of_facets == 0) | ||||
|         return false; | ||||
|     std::vector<unsigned char> visited; | ||||
|     find_unvisited_neighbors(visited); | ||||
| 
 | ||||
|     std::vector<int>  facet_queue(this->stl.stats.number_of_facets, 0); | ||||
|     std::vector<char> facet_visited(this->stl.stats.number_of_facets, false); | ||||
|     int               facet_queue_cnt = 1; | ||||
|     facet_queue[0] = 0; | ||||
|     facet_visited[0] = true; | ||||
|     while (facet_queue_cnt > 0) { | ||||
|         int facet_idx = facet_queue[-- facet_queue_cnt]; | ||||
|         facet_visited[facet_idx] = true; | ||||
|         for (int j = 0; j < 3; ++ j) { | ||||
|             int neighbor_idx = this->stl.neighbors_start[facet_idx].neighbor[j]; | ||||
|             if (neighbor_idx != -1 && ! facet_visited[neighbor_idx]) | ||||
|                 facet_queue[facet_queue_cnt ++] = neighbor_idx; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // If any of the face was not visited at the first time, return "multiple bodies".
 | ||||
|     for (int facet_idx = 0; facet_idx < this->stl.stats.number_of_facets; ++ facet_idx) | ||||
|         if (! facet_visited[facet_idx]) | ||||
|             return true; | ||||
|     return false; | ||||
|     // Try finding an unvisited facet. If there are none, the mesh is not splittable.
 | ||||
|     auto it = std::find(visited.begin(), visited.end(), false); | ||||
|     return it != visited.end(); | ||||
| } | ||||
| 
 | ||||
| size_t TriangleMesh::number_of_patches() const | ||||
| /**
 | ||||
|  * Visit all unvisited neighboring facets that are reachable from the first unvisited facet, | ||||
|  * and return them. | ||||
|  *  | ||||
|  * @param facet_visited A reference to a vector of booleans. Contains whether or not a | ||||
|  *                      facet with the same index has been visited. | ||||
|  * @return A deque with all newly visited facets. | ||||
|  */ | ||||
| std::deque<uint32_t> TriangleMesh::find_unvisited_neighbors(std::vector<unsigned char> &facet_visited) const | ||||
| { | ||||
|     // we need neighbors
 | ||||
|     // Make sure we're not operating on a broken mesh.
 | ||||
|     if (!this->repaired) | ||||
|         throw std::runtime_error("split() requires repair()"); | ||||
|      | ||||
|     if (this->stl.stats.number_of_facets == 0) | ||||
|         return false; | ||||
|         throw std::runtime_error("find_unvisited_neighbors() requires repair()"); | ||||
| 
 | ||||
|     std::vector<int>  facet_queue(this->stl.stats.number_of_facets, 0); | ||||
|     std::vector<char> facet_visited(this->stl.stats.number_of_facets, false); | ||||
|     int               facet_queue_cnt = 0; | ||||
|     size_t            num_bodies = 0; | ||||
|     for (;;) { | ||||
|         // Find a seeding triangle for a new body.
 | ||||
|         int facet_idx = 0; | ||||
|         for (; facet_idx < this->stl.stats.number_of_facets; ++ facet_idx) | ||||
|             if (! facet_visited[facet_idx]) { | ||||
|                 // A seed triangle was found.
 | ||||
|                 facet_queue[facet_queue_cnt ++] = facet_idx; | ||||
|                 facet_visited[facet_idx] = true; | ||||
|                 break; | ||||
|             } | ||||
|         if (facet_idx == this->stl.stats.number_of_facets) | ||||
|             // No seed found.
 | ||||
|             break; | ||||
|         ++ num_bodies; | ||||
|         while (facet_queue_cnt > 0) { | ||||
|             int facet_idx = facet_queue[-- facet_queue_cnt]; | ||||
|             facet_visited[facet_idx] = true; | ||||
|             for (int j = 0; j < 3; ++ j) { | ||||
|                 int neighbor_idx = this->stl.neighbors_start[facet_idx].neighbor[j]; | ||||
|                 if (neighbor_idx != -1 && ! facet_visited[neighbor_idx]) | ||||
|                     facet_queue[facet_queue_cnt ++] = neighbor_idx; | ||||
|             } | ||||
|         } | ||||
|     // If the visited list is empty, populate it with false for every facet.
 | ||||
|     if (facet_visited.empty()) | ||||
|         facet_visited = std::vector<unsigned char>(this->stl.stats.number_of_facets, false); | ||||
| 
 | ||||
|     // Find the first unvisited facet.
 | ||||
|     std::queue<uint32_t> facet_queue; | ||||
|     std::deque<uint32_t> facets; | ||||
|     auto facet = std::find(facet_visited.begin(), facet_visited.end(), false); | ||||
|     if (facet != facet_visited.end()) { | ||||
|         uint32_t idx = uint32_t(facet - facet_visited.begin()); | ||||
|         facet_queue.push(idx); | ||||
|         facet_visited[idx] = true; | ||||
|         facets.emplace_back(idx); | ||||
|     } | ||||
| 
 | ||||
|     return num_bodies; | ||||
|     // Traverse all reachable neighbors and mark them as visited.
 | ||||
|     while (! facet_queue.empty()) { | ||||
|         uint32_t facet_idx = facet_queue.front(); | ||||
|         facet_queue.pop(); | ||||
|         for (int neighbor_idx : this->stl.neighbors_start[facet_idx].neighbor) | ||||
|             if (neighbor_idx != -1 && ! facet_visited[neighbor_idx]) { | ||||
|                 facet_queue.push(uint32_t(neighbor_idx)); | ||||
|                 facet_visited[neighbor_idx] = true; | ||||
|                 facets.emplace_back(uint32_t(neighbor_idx)); | ||||
|             } | ||||
|     } | ||||
| 
 | ||||
|     return facets; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Splits a mesh into multiple meshes when possible. | ||||
|  *  | ||||
|  * @return A TriangleMeshPtrs with the newly created meshes. | ||||
|  */ | ||||
| TriangleMeshPtrs TriangleMesh::split() const | ||||
| { | ||||
|     TriangleMeshPtrs            meshes; | ||||
|     std::vector<unsigned char>  facet_visited(this->stl.stats.number_of_facets, false); | ||||
|      | ||||
|     // we need neighbors
 | ||||
|     if (!this->repaired) | ||||
|         throw std::runtime_error("split() requires repair()"); | ||||
|      | ||||
|     // loop while we have remaining facets
 | ||||
|     // Loop while we have remaining facets.
 | ||||
|     std::vector<unsigned char> facet_visited; | ||||
|     TriangleMeshPtrs meshes; | ||||
|     for (;;) { | ||||
|         // get the first facet
 | ||||
|         std::queue<int> facet_queue; | ||||
|         std::deque<int> facets; | ||||
|         for (int facet_idx = 0; facet_idx < this->stl.stats.number_of_facets; ++ facet_idx) { | ||||
|             if (! facet_visited[facet_idx]) { | ||||
|                 // if facet was not seen put it into queue and start searching
 | ||||
|                 facet_queue.push(facet_idx); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         if (facet_queue.empty()) | ||||
|         std::deque<uint32_t> facets = find_unvisited_neighbors(facet_visited); | ||||
|         if (facets.empty()) | ||||
|             break; | ||||
| 
 | ||||
|         while (! facet_queue.empty()) { | ||||
|             int facet_idx = facet_queue.front(); | ||||
|             facet_queue.pop(); | ||||
|             if (! facet_visited[facet_idx]) { | ||||
|                 facets.emplace_back(facet_idx); | ||||
|                 for (int j = 0; j < 3; ++ j) | ||||
|                     facet_queue.push(this->stl.neighbors_start[facet_idx].neighbor[j]); | ||||
|                 facet_visited[facet_idx] = true; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Create a new mesh for the part that was just split off.
 | ||||
|         TriangleMesh* mesh = new TriangleMesh; | ||||
|         meshes.emplace_back(mesh); | ||||
|         mesh->stl.stats.type = inmemory; | ||||
|  | @ -452,14 +428,15 @@ TriangleMeshPtrs TriangleMesh::split() const | |||
|         mesh->stl.stats.original_num_facets = mesh->stl.stats.number_of_facets; | ||||
|         stl_clear_error(&mesh->stl); | ||||
|         stl_allocate(&mesh->stl); | ||||
|          | ||||
| 
 | ||||
|         // Assign the facets to the new mesh.
 | ||||
|         bool first = true; | ||||
|         for (std::deque<int>::const_iterator facet = facets.begin(); facet != facets.end(); ++ facet) { | ||||
|         for (auto facet = facets.begin(); facet != facets.end(); ++ facet) { | ||||
|             mesh->stl.facet_start[facet - facets.begin()] = this->stl.facet_start[*facet]; | ||||
|             stl_facet_stats(&mesh->stl, this->stl.facet_start[*facet], first); | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     return meshes; | ||||
| } | ||||
| 
 | ||||
|  | @ -476,7 +453,7 @@ void TriangleMesh::merge(const TriangleMesh &mesh) | |||
|     stl_reallocate(&this->stl); | ||||
|      | ||||
|     // copy facets
 | ||||
|     for (int i = 0; i < mesh.stl.stats.number_of_facets; ++ i) | ||||
|     for (uint32_t i = 0; i < mesh.stl.stats.number_of_facets; ++ i) | ||||
|         this->stl.facet_start[number_of_facets + i] = mesh.stl.facet_start[i]; | ||||
|      | ||||
|     // update size
 | ||||
|  | @ -489,7 +466,7 @@ ExPolygons TriangleMesh::horizontal_projection() const | |||
| { | ||||
|     Polygons pp; | ||||
|     pp.reserve(this->stl.stats.number_of_facets); | ||||
|     for (int i = 0; i < this->stl.stats.number_of_facets; ++ i) { | ||||
|     for (uint32_t i = 0; i < this->stl.stats.number_of_facets; ++ i) { | ||||
|         stl_facet* facet = &this->stl.facet_start[i]; | ||||
|         Polygon p; | ||||
|         p.points.resize(3); | ||||
|  | @ -531,7 +508,7 @@ BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d &trafo) c | |||
|     BoundingBoxf3 bbox; | ||||
|     if (stl.v_shared == nullptr) { | ||||
|         // Using the STL faces.
 | ||||
|         for (int i = 0; i < this->facets_count(); ++ i) { | ||||
|         for (size_t i = 0; i < this->facets_count(); ++ i) { | ||||
|             const stl_facet &facet = this->stl.facet_start[i]; | ||||
|             for (size_t j = 0; j < 3; ++ j) | ||||
|                 bbox.merge(trafo * facet.vertex[j].cast<double>()); | ||||
|  | @ -656,7 +633,7 @@ void TriangleMeshSlicer::init(TriangleMesh *_mesh, throw_on_cancel_callback_type | |||
|     }; | ||||
|     std::vector<EdgeToFace> edges_map; | ||||
|     edges_map.assign(this->mesh->stl.stats.number_of_facets * 3, EdgeToFace()); | ||||
|     for (int facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx) | ||||
|     for (uint32_t facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx) | ||||
|         for (int i = 0; i < 3; ++ i) { | ||||
|             EdgeToFace &e2f = edges_map[facet_idx*3+i]; | ||||
|             e2f.vertex_low  = this->mesh->stl.v_indices[facet_idx].vertex[i]; | ||||
|  | @ -905,7 +882,6 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( | |||
|             const stl_normal &normal = this->mesh->stl.facet_start[facet_idx].normal; | ||||
|             // We may ignore this edge for slicing purposes, but we may still use it for object cutting.
 | ||||
|             FacetSliceType    result = Slicing; | ||||
|             const stl_neighbors &nbr = this->mesh->stl.neighbors_start[facet_idx]; | ||||
|             if (min_z == max_z) { | ||||
|                 // All three vertices are aligned with slice_z.
 | ||||
|                 line_out->edge_type = feHorizontal; | ||||
|  | @ -917,8 +893,6 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( | |||
|                 } | ||||
|             } else { | ||||
|                 // Two vertices are aligned with the cutting plane, the third vertex is below or above the cutting plane.
 | ||||
|                 int  nbr_idx     = j % 3; | ||||
|                 int  nbr_face    = nbr.neighbor[nbr_idx]; | ||||
|                 // Is the third vertex below the cutting plane?
 | ||||
|                 bool third_below = v0.z() < slice_z || v1.z() < slice_z || v2.z() < slice_z; | ||||
|                 // Two vertices on the cutting plane, the third vertex is below the plane. Consider the edge to be part of the slice
 | ||||
|  | @ -1697,7 +1671,7 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) | |||
|      | ||||
|     BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::cut - slicing object"; | ||||
|     float scaled_z = scale_(z); | ||||
|     for (int facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx) { | ||||
|     for (uint32_t facet_idx = 0; facet_idx < this->mesh->stl.stats.number_of_facets; ++ facet_idx) { | ||||
|         stl_facet* facet = &this->mesh->stl.facet_start[facet_idx]; | ||||
|          | ||||
|         // find facet extents
 | ||||
|  |  | |||
|  | @ -40,6 +40,7 @@ public: | |||
|     void scale(float factor); | ||||
|     void scale(const Vec3d &versor); | ||||
|     void translate(float x, float y, float z); | ||||
|     void translate(const Vec3f &displacement); | ||||
|     void rotate(float angle, const Axis &axis); | ||||
|     void rotate(float angle, const Vec3d& axis); | ||||
|     void rotate_x(float angle) { this->rotate(angle, X); } | ||||
|  | @ -49,7 +50,7 @@ public: | |||
|     void mirror_x() { this->mirror(X); } | ||||
|     void mirror_y() { this->mirror(Y); } | ||||
|     void mirror_z() { this->mirror(Z); } | ||||
|     void transform(const Transform3d& t); | ||||
|     void transform(const Transform3d& t, bool fix_left_handed = false); | ||||
|     void align_to_origin(); | ||||
|     void rotate(double angle, Point* center); | ||||
|     TriangleMeshPtrs split() const; | ||||
|  | @ -68,18 +69,14 @@ public: | |||
|     size_t facets_count() const { return this->stl.stats.number_of_facets; } | ||||
|     bool   empty() const { return this->facets_count() == 0; } | ||||
| 
 | ||||
|     // Returns true, if there are two and more connected patches in the mesh.
 | ||||
|     // Returns false, if one or zero connected patch is in the mesh.
 | ||||
|     bool has_multiple_patches() const; | ||||
| 
 | ||||
|     // Count disconnected triangle patches.
 | ||||
|     size_t number_of_patches() const; | ||||
|     bool is_splittable() const; | ||||
| 
 | ||||
|     stl_file stl; | ||||
|     bool repaired; | ||||
|      | ||||
| private: | ||||
|     void require_shared_vertices(); | ||||
|     std::deque<uint32_t> find_unvisited_neighbors(std::vector<unsigned char> &facet_visited) const; | ||||
|     friend class TriangleMeshSlicer; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -208,7 +208,7 @@ public: | |||
| 
 | ||||
| // Shorten the dhms time by removing the seconds, rounding the dhm to full minutes
 | ||||
| // and removing spaces.
 | ||||
| static std::string short_time(const std::string &time) | ||||
| inline std::string short_time(const std::string &time) | ||||
| { | ||||
|     // Parse the dhms time format.
 | ||||
|     int days = 0; | ||||
|  | @ -247,7 +247,7 @@ static std::string short_time(const std::string &time) | |||
| } | ||||
| 
 | ||||
| // Returns the given time is seconds in format DDd HHh MMm SSs
 | ||||
| static std::string get_time_dhms(float time_in_secs) | ||||
| inline std::string get_time_dhms(float time_in_secs) | ||||
| { | ||||
|     int days = (int)(time_in_secs / 86400.0f); | ||||
|     time_in_secs -= (float)days * 86400.0f; | ||||
|  |  | |||
							
								
								
									
										223
									
								
								src/libslic3r/Zipper.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,223 @@ | |||
| #include <exception> | ||||
| #include <sstream> | ||||
| #include <iostream> | ||||
| 
 | ||||
| #include "Zipper.hpp" | ||||
| #include "miniz/miniz_zip.h" | ||||
| #include <boost/log/trivial.hpp> | ||||
| 
 | ||||
| #include "I18N.hpp" | ||||
| 
 | ||||
| //! macro used to mark string used at localization,
 | ||||
| //! return same string
 | ||||
| #define L(s) Slic3r::I18N::translate(s) | ||||
| 
 | ||||
| #if defined(_MSC_VER) &&  _MSC_VER <= 1800 || __cplusplus < 201103L | ||||
|     #define SLIC3R_NORETURN | ||||
| #elif __cplusplus >= 201103L | ||||
|     #define SLIC3R_NORETURN [[noreturn]] | ||||
| #endif | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| class Zipper::Impl { | ||||
| public: | ||||
|     mz_zip_archive arch; | ||||
|     std::string m_zipname; | ||||
| 
 | ||||
|     static std::string get_errorstr(mz_zip_error mz_err) | ||||
|     { | ||||
|         switch (mz_err) | ||||
|         { | ||||
|             case MZ_ZIP_NO_ERROR: | ||||
|                 return "no error"; | ||||
|             case MZ_ZIP_UNDEFINED_ERROR: | ||||
|                 return L("undefined error"); | ||||
|             case MZ_ZIP_TOO_MANY_FILES: | ||||
|                 return L("too many files"); | ||||
|             case MZ_ZIP_FILE_TOO_LARGE: | ||||
|                 return L("file too large"); | ||||
|             case MZ_ZIP_UNSUPPORTED_METHOD: | ||||
|                 return L("unsupported method"); | ||||
|             case MZ_ZIP_UNSUPPORTED_ENCRYPTION: | ||||
|                 return L("unsupported encryption"); | ||||
|             case MZ_ZIP_UNSUPPORTED_FEATURE: | ||||
|                 return L("unsupported feature"); | ||||
|             case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: | ||||
|                 return L("failed finding central directory"); | ||||
|             case MZ_ZIP_NOT_AN_ARCHIVE: | ||||
|                 return L("not a ZIP archive"); | ||||
|             case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: | ||||
|                 return L("invalid header or archive is corrupted"); | ||||
|             case MZ_ZIP_UNSUPPORTED_MULTIDISK: | ||||
|                 return L("unsupported multidisk archive"); | ||||
|             case MZ_ZIP_DECOMPRESSION_FAILED: | ||||
|                 return L("decompression failed or archive is corrupted"); | ||||
|             case MZ_ZIP_COMPRESSION_FAILED: | ||||
|                 return L("compression failed"); | ||||
|             case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: | ||||
|                 return L("unexpected decompressed size"); | ||||
|             case MZ_ZIP_CRC_CHECK_FAILED: | ||||
|                 return L("CRC-32 check failed"); | ||||
|             case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: | ||||
|                 return L("unsupported central directory size"); | ||||
|             case MZ_ZIP_ALLOC_FAILED: | ||||
|                 return L("allocation failed"); | ||||
|             case MZ_ZIP_FILE_OPEN_FAILED: | ||||
|                 return L("file open failed"); | ||||
|             case MZ_ZIP_FILE_CREATE_FAILED: | ||||
|                 return L("file create failed"); | ||||
|             case MZ_ZIP_FILE_WRITE_FAILED: | ||||
|                 return L("file write failed"); | ||||
|             case MZ_ZIP_FILE_READ_FAILED: | ||||
|                 return L("file read failed"); | ||||
|             case MZ_ZIP_FILE_CLOSE_FAILED: | ||||
|                 return L("file close failed"); | ||||
|             case MZ_ZIP_FILE_SEEK_FAILED: | ||||
|                 return L("file seek failed"); | ||||
|             case MZ_ZIP_FILE_STAT_FAILED: | ||||
|                 return L("file stat failed"); | ||||
|             case MZ_ZIP_INVALID_PARAMETER: | ||||
|                 return L("invalid parameter"); | ||||
|             case MZ_ZIP_INVALID_FILENAME: | ||||
|                 return L("invalid filename"); | ||||
|             case MZ_ZIP_BUF_TOO_SMALL: | ||||
|                 return L("buffer too small"); | ||||
|             case MZ_ZIP_INTERNAL_ERROR: | ||||
|                 return L("internal error"); | ||||
|             case MZ_ZIP_FILE_NOT_FOUND: | ||||
|                 return L("file not found"); | ||||
|             case MZ_ZIP_ARCHIVE_TOO_LARGE: | ||||
|                 return L("archive is too large"); | ||||
|             case MZ_ZIP_VALIDATION_FAILED: | ||||
|                 return L("validation failed"); | ||||
|             case MZ_ZIP_WRITE_CALLBACK_FAILED: | ||||
|                 return L("write calledback failed"); | ||||
|             default: | ||||
|                 break; | ||||
|         } | ||||
| 
 | ||||
|         return "unknown error"; | ||||
|     } | ||||
| 
 | ||||
|     std::string formatted_errorstr() const | ||||
|     { | ||||
|         return L("Error with zip archive") + " " + m_zipname + ": " + | ||||
|                get_errorstr(arch.m_last_error) + "!"; | ||||
|     } | ||||
| 
 | ||||
|     SLIC3R_NORETURN void blow_up() const | ||||
|     { | ||||
|         throw std::runtime_error(formatted_errorstr()); | ||||
|     } | ||||
| 
 | ||||
|     bool is_alive() | ||||
|     { | ||||
|         return arch.m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| Zipper::Zipper(const std::string &zipfname, e_compression compression) | ||||
| { | ||||
|     m_impl.reset(new Impl()); | ||||
| 
 | ||||
|     m_compression = compression; | ||||
|     m_impl->m_zipname = zipfname; | ||||
| 
 | ||||
|     memset(&m_impl->arch, 0, sizeof(m_impl->arch)); | ||||
| 
 | ||||
|     // Initialize the archive data
 | ||||
|     if(!mz_zip_writer_init_file(&m_impl->arch, zipfname.c_str(), 0)) | ||||
|         m_impl->blow_up(); | ||||
| } | ||||
| 
 | ||||
| Zipper::~Zipper() | ||||
| { | ||||
|     if(m_impl->is_alive()) { | ||||
|         // Flush the current entry if not finished yet.
 | ||||
|         try { finish_entry(); } catch(...) { | ||||
|             BOOST_LOG_TRIVIAL(error) << m_impl->formatted_errorstr(); | ||||
|         } | ||||
| 
 | ||||
|         if(!mz_zip_writer_finalize_archive(&m_impl->arch)) | ||||
|             BOOST_LOG_TRIVIAL(error) << m_impl->formatted_errorstr(); | ||||
|     } | ||||
| 
 | ||||
|     // The file should be closed no matter what...
 | ||||
|     if(!mz_zip_writer_end(&m_impl->arch)) | ||||
|         BOOST_LOG_TRIVIAL(error) << m_impl->formatted_errorstr(); | ||||
| } | ||||
| 
 | ||||
| Zipper::Zipper(Zipper &&m): | ||||
|     m_impl(std::move(m.m_impl)), | ||||
|     m_data(std::move(m.m_data)), | ||||
|     m_entry(std::move(m.m_entry)), | ||||
|     m_compression(m.m_compression) {} | ||||
| 
 | ||||
| Zipper &Zipper::operator=(Zipper &&m) { | ||||
|     m_impl = std::move(m.m_impl); | ||||
|     m_data = std::move(m.m_data); | ||||
|     m_entry = std::move(m.m_entry); | ||||
|     m_compression = m.m_compression; | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| void Zipper::add_entry(const std::string &name) | ||||
| { | ||||
|     if(!m_impl->is_alive()) return; | ||||
| 
 | ||||
|     finish_entry(); // finish previous business
 | ||||
|     m_entry = name; | ||||
| } | ||||
| 
 | ||||
| void Zipper::add_entry(const std::string &name, const uint8_t *data, size_t l) | ||||
| { | ||||
|     if(!m_impl->is_alive()) return; | ||||
| 
 | ||||
|     finish_entry(); | ||||
|     mz_uint cmpr = MZ_NO_COMPRESSION; | ||||
|     switch (m_compression) { | ||||
|     case NO_COMPRESSION: cmpr = MZ_NO_COMPRESSION; break; | ||||
|     case FAST_COMPRESSION: cmpr = MZ_BEST_SPEED; break; | ||||
|     case TIGHT_COMPRESSION: cmpr = MZ_BEST_COMPRESSION; break; | ||||
|     } | ||||
| 
 | ||||
|     if(!mz_zip_writer_add_mem(&m_impl->arch, name.c_str(), data, l, cmpr)) | ||||
|         m_impl->blow_up(); | ||||
| 
 | ||||
|     m_entry.clear(); | ||||
|     m_data.clear(); | ||||
| } | ||||
| 
 | ||||
| void Zipper::finish_entry() | ||||
| { | ||||
|     if(!m_impl->is_alive()) return; | ||||
| 
 | ||||
|     if(!m_data.empty() && !m_entry.empty()) { | ||||
|         mz_uint compression = MZ_NO_COMPRESSION; | ||||
| 
 | ||||
|         switch (m_compression) { | ||||
|         case NO_COMPRESSION: compression = MZ_NO_COMPRESSION; break; | ||||
|         case FAST_COMPRESSION: compression = MZ_BEST_SPEED; break; | ||||
|         case TIGHT_COMPRESSION: compression = MZ_BEST_COMPRESSION; break; | ||||
|         } | ||||
| 
 | ||||
|         if(!mz_zip_writer_add_mem(&m_impl->arch, m_entry.c_str(), | ||||
|                                   m_data.c_str(), | ||||
|                                   m_data.size(), | ||||
|                                   compression)) m_impl->blow_up(); | ||||
|     } | ||||
| 
 | ||||
|     m_data.clear(); | ||||
|     m_entry.clear(); | ||||
| } | ||||
| 
 | ||||
| void Zipper::finalize() | ||||
| { | ||||
|     finish_entry(); | ||||
| 
 | ||||
|     if(m_impl->is_alive()) if(!mz_zip_writer_finalize_archive(&m_impl->arch)) | ||||
|         m_impl->blow_up(); | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										90
									
								
								src/libslic3r/Zipper.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,90 @@ | |||
| #ifndef ZIPPER_HPP | ||||
| #define ZIPPER_HPP | ||||
| 
 | ||||
| #include <string> | ||||
| #include <memory> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| // Class for creating zip archives.
 | ||||
| class Zipper { | ||||
| public: | ||||
|     // Three compression levels supported
 | ||||
|     enum e_compression { | ||||
|         NO_COMPRESSION, | ||||
|         FAST_COMPRESSION, | ||||
|         TIGHT_COMPRESSION | ||||
|     }; | ||||
| 
 | ||||
| private: | ||||
|     class Impl; | ||||
|     std::unique_ptr<Impl> m_impl; | ||||
|     std::string m_data; | ||||
|     std::string m_entry; | ||||
|     e_compression m_compression; | ||||
| 
 | ||||
| public: | ||||
| 
 | ||||
|     // Will blow up in a runtime exception if the file cannot be created.
 | ||||
|     explicit Zipper(const std::string& zipfname, | ||||
|                     e_compression level = NO_COMPRESSION); | ||||
|     ~Zipper(); | ||||
| 
 | ||||
|     // No copies allwed, this is a file resource...
 | ||||
|     Zipper(const Zipper&) = delete; | ||||
|     Zipper& operator=(const Zipper&) = delete; | ||||
| 
 | ||||
|     // Moving is fine.
 | ||||
|     // Zipper(Zipper&&) = default;
 | ||||
|     // Zipper& operator=(Zipper&&) = default;
 | ||||
|     // All becouse of VS2013:
 | ||||
|     Zipper(Zipper &&m); | ||||
|     Zipper& operator=(Zipper &&m); | ||||
| 
 | ||||
|     /// Adding an entry means a file inside the new archive. Name param is the
 | ||||
|     /// name of the new file. To create directories, append a forward slash.
 | ||||
|     /// The previous entry is finished (see finish_entry)
 | ||||
|     void add_entry(const std::string& name); | ||||
| 
 | ||||
|     /// Add a new binary file entry with an instantly given byte buffer.
 | ||||
|     /// This method throws exactly like finish_entry() does.
 | ||||
|     void add_entry(const std::string& name, const std::uint8_t* data, size_t l); | ||||
| 
 | ||||
|     // Writing data to the archive works like with standard streams. The target
 | ||||
|     // within the zip file is the entry created with the add_entry method.
 | ||||
| 
 | ||||
|     // Template taking only arithmetic values, that std::to_string can handle.
 | ||||
|     template<class T> inline | ||||
|     typename std::enable_if<std::is_arithmetic<T>::value, Zipper&>::type | ||||
|     operator<<(T &&val) { | ||||
|         return this->operator<<(std::to_string(std::forward<T>(val))); | ||||
|     } | ||||
| 
 | ||||
|     // Template applied only for types that std::string can handle for append
 | ||||
|     // and copy. This includes c style strings...
 | ||||
|     template<class T> inline | ||||
|     typename std::enable_if<!std::is_arithmetic<T>::value, Zipper&>::type | ||||
|     operator<<(T &&val) { | ||||
|         if(m_data.empty()) m_data = std::forward<T>(val); | ||||
|         else m_data.append(val); | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     /// Finishing an entry means that subsequent writes will no longer be
 | ||||
|     /// appended to the previous entry. They will be written into the internal
 | ||||
|     /// buffer and ones an entry is added, the buffer will bind to the new entry
 | ||||
|     /// If the buffer was written, but no entry was added, the buffer will be
 | ||||
|     /// cleared after this call.
 | ||||
|     ///
 | ||||
|     /// This method will throw a runtime exception if an error occures. The
 | ||||
|     /// entry will still be open (with the data intact) but the state of the
 | ||||
|     /// file is up to minz after the erroneous write.
 | ||||
|     void finish_entry(); | ||||
| 
 | ||||
|     void finalize(); | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // ZIPPER_HPP
 | ||||
|  | @ -2897,6 +2897,8 @@ NSVGimage* nsvgParse(char* input, const char* units, float dpi) | |||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| #include <boost/nowide/cstdio.hpp> | ||||
| 
 | ||||
| NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) | ||||
| { | ||||
| 	FILE* fp = NULL; | ||||
|  | @ -2904,8 +2906,8 @@ NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) | |||
| 	char* data = NULL; | ||||
| 	NSVGimage* image = NULL; | ||||
| 
 | ||||
| 	fp = fopen(filename, "rb"); | ||||
| 	if (!fp) goto error; | ||||
|     fp = boost::nowide::fopen(filename, "rb"); | ||||
|     if (!fp) goto error; | ||||
| 	fseek(fp, 0, SEEK_END); | ||||
| 	size = ftell(fp); | ||||
| 	fseek(fp, 0, SEEK_SET); | ||||
|  |  | |||
|  | @ -1,4 +0,0 @@ | |||
| png++ is written by Alexander Shulgin  (alex dot shulgin at gmail dot com) | ||||
| Copyright (C) 2007,2008 | ||||
| 
 | ||||
| When writing to me be sure to put png++: in the subject :-) | ||||
|  | @ -1,25 +0,0 @@ | |||
| Copying png++ is subject to the following license: | ||||
| 
 | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
| 
 | ||||
|    1. Redistributions of source code must retain the above copyright notice, | ||||
|       this list of conditions and the following disclaimer. | ||||
| 
 | ||||
|    2. Redistributions in binary form must reproduce the above copyright | ||||
|       notice, this list of conditions and the following disclaimer in the | ||||
|       documentation and/or other materials provided with the distribution. | ||||
| 
 | ||||
|    3. The name of the author may not be used to endorse or promote products | ||||
|       derived from this software without specific prior written permission. | ||||
| 
 | ||||
| THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||||
| WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||||
| MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | ||||
| EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||||
| PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||||
| BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | ||||
| IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||||
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
| POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										60
									
								
								src/png/NEWS
									
										
									
									
									
								
							
							
						
						|  | @ -1,60 +0,0 @@ | |||
| Version 0.2.7: | ||||
| 
 | ||||
|   - Added solid_pixel_buffer (patch by Andrey Potapov). | ||||
| 
 | ||||
|   - Fixed some compilation problems on Win32. | ||||
| 
 | ||||
| Version 0.2.5: | ||||
| 
 | ||||
|   - Fixed compatibility with newer libpng versions (>= 1.4) | ||||
| 
 | ||||
|   - Fixed compilation on FreeBSD. | ||||
| 
 | ||||
|   - Fixed tRNS handling with transformations. | ||||
| 
 | ||||
|   - Added IO transformation debugging facility. | ||||
| 
 | ||||
|   - Better organized test suite. | ||||
| 
 | ||||
| Version 0.2.3: | ||||
| 
 | ||||
|   - Fixed numerous `already defined' errors due to require_color_space | ||||
|     implementation. | ||||
| 
 | ||||
|   - Added `config.hpp'. | ||||
| 
 | ||||
|   - Fixed `strerror' usage. | ||||
| 
 | ||||
|   - Minor docs fixes. | ||||
| 
 | ||||
| 
 | ||||
| Version 0.2.1: | ||||
| 
 | ||||
|   - Added support for tRNS chunk. | ||||
| 
 | ||||
|   - Added non-std IO streams support. | ||||
| 
 | ||||
|   - Fixed 16-bit endianness problems. | ||||
| 
 | ||||
|   - Improved test script. | ||||
| 
 | ||||
| 
 | ||||
| Version 0.2.0: | ||||
| 
 | ||||
|   - Added support for 16-bit data (RGB, RGBA, Grayscale and Gray+Alpha | ||||
|     color types) | ||||
| 
 | ||||
|   - Added support for packed 1-, 2- or 4-bit pixels (Grayscale and | ||||
|     Indexed colors) | ||||
| 
 | ||||
|   - Fixed interlace handling code which was severely broken | ||||
| 
 | ||||
|   - Added possibility to process images without reading the entire | ||||
|     image into memory | ||||
| 
 | ||||
|   - Internals are refactored while the client interface is mostly | ||||
|     unchanged | ||||
| 
 | ||||
|   - Added intensive test suite | ||||
| 
 | ||||
|   - Added documentation | ||||
|  | @ -1,65 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2007,2008   Alex Shulgin | ||||
|  * | ||||
|  * This file is part of png++ the C++ wrapper for libpng.  PNG++ is free | ||||
|  * software; the exact copying conditions are as follows: | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  * | ||||
|  * 1. Redistributions of source code must retain the above copyright notice, | ||||
|  * this list of conditions and the following disclaimer. | ||||
|  * | ||||
|  * 2. Redistributions in binary form must reproduce the above copyright | ||||
|  * notice, this list of conditions and the following disclaimer in the | ||||
|  * documentation and/or other materials provided with the distribution. | ||||
|  * | ||||
|  * 3. The name of the author may not be used to endorse or promote products | ||||
|  * derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||||
|  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
|  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||||
|  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
|  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | ||||
|  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||||
|  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||||
|  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||||
|  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| #ifndef PNGPP_COLOR_HPP_INCLUDED | ||||
| #define PNGPP_COLOR_HPP_INCLUDED | ||||
| 
 | ||||
| #include "types.hpp" | ||||
| 
 | ||||
| namespace png | ||||
| { | ||||
| 
 | ||||
|     /**
 | ||||
|      * \brief PNG color struct extension.  Adds constructors.  | ||||
|      */ | ||||
|     struct color | ||||
|         : png_color | ||||
|     { | ||||
|         explicit color(byte r = 0, byte g = 0, byte b = 0) | ||||
|         { | ||||
|             this->red = r; | ||||
|             this->green = g; | ||||
|             this->blue = b; | ||||
|         } | ||||
| 
 | ||||
|         /**
 | ||||
|          * \brief Initializes color with a copy of png_color object. | ||||
|          */ | ||||
|         color(png_color const& other) | ||||
|         { | ||||
|             this->red = other.red; | ||||
|             this->green = other.green; | ||||
|             this->blue = other.blue; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
| } // namespace png
 | ||||
| 
 | ||||
| #endif // PNGPP_COLOR_HPP_INCLUDED
 | ||||
|  | @ -1,74 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2007,2008   Alex Shulgin | ||||
|  * | ||||
|  * This file is part of png++ the C++ wrapper for libpng.  PNG++ is free | ||||
|  * software; the exact copying conditions are as follows: | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  * | ||||
|  * 1. Redistributions of source code must retain the above copyright notice, | ||||
|  * this list of conditions and the following disclaimer. | ||||
|  * | ||||
|  * 2. Redistributions in binary form must reproduce the above copyright | ||||
|  * notice, this list of conditions and the following disclaimer in the | ||||
|  * documentation and/or other materials provided with the distribution. | ||||
|  * | ||||
|  * 3. The name of the author may not be used to endorse or promote products | ||||
|  * derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||||
|  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
|  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||||
|  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
|  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | ||||
|  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||||
|  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||||
|  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||||
|  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| #ifndef PNGPP_END_INFO_HPP_INCLUDED | ||||
| #define PNGPP_END_INFO_HPP_INCLUDED | ||||
| 
 | ||||
| #include "info_base.hpp" | ||||
| 
 | ||||
| namespace png | ||||
| { | ||||
| 
 | ||||
|     /**
 | ||||
|      * \brief Internal class to hold PNG ending %info. | ||||
|      * | ||||
|      * \see info, info_base | ||||
|      */ | ||||
|     class end_info | ||||
|         : public info_base | ||||
|     { | ||||
|     public: | ||||
|         end_info(io_base& io, png_struct* png) | ||||
|             : info_base(io, png) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         void destroy() | ||||
|         { | ||||
|             assert(m_info); | ||||
|             png_destroy_info_struct(m_png, & m_info); | ||||
|         } | ||||
| 
 | ||||
|         void read() | ||||
|         { | ||||
|             png_read_end(m_png, m_info); | ||||
|         } | ||||
|          | ||||
|         void write() const | ||||
|         { | ||||
|             png_write_end(m_png, m_info); | ||||
|         } | ||||
| 
 | ||||
|         // TODO: add methods to read/write text comments etc.
 | ||||
|     }; | ||||
| 
 | ||||
| } // namespace png
 | ||||
| 
 | ||||
| #endif // PNGPP_END_INFO_HPP_INCLUDED
 | ||||
|  | @ -1,125 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2007,2008   Alex Shulgin | ||||
|  * | ||||
|  * This file is part of png++ the C++ wrapper for libpng.  PNG++ is free | ||||
|  * software; the exact copying conditions are as follows: | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  * | ||||
|  * 1. Redistributions of source code must retain the above copyright notice, | ||||
|  * this list of conditions and the following disclaimer. | ||||
|  * | ||||
|  * 2. Redistributions in binary form must reproduce the above copyright | ||||
|  * notice, this list of conditions and the following disclaimer in the | ||||
|  * documentation and/or other materials provided with the distribution. | ||||
|  * | ||||
|  * 3. The name of the author may not be used to endorse or promote products | ||||
|  * derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||||
|  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
|  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||||
|  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
|  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | ||||
|  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||||
|  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||||
|  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||||
|  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| #ifndef PNGPP_ERROR_HPP_INCLUDED | ||||
| #define PNGPP_ERROR_HPP_INCLUDED | ||||
| 
 | ||||
| /* check if we have strerror_s or strerror_r, prefer the former which is C11 std */ | ||||
| #ifdef __STDC_LIB_EXT1__ | ||||
| #define __STDC_WANT_LIB_EXT1__ 1 | ||||
| #include <string.h> | ||||
| 
 | ||||
| #define HAVE_STRERROR_S 1 | ||||
| #else | ||||
| #undef  HAVE_STRERROR_S | ||||
| #endif | ||||
| 
 | ||||
| #include <string> | ||||
| #include <stdexcept> | ||||
| #include <cerrno> | ||||
| #include <cstdlib> | ||||
| #include <cstring> | ||||
| 
 | ||||
| namespace png | ||||
| { | ||||
| 
 | ||||
|     /**
 | ||||
|      * \brief Exception class to represent runtime errors related to | ||||
|      * png++ operation. | ||||
|      */ | ||||
|     class error | ||||
|         : public std::runtime_error | ||||
|     { | ||||
|     public: | ||||
|         /**
 | ||||
|          * \param  message  error description | ||||
|          */ | ||||
|         explicit error(std::string const& message) | ||||
|             : std::runtime_error(message) | ||||
|         { | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /**
 | ||||
|      * \brief Exception class to represent standard library errors | ||||
|      * (generally IO). | ||||
|      * | ||||
|      * \see  reader, writer | ||||
|      */ | ||||
|     class std_error | ||||
|         : public std::runtime_error | ||||
|     { | ||||
|     public: | ||||
|         /**
 | ||||
|          * Constructs an std_error object.  The \a message string is | ||||
|          * appended with <tt>": "</tt> and the error description as | ||||
|          * returned by \c strerror(\a error). | ||||
|          * | ||||
|          * \param  message  error description | ||||
|          * \param  error    error number | ||||
|          */ | ||||
|         explicit std_error(std::string const& message, int errnum = errno) | ||||
|             : std::runtime_error((message + ": ") + thread_safe_strerror(errnum)) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|     protected: | ||||
|         static std::string thread_safe_strerror(int errnum) | ||||
|         { | ||||
| #define ERRBUF_SIZE 512 | ||||
| 
 | ||||
| #ifdef HAVE_STRERROR_S | ||||
|             char buf[ERRBUF_SIZE] = { 0 }; | ||||
|             strerror_s(buf, ERRBUF_SIZE, errnum); | ||||
|             return std::string(buf); | ||||
| #else | ||||
| #if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE | ||||
|             char buf[ERRBUF_SIZE] = { 0 }; | ||||
|             strerror_r(errnum, buf, ERRBUF_SIZE); | ||||
|             return std::string(buf); | ||||
| #elif _GNU_SOURCE | ||||
|             /* GNU variant can return a pointer to static buffer instead of buf */ | ||||
|             char buf[ERRBUF_SIZE] = { 0 }; | ||||
|             return std::string(strerror_r(errnum, buf, ERRBUF_SIZE)); | ||||
| #else | ||||
|             return std::string("An error occured with errnum ") + | ||||
|                     std::to_string(errnum) + | ||||
|                     ". Converting to the appropriate error message is disabled" | ||||
|                     "in this instance of the png++ library."; | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| #undef ERRBUF_SIZE | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
| } // namespace png
 | ||||
| 
 | ||||
| #endif // PNGPP_ERROR_HPP_INCLUDED
 | ||||
|  | @ -1,215 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2007,2008   Alex Shulgin | ||||
|  * | ||||
|  * This file is part of png++ the C++ wrapper for libpng.  PNG++ is free | ||||
|  * software; the exact copying conditions are as follows: | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  * | ||||
|  * 1. Redistributions of source code must retain the above copyright notice, | ||||
|  * this list of conditions and the following disclaimer. | ||||
|  * | ||||
|  * 2. Redistributions in binary form must reproduce the above copyright | ||||
|  * notice, this list of conditions and the following disclaimer in the | ||||
|  * documentation and/or other materials provided with the distribution. | ||||
|  * | ||||
|  * 3. The name of the author may not be used to endorse or promote products | ||||
|  * derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||||
|  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
|  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||||
|  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
|  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | ||||
|  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||||
|  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||||
|  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||||
|  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| #ifndef PNGPP_IMAGE_INFO_HPP_INCLUDED | ||||
| #define PNGPP_IMAGE_INFO_HPP_INCLUDED | ||||
| 
 | ||||
| #include "types.hpp" | ||||
| #include "palette.hpp" | ||||
| #include "tRNS.hpp" | ||||
| #include "pixel_traits.hpp" | ||||
| 
 | ||||
| namespace png | ||||
| { | ||||
| 
 | ||||
|     /**
 | ||||
|      * \brief Holds information about PNG image. | ||||
|      * | ||||
|      * \see image, generator, consumer | ||||
|      */ | ||||
|     class image_info | ||||
|     { | ||||
|     public: | ||||
|         /**
 | ||||
|          * \brief Constructs the image_info object with default values | ||||
|          * for color_type, interlace_type, compression_method and | ||||
|          * filter_type. | ||||
|          */ | ||||
|         image_info() | ||||
|             : m_width(0), | ||||
|               m_height(0), | ||||
|               m_bit_depth(0), | ||||
|               m_color_type(color_type_none), | ||||
|               m_interlace_type(interlace_none), | ||||
|               m_compression_type(compression_type_default), | ||||
|               m_filter_type(filter_type_default), | ||||
|               m_gamma(0.0) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         uint_32 get_width() const | ||||
|         { | ||||
|             return m_width; | ||||
|         } | ||||
| 
 | ||||
|         void set_width(uint_32 width) | ||||
|         { | ||||
|             m_width = width; | ||||
|         } | ||||
| 
 | ||||
|         uint_32 get_height() const | ||||
|         { | ||||
|             return m_height; | ||||
|         } | ||||
| 
 | ||||
|         void set_height(uint_32 height) | ||||
|         { | ||||
|             m_height = height; | ||||
|         } | ||||
| 
 | ||||
|         color_type get_color_type() const | ||||
|         { | ||||
|             return m_color_type; | ||||
|         } | ||||
| 
 | ||||
|         void set_color_type(color_type color_space) | ||||
|         { | ||||
|             m_color_type = color_space; | ||||
|         } | ||||
| 
 | ||||
|         int get_bit_depth() const | ||||
|         { | ||||
|             return m_bit_depth; | ||||
|         } | ||||
| 
 | ||||
|         void set_bit_depth(int bit_depth) | ||||
|         { | ||||
|             m_bit_depth = bit_depth; | ||||
|         } | ||||
| 
 | ||||
|         interlace_type get_interlace_type() const | ||||
|         { | ||||
|             return m_interlace_type; | ||||
|         } | ||||
| 
 | ||||
|         void set_interlace_type(interlace_type interlace) | ||||
|         { | ||||
|             m_interlace_type = interlace; | ||||
|         } | ||||
| 
 | ||||
|         compression_type get_compression_type() const | ||||
|         { | ||||
|             return m_compression_type; | ||||
|         } | ||||
| 
 | ||||
|         void set_compression_type(compression_type compression) | ||||
|         { | ||||
|             m_compression_type = compression; | ||||
|         } | ||||
| 
 | ||||
|         filter_type get_filter_type() const | ||||
|         { | ||||
|             return m_filter_type; | ||||
|         } | ||||
| 
 | ||||
|         void set_filter_type(filter_type filter) | ||||
|         { | ||||
|             m_filter_type = filter; | ||||
|         } | ||||
| 
 | ||||
|         palette const& get_palette() const | ||||
|         { | ||||
|             return m_palette; | ||||
|         } | ||||
| 
 | ||||
|         palette& get_palette() | ||||
|         { | ||||
|             return m_palette; | ||||
|         } | ||||
| 
 | ||||
|         void set_palette(palette const& plte) | ||||
|         { | ||||
|             m_palette = plte; | ||||
|         } | ||||
| 
 | ||||
|         /**
 | ||||
|          * \brief Removes all entries from the palette. | ||||
|          */ | ||||
|         void drop_palette() | ||||
|         { | ||||
|             m_palette.clear(); | ||||
|         } | ||||
| 
 | ||||
|         tRNS const& get_tRNS() const | ||||
|         { | ||||
|             return m_tRNS; | ||||
|         } | ||||
| 
 | ||||
|         tRNS& get_tRNS() | ||||
|         { | ||||
|             return m_tRNS; | ||||
|         } | ||||
| 
 | ||||
|         void set_tRNS(tRNS const& trns) | ||||
|         { | ||||
|             m_tRNS = trns; | ||||
|         } | ||||
| 
 | ||||
|         double get_gamma() const | ||||
|         { | ||||
|             return m_gamma; | ||||
|         } | ||||
| 
 | ||||
|         void set_gamma(double gamma) | ||||
|         { | ||||
|             m_gamma = gamma; | ||||
|         } | ||||
| 
 | ||||
|     protected: | ||||
|         uint_32 m_width; | ||||
|         uint_32 m_height; | ||||
|         int m_bit_depth; | ||||
|         color_type m_color_type; | ||||
|         interlace_type m_interlace_type; | ||||
|         compression_type m_compression_type; | ||||
|         filter_type m_filter_type; | ||||
|         palette m_palette; | ||||
|         tRNS m_tRNS; | ||||
|         double m_gamma; | ||||
|     }; | ||||
| 
 | ||||
|     /**
 | ||||
|      * \brief Returns an image_info object with color_type and | ||||
|      * bit_depth fields setup appropriate for the \c pixel type. | ||||
|      */ | ||||
|     template< typename pixel > | ||||
|     image_info | ||||
|     make_image_info() | ||||
|     { | ||||
|         typedef pixel_traits< pixel > traits; | ||||
|         image_info info; | ||||
|         info.set_color_type(traits::get_color_type()); | ||||
|         info.set_bit_depth(traits::get_bit_depth()); | ||||
|         return info; | ||||
|     } | ||||
| 
 | ||||
| } // namespace png
 | ||||
| 
 | ||||
| #endif // PNGPP_IMAGE_INFO_HPP_INCLUDED
 | ||||
							
								
								
									
										186
									
								
								src/png/info.hpp
									
										
									
									
									
								
							
							
						
						|  | @ -1,186 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2007,2008   Alex Shulgin | ||||
|  * | ||||
|  * This file is part of png++ the C++ wrapper for libpng.  PNG++ is free | ||||
|  * software; the exact copying conditions are as follows: | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  * | ||||
|  * 1. Redistributions of source code must retain the above copyright notice, | ||||
|  * this list of conditions and the following disclaimer. | ||||
|  * | ||||
|  * 2. Redistributions in binary form must reproduce the above copyright | ||||
|  * notice, this list of conditions and the following disclaimer in the | ||||
|  * documentation and/or other materials provided with the distribution. | ||||
|  * | ||||
|  * 3. The name of the author may not be used to endorse or promote products | ||||
|  * derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||||
|  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
|  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||||
|  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
|  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | ||||
|  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||||
|  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||||
|  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||||
|  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| #ifndef PNGPP_INFO_HPP_INCLUDED | ||||
| #define PNGPP_INFO_HPP_INCLUDED | ||||
| 
 | ||||
| #include <cassert> | ||||
| #include "info_base.hpp" | ||||
| #include "image_info.hpp" | ||||
| 
 | ||||
| namespace png | ||||
| { | ||||
| 
 | ||||
|     /**
 | ||||
|      * \brief Holds information about PNG image.  Adapter class for IO | ||||
|      * image operations. | ||||
|      */ | ||||
|     class info | ||||
|         : public info_base, | ||||
|           public image_info | ||||
|     { | ||||
|     public: | ||||
|         info(io_base& io, png_struct* png) | ||||
|             : info_base(io, png) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         void read() | ||||
|         { | ||||
|             assert(m_png); | ||||
|             assert(m_info); | ||||
| 
 | ||||
|             png_read_info(m_png, m_info); | ||||
|             png_get_IHDR(m_png, | ||||
|                          m_info, | ||||
|                          & m_width, | ||||
|                          & m_height, | ||||
|                          reinterpret_cast< int* >(& m_bit_depth), | ||||
|                          reinterpret_cast< int* >(& m_color_type), | ||||
|                          reinterpret_cast< int* >(& m_interlace_type), | ||||
|                          reinterpret_cast< int* >(& m_compression_type), | ||||
|                          reinterpret_cast< int* >(& m_filter_type)); | ||||
| 
 | ||||
|             if (png_get_valid(m_png, m_info, chunk_PLTE) == chunk_PLTE) | ||||
|             { | ||||
|                 png_color* colors = 0; | ||||
|                 int count = 0; | ||||
|                 png_get_PLTE(m_png, m_info, & colors, & count); | ||||
|                 m_palette.assign(colors, colors + count); | ||||
|             } | ||||
| 
 | ||||
| #ifdef PNG_tRNS_SUPPORTED | ||||
|             if (png_get_valid(m_png, m_info, chunk_tRNS) == chunk_tRNS) | ||||
|             { | ||||
|                 if (m_color_type == color_type_palette) | ||||
|                 { | ||||
|                     int count; | ||||
|                     byte* values; | ||||
|                     if (png_get_tRNS(m_png, m_info, & values, & count, NULL) | ||||
|                         != PNG_INFO_tRNS) | ||||
|                     { | ||||
|                         throw error("png_get_tRNS() failed"); | ||||
|                     } | ||||
|                     m_tRNS.assign(values, values + count); | ||||
|                 } | ||||
|             } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef PNG_gAMA_SUPPORTED | ||||
|             if (png_get_valid(m_png, m_info, chunk_gAMA) == chunk_gAMA) | ||||
|             { | ||||
| #ifdef PNG_FLOATING_POINT_SUPPORTED | ||||
|                 if (png_get_gAMA(m_png, m_info, &m_gamma) != PNG_INFO_gAMA) | ||||
|                 { | ||||
|                     throw error("png_get_gAMA() failed"); | ||||
|                 } | ||||
| #else | ||||
|                 png_fixed_point gamma = 0; | ||||
|                 if (png_get_gAMA_fixed(m_png, m_info, &gamma) != PNG_INFO_gAMA) | ||||
|                 { | ||||
|                     throw error("png_get_gAMA_fixed() failed"); | ||||
|                 } | ||||
|                 m_gamma = gamma / 100000.0; | ||||
| #endif | ||||
|             } | ||||
| #endif | ||||
|         } | ||||
| 
 | ||||
|         void write() const | ||||
|         { | ||||
|             assert(m_png); | ||||
|             assert(m_info); | ||||
| 
 | ||||
|             sync_ihdr(); | ||||
|             if (m_color_type == color_type_palette) | ||||
|             { | ||||
|                 if (! m_palette.empty()) | ||||
|                 { | ||||
|                     png_set_PLTE(m_png, m_info, | ||||
|                                  const_cast< color* >(& m_palette[0]), | ||||
|                                  (int) m_palette.size()); | ||||
|                 } | ||||
|                 if (! m_tRNS.empty()) | ||||
|                 { | ||||
| #ifdef PNG_tRNS_SUPPORTED | ||||
|                     png_set_tRNS(m_png, m_info, | ||||
|                                  const_cast< byte* >(& m_tRNS[0]), | ||||
|                                  m_tRNS.size(), | ||||
|                                  NULL); | ||||
| #else | ||||
|                     throw error("attempted to write tRNS chunk; recompile with PNG_tRNS_SUPPORTED"); | ||||
| #endif | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (m_gamma > 0) | ||||
|             { | ||||
| #ifdef PNG_gAMA_SUPPORTED | ||||
| #ifdef PNG_FLOATING_POINT_SUPPORTED | ||||
|                 png_set_gAMA(m_png, m_info, m_gamma); | ||||
| #else | ||||
|                 png_set_gAMA_fixed(m_png, m_info, | ||||
|                                    (png_fixed_point)(m_gamma * 100000)); | ||||
| #endif | ||||
| #else | ||||
|                 throw error("attempted to write gAMA chunk; recompile with PNG_gAMA_SUPPORTED"); | ||||
| #endif | ||||
|             } | ||||
| 
 | ||||
|             png_write_info(m_png, m_info); | ||||
|         } | ||||
| 
 | ||||
|         void update() | ||||
|         { | ||||
|             assert(m_png); | ||||
|             assert(m_info); | ||||
| 
 | ||||
|             sync_ihdr(); | ||||
|             png_read_update_info(m_png, m_info); | ||||
|         } | ||||
| 
 | ||||
|     protected: | ||||
|         void sync_ihdr(void) const | ||||
|         { | ||||
|             png_set_IHDR(m_png, | ||||
|                          m_info, | ||||
|                          m_width, | ||||
|                          m_height, | ||||
|                          m_bit_depth, | ||||
|                          m_color_type, | ||||
|                          m_interlace_type, | ||||
|                          m_compression_type, | ||||
|                          m_filter_type); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
| } // namespace png
 | ||||
| 
 | ||||
| #endif // PNGPP_INFO_HPP_INCLUDED
 | ||||
|  | @ -1,77 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2007,2008   Alex Shulgin | ||||
|  * | ||||
|  * This file is part of png++ the C++ wrapper for libpng.  PNG++ is free | ||||
|  * software; the exact copying conditions are as follows: | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  * | ||||
|  * 1. Redistributions of source code must retain the above copyright notice, | ||||
|  * this list of conditions and the following disclaimer. | ||||
|  * | ||||
|  * 2. Redistributions in binary form must reproduce the above copyright | ||||
|  * notice, this list of conditions and the following disclaimer in the | ||||
|  * documentation and/or other materials provided with the distribution. | ||||
|  * | ||||
|  * 3. The name of the author may not be used to endorse or promote products | ||||
|  * derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||||
|  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
|  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||||
|  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
|  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | ||||
|  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||||
|  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||||
|  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||||
|  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| #ifndef PNGPP_INFO_BASE_HPP_INCLUDED | ||||
| #define PNGPP_INFO_BASE_HPP_INCLUDED | ||||
| 
 | ||||
| #include <cassert> | ||||
| #include "error.hpp" | ||||
| #include "types.hpp" | ||||
| 
 | ||||
| namespace png | ||||
| { | ||||
| 
 | ||||
|     class io_base; | ||||
| 
 | ||||
|     /**
 | ||||
|      * \brief Internal class to hold PNG info or end_info. | ||||
|      */ | ||||
|     class info_base | ||||
|     { | ||||
|         info_base(info_base const&); | ||||
|         info_base& operator=(info_base const&); | ||||
| 
 | ||||
|     public: | ||||
|         info_base(io_base& io, png_struct* png) | ||||
|             : m_io(io), | ||||
|               m_png(png), | ||||
|               m_info(png_create_info_struct(m_png)) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         png_info* get_png_info() const | ||||
|         { | ||||
|             return m_info; | ||||
|         } | ||||
| 
 | ||||
|         png_info** get_png_info_ptr() | ||||
|         { | ||||
|             return & m_info; | ||||
|         } | ||||
| 
 | ||||
|     protected: | ||||
|         io_base& m_io; | ||||
|         png_struct* m_png; | ||||
|         png_info* m_info; | ||||
|     }; | ||||
| 
 | ||||
| } // namespace png
 | ||||
| 
 | ||||
| #endif // PNGPP_INFO_BASE_HPP_INCLUDED
 | ||||
|  | @ -1,467 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2007,2008   Alex Shulgin | ||||
|  * | ||||
|  * This file is part of png++ the C++ wrapper for libpng.  PNG++ is free | ||||
|  * software; the exact copying conditions are as follows: | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  * | ||||
|  * 1. Redistributions of source code must retain the above copyright notice, | ||||
|  * this list of conditions and the following disclaimer. | ||||
|  * | ||||
|  * 2. Redistributions in binary form must reproduce the above copyright | ||||
|  * notice, this list of conditions and the following disclaimer in the | ||||
|  * documentation and/or other materials provided with the distribution. | ||||
|  * | ||||
|  * 3. The name of the author may not be used to endorse or promote products | ||||
|  * derived from this software without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||||
|  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
|  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | ||||
|  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
|  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | ||||
|  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||||
|  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||||
|  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||||
|  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| #ifndef PNGPP_IO_BASE_HPP_INCLUDED | ||||
| #define PNGPP_IO_BASE_HPP_INCLUDED | ||||
| 
 | ||||
| #include <cassert> | ||||
| #include <cstdio> | ||||
| #include <cstdarg> | ||||
| #include "error.hpp" | ||||
| #include "info.hpp" | ||||
| #include "end_info.hpp" | ||||
| 
 | ||||
| static void | ||||
| trace_io_transform(char const* fmt, ...) | ||||
| { | ||||
| #ifdef DEBUG_IO_TRANSFORM | ||||
|     va_list va; | ||||
|     va_start(va, fmt); | ||||
|     fprintf(stderr, "TRANSFORM_IO: "); | ||||
|     vfprintf(stderr, fmt, va); | ||||
|     va_end(va); | ||||
| #endif | ||||
| } | ||||
| #define TRACE_IO_TRANSFORM trace_io_transform | ||||
| 
 | ||||
| namespace png | ||||
| { | ||||
| 
 | ||||
|     /**
 | ||||
|      * \brief Base class for PNG reader/writer classes. | ||||
|      * | ||||
|      * \see  reader, writer | ||||
|      */ | ||||
|     class io_base | ||||
|     { | ||||
|         io_base(io_base const&); | ||||
|         io_base& operator=(io_base const&); | ||||
| 
 | ||||
|     public: | ||||
|         explicit io_base(png_struct* png) | ||||
|             : m_png(png), | ||||
|               m_info(*this, m_png), | ||||
|               m_end_info(*this, m_png) | ||||
|         { | ||||
|         } | ||||
| 
 | ||||
|         ~io_base() | ||||
|         { | ||||
|             assert(! m_png); | ||||
|             assert(! m_info.get_png_info()); | ||||
|             assert(! m_end_info.get_png_info()); | ||||
|         } | ||||
| 
 | ||||
|         png_struct* get_png_struct() const | ||||
|         { | ||||
|             return m_png; | ||||
|         } | ||||
| 
 | ||||
|         info& get_info() | ||||
|         { | ||||
|             return m_info; | ||||
|         } | ||||
| 
 | ||||
|         info const& get_info() const | ||||
|         { | ||||
|             return m_info; | ||||
|         } | ||||
| 
 | ||||
|         image_info const& get_image_info() const | ||||
|         { | ||||
|             return m_info; | ||||
|         } | ||||
| 
 | ||||
|         void set_image_info(image_info const& info) | ||||
|         { | ||||
|             static_cast< image_info& >(m_info) = info; // slice it
 | ||||
|         } | ||||
| 
 | ||||
|         end_info& get_end_info() | ||||
|         { | ||||
|             return m_end_info; | ||||
|         } | ||||
| 
 | ||||
|         end_info const& get_end_info() const | ||||
|         { | ||||
|             return m_end_info; | ||||
|         } | ||||
| 
 | ||||
|         //////////////////////////////////////////////////////////////////////
 | ||||
|         // info accessors
 | ||||
|         //
 | ||||
|         uint_32 get_width() const | ||||
|         { | ||||
|             return m_info.get_width(); | ||||
|         } | ||||
| 
 | ||||
|         void set_width(uint_32 width) | ||||
|         { | ||||
|             m_info.set_width(width); | ||||
|         } | ||||
| 
 | ||||
|         uint_32 get_height() const | ||||
|         { | ||||
|             return m_info.get_height(); | ||||
|         } | ||||
| 
 | ||||
|         void set_height(uint_32 height) | ||||
|         { | ||||
|             m_info.set_height(height); | ||||
|         } | ||||
| 
 | ||||
|         color_type get_color_type() const | ||||
|         { | ||||
|             return m_info.get_color_type(); | ||||
|         } | ||||
| 
 | ||||
|         void set_color_type(color_type color_space) | ||||
|         { | ||||
|             m_info.set_color_type(color_space); | ||||
|         } | ||||
| 
 | ||||
|         int get_bit_depth() const | ||||
|         { | ||||
|             return m_info.get_bit_depth(); | ||||
|         } | ||||
| 
 | ||||
|         void set_bit_depth(int bit_depth) | ||||
|         { | ||||
|             m_info.set_bit_depth(bit_depth); | ||||
|         } | ||||
| 
 | ||||
|         interlace_type get_interlace_type() const | ||||
|         { | ||||
|             return m_info.get_interlace_type(); | ||||
|         } | ||||
| 
 | ||||
|         void set_interlace_type(interlace_type interlace) | ||||
|         { | ||||
|             m_info.set_interlace_type(interlace); | ||||
|         } | ||||
| 
 | ||||
|         compression_type get_compression_type() const | ||||
|         { | ||||
|             return m_info.get_compression_type(); | ||||
|         } | ||||
| 
 | ||||
|         void set_compression_type(compression_type compression) | ||||
|         { | ||||
|             m_info.set_compression_type(compression); | ||||
|         } | ||||
| 
 | ||||
|         filter_type get_filter_type() const | ||||
|         { | ||||
|             return m_info.get_filter_type(); | ||||
|         } | ||||
| 
 | ||||
|         void set_filter_type(filter_type filter) | ||||
|         { | ||||
|             m_info.set_filter_type(filter); | ||||
|         } | ||||
| 
 | ||||
|         //////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
|         bool has_chunk(chunk id) | ||||
|         { | ||||
|             return png_get_valid(m_png, | ||||
|                                  m_info.get_png_info(), | ||||
|                                  uint_32(id)) == uint_32(id); | ||||
|         } | ||||
| 
 | ||||
| #if defined(PNG_READ_EXPAND_SUPPORTED) | ||||
|         void set_gray_1_2_4_to_8() const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_expand_gray_1_2_4_to_8\n"); | ||||
|             png_set_expand_gray_1_2_4_to_8(m_png); | ||||
|         } | ||||
| 
 | ||||
|         void set_palette_to_rgb() const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_palette_to_rgb\n"); | ||||
|             png_set_palette_to_rgb(m_png); | ||||
|         } | ||||
| 
 | ||||
|         void set_tRNS_to_alpha() const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_tRNS_to_alpha\n"); | ||||
|             png_set_tRNS_to_alpha(m_png); | ||||
|         } | ||||
| #endif // defined(PNG_READ_EXPAND_SUPPORTED)
 | ||||
| 
 | ||||
| #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) | ||||
|         void set_bgr() const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_bgr\n"); | ||||
|             png_set_bgr(m_png); | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
| #if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) | ||||
|         void set_gray_to_rgb() const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_gray_to_rgb\n"); | ||||
|             png_set_gray_to_rgb(m_png); | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef PNG_FLOATING_POINT_SUPPORTED | ||||
|         void set_rgb_to_gray(rgb_to_gray_error_action error_action | ||||
|                              = rgb_to_gray_silent, | ||||
|                              double red_weight   = -1.0, | ||||
|                              double green_weight = -1.0) const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_rgb_to_gray: error_action=%d," | ||||
|                                " red_weight=%lf, green_weight=%lf\n", | ||||
|                                error_action, red_weight, green_weight); | ||||
| 
 | ||||
|             png_set_rgb_to_gray(m_png, error_action, red_weight, green_weight); | ||||
|         } | ||||
| #else | ||||
|         void set_rgb_to_gray(rgb_to_gray_error_action error_action | ||||
|                              = rgb_to_gray_silent, | ||||
|                              fixed_point red_weight   = -1, | ||||
|                              fixed_point green_weight = -1) const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_rgb_to_gray_fixed: error_action=%d," | ||||
|                                " red_weight=%d, green_weight=%d\n", | ||||
|                                error_action, red_weight, green_weight); | ||||
| 
 | ||||
|             png_set_rgb_to_gray_fixed(m_png, error_action, | ||||
|                                       red_weight, green_weight); | ||||
|         } | ||||
| #endif // PNG_FLOATING_POINT_SUPPORTED
 | ||||
| 
 | ||||
|         //////////////////////////////////////////////////////////////////////
 | ||||
|         // alpha channel transformations
 | ||||
|         //
 | ||||
| #if defined(PNG_READ_STRIP_ALPHA_SUPPORTED) | ||||
|         void set_strip_alpha() const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_strip_alpha\n"); | ||||
|             png_set_strip_alpha(m_png); | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
| #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) \ | ||||
|     || defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) | ||||
|         void set_swap_alpha() const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_swap_alpha\n"); | ||||
|             png_set_swap_alpha(m_png); | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
| #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) \ | ||||
|     || defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) | ||||
|         void set_invert_alpha() const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_invert_alpha\n"); | ||||
|             png_set_invert_alpha(m_png); | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
| #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) | ||||
|         void set_filler(uint_32 filler, filler_type type) const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_filler: filler=%08x, type=%d\n", | ||||
|                                filler, type); | ||||
| 
 | ||||
|             png_set_filler(m_png, filler, type); | ||||
|         } | ||||
| 
 | ||||
| #if !defined(PNG_1_0_X) | ||||
|         void set_add_alpha(uint_32 filler, filler_type type) const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_add_alpha: filler=%08x, type=%d\n", | ||||
|                                filler, type); | ||||
| 
 | ||||
|             png_set_add_alpha(m_png, filler, type); | ||||
|         } | ||||
| #endif | ||||
| #endif // PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED
 | ||||
| 
 | ||||
| #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) | ||||
|         void set_swap() const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_swap\n"); | ||||
|             png_set_swap(m_png); | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
| #if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) | ||||
|         void set_packing() const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_packing\n"); | ||||
|             png_set_packing(m_png); | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
| #if defined(PNG_READ_PACKSWAP_SUPPORTED) \ | ||||
|     || defined(PNG_WRITE_PACKSWAP_SUPPORTED) | ||||
|         void set_packswap() const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_packswap\n"); | ||||
|             png_set_packswap(m_png); | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
| #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) | ||||
|         void set_shift(byte red_bits, byte green_bits, byte blue_bits, | ||||
|                        byte alpha_bits = 0) const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_shift: red_bits=%d, green_bits=%d," | ||||
|                                " blue_bits=%d, alpha_bits=%d\n", | ||||
|                                red_bits, green_bits, blue_bits, alpha_bits); | ||||
| 
 | ||||
|             if (get_color_type() != color_type_rgb | ||||
|                 || get_color_type() != color_type_rgb_alpha) | ||||
|             { | ||||
|                 throw error("set_shift: expected RGB or RGBA color type"); | ||||
|             } | ||||
|             color_info bits; | ||||
|             bits.red = red_bits; | ||||
|             bits.green = green_bits; | ||||
|             bits.blue = blue_bits; | ||||
|             bits.alpha = alpha_bits; | ||||
|             png_set_shift(m_png, & bits); | ||||
|         } | ||||
| 
 | ||||
|         void set_shift(byte gray_bits, byte alpha_bits = 0) const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_shift: gray_bits=%d, alpha_bits=%d\n", | ||||
|                                gray_bits, alpha_bits); | ||||
| 
 | ||||
|             if (get_color_type() != color_type_gray | ||||
|                 || get_color_type() != color_type_gray_alpha) | ||||
|             { | ||||
|                 throw error("set_shift: expected Gray or Gray+Alpha color type"); | ||||
|             } | ||||
|             color_info bits; | ||||
|             bits.gray = gray_bits; | ||||
|             bits.alpha = alpha_bits; | ||||
|             png_set_shift(m_png, & bits); | ||||
|         } | ||||
| #endif // PNG_READ_SHIFT_SUPPORTED || PNG_WRITE_SHIFT_SUPPORTED
 | ||||
| 
 | ||||
| #if defined(PNG_READ_INTERLACING_SUPPORTED) \ | ||||
|     || defined(PNG_WRITE_INTERLACING_SUPPORTED) | ||||
|         int set_interlace_handling() const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_interlace_handling\n"); | ||||
|             return png_set_interlace_handling(m_png); | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
| #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) | ||||
|         void set_invert_mono() const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_invert_mono\n"); | ||||
|             png_set_invert_mono(m_png); | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
| #if defined(PNG_READ_16_TO_8_SUPPORTED) | ||||
|         void set_strip_16() const | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_strip_16\n"); | ||||
|             png_set_strip_16(m_png); | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
| #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) | ||||
|         void set_read_user_transform(png_user_transform_ptr transform_fn) | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_read_user_transform_fn\n"); | ||||
|             png_set_read_user_transform_fn(m_png, transform_fn); | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
| #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) \ | ||||
|     || defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) | ||||
|         void set_user_transform_info(void* info, int bit_depth, int channels) | ||||
|         { | ||||
|             TRACE_IO_TRANSFORM("png_set_user_transform_info: bit_depth=%d," | ||||
|                                " channels=%d\n", bit_depth, channels); | ||||
| 
 | ||||
|             png_set_user_transform_info(m_png, info, bit_depth, channels); | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
|     protected: | ||||
|         void* get_io_ptr() const | ||||
|         { | ||||
|             return png_get_io_ptr(m_png); | ||||
|         } | ||||
| 
 | ||||
|         void set_error(char const* message) | ||||
|         { | ||||
|             assert(message); | ||||
|             m_error = message; | ||||
|         } | ||||
| 
 | ||||
|         void reset_error() | ||||
|         { | ||||
|             m_error.clear(); | ||||
|         } | ||||
| 
 | ||||
| /*
 | ||||
|         std::string const& get_error() const | ||||
|         { | ||||
|             return m_error; | ||||
|         } | ||||
| */ | ||||
| 
 | ||||
|         bool is_error() const | ||||
|         { | ||||
|             return !m_error.empty(); | ||||
|         } | ||||
| 
 | ||||
|         void raise_error() | ||||
|         { | ||||
|             longjmp(png_jmpbuf(m_png), -1); | ||||
|         } | ||||
| 
 | ||||
|         static void raise_error(png_struct* png, char const* message) | ||||
|         { | ||||
|             io_base* io = static_cast< io_base* >(png_get_error_ptr(png)); | ||||
|             io->set_error(message); | ||||
|             io->raise_error(); | ||||
|         } | ||||
| 
 | ||||
|         png_struct* m_png; | ||||
|         info m_info; | ||||
|         end_info m_end_info; | ||||
|         std::string m_error; | ||||
|     }; | ||||
| 
 | ||||
| } // namespace png
 | ||||
| 
 | ||||
| #endif // PNGPP_IO_BASE_HPP_INCLUDED
 | ||||
|  | @ -1,35 +0,0 @@ | |||
| Libpng 1.6.34 - September 29, 2017 | ||||
| 
 | ||||
| This is a public release of libpng, intended for use in production codes. | ||||
| 
 | ||||
| Files available for download: | ||||
| 
 | ||||
| Source files with LF line endings (for Unix/Linux) and with a | ||||
| "configure" script | ||||
| 
 | ||||
|    libpng-1.6.34.tar.xz (LZMA-compressed, recommended) | ||||
|    libpng-1.6.34.tar.gz | ||||
| 
 | ||||
| Source files with CRLF line endings (for Windows), without the | ||||
| "configure" script | ||||
| 
 | ||||
|    lpng1634.7z  (LZMA-compressed, recommended) | ||||
|    lpng1634.zip | ||||
| 
 | ||||
| Other information: | ||||
| 
 | ||||
|    libpng-1.6.34-README.txt | ||||
|    libpng-1.6.34-LICENSE.txt | ||||
|    libpng-1.6.34-*.asc (armored detached GPG signatures) | ||||
| 
 | ||||
| Changes since the last public release (1.6.33): | ||||
|   Removed contrib/pngsuite/i*.png; some of these were incorrect and caused | ||||
|     test failures. | ||||
| 
 | ||||
| Send comments/corrections/commendations to png-mng-implement at lists.sf.net | ||||
| (subscription required; visit | ||||
| https://lists.sourceforge.net/lists/listinfo/png-mng-implement | ||||
| to subscribe) | ||||
| or to glennrp at users.sourceforge.net | ||||
| 
 | ||||
| Glenn R-P | ||||
|  | @ -1,937 +0,0 @@ | |||
| # CMakeLists.txt | ||||
| 
 | ||||
| # Copyright (C) 2007,2009-2017 Glenn Randers-Pehrson | ||||
| # Written by Christian Ehrlicher, 2007 | ||||
| # Revised by Roger Lowman, 2009-2010 | ||||
| # Revised by Clifford Yapp, 2011-2012 | ||||
| # Revised by Roger Leigh, 2016 | ||||
| # Revised by Andreas Franek, 2016 | ||||
| 
 | ||||
| # This code is released under the libpng license. | ||||
| # For conditions of distribution and use, see the disclaimer | ||||
| # and license in png.h | ||||
| 
 | ||||
| cmake_minimum_required(VERSION 3.0.2) | ||||
| cmake_policy(VERSION 3.0.2) | ||||
| 
 | ||||
| # Set MacOSX @rpath usage globally. | ||||
| if (POLICY CMP0020) | ||||
|   cmake_policy(SET CMP0020 NEW) | ||||
| endif(POLICY CMP0020) | ||||
| if (POLICY CMP0042) | ||||
|   cmake_policy(SET CMP0042 NEW) | ||||
| endif(POLICY CMP0042) | ||||
| # Use new variable expansion policy. | ||||
| if (POLICY CMP0053) | ||||
|   cmake_policy(SET CMP0053 NEW) | ||||
| endif(POLICY CMP0053) | ||||
| if (POLICY CMP0054) | ||||
|   cmake_policy(SET CMP0054 NEW) | ||||
| endif(POLICY CMP0054) | ||||
| 
 | ||||
| set(CMAKE_CONFIGURATION_TYPES "Release;Debug;MinSizeRel;RelWithDebInfo") | ||||
| 
 | ||||
| project(libpng ASM C) | ||||
| 
 | ||||
| set(PNGLIB_MAJOR 1) | ||||
| set(PNGLIB_MINOR 6) | ||||
| set(PNGLIB_RELEASE 34) | ||||
| set(PNGLIB_NAME libpng${PNGLIB_MAJOR}${PNGLIB_MINOR}) | ||||
| set(PNGLIB_VERSION ${PNGLIB_MAJOR}.${PNGLIB_MINOR}.${PNGLIB_RELEASE}) | ||||
| 
 | ||||
| # needed packages | ||||
| 
 | ||||
| #Allow users to specify location of Zlib, | ||||
| # Useful if zlib is being built alongside this as a sub-project | ||||
| 
 | ||||
| set(PNG_BUILD_ZLIB ${CMAKE_CURRENT_SOURCE_DIR}/zlib) | ||||
| 
 | ||||
| if(NOT WIN32) | ||||
|   find_library(M_LIBRARY | ||||
|     NAMES m | ||||
|     PATHS /usr/lib /usr/local/lib | ||||
|   ) | ||||
|   if(NOT M_LIBRARY) | ||||
|     message(STATUS "math lib 'libm' not found; floating point support disabled") | ||||
|   endif() | ||||
| else() | ||||
|   # not needed on windows | ||||
|   set(M_LIBRARY "") | ||||
| endif() | ||||
| 
 | ||||
| # COMMAND LINE OPTIONS | ||||
| option(PNG_SHARED "Build shared lib" OFF) | ||||
| option(PNG_STATIC "Build static lib" ON) | ||||
| option(PNG_TESTS  "Build libpng tests" OFF) | ||||
| 
 | ||||
| # Many more configuration options could be added here | ||||
| option(PNG_FRAMEWORK "Build OS X framework" OFF) | ||||
| option(PNG_DEBUG     "Build with debug output" OFF) | ||||
| option(PNGARG        "Disable ANSI-C prototypes" OFF) | ||||
| 
 | ||||
| option(PNG_HARDWARE_OPTIMIZATIONS "Enable Hardware Optimizations" ON) | ||||
| 
 | ||||
| set(PNG_PREFIX "" CACHE STRING "Prefix to add to the API function names") | ||||
| set(DFA_XTRA "" CACHE FILEPATH "File containing extra configuration settings") | ||||
| 
 | ||||
| if(PNG_HARDWARE_OPTIMIZATIONS) | ||||
| # set definitions and sources for arm | ||||
| if(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm" OR | ||||
|   CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64") | ||||
|   set(PNG_ARM_NEON_POSSIBLE_VALUES check on off) | ||||
|   set(PNG_ARM_NEON "check" CACHE STRING "Enable ARM NEON optimizations: | ||||
|      check: (default) use internal checking code; | ||||
|      off: disable the optimizations; | ||||
|      on: turn on unconditionally.") | ||||
|   set_property(CACHE PNG_ARM_NEON PROPERTY STRINGS | ||||
|      ${PNG_ARM_NEON_POSSIBLE_VALUES}) | ||||
|   list(FIND PNG_ARM_NEON_POSSIBLE_VALUES ${PNG_ARM_NEON} index) | ||||
|   if(index EQUAL -1) | ||||
|     message(FATAL_ERROR | ||||
|       " PNG_ARM_NEON must be one of [${PNG_ARM_NEON_POSSIBLE_VALUES}]") | ||||
|   elseif(NOT ${PNG_ARM_NEON} STREQUAL "no") | ||||
|     set(libpng_arm_sources | ||||
|       arm/arm_init.c | ||||
|       arm/filter_neon.S | ||||
|       arm/filter_neon_intrinsics.c) | ||||
| 
 | ||||
|     if(${PNG_ARM_NEON} STREQUAL "on") | ||||
|       add_definitions(-DPNG_ARM_NEON_OPT=2) | ||||
|     elseif(${PNG_ARM_NEON} STREQUAL "check") | ||||
|       add_definitions(-DPNG_ARM_NEON_CHECK_SUPPORTED) | ||||
|     endif() | ||||
|   else() | ||||
|     add_definitions(-DPNG_ARM_NEON_OPT=0) | ||||
|   endif() | ||||
| endif() | ||||
| 
 | ||||
| # set definitions and sources for powerpc | ||||
| if(CMAKE_SYSTEM_PROCESSOR MATCHES "^powerpc*" OR | ||||
|   CMAKE_SYSTEM_PROCESSOR MATCHES "^ppc64*" ) | ||||
|   set(PNG_POWERPC_VSX_POSSIBLE_VALUES on off) | ||||
|   set(PNG_POWERPC_VSX "on" CACHE STRING "Enable POWERPC VSX optimizations: | ||||
|      off: disable the optimizations.") | ||||
|   set_property(CACHE PNG_POWERPC_VSX PROPERTY STRINGS | ||||
|      ${PNG_POWERPC_VSX_POSSIBLE_VALUES}) | ||||
|   list(FIND PNG_POWERPC_VSX_POSSIBLE_VALUES ${PNG_POWERPC_VSX} index) | ||||
|   if(index EQUAL -1) | ||||
|     message(FATAL_ERROR | ||||
|       " PNG_POWERPC_VSX must be one of [${PNG_POWERPC_VSX_POSSIBLE_VALUES}]") | ||||
|   elseif(NOT ${PNG_POWERPC_VSX} STREQUAL "no") | ||||
|     set(libpng_powerpc_sources | ||||
|       powerpc/powerpc_init.c | ||||
|       powerpc/filter_vsx_intrinsics.c) | ||||
|     if(${PNG_POWERPC_VSX} STREQUAL "on") | ||||
|       add_definitions(-DPNG_POWERPC_VSX_OPT=2) | ||||
|     endif() | ||||
|   else() | ||||
|     add_definitions(-DPNG_POWERPC_VSX_OPT=0) | ||||
|   endif() | ||||
| endif() | ||||
| 
 | ||||
| # set definitions and sources for intel | ||||
| if(CMAKE_SYSTEM_PROCESSOR MATCHES "^i?86" OR | ||||
|   CMAKE_SYSTEM_PROCESSOR MATCHES "^x86_64*" ) | ||||
|   set(PNG_INTEL_SSE_POSSIBLE_VALUES on off) | ||||
|   set(PNG_INTEL_SSE "on" CACHE STRING "Enable INTEL_SSE optimizations: | ||||
|      off: disable the optimizations") | ||||
|   set_property(CACHE PNG_INTEL_SSE PROPERTY STRINGS | ||||
|      ${PNG_INTEL_SSE_POSSIBLE_VALUES}) | ||||
|   list(FIND PNG_INTEL_SSE_POSSIBLE_VALUES ${PNG_INTEL_SSE} index) | ||||
|   if(index EQUAL -1) | ||||
|     message(FATAL_ERROR | ||||
|       " PNG_INTEL_SSE must be one of [${PNG_INTEL_SSE_POSSIBLE_VALUES}]") | ||||
|   elseif(NOT ${PNG_INTEL_SSE} STREQUAL "no") | ||||
|     set(libpng_intel_sources | ||||
|       intel/intel_init.c | ||||
|       intel/filter_sse2_intrinsics.c) | ||||
|     if(${PNG_INTEL_SSE} STREQUAL "on") | ||||
|       add_definitions(-DPNG_INTEL_SSE_OPT=1) | ||||
|     endif() | ||||
|   else() | ||||
|     add_definitions(-DPNG_INTEL_SSE_OPT=0) | ||||
|   endif() | ||||
| endif() | ||||
| 
 | ||||
| # set definitions and sources for MIPS | ||||
| if(CMAKE_SYSTEM_PROCESSOR MATCHES "mipsel*" OR | ||||
|   CMAKE_SYSTEM_PROCESSOR MATCHES "mips64el*" ) | ||||
|   set(PNG_MIPS_MSA_POSSIBLE_VALUES on off) | ||||
|   set(PNG_MIPS_MSA "on" CACHE STRING "Enable MIPS_MSA optimizations: | ||||
|      off: disable the optimizations") | ||||
|   set_property(CACHE PNG_MIPS_MSA PROPERTY STRINGS | ||||
|      ${PNG_MIPS_MSA_POSSIBLE_VALUES}) | ||||
|   list(FIND PNG_MIPS_MSA_POSSIBLE_VALUES ${PNG_MIPS_MSA} index) | ||||
|   if(index EQUAL -1) | ||||
|     message(FATAL_ERROR | ||||
|       " PNG_MIPS_MSA must be one of [${PNG_MIPS_MSA_POSSIBLE_VALUES}]") | ||||
|   elseif(NOT ${PNG_MIPS_MSA} STREQUAL "no") | ||||
|     set(libpng_mips_sources | ||||
|       mips/mips_init.c | ||||
|       mips/filter_msa_intrinsics.c) | ||||
|     if(${PNG_MIPS_MSA} STREQUAL "on") | ||||
|       add_definitions(-DPNG_MIPS_MSA_OPT=2) | ||||
|     endif() | ||||
|   else() | ||||
|     add_definitions(-DPNG_MIPS_MSA_OPT=0) | ||||
|   endif() | ||||
| endif() | ||||
| endif(PNG_HARDWARE_OPTIMIZATIONS) | ||||
| 
 | ||||
| # SET LIBNAME | ||||
| set(PNG_LIB_NAME png${PNGLIB_MAJOR}${PNGLIB_MINOR}) | ||||
| 
 | ||||
| # to distinguish between debug and release lib | ||||
| set(CMAKE_DEBUG_POSTFIX "d") | ||||
| 
 | ||||
| include(CheckCSourceCompiles) | ||||
| option(ld-version-script "Enable linker version script" ON) | ||||
| if(ld-version-script AND NOT APPLE) | ||||
|   # Check if LD supports linker scripts. | ||||
|   file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/conftest.map" "VERS_1 { | ||||
|         global: sym; | ||||
|         local: *; | ||||
| }; | ||||
| 
 | ||||
| VERS_2 { | ||||
|         global: sym2; | ||||
|                 main; | ||||
| } VERS_1; | ||||
| ") | ||||
|   set(CMAKE_REQUIRED_FLAGS_SAVE ${CMAKE_REQUIRED_FLAGS}) | ||||
|   set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} "-Wl,--version-script='${CMAKE_CURRENT_BINARY_DIR}/conftest.map'") | ||||
|   check_c_source_compiles("void sym(void) {} | ||||
| void sym2(void) {} | ||||
| int main(void) {return 0;} | ||||
| " HAVE_LD_VERSION_SCRIPT) | ||||
|   if(NOT HAVE_LD_VERSION_SCRIPT) | ||||
|     set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS_SAVE} "-Wl,-M -Wl,${CMAKE_CURRENT_BINARY_DIR}/conftest.map") | ||||
|   check_c_source_compiles("void sym(void) {} | ||||
| void sym2(void) {} | ||||
| int main(void) {return 0;} | ||||
| " HAVE_SOLARIS_LD_VERSION_SCRIPT) | ||||
|   endif() | ||||
|   set(CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS_SAVE}) | ||||
|   file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/conftest.map") | ||||
| endif() | ||||
| 
 | ||||
| # Find symbol prefix.  Likely obsolete and unnecessary with recent | ||||
| # toolchains (it's not done in many other projects). | ||||
| function(symbol_prefix) | ||||
|   set(SYMBOL_PREFIX) | ||||
| 
 | ||||
|   execute_process(COMMAND "${CMAKE_C_COMPILER}" "-E" "-" | ||||
|                   INPUT_FILE /dev/null | ||||
|                   OUTPUT_VARIABLE OUT | ||||
|                   RESULT_VARIABLE STATUS) | ||||
| 
 | ||||
|   if(CPP_FAIL) | ||||
|     message(WARNING "Failed to run the C preprocessor") | ||||
|   endif() | ||||
| 
 | ||||
|   string(REPLACE "\n" ";" OUT "${OUT}") | ||||
|   foreach(line ${OUT}) | ||||
|     string(REGEX MATCH "^PREFIX=" found_match "${line}") | ||||
|     if(found_match) | ||||
|       STRING(REGEX REPLACE "^PREFIX=(.*\)" "\\1" prefix "${line}") | ||||
|       string(REGEX MATCH "__USER_LABEL_PREFIX__" found_match "${prefix}") | ||||
|       if(found_match) | ||||
|         STRING(REGEX REPLACE "(.*)__USER_LABEL_PREFIX__(.*)" "\\1\\2" prefix "${prefix}") | ||||
|       endif() | ||||
|       set(SYMBOL_PREFIX "${prefix}") | ||||
|     endif() | ||||
|   endforeach() | ||||
| 
 | ||||
|     message(STATUS "Symbol prefix: ${SYMBOL_PREFIX}") | ||||
|     set(SYMBOL_PREFIX "${SYMBOL_PREFIX}" PARENT_SCOPE) | ||||
| endfunction() | ||||
| 
 | ||||
| if(UNIX) | ||||
|   symbol_prefix() | ||||
| endif() | ||||
| 
 | ||||
| find_program(AWK NAMES gawk awk) | ||||
| 
 | ||||
| include_directories(${CMAKE_CURRENT_BINARY_DIR}) | ||||
| 
 | ||||
| if(NOT AWK OR ANDROID) | ||||
|   # No awk available to generate sources; use pre-built pnglibconf.h | ||||
|   configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt | ||||
|                  ${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h) | ||||
|   add_custom_target(genfiles) # Dummy | ||||
| else() | ||||
|   include(CMakeParseArguments) | ||||
|   # Generate .chk from .out with awk | ||||
|   # generate_chk(INPUT inputfile OUTPUT outputfile [DEPENDS dep1 [dep2...]]) | ||||
|   function(generate_chk) | ||||
|     set(options) | ||||
|     set(oneValueArgs INPUT OUTPUT) | ||||
|     set(multiValueArgs DEPENDS) | ||||
|     cmake_parse_arguments(_GC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) | ||||
|     if (NOT _GC_INPUT) | ||||
|       message(FATAL_ERROR "Invalid arguments.  generate_out requires input.") | ||||
|     endif() | ||||
|     if (NOT _GC_OUTPUT) | ||||
|       message(FATAL_ERROR "Invalid arguments.  generate_out requires output.") | ||||
|     endif() | ||||
| 
 | ||||
|     add_custom_command(OUTPUT "${_GC_OUTPUT}" | ||||
|                        COMMAND "${CMAKE_COMMAND}" | ||||
|                                "-DINPUT=${_GC_INPUT}" | ||||
|                                "-DOUTPUT=${_GC_OUTPUT}" | ||||
|                                -P "${CMAKE_CURRENT_BINARY_DIR}/scripts/genchk.cmake" | ||||
|                        DEPENDS "${_GC_INPUT}" ${_GC_DEPENDS} | ||||
|                        WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") | ||||
|   endfunction() | ||||
| 
 | ||||
|   # Generate .out from .c with awk | ||||
|   # generate_out(INPUT inputfile OUTPUT outputfile [DEPENDS dep1 [dep2...]]) | ||||
|   function(generate_out) | ||||
|     set(options) | ||||
|     set(oneValueArgs INPUT OUTPUT) | ||||
|     set(multiValueArgs DEPENDS) | ||||
|     cmake_parse_arguments(_GO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) | ||||
|     if (NOT _GO_INPUT) | ||||
|       message(FATAL_ERROR "Invalid arguments.  generate_out requires input.") | ||||
|     endif() | ||||
|     if (NOT _GO_OUTPUT) | ||||
|       message(FATAL_ERROR "Invalid arguments.  generate_out requires output.") | ||||
|     endif() | ||||
| 
 | ||||
|     add_custom_command(OUTPUT "${_GO_OUTPUT}" | ||||
|                        COMMAND "${CMAKE_COMMAND}" | ||||
|                                "-DINPUT=${_GO_INPUT}" | ||||
|                                "-DOUTPUT=${_GO_OUTPUT}" | ||||
|                                -P "${CMAKE_CURRENT_BINARY_DIR}/scripts/genout.cmake" | ||||
|                        DEPENDS "${_GO_INPUT}" ${_GO_DEPENDS} | ||||
|                        WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") | ||||
|   endfunction() | ||||
| 
 | ||||
|   # Generate specific source file with awk | ||||
|   # generate_source(OUTPUT outputfile [DEPENDS dep1 [dep2...]]) | ||||
|   function(generate_source) | ||||
|     set(options) | ||||
|     set(oneValueArgs OUTPUT) | ||||
|     set(multiValueArgs DEPENDS) | ||||
|     cmake_parse_arguments(_GSO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) | ||||
|     if (NOT _GSO_OUTPUT) | ||||
|       message(FATAL_ERROR "Invalid arguments.  generate_source requires output.") | ||||
|     endif() | ||||
| 
 | ||||
|     add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${_GSO_OUTPUT}" | ||||
|                        COMMAND "${CMAKE_COMMAND}" | ||||
|                                "-DOUTPUT=${_GSO_OUTPUT}" | ||||
|                                -P "${CMAKE_CURRENT_BINARY_DIR}/scripts/gensrc.cmake" | ||||
|                        DEPENDS ${_GSO_DEPENDS} | ||||
|                        WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") | ||||
|   endfunction() | ||||
| 
 | ||||
|   # Copy file | ||||
|   function(generate_copy source destination) | ||||
|     add_custom_command(OUTPUT "${destination}" | ||||
|                        COMMAND "${CMAKE_COMMAND}" -E remove "${destination}" | ||||
|                        COMMAND "${CMAKE_COMMAND}" -E copy "${source}" | ||||
|                                                           "${destination}" | ||||
|                        DEPENDS "${source}") | ||||
|   endfunction() | ||||
| 
 | ||||
|   # Generate scripts/pnglibconf.h | ||||
|   generate_source(OUTPUT "scripts/pnglibconf.c" | ||||
|                   DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.dfa" | ||||
|                           "${CMAKE_CURRENT_SOURCE_DIR}/scripts/options.awk" | ||||
|                           "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h") | ||||
| 
 | ||||
|   # Generate pnglibconf.c | ||||
|   generate_source(OUTPUT "pnglibconf.c" | ||||
|                   DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.dfa" | ||||
|                           "${CMAKE_CURRENT_SOURCE_DIR}/scripts/options.awk" | ||||
|                           "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h") | ||||
| 
 | ||||
|   if(PNG_PREFIX) | ||||
|     set(PNGLIBCONF_H_EXTRA_DEPENDS | ||||
|         "${CMAKE_CURRENT_BINARY_DIR}/scripts/prefix.out" | ||||
|         "${CMAKE_CURRENT_SOURCE_DIR}/scripts/macro.lst") | ||||
|     set(PNGPREFIX_H_EXTRA_DEPENDS | ||||
|         "${CMAKE_CURRENT_BINARY_DIR}/scripts/intprefix.out") | ||||
|   endif() | ||||
| 
 | ||||
|   generate_out(INPUT "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.c" | ||||
|                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.out") | ||||
| 
 | ||||
|   # Generate pnglibconf.h | ||||
|   generate_source(OUTPUT "pnglibconf.h" | ||||
|                   DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.out" | ||||
|                           ${PNGLIBCONF_H_EXTRA_DEPENDS}) | ||||
| 
 | ||||
|   generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/intprefix.c" | ||||
|                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/intprefix.out" | ||||
|                DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h") | ||||
| 
 | ||||
|   generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/prefix.c" | ||||
|                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/prefix.out" | ||||
|                DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/png.h" | ||||
|                        "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h" | ||||
|                        "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.out") | ||||
| 
 | ||||
|   # Generate pngprefix.h | ||||
|   generate_source(OUTPUT "pngprefix.h" | ||||
|                   DEPENDS ${PNGPREFIX_H_EXTRA_DEPENDS}) | ||||
| 
 | ||||
|   generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/sym.c" | ||||
|                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/sym.out" | ||||
|                DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h") | ||||
| 
 | ||||
|   generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/symbols.c" | ||||
|                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.out" | ||||
|                DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/png.h" | ||||
|                        "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h" | ||||
|                        "${CMAKE_CURRENT_SOURCE_DIR}/scripts/pnglibconf.h.prebuilt") | ||||
| 
 | ||||
|   generate_out(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/scripts/vers.c" | ||||
|                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/vers.out" | ||||
|                DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/png.h" | ||||
|                        "${CMAKE_CURRENT_SOURCE_DIR}/pngconf.h" | ||||
|                        "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h") | ||||
| 
 | ||||
|   generate_chk(INPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.out" | ||||
|                OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.chk" | ||||
|                DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/checksym.awk" | ||||
|                        "${CMAKE_CURRENT_SOURCE_DIR}/scripts/symbols.def") | ||||
| 
 | ||||
|   add_custom_target(symbol-check DEPENDS | ||||
|                     "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.chk") | ||||
| 
 | ||||
|   generate_copy("${CMAKE_CURRENT_BINARY_DIR}/scripts/sym.out" | ||||
|                 "${CMAKE_CURRENT_BINARY_DIR}/libpng.sym") | ||||
|   generate_copy("${CMAKE_CURRENT_BINARY_DIR}/scripts/vers.out" | ||||
|                 "${CMAKE_CURRENT_BINARY_DIR}/libpng.vers") | ||||
| 
 | ||||
|   add_custom_target(genvers DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/libpng.vers") | ||||
|   add_custom_target(gensym DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/libpng.sym") | ||||
| 
 | ||||
|   add_custom_target("genprebuilt" | ||||
|                     COMMAND "${CMAKE_COMMAND}" | ||||
|                             "-DOUTPUT=scripts/pnglibconf.h.prebuilt" | ||||
|                             -P "${CMAKE_CURRENT_BINARY_DIR}/scripts/gensrc.cmake" | ||||
|                     WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") | ||||
| 
 | ||||
|   # A single target handles generation of all generated files.  If | ||||
|   # they are dependend upon separately by multiple targets, this | ||||
|   # confuses parallel make (it would require a separate top-level | ||||
|   # target for each file to track the dependencies properly). | ||||
|   add_custom_target(genfiles DEPENDS | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/libpng.sym" | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/libpng.vers" | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.c" | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h" | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.out" | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/pngprefix.h" | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/scripts/intprefix.out" | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/scripts/pnglibconf.c" | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/scripts/prefix.out" | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/scripts/sym.out" | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.chk" | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/scripts/symbols.out" | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/scripts/vers.out") | ||||
| endif(NOT AWK OR ANDROID) | ||||
| 
 | ||||
| # OUR SOURCES | ||||
| set(libpng_public_hdrs | ||||
|   png.h | ||||
|   pngconf.h | ||||
|   "${CMAKE_CURRENT_BINARY_DIR}/pnglibconf.h" | ||||
| ) | ||||
| set(libpng_private_hdrs | ||||
|   pngpriv.h | ||||
|   pngdebug.h | ||||
|   pnginfo.h | ||||
|   pngstruct.h | ||||
| ) | ||||
| if(AWK AND NOT ANDROID) | ||||
|   list(APPEND libpng_private_hdrs "${CMAKE_CURRENT_BINARY_DIR}/pngprefix.h") | ||||
| endif() | ||||
| set(libpng_sources | ||||
|   ${libpng_public_hdrs} | ||||
|   ${libpng_private_hdrs} | ||||
|   png.c | ||||
|   pngerror.c | ||||
|   pngget.c | ||||
|   pngmem.c | ||||
|   pngpread.c | ||||
|   pngread.c | ||||
|   pngrio.c | ||||
|   pngrtran.c | ||||
|   pngrutil.c | ||||
|   pngset.c | ||||
|   pngtrans.c | ||||
|   pngwio.c | ||||
|   pngwrite.c | ||||
|   pngwtran.c | ||||
|   pngwutil.c | ||||
|   ${libpng_arm_sources} | ||||
|   ${libpng_intel_sources} | ||||
|   ${libpng_mips_sources} | ||||
|   ${libpng_powerpc_sources} | ||||
| ) | ||||
| set(pngtest_sources | ||||
|   pngtest.c | ||||
| ) | ||||
| set(pngvalid_sources | ||||
|   contrib/libtests/pngvalid.c | ||||
| ) | ||||
| set(pngstest_sources | ||||
|   contrib/libtests/pngstest.c | ||||
| ) | ||||
| set(pngunknown_sources | ||||
|   contrib/libtests/pngunknown.c | ||||
| ) | ||||
| set(pngimage_sources | ||||
|   contrib/libtests/pngimage.c | ||||
| ) | ||||
| set(pngfix_sources | ||||
|   contrib/tools/pngfix.c | ||||
| ) | ||||
| set(png_fix_itxt_sources | ||||
|   contrib/tools/png-fix-itxt.c | ||||
| ) | ||||
| 
 | ||||
| if(MSVC) | ||||
|   add_definitions(-D_CRT_SECURE_NO_DEPRECATE) | ||||
| endif(MSVC) | ||||
| 
 | ||||
| if(PNG_DEBUG) | ||||
|   add_definitions(-DPNG_DEBUG) | ||||
| endif() | ||||
| 
 | ||||
| # NOW BUILD OUR TARGET | ||||
| include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${ZLIB_INCLUDE_DIR}) | ||||
| 
 | ||||
| unset(PNG_LIB_TARGETS) | ||||
| 
 | ||||
| if(PNG_SHARED) | ||||
|   add_library(png SHARED ${libpng_sources}) | ||||
|   set(PNG_LIB_TARGETS png) | ||||
|   set_target_properties(png PROPERTIES OUTPUT_NAME ${PNG_LIB_NAME}) | ||||
|   add_dependencies(png genfiles) | ||||
|   if(MSVC) | ||||
|     # msvc does not append 'lib' - do it here to have consistent name | ||||
|     set_target_properties(png PROPERTIES PREFIX "lib") | ||||
|     set_target_properties(png PROPERTIES IMPORT_PREFIX "lib") | ||||
|   endif() | ||||
|   target_link_libraries(png ${ZLIB_LIBRARY} ${M_LIBRARY}) | ||||
| 
 | ||||
|   if(UNIX AND AWK) | ||||
|     if(HAVE_LD_VERSION_SCRIPT) | ||||
|       set_target_properties(png PROPERTIES LINK_FLAGS | ||||
|         "-Wl,--version-script='${CMAKE_CURRENT_BINARY_DIR}/libpng.vers'") | ||||
|     elseif(HAVE_SOLARIS_LD_VERSION_SCRIPT) | ||||
|       set_target_properties(png PROPERTIES LINK_FLAGS | ||||
|         "-Wl,-M -Wl,'${CMAKE_CURRENT_BINARY_DIR}/libpng.vers'") | ||||
|     endif() | ||||
|   endif() | ||||
| endif() | ||||
| 
 | ||||
| if(PNG_STATIC) | ||||
|   # does not work without changing name | ||||
|   set(PNG_LIB_NAME_STATIC png_static) | ||||
|   add_library(png_static STATIC ${libpng_sources}) | ||||
|   add_dependencies(png_static genfiles) | ||||
|   # MSVC doesn't use a different file extension for shared vs. static | ||||
|   # libs.  We are able to change OUTPUT_NAME to remove the _static | ||||
|   # for all other platforms. | ||||
|   if(NOT MSVC) | ||||
|     set_target_properties(png_static PROPERTIES | ||||
|       OUTPUT_NAME "${PNG_LIB_NAME}" | ||||
|       CLEAN_DIRECT_OUTPUT 1) | ||||
|   else() | ||||
|     set_target_properties(png_static PROPERTIES | ||||
|       OUTPUT_NAME "${PNG_LIB_NAME}_static" | ||||
|       CLEAN_DIRECT_OUTPUT 1) | ||||
|   endif() | ||||
|   list(APPEND PNG_LIB_TARGETS png_static) | ||||
|   if(MSVC) | ||||
|     # msvc does not append 'lib' - do it here to have consistent name | ||||
|     set_target_properties(png_static PROPERTIES PREFIX "lib") | ||||
|   endif() | ||||
|   target_link_libraries(png_static ${ZLIB_LIBRARY} ${M_LIBRARY}) | ||||
| endif() | ||||
| 
 | ||||
| if(PNG_FRAMEWORK) | ||||
|   set(PNG_LIB_NAME_FRAMEWORK png_framework) | ||||
|   add_library(png_framework SHARED ${libpng_sources}) | ||||
|   add_dependencies(png_framework genfiles) | ||||
|   list(APPEND PNG_LIB_TARGETS png_framework) | ||||
|   set_target_properties(png_framework PROPERTIES | ||||
|     FRAMEWORK TRUE | ||||
|     FRAMEWORK_VERSION ${PNGLIB_VERSION} | ||||
|     MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PNGLIB_MAJOR}.${PNGLIB_MINOR} | ||||
|     MACOSX_FRAMEWORK_BUNDLE_VERSION ${PNGLIB_VERSION} | ||||
|     MACOSX_FRAMEWORK_IDENTIFIER org.libpng.libpng | ||||
|     XCODE_ATTRIBUTE_INSTALL_PATH "@rpath" | ||||
|     PUBLIC_HEADER "${libpng_public_hdrs}" | ||||
|     OUTPUT_NAME png) | ||||
|   target_link_libraries(png_framework ${ZLIB_LIBRARY} ${M_LIBRARY}) | ||||
| endif() | ||||
| 
 | ||||
| if(NOT PNG_LIB_TARGETS) | ||||
|   message(SEND_ERROR | ||||
|     "No library variant selected to build. " | ||||
|     "Please enable at least one of the following options: " | ||||
|     " PNG_STATIC, PNG_SHARED, PNG_FRAMEWORK") | ||||
| endif() | ||||
| 
 | ||||
| if(PNG_SHARED AND WIN32) | ||||
|   set_target_properties(png PROPERTIES DEFINE_SYMBOL PNG_BUILD_DLL) | ||||
| endif() | ||||
| 
 | ||||
| function(png_add_test) | ||||
|   set(options) | ||||
|   set(oneValueArgs NAME COMMAND) | ||||
|   set(multiValueArgs OPTIONS FILES) | ||||
|   cmake_parse_arguments(_PAT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) | ||||
| 
 | ||||
|   if (NOT _PAT_NAME) | ||||
|     message(FATAL_ERROR "Invalid arguments.  png_add_test requires name.") | ||||
|   endif() | ||||
|   if (NOT _PAT_COMMAND) | ||||
|     message(FATAL_ERROR "Invalid arguments.  png_add_test requires command.") | ||||
|   endif() | ||||
| 
 | ||||
|   set(TEST_OPTIONS "${_PAT_OPTIONS}") | ||||
|   set(TEST_FILES "${_PAT_FILES}") | ||||
| 
 | ||||
|   configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scripts/test.cmake.in" | ||||
|                  "${CMAKE_CURRENT_BINARY_DIR}/tests/${_PAT_NAME}.cmake" @ONLY) | ||||
|   if(CMAKE_MAJOR_VERSION GREATER 2) # have generator expressions | ||||
|     add_test(NAME "${_PAT_NAME}" | ||||
|              COMMAND "${CMAKE_COMMAND}" | ||||
|              "-DLIBPNG=$<TARGET_FILE:png>" | ||||
|              "-DTEST_COMMAND=$<TARGET_FILE:${_PAT_COMMAND}>" | ||||
|              -P "${CMAKE_CURRENT_BINARY_DIR}/tests/${_PAT_NAME}.cmake") | ||||
|   else() # old 2.x add_test; limited and won't work well on Windows | ||||
|     # Note LIBPNG is a dummy value as there are no generator expressions | ||||
|     add_test("${_PAT_NAME}" "${CMAKE_COMMAND}" | ||||
|              "-DLIBPNG=${CMAKE_CURRENT_BINARY_DIR}/libpng.so" | ||||
|              "-DTEST_COMMAND=./${_PAT_COMMAND}" | ||||
|              -P "${CMAKE_CURRENT_BINARY_DIR}/tests/${_PAT_NAME}.cmake") | ||||
|   endif() | ||||
| endfunction() | ||||
| 
 | ||||
| if(PNG_TESTS AND PNG_SHARED) | ||||
|   # Find test PNG files by globbing, but sort lists to ensure | ||||
|   # consistency between different filesystems. | ||||
|   file(GLOB PNGSUITE_PNGS "${CMAKE_CURRENT_SOURCE_DIR}/contrib/pngsuite/*.png") | ||||
|   list(SORT PNGSUITE_PNGS) | ||||
|   file(GLOB TEST_PNGS "${CMAKE_CURRENT_SOURCE_DIR}/contrib/testpngs/*.png") | ||||
|   list(SORT TEST_PNGS) | ||||
| 
 | ||||
|   set(PNGTEST_PNG "${CMAKE_CURRENT_SOURCE_DIR}/pngtest.png") | ||||
| 
 | ||||
|   add_executable(pngtest ${pngtest_sources}) | ||||
|   target_link_libraries(pngtest png) | ||||
| 
 | ||||
|   png_add_test(NAME pngtest COMMAND pngtest FILES "${PNGTEST_PNG}") | ||||
| 
 | ||||
|   add_executable(pngvalid ${pngvalid_sources}) | ||||
|   target_link_libraries(pngvalid png) | ||||
| 
 | ||||
|   png_add_test(NAME pngvalid-gamma-16-to-8 | ||||
|                COMMAND pngvalid OPTIONS --gamma-16-to-8) | ||||
|   png_add_test(NAME pngvalid-gamma-alpha-mode | ||||
|                COMMAND pngvalid OPTIONS --gamma-alpha-mode) | ||||
|   png_add_test(NAME pngvalid-gamma-background | ||||
|                COMMAND pngvalid OPTIONS --gamma-background) | ||||
|   png_add_test(NAME pngvalid-gamma-expand16-alpha-mode | ||||
|                COMMAND pngvalid OPTIONS --gamma-alpha-mode --expand16) | ||||
|   png_add_test(NAME pngvalid-gamma-expand16-background | ||||
|                COMMAND pngvalid OPTIONS --gamma-background --expand16) | ||||
|   png_add_test(NAME pngvalid-gamma-expand16-transform | ||||
|                COMMAND pngvalid OPTIONS --gamma-transform --expand16) | ||||
|   png_add_test(NAME pngvalid-gamma-sbit | ||||
|                COMMAND pngvalid OPTIONS --gamma-sbit) | ||||
|   png_add_test(NAME pngvalid-gamma-threshold | ||||
|                COMMAND pngvalid OPTIONS --gamma-threshold) | ||||
|   png_add_test(NAME pngvalid-gamma-transform | ||||
|                COMMAND pngvalid OPTIONS --gamma-transform) | ||||
|   png_add_test(NAME pngvalid-progressive-interlace-standard | ||||
|                COMMAND pngvalid OPTIONS --standard --progressive-read --interlace) | ||||
|   png_add_test(NAME pngvalid-progressive-size | ||||
|                COMMAND pngvalid OPTIONS --size --progressive-read) | ||||
|   png_add_test(NAME pngvalid-progressive-standard | ||||
|                COMMAND pngvalid OPTIONS --standard --progressive-read) | ||||
|   png_add_test(NAME pngvalid-standard | ||||
|                COMMAND pngvalid OPTIONS --standard) | ||||
|   png_add_test(NAME pngvalid-transform | ||||
|                COMMAND pngvalid OPTIONS --transform) | ||||
| 
 | ||||
|   add_executable(pngstest ${pngstest_sources}) | ||||
|   target_link_libraries(pngstest png) | ||||
| 
 | ||||
|   foreach(gamma_type 1.8 linear none sRGB) | ||||
|     foreach(alpha_type none alpha) | ||||
|       set(PNGSTEST_FILES) | ||||
|       foreach(test_png ${TEST_PNGS}) | ||||
|         string(REGEX MATCH ".*-linear[-.].*" TEST_PNG_LINEAR "${test_png}") | ||||
|         string(REGEX MATCH ".*-sRGB[-.].*" TEST_PNG_SRGB "${test_png}") | ||||
|         string(REGEX MATCH ".*-1.8[-.].*" TEST_PNG_G18 "${test_png}") | ||||
|         string(REGEX MATCH ".*-alpha-.*" TEST_PNG_ALPHA "${test_png}") | ||||
| 
 | ||||
|         set(TEST_PNG_VALID TRUE) | ||||
| 
 | ||||
|         if(TEST_PNG_ALPHA) | ||||
|           if (NOT "${alpha_type}" STREQUAL "alpha") | ||||
|             set(TEST_PNG_VALID FALSE) | ||||
|           endif() | ||||
|         else() | ||||
|           if ("${alpha_type}" STREQUAL "alpha") | ||||
|             set(TEST_PNG_VALID FALSE) | ||||
|           endif() | ||||
|         endif() | ||||
| 
 | ||||
|         if(TEST_PNG_LINEAR) | ||||
|           if(NOT "${gamma_type}" STREQUAL "linear") | ||||
|             set(TEST_PNG_VALID FALSE) | ||||
|           endif() | ||||
|         elseif(TEST_PNG_SRGB) | ||||
|           if(NOT "${gamma_type}" STREQUAL "sRGB") | ||||
|             set(TEST_PNG_VALID FALSE) | ||||
|           endif() | ||||
|         elseif(TEST_PNG_G18) | ||||
|           if(NOT "${gamma_type}" STREQUAL "1.8") | ||||
|             set(TEST_PNG_VALID FALSE) | ||||
|           endif() | ||||
|         else() | ||||
|           if(NOT "${gamma_type}" STREQUAL "none") | ||||
|             set(TEST_PNG_VALID FALSE) | ||||
|           endif() | ||||
|         endif() | ||||
| 
 | ||||
|         if(TEST_PNG_VALID) | ||||
|           list(APPEND PNGSTEST_FILES "${test_png}") | ||||
|         endif() | ||||
|       endforeach() | ||||
|       # Should already be sorted, but sort anyway to be certain. | ||||
|       list(SORT PNGSTEST_FILES) | ||||
|       png_add_test(NAME pngstest-${gamma_type}-${alpha_type} | ||||
|                    COMMAND pngstest | ||||
|                    OPTIONS --tmpfile "${gamma_type}-${alpha_type}-" --log | ||||
|                    FILES ${PNGSTEST_FILES}) | ||||
|     endforeach() | ||||
|   endforeach() | ||||
| 
 | ||||
|   add_executable(pngunknown ${pngunknown_sources}) | ||||
|   target_link_libraries(pngunknown png) | ||||
| 
 | ||||
|   png_add_test(NAME pngunknown-discard COMMAND pngunknown OPTIONS --strict default=discard FILES "${PNGTEST_PNG}") | ||||
|   png_add_test(NAME pngunknown-IDAT COMMAND pngunknown OPTIONS --strict default=discard IDAT=save FILES "${PNGTEST_PNG}") | ||||
|   png_add_test(NAME pngunknown-if-safe COMMAND pngunknown OPTIONS --strict default=if-safe FILES "${PNGTEST_PNG}") | ||||
|   png_add_test(NAME pngunknown-sAPI COMMAND pngunknown OPTIONS --strict bKGD=save cHRM=save gAMA=save all=discard iCCP=save sBIT=save sRGB=save FILES "${PNGTEST_PNG}") | ||||
|   png_add_test(NAME pngunknown-save COMMAND pngunknown OPTIONS --strict default=save FILES "${PNGTEST_PNG}") | ||||
|   png_add_test(NAME pngunknown-sTER COMMAND pngunknown OPTIONS --strict sTER=if-safe FILES "${PNGTEST_PNG}") | ||||
|   png_add_test(NAME pngunknown-vpAg COMMAND pngunknown OPTIONS --strict vpAg=if-safe FILES "${PNGTEST_PNG}") | ||||
| 
 | ||||
|   add_executable(pngimage ${pngimage_sources}) | ||||
|   target_link_libraries(pngimage png) | ||||
| 
 | ||||
|   png_add_test(NAME pngimage-quick COMMAND pngimage OPTIONS --list-combos --log FILES ${PNGSUITE_PNGS}) | ||||
|   png_add_test(NAME pngimage-full COMMAND pngimage OPTIONS --exhaustive --list-combos --log FILES ${PNGSUITE_PNGS}) | ||||
| endif() | ||||
| 
 | ||||
| if(PNG_SHARED) | ||||
|   add_executable(pngfix ${pngfix_sources}) | ||||
|   target_link_libraries(pngfix png) | ||||
|   set(PNG_BIN_TARGETS pngfix) | ||||
| 
 | ||||
|   add_executable(png-fix-itxt ${png_fix_itxt_sources}) | ||||
|   target_link_libraries(png-fix-itxt ${ZLIB_LIBRARY} ${M_LIBRARY}) | ||||
|   list(APPEND PNG_BIN_TARGETS png-fix-itxt) | ||||
| endif() | ||||
| 
 | ||||
| # Set a variable with CMake code which: | ||||
| # Creates a symlink from src to dest (if possible) or alternatively | ||||
| # copies if different. | ||||
| include(CMakeParseArguments) | ||||
| 
 | ||||
| function(CREATE_SYMLINK DEST_FILE) | ||||
| 
 | ||||
|   cmake_parse_arguments(S "" "FILE;TARGET" "" ${ARGN}) | ||||
| 
 | ||||
|   if(NOT S_TARGET AND NOT S_FILE) | ||||
|     message(FATAL_ERROR "Specify either a TARGET or a FILE for CREATE_SYMLINK to link to.") | ||||
|   endif(NOT S_TARGET AND NOT S_FILE) | ||||
| 
 | ||||
|   if(S_TARGET AND S_FILE) | ||||
|     message(FATAL_ERROR "CREATE_SYMLINK called with both source file ${S_FILE} and build target ${S_TARGET} arguments - can only handle 1 type per call.") | ||||
|   endif(S_TARGET AND S_FILE) | ||||
| 
 | ||||
|   if(S_FILE) | ||||
|     # If we don't need to symlink something that's coming from a build target, | ||||
|     # we can go ahead and symlink/copy at configure time. | ||||
| 
 | ||||
|     if(CMAKE_HOST_WIN32 AND NOT CYGWIN AND NOT MSYS) | ||||
|       execute_process( | ||||
|   COMMAND "${CMAKE_COMMAND}" -E copy_if_different ${S_FILE} ${DEST_FILE} | ||||
|   WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" | ||||
|   ) | ||||
|     else(CMAKE_HOST_WIN32 AND NOT CYGWIN AND NOT MSYS) | ||||
|       execute_process( | ||||
|   COMMAND ${CMAKE_COMMAND} -E create_symlink ${S_FILE} ${DEST_FILE} | ||||
|   WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" | ||||
|   ) | ||||
|     endif(CMAKE_HOST_WIN32 AND NOT CYGWIN AND NOT MSYS) | ||||
|   endif(S_FILE) | ||||
| 
 | ||||
|   if(S_TARGET) | ||||
|     # We need to use generator expressions, which can be a bit tricky, so for | ||||
|     # simplicity make the symlink a POST_BUILD step and use the TARGET | ||||
|     # signature of add_custom_command. | ||||
| 
 | ||||
|     if(CMAKE_HOST_WIN32 AND NOT CYGWIN AND NOT MSYS) | ||||
|       add_custom_command(TARGET ${S_TARGET} POST_BUILD | ||||
|   COMMAND "${CMAKE_COMMAND}" -E copy_if_different $<TARGET_LINKER_FILE_NAME:${S_TARGET}> $<TARGET_LINKER_FILE_DIR:${S_TARGET}>/${DEST_FILE} | ||||
|   ) | ||||
|     else(CMAKE_HOST_WIN32 AND NOT CYGWIN AND NOT MSYS) | ||||
|       add_custom_command(TARGET ${S_TARGET} POST_BUILD | ||||
|   COMMAND "${CMAKE_COMMAND}" -E create_symlink $<TARGET_LINKER_FILE_NAME:${S_TARGET}> $<TARGET_LINKER_FILE_DIR:${S_TARGET}>/${DEST_FILE} | ||||
|   ) | ||||
|     endif(CMAKE_HOST_WIN32 AND NOT CYGWIN AND NOT MSYS) | ||||
| 
 | ||||
|   endif(S_TARGET) | ||||
| 
 | ||||
| endfunction() | ||||
| 
 | ||||
| # Create source generation scripts. | ||||
| configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/genchk.cmake.in | ||||
|                ${CMAKE_CURRENT_BINARY_DIR}/scripts/genchk.cmake @ONLY) | ||||
| configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/genout.cmake.in | ||||
|                ${CMAKE_CURRENT_BINARY_DIR}/scripts/genout.cmake @ONLY) | ||||
| configure_file(${CMAKE_CURRENT_SOURCE_DIR}/scripts/gensrc.cmake.in | ||||
|                ${CMAKE_CURRENT_BINARY_DIR}/scripts/gensrc.cmake @ONLY) | ||||
| 
 | ||||
| 
 | ||||
| # libpng is a library so default to 'lib' | ||||
| if(NOT DEFINED CMAKE_INSTALL_LIBDIR) | ||||
|   set(CMAKE_INSTALL_LIBDIR lib) | ||||
| endif(NOT DEFINED CMAKE_INSTALL_LIBDIR) | ||||
| 
 | ||||
| # CREATE PKGCONFIG FILES | ||||
| # we use the same files like ./configure, so we have to set its vars | ||||
| # Only do this on Windows for Cygwin - the files don't make much sense outside | ||||
| # a UNIX look alike | ||||
| if(NOT WIN32 OR CYGWIN OR MINGW) | ||||
|   set(prefix      ${CMAKE_INSTALL_PREFIX}) | ||||
|   set(exec_prefix ${CMAKE_INSTALL_PREFIX}) | ||||
|   set(libdir      ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}) | ||||
|   set(includedir  ${CMAKE_INSTALL_PREFIX}/include) | ||||
|   set(LIBS        "-lz -lm") | ||||
|   configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libpng.pc.in | ||||
|     ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}.pc @ONLY) | ||||
|   CREATE_SYMLINK(libpng.pc FILE ${PNGLIB_NAME}.pc) | ||||
| 
 | ||||
|   configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libpng-config.in | ||||
|     ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config @ONLY) | ||||
|   CREATE_SYMLINK(libpng-config FILE ${PNGLIB_NAME}-config) | ||||
| endif(NOT WIN32 OR CYGWIN OR MINGW) | ||||
| 
 | ||||
| # SET UP LINKS | ||||
| if(PNG_SHARED) | ||||
|   set_target_properties(png PROPERTIES | ||||
| #   VERSION 16.${PNGLIB_RELEASE}.1.6.34 | ||||
|     VERSION 16.${PNGLIB_RELEASE}.0 | ||||
|     SOVERSION 16 | ||||
|     CLEAN_DIRECT_OUTPUT 1) | ||||
| endif() | ||||
| 
 | ||||
| # If CMake > 2.4.x, we set a variable used below to export | ||||
| # targets to an export file. | ||||
| # TODO: Use VERSION_GREATER after our cmake_minimum_required >= 2.6.2 | ||||
| if(CMAKE_MAJOR_VERSION GREATER 1 AND CMAKE_MINOR_VERSION GREATER 4) | ||||
|   set(PNG_EXPORT_RULE EXPORT libpng) | ||||
| elseif(CMAKE_MAJOR_VERSION GREATER 2) # future proof | ||||
|   set(PNG_EXPORT_RULE EXPORT libpng) | ||||
| endif() | ||||
| 
 | ||||
| # INSTALL | ||||
| if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) | ||||
|   install(TARGETS ${PNG_LIB_TARGETS} | ||||
|       ${PNG_EXPORT_RULE} | ||||
|       RUNTIME DESTINATION bin | ||||
|       LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||||
|       ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||||
|       FRAMEWORK DESTINATION ${CMAKE_INSTALL_LIBDIR}) | ||||
| 
 | ||||
|   if(PNG_SHARED) | ||||
|     # Create a symlink for libpng.dll.a => libpng16.dll.a on Cygwin | ||||
|     if(CYGWIN OR MINGW) | ||||
|       CREATE_SYMLINK(libpng${CMAKE_IMPORT_LIBRARY_SUFFIX} TARGET png) | ||||
|       install(FILES $<TARGET_LINKER_FILE_DIR:png>/libpng${CMAKE_IMPORT_LIBRARY_SUFFIX} DESTINATION ${CMAKE_INSTALL_LIBDIR}) | ||||
|     endif(CYGWIN OR MINGW) | ||||
| 
 | ||||
|     if(NOT WIN32) | ||||
|       CREATE_SYMLINK(libpng${CMAKE_SHARED_LIBRARY_SUFFIX} TARGET png) | ||||
|       install(FILES $<TARGET_LINKER_FILE_DIR:png>/libpng${CMAKE_SHARED_LIBRARY_SUFFIX} DESTINATION ${CMAKE_INSTALL_LIBDIR}) | ||||
|     endif(NOT WIN32) | ||||
|   endif(PNG_SHARED) | ||||
| 
 | ||||
|   if(PNG_STATIC) | ||||
|     if(NOT WIN32 OR CYGWIN OR MINGW) | ||||
|       CREATE_SYMLINK( libpng${CMAKE_STATIC_LIBRARY_SUFFIX} TARGET png_static) | ||||
|       install(FILES $<TARGET_LINKER_FILE_DIR:png_static>/libpng${CMAKE_STATIC_LIBRARY_SUFFIX} DESTINATION ${CMAKE_INSTALL_LIBDIR}) | ||||
|     endif(NOT WIN32 OR CYGWIN OR MINGW) | ||||
|  endif() | ||||
| endif() | ||||
| 
 | ||||
| if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL ) | ||||
|   install(FILES ${libpng_public_hdrs}   DESTINATION include) | ||||
|   install(FILES ${libpng_public_hdrs}   DESTINATION include/${PNGLIB_NAME}) | ||||
| endif() | ||||
| if(NOT SKIP_INSTALL_EXECUTABLES AND NOT SKIP_INSTALL_ALL ) | ||||
|   if(NOT WIN32 OR CYGWIN OR MINGW) | ||||
|     install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libpng-config DESTINATION bin) | ||||
|     install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config | ||||
|             DESTINATION bin) | ||||
|   endif(NOT WIN32 OR CYGWIN OR MINGW) | ||||
| endif() | ||||
| 
 | ||||
| if(NOT SKIP_INSTALL_PROGRAMS AND NOT SKIP_INSTALL_ALL ) | ||||
|   install(TARGETS ${PNG_BIN_TARGETS} | ||||
|       RUNTIME DESTINATION bin) | ||||
| endif() | ||||
| 
 | ||||
| if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) | ||||
|   # Install man pages | ||||
|   if(NOT PNG_MAN_DIR) | ||||
|     set(PNG_MAN_DIR "share/man") | ||||
|   endif() | ||||
|   install(FILES libpng.3 libpngpf.3      DESTINATION ${PNG_MAN_DIR}/man3) | ||||
|   install(FILES png.5                    DESTINATION ${PNG_MAN_DIR}/man5) | ||||
|   # Install pkg-config files | ||||
|   if(NOT CMAKE_HOST_WIN32 OR CYGWIN OR MINGW) | ||||
|     install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libpng.pc | ||||
|             DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) | ||||
|     install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/libpng-config | ||||
|             DESTINATION bin) | ||||
|     install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}.pc | ||||
|             DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) | ||||
|     install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${PNGLIB_NAME}-config | ||||
|             DESTINATION bin) | ||||
|   endif(NOT CMAKE_HOST_WIN32 OR CYGWIN OR MINGW) | ||||
| endif() | ||||
| 
 | ||||
| # On versions of CMake that support it, create an export file CMake | ||||
| # users can include() to import our targets | ||||
| if(PNG_EXPORT_RULE AND NOT SKIP_INSTALL_EXPORT AND NOT SKIP_INSTALL_ALL ) | ||||
|   install(EXPORT libpng DESTINATION lib/libpng FILE lib${PNG_LIB_NAME}.cmake) | ||||
| endif() | ||||
| 
 | ||||
| # what's with libpng-manual.txt and all the extra files? | ||||
| 
 | ||||
| # UNINSTALL | ||||
| # do we need this? | ||||
| 
 | ||||
| # DIST | ||||
| # do we need this? | ||||
| 
 | ||||
| # to create msvc import lib for mingw compiled shared lib | ||||
| # pexports libpng.dll > libpng.def | ||||
| # lib /def:libpng.def /machine:x86 | ||||
 bubnikv
						bubnikv