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.
|
||||
![Slic3rPE logo](/resources/icons/Slic3r.png?raw=true)
|
||||
|
||||
# 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.0 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
|