Merge remote-tracking branch 'origin/master' into ys_unsaved_changes
This commit is contained in:
commit
4d053cc4ee
148 changed files with 13789 additions and 3328 deletions
CMakeLists.txt
deps
resources
icons
PrusaSlicer-gcodeviewer.icoPrusaSlicerGCodeViewer_128px.pngnotification_close.svgnotification_close_hover.svgnotification_error.svgnotification_minimalize.svgnotification_minimalize_hover.svgnotification_warning.svgseam.svgthumb_left.svgthumb_right.svg
shaders
sandboxes/opencsg
src
CMakeLists.txtPrusaSlicer.cppPrusaSlicer_app_msvc.cpp
clipper
imgui
libslic3r
CMakeLists.txtClipperUtils.cppCustomGCode.cppExtrusionEntity.cppExtrusionEntity.hpp
Format
GCode.cppGCode.hppGCode
Analyzer.cppAnalyzer.hppGCodeProcessor.cppGCodeProcessor.hppPreviewData.cppPreviewData.hppWipeTower.cpp
GCodeReader.cppGCodeReader.hppGCodeTimeEstimator.cppGCodeTimeEstimator.hppModel.cppModel.hppPNGRead.cppPNGRead.hppPreset.cppPreset.hppPrint.cppPrint.hppPrintBase.hppPrintConfig.cppPrintConfig.hppPrintObject.cppSLA
SLAPrint.cppSupportMaterial.cppTechnologies.hppTriangleSelector.cppTriangleSelector.hppUtils.hppplatform/msw
slic3r
CMakeLists.txt
GUI
3DBed.cpp3DBed.hpp3DScene.cpp3DScene.hppBackgroundSlicingProcess.cppBackgroundSlicingProcess.hppBitmapCache.cppCamera.cppCamera.hppConfigWizard.cppConfigWizard_private.hppDoubleSlider.cppDoubleSlider.hppGCodeViewer.cppGCodeViewer.hppGLCanvas3D.cppGLCanvas3D.hppGLModel.cppGLModel.hppGLShader.cppGLShader.hppGLShadersManager.cppGLShadersManager.hppGLToolbar.cppGLToolbar.hppGUI.cppGUI.hpp
|
@ -35,6 +35,11 @@ option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
|
|||
|
||||
set(SLIC3R_GTK "2" CACHE STRING "GTK version to use with wxWidgets on Linux")
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_FIND_FRAMEWORK LAST)
|
||||
set(CMAKE_FIND_APPBUNDLE LAST)
|
||||
endif ()
|
||||
|
||||
# Proposal for C++ unit tests and sandboxes
|
||||
option(SLIC3R_BUILD_SANDBOXES "Build development sandboxes" OFF)
|
||||
option(SLIC3R_BUILD_TESTS "Build unit tests" ON)
|
||||
|
@ -386,7 +391,7 @@ if (NOT EXPAT_FOUND)
|
|||
set(EXPAT_LIBRARIES expat)
|
||||
endif ()
|
||||
|
||||
find_package(PNG)
|
||||
find_package(PNG REQUIRED)
|
||||
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
|
|
9
deps/deps-linux.cmake
vendored
9
deps/deps-linux.cmake
vendored
|
@ -3,10 +3,11 @@ set(DEP_CMAKE_OPTS "-DCMAKE_POSITION_INDEPENDENT_CODE=ON")
|
|||
|
||||
include("deps-unix-common.cmake")
|
||||
|
||||
find_package(PNG QUIET)
|
||||
if (NOT PNG_FOUND)
|
||||
message(WARNING "No PNG dev package found in system, building static library. You should install the system package.")
|
||||
endif ()
|
||||
# Some Linuxes may have very old libpng, so it's best to bundle it instead of relying on the system version.
|
||||
# find_package(PNG QUIET)
|
||||
# if (NOT PNG_FOUND)
|
||||
# message(WARNING "No PNG dev package found in system, building static library. You should install the system package.")
|
||||
# endif ()
|
||||
|
||||
#TODO UDEV
|
||||
|
||||
|
|
BIN
resources/icons/PrusaSlicer-gcodeviewer.ico
Normal file
BIN
resources/icons/PrusaSlicer-gcodeviewer.ico
Normal file
Binary file not shown.
After (image error) Size: 111 KiB |
BIN
resources/icons/PrusaSlicerGCodeViewer_128px.png
Normal file
BIN
resources/icons/PrusaSlicerGCodeViewer_128px.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 16 KiB |
18
resources/icons/notification_close.svg
Normal file
18
resources/icons/notification_close.svg
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.0" id="close_window" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
|
||||
y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#ED6B21" d="M80,92.83H20c-7.08,0-12.83-5.76-12.83-12.84V20c0-7.08,5.76-12.83,12.83-12.83h60
|
||||
c7.08,0,12.84,5.76,12.84,12.83v60C92.83,87.08,87.08,92.83,80,92.83z M20,12.83c-3.95,0-7.17,3.21-7.17,7.17v60
|
||||
c0,3.95,3.21,7.17,7.17,7.17h60c3.95,0,7.17-3.21,7.17-7.17V20c0-3.95-3.21-7.17-7.17-7.17H20z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#ED6B21" d="M70,75.67c-1.45,0-2.9-0.55-4.01-1.66l-40-40c-2.21-2.21-2.21-5.8,0-8.02s5.8-2.21,8.02,0l40,40
|
||||
c2.21,2.21,2.21,5.8,0,8.02C72.9,75.12,71.45,75.67,70,75.67z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#ED6B21" d="M30,75.67c-1.45,0-2.9-0.55-4.01-1.66c-2.21-2.21-2.21-5.8,0-8.02l40-40c2.21-2.21,5.8-2.21,8.02,0
|
||||
c2.21,2.21,2.21,5.8,0,8.02l-40,40C32.9,75.12,31.45,75.67,30,75.67z"/>
|
||||
</g>
|
||||
</svg>
|
After (image error) Size: 1 KiB |
66
resources/icons/notification_close_hover.svg
Normal file
66
resources/icons/notification_close_hover.svg
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
sodipodi:docname="notification_close_hover.svg"
|
||||
xml:space="preserve"
|
||||
enable-background="new 0 0 100 100"
|
||||
viewBox="0 0 100 100"
|
||||
y="0px"
|
||||
x="0px"
|
||||
id="close_window"
|
||||
version="1.0"><metadata
|
||||
id="metadata19"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs17" /><sodipodi:namedview
|
||||
inkscape:current-layer="close_window"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:cy="50"
|
||||
inkscape:cx="50"
|
||||
inkscape:zoom="10.08"
|
||||
showgrid="false"
|
||||
id="namedview15"
|
||||
inkscape:window-height="1377"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
guidetolerance="10"
|
||||
gridtolerance="10"
|
||||
objecttolerance="10"
|
||||
borderopacity="1"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff" />
|
||||
<g
|
||||
transform="matrix(1.15,0,0,1.15,-7.50075,-7.5)"
|
||||
id="g4">
|
||||
<path
|
||||
id="path2"
|
||||
d="M 80,92.83 H 20 C 12.92,92.83 7.17,87.07 7.17,79.99 V 20 C 7.17,12.92 12.93,7.17 20,7.17 h 60 c 7.08,0 12.84,5.76 12.84,12.83 V 80 C 92.83,87.08 87.08,92.83 80,92.83 Z m -60,-80 c -3.95,0 -7.17,3.21 -7.17,7.17 v 60 c 0,3.95 3.21,7.17 7.17,7.17 h 60 c 3.95,0 7.17,-3.21 7.17,-7.17 V 20 c 0,-3.95 -3.21,-7.17 -7.17,-7.17 z"
|
||||
fill="#ED6B21" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(1.15,0,0,1.15,-7.50075,-7.5)"
|
||||
id="g8">
|
||||
<path
|
||||
id="path6"
|
||||
d="m 70,75.67 c -1.45,0 -2.9,-0.55 -4.01,-1.66 l -40,-40 c -2.21,-2.21 -2.21,-5.8 0,-8.02 2.21,-2.22 5.8,-2.21 8.02,0 l 40,40 c 2.21,2.21 2.21,5.8 0,8.02 -1.11,1.11 -2.56,1.66 -4.01,1.66 z"
|
||||
fill="#ED6B21" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(1.15,0,0,1.15,-7.50075,-7.5)"
|
||||
id="g12">
|
||||
<path
|
||||
id="path10"
|
||||
d="m 30,75.67 c -1.45,0 -2.9,-0.55 -4.01,-1.66 -2.21,-2.21 -2.21,-5.8 0,-8.02 l 40,-40 c 2.21,-2.21 5.8,-2.21 8.02,0 2.21,2.21 2.21,5.8 0,8.02 l -40,40 C 32.9,75.12 31.45,75.67 30,75.67 Z"
|
||||
fill="#ED6B21" />
|
||||
</g>
|
||||
</svg>
|
After (image error) Size: 2.4 KiB |
71
resources/icons/notification_error.svg
Normal file
71
resources/icons/notification_error.svg
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.0"
|
||||
id="error"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 200 200"
|
||||
enable-background="new 0 0 100 100"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="notification_error.svg"
|
||||
width="200"
|
||||
height="200"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"><metadata
|
||||
id="metadata19"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs17" /><sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1377"
|
||||
id="namedview15"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.04"
|
||||
inkscape:cx="117.17146"
|
||||
inkscape:cy="98.609664"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="error" />
|
||||
<g
|
||||
id="g4"
|
||||
transform="matrix(2.52,0,0,2.52,-26,-26)">
|
||||
<path
|
||||
fill="#ed6b21"
|
||||
d="m 50,54.25 c -2.35,0 -4.25,-1.9 -4.25,-4.25 V 35 c 0,-2.35 1.9,-4.25 4.25,-4.25 2.35,0 4.25,1.9 4.25,4.25 v 15 c 0,2.35 -1.9,4.25 -4.25,4.25 z"
|
||||
id="path2" />
|
||||
</g>
|
||||
<g
|
||||
id="g8"
|
||||
transform="matrix(2.52,0,0,2.52,-26,-26)">
|
||||
<circle
|
||||
fill="#ed6b21"
|
||||
cx="50"
|
||||
cy="65"
|
||||
r="5"
|
||||
id="circle6" />
|
||||
</g>
|
||||
<g
|
||||
id="g12"
|
||||
transform="matrix(2.52,0,0,2.52,-26,-26)">
|
||||
<path
|
||||
fill="#ed6b21"
|
||||
d="M 50,89.25 C 28.36,89.25 10.75,71.64 10.75,50 10.75,28.36 28.36,10.75 50,10.75 71.64,10.75 89.25,28.36 89.25,50 89.25,71.64 71.64,89.25 50,89.25 Z m 0,-70 C 33.05,19.25 19.25,33.04 19.25,50 19.25,66.95 33.04,80.75 50,80.75 66.95,80.75 80.75,66.96 80.75,50 80.75,33.05 66.95,19.25 50,19.25 Z"
|
||||
id="path10" />
|
||||
</g>
|
||||
</svg>
|
After (image error) Size: 2.3 KiB |
14
resources/icons/notification_minimalize.svg
Normal file
14
resources/icons/notification_minimalize.svg
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.0" id="minimalize_window" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
|
||||
y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#ED6B21" d="M80,92.83H20c-7.08,0-12.83-5.76-12.83-12.84V20c0-7.08,5.76-12.83,12.83-12.83h60
|
||||
c7.08,0,12.84,5.76,12.84,12.83v60C92.83,87.08,87.08,92.83,80,92.83z M20,12.83c-3.95,0-7.17,3.21-7.17,7.17v60
|
||||
c0,3.95,3.21,7.17,7.17,7.17h60c3.95,0,7.17-3.21,7.17-7.17V20c0-3.95-3.21-7.17-7.17-7.17H20z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#ED6B21" d="M70,75.67H30c-3.13,0-5.67-2.54-5.67-5.67v-5c0-3.13,2.54-5.67,5.67-5.67h40c3.13,0,5.67,2.54,5.67,5.67v5
|
||||
C75.67,73.13,73.13,75.67,70,75.67z"/>
|
||||
</g>
|
||||
</svg>
|
After (image error) Size: 858 B |
58
resources/icons/notification_minimalize_hover.svg
Normal file
58
resources/icons/notification_minimalize_hover.svg
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
sodipodi:docname="notification_minimalize.svg"
|
||||
xml:space="preserve"
|
||||
enable-background="new 0 0 100 100"
|
||||
viewBox="0 0 100 100"
|
||||
y="0px"
|
||||
x="0px"
|
||||
id="minimalize_window"
|
||||
version="1.0"><metadata
|
||||
id="metadata15"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs13" /><sodipodi:namedview
|
||||
inkscape:current-layer="minimalize_window"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:cy="50"
|
||||
inkscape:cx="50"
|
||||
inkscape:zoom="10.08"
|
||||
showgrid="false"
|
||||
id="namedview11"
|
||||
inkscape:window-height="1377"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
guidetolerance="10"
|
||||
gridtolerance="10"
|
||||
objecttolerance="10"
|
||||
borderopacity="1"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff" />
|
||||
<g
|
||||
transform="matrix(1.15,0,0,1.15,-7.50075,-7.5)"
|
||||
id="g4">
|
||||
<path
|
||||
id="path2"
|
||||
d="M 80,92.83 H 20 C 12.92,92.83 7.17,87.07 7.17,79.99 V 20 C 7.17,12.92 12.93,7.17 20,7.17 h 60 c 7.08,0 12.84,5.76 12.84,12.83 V 80 C 92.83,87.08 87.08,92.83 80,92.83 Z m -60,-80 c -3.95,0 -7.17,3.21 -7.17,7.17 v 60 c 0,3.95 3.21,7.17 7.17,7.17 h 60 c 3.95,0 7.17,-3.21 7.17,-7.17 V 20 c 0,-3.95 -3.21,-7.17 -7.17,-7.17 z"
|
||||
fill="#ed6b21" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(1.15,0,0,1.15,-7.50075,-7.5)"
|
||||
id="g8">
|
||||
<path
|
||||
id="path6"
|
||||
d="M 70,75.67 H 30 c -3.13,0 -5.67,-2.54 -5.67,-5.67 v -5 c 0,-3.13 2.54,-5.67 5.67,-5.67 h 40 c 3.13,0 5.67,2.54 5.67,5.67 v 5 c 0,3.13 -2.54,5.67 -5.67,5.67 z"
|
||||
fill="#ed6b21" />
|
||||
</g>
|
||||
</svg>
|
After (image error) Size: 2.1 KiB |
70
resources/icons/notification_warning.svg
Normal file
70
resources/icons/notification_warning.svg
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
height="200"
|
||||
width="200"
|
||||
sodipodi:docname="notification_warning.svg"
|
||||
xml:space="preserve"
|
||||
enable-background="new 0 0 100 100"
|
||||
viewBox="0 0 200 200"
|
||||
y="0px"
|
||||
x="0px"
|
||||
id="warning"
|
||||
version="1.0"><metadata
|
||||
id="metadata19"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs17" /><sodipodi:namedview
|
||||
inkscape:current-layer="warning"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:cy="71.071558"
|
||||
inkscape:cx="34.775892"
|
||||
inkscape:zoom="3.5638182"
|
||||
showgrid="false"
|
||||
id="namedview15"
|
||||
inkscape:window-height="1377"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
guidetolerance="10"
|
||||
gridtolerance="10"
|
||||
objecttolerance="10"
|
||||
borderopacity="1"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff" />
|
||||
<g
|
||||
transform="matrix(2.2,0,0,2.2,-9.9977389,-10)"
|
||||
id="g4">
|
||||
<path
|
||||
id="path2"
|
||||
d="M 90,89.25 H 10 C 8.48,89.25 7.08,88.44 6.32,87.13 5.56,85.82 5.55,84.2 6.31,82.89 l 40,-70 c 0.76,-1.33 2.17,-2.14 3.69,-2.14 1.53,0 2.93,0.82 3.69,2.14 l 40,70 c 0.75,1.32 0.75,2.93 -0.01,4.24 -0.76,1.32 -2.16,2.12 -3.68,2.12 z M 17.33,80.75 H 82.68 L 50,23.57 Z"
|
||||
fill="#ed6b21" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(2.2,0,0,2.2,-9.9977389,-10)"
|
||||
id="g8">
|
||||
<path
|
||||
id="path6"
|
||||
d="m 50,59.25 c -2.35,0 -4.25,-1.9 -4.25,-4.25 V 40 c 0,-2.35 1.9,-4.25 4.25,-4.25 2.35,0 4.25,1.9 4.25,4.25 v 15 c 0,2.35 -1.9,4.25 -4.25,4.25 z"
|
||||
fill="#ed6b21" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(2.2,0,0,2.2,-9.9977389,-10)"
|
||||
id="g12">
|
||||
<circle
|
||||
id="circle10"
|
||||
r="5"
|
||||
cy="70"
|
||||
cx="50"
|
||||
fill="#ed6b21" />
|
||||
</g>
|
||||
</svg>
|
After (image error) Size: 2.2 KiB |
42
resources/icons/seam.svg
Normal file
42
resources/icons/seam.svg
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.2, 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 id="SLA_supports">
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M117.02,121.54H11.12c-1.93,0-3.5-1.57-3.5-3.5v-3.99c0-1.93,1.57-3.5,3.5-3.5h105.9
|
||||
c1.93,0,3.5,1.57,3.5,3.5v3.99C120.52,119.97,118.95,121.54,117.02,121.54z M11.12,113.55c-0.27,0-0.5,0.23-0.5,0.5v3.99
|
||||
c0,0.27,0.23,0.5,0.5,0.5h105.9c0.27,0,0.5-0.23,0.5-0.5v-3.99c0-0.27-0.23-0.5-0.5-0.5H11.12z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#ED6B21" d="M32.08,108.06c-0.83,0-1.5-0.67-1.5-1.5v-18.8c0-0.83,0.67-1.5,1.5-1.5s1.5,0.67,1.5,1.5v18.8
|
||||
C33.58,107.39,32.9,108.06,32.08,108.06z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#ED6B21" d="M48.02,108.06c-0.83,0-1.5-0.67-1.5-1.5v-8.14c0-0.83,0.67-1.5,1.5-1.5s1.5,0.67,1.5,1.5v8.14
|
||||
C49.52,107.39,48.85,108.06,48.02,108.06z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#ED6B21" d="M88.04,108.06c-0.83,0-1.5-0.67-1.5-1.5V93.09c0-0.83,0.67-1.5,1.5-1.5s1.5,0.67,1.5,1.5v13.47
|
||||
C89.54,107.39,88.87,108.06,88.04,108.06z"/>
|
||||
</g>
|
||||
<path fill="#FFFFFF" d="M70.36,95.12l-6.29,4.2l-14.45-9.63l-2.5,2.6l15.96,10.64c0.3,0.2,0.64,0.3,0.99,0.3s0.69-0.1,0.99-0.3
|
||||
l7.9-5.27L70.36,95.12z"/>
|
||||
<polygon fill="#FFFFFF" points="88.97,86.99 86.35,84.46 77.91,90.09 80.5,92.63 "/>
|
||||
<path fill="#FFFFFF" d="M103.99,35.1L65.05,9.14c-0.6-0.4-1.37-0.4-1.97,0L24.14,35.1c-0.49,0.33-0.79,0.88-0.79,1.48v38.91
|
||||
c0,0.59,0.3,1.15,0.79,1.48l15.47,10.32l2.5-2.6L26.9,74.54V37.53l37.16-24.78l37.16,24.78v37.01l-7.32,4.88l2.61,2.53l7.46-4.98
|
||||
c0.49-0.33,0.79-0.88,0.79-1.48V36.58C104.78,35.99,104.49,35.43,103.99,35.1z"/>
|
||||
<g>
|
||||
<path fill="#ED6B21" d="M96.16,108.06c-0.83,0-1.5-0.67-1.5-1.5V87.93L79,73.22c-0.6-0.57-0.63-1.52-0.07-2.12
|
||||
c0.57-0.6,1.52-0.63,2.12-0.07l16.13,15.15c0.3,0.28,0.47,0.68,0.47,1.09v19.27C97.66,107.39,96.99,108.06,96.16,108.06z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#ED6B21" d="M40.08,108.06c-0.83,0-1.5-0.67-1.5-1.5V93.29c0-0.39,0.15-0.76,0.41-1.04l16.13-16.91
|
||||
c0.57-0.6,1.52-0.62,2.12-0.05c0.6,0.57,0.62,1.52,0.05,2.12L41.58,93.89v12.67C41.58,107.39,40.91,108.06,40.08,108.06z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#ED6B21" d="M80.13,108.06c-0.83,0-1.5-0.67-1.5-1.5v-7.65L62.94,83.19c-0.59-0.59-0.58-1.54,0-2.12
|
||||
c0.59-0.58,1.54-0.59,2.12,0l16.13,16.15c0.28,0.28,0.44,0.66,0.44,1.06v8.27C81.63,107.39,80.96,108.06,80.13,108.06z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After (image error) Size: 2.5 KiB |
54
resources/icons/thumb_left.svg
Normal file
54
resources/icons/thumb_left.svg
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
sodipodi:docname="thumb_left.svg"
|
||||
xml:space="preserve"
|
||||
enable-background="new 0 0 16 16"
|
||||
viewBox="0 0 16 16"
|
||||
y="0px"
|
||||
x="0px"
|
||||
id="Layer_1"
|
||||
version="1.0"><metadata
|
||||
id="metadata32"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs30" /><sodipodi:namedview
|
||||
inkscape:current-layer="Layer_1"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-x="1268"
|
||||
inkscape:cy="8"
|
||||
inkscape:cx="8"
|
||||
inkscape:zoom="63"
|
||||
showgrid="false"
|
||||
id="namedview28"
|
||||
inkscape:window-height="1368"
|
||||
inkscape:window-width="1283"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
guidetolerance="10"
|
||||
gridtolerance="10"
|
||||
objecttolerance="10"
|
||||
borderopacity="1"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff" />
|
||||
<g
|
||||
transform="rotate(-90,8.0158731,7.984127)"
|
||||
id="hex_x5F_plus">
|
||||
<g
|
||||
id="g24">
|
||||
<polygon
|
||||
id="polygon22"
|
||||
style="stroke:#ffffff;stroke-width:1"
|
||||
points="15,7 15,5 8,0 1,5 1,7 1,8 15,8 "
|
||||
fill="#ed6b21" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After (image error) Size: 1.6 KiB |
54
resources/icons/thumb_right.svg
Normal file
54
resources/icons/thumb_right.svg
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
sodipodi:docname="thumb_right.svg"
|
||||
xml:space="preserve"
|
||||
enable-background="new 0 0 16 16"
|
||||
viewBox="0 0 16 16"
|
||||
y="0px"
|
||||
x="0px"
|
||||
id="Layer_1"
|
||||
version="1.0"><metadata
|
||||
id="metadata32"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs30" /><sodipodi:namedview
|
||||
inkscape:current-layer="Layer_1"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-x="1268"
|
||||
inkscape:cy="8"
|
||||
inkscape:cx="8"
|
||||
inkscape:zoom="63"
|
||||
showgrid="false"
|
||||
id="namedview28"
|
||||
inkscape:window-height="1368"
|
||||
inkscape:window-width="1283"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
guidetolerance="10"
|
||||
gridtolerance="10"
|
||||
objecttolerance="10"
|
||||
borderopacity="1"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff" />
|
||||
<g
|
||||
transform="matrix(0,-1,-1,0,16.012532,16)"
|
||||
id="hex_x5F_plus">
|
||||
<g
|
||||
id="g24">
|
||||
<polygon
|
||||
id="polygon22"
|
||||
style="stroke:#ffffff;stroke-width:1"
|
||||
points="15,8 15,7 15,5 8,0 1,5 1,7 1,8 "
|
||||
fill="#ed6b21" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After (image error) Size: 1.6 KiB |
11
resources/shaders/gouraud_light.fs
Normal file
11
resources/shaders/gouraud_light.fs
Normal file
|
@ -0,0 +1,11 @@
|
|||
#version 110
|
||||
|
||||
uniform vec4 uniform_color;
|
||||
|
||||
// x = tainted, y = specular;
|
||||
varying vec2 intensity;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + uniform_color.rgb * intensity.x, uniform_color.a);
|
||||
}
|
38
resources/shaders/gouraud_light.vs
Normal file
38
resources/shaders/gouraud_light.vs
Normal file
|
@ -0,0 +1,38 @@
|
|||
#version 110
|
||||
|
||||
#define INTENSITY_CORRECTION 0.6
|
||||
|
||||
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
|
||||
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
|
||||
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
|
||||
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
|
||||
#define LIGHT_TOP_SHININESS 20.0
|
||||
|
||||
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
|
||||
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
|
||||
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
|
||||
|
||||
#define INTENSITY_AMBIENT 0.3
|
||||
|
||||
// x = tainted, y = specular;
|
||||
varying vec2 intensity;
|
||||
|
||||
void main()
|
||||
{
|
||||
// First transform the normal into camera space and normalize the result.
|
||||
vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
|
||||
|
||||
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
|
||||
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
|
||||
float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0);
|
||||
|
||||
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
|
||||
vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz;
|
||||
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS);
|
||||
|
||||
// Perform the same lighting calculation for the 2nd light source (no specular applied).
|
||||
NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0);
|
||||
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
|
||||
|
||||
gl_Position = ftransform();
|
||||
}
|
8
resources/shaders/options_110.fs
Normal file
8
resources/shaders/options_110.fs
Normal file
|
@ -0,0 +1,8 @@
|
|||
#version 110
|
||||
|
||||
uniform vec4 uniform_color;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragColor = uniform_color;
|
||||
}
|
11
resources/shaders/options_110.vs
Normal file
11
resources/shaders/options_110.vs
Normal file
|
@ -0,0 +1,11 @@
|
|||
#version 110
|
||||
|
||||
uniform float zoom;
|
||||
uniform float point_size;
|
||||
uniform float near_plane_height;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = ftransform();
|
||||
gl_PointSize = (gl_Position.w == 1.0) ? zoom * near_plane_height * point_size : near_plane_height * point_size / gl_Position.w;
|
||||
}
|
22
resources/shaders/options_120.fs
Normal file
22
resources/shaders/options_120.fs
Normal file
|
@ -0,0 +1,22 @@
|
|||
// version 120 is needed for gl_PointCoord
|
||||
#version 120
|
||||
|
||||
uniform vec4 uniform_color;
|
||||
uniform float percent_outline_radius;
|
||||
uniform float percent_center_radius;
|
||||
|
||||
vec4 calc_color(float radius, vec4 color)
|
||||
{
|
||||
return ((radius < percent_center_radius) || (radius > 1.0 - percent_outline_radius)) ?
|
||||
vec4(0.5 * color.rgb, color.a) : color;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 pos = (gl_PointCoord - 0.5) * 2.0;
|
||||
float radius = length(pos);
|
||||
if (radius > 1.0)
|
||||
discard;
|
||||
|
||||
gl_FragColor = calc_color(radius, uniform_color);
|
||||
}
|
11
resources/shaders/options_120.vs
Normal file
11
resources/shaders/options_120.vs
Normal file
|
@ -0,0 +1,11 @@
|
|||
#version 120
|
||||
|
||||
uniform float zoom;
|
||||
uniform float point_size;
|
||||
uniform float near_plane_height;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = ftransform();
|
||||
gl_PointSize = (gl_Position.w == 1.0) ? zoom * near_plane_height * point_size : near_plane_height * point_size / gl_Position.w;
|
||||
}
|
28
resources/shaders/toolpaths_lines.fs
Normal file
28
resources/shaders/toolpaths_lines.fs
Normal file
|
@ -0,0 +1,28 @@
|
|||
#version 110
|
||||
|
||||
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
|
||||
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
|
||||
const vec3 LIGHT_FRONT_DIR = vec3(0.0, 0.0, 1.0);
|
||||
|
||||
// x = ambient, y = top diffuse, z = front diffuse, w = global
|
||||
uniform vec4 light_intensity;
|
||||
uniform vec4 uniform_color;
|
||||
|
||||
varying vec3 eye_normal;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec3 normal = normalize(eye_normal);
|
||||
|
||||
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
|
||||
// Since these two are normalized the cosine is the dot product. Take the abs value to light the lines no matter in which direction the normal points.
|
||||
float NdotL = abs(dot(normal, LIGHT_TOP_DIR));
|
||||
|
||||
float intensity = light_intensity.x + NdotL * light_intensity.y;
|
||||
|
||||
// Perform the same lighting calculation for the 2nd light source.
|
||||
NdotL = abs(dot(normal, LIGHT_FRONT_DIR));
|
||||
intensity += NdotL * light_intensity.z;
|
||||
|
||||
gl_FragColor = vec4(uniform_color.rgb * light_intensity.w * intensity, uniform_color.a);
|
||||
}
|
19
resources/shaders/toolpaths_lines.vs
Normal file
19
resources/shaders/toolpaths_lines.vs
Normal file
|
@ -0,0 +1,19 @@
|
|||
#version 110
|
||||
|
||||
varying vec3 eye_normal;
|
||||
|
||||
vec3 world_normal()
|
||||
{
|
||||
// the world normal is always parallel to the world XY plane
|
||||
// the x component is stored into gl_Vertex.w
|
||||
float x = gl_Vertex.w;
|
||||
float y = sqrt(1.0 - x * x);
|
||||
return vec3(x, y, 0.0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 world_position = vec4(gl_Vertex.xyz, 1.0);
|
||||
gl_Position = gl_ModelViewProjectionMatrix * world_position;
|
||||
eye_normal = gl_NormalMatrix * world_normal();
|
||||
}
|
|
@ -6,6 +6,7 @@ add_executable(opencsg_example WIN32
|
|||
main.cpp
|
||||
Engine.hpp Engine.cpp
|
||||
ShaderCSGDisplay.hpp ShaderCSGDisplay.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/Jobs/Job.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/ProgressStatusBar.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/I18N.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/I18N.cpp)
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "libslic3r/Format/3mf.hpp"
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
|
||||
#include "slic3r/GUI/Job.hpp"
|
||||
#include "slic3r/GUI/Jobs/Job.hpp"
|
||||
#include "slic3r/GUI/ProgressStatusBar.hpp"
|
||||
|
||||
using namespace Slic3r::GL;
|
||||
|
|
|
@ -92,6 +92,7 @@ endif()
|
|||
# Create a slic3r executable
|
||||
# Process mainfests for various platforms.
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/msw/PrusaSlicer.rc.in ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer.rc @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/msw/PrusaSlicer-gcodeviewer.rc.in ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer-gcodeviewer.rc @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/msw/PrusaSlicer.manifest.in ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer.manifest @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/platform/osx/Info.plist.in ${CMAKE_CURRENT_BINARY_DIR}/Info.plist @ONLY)
|
||||
if (WIN32)
|
||||
|
@ -161,12 +162,22 @@ if (WIN32)
|
|||
add_executable(PrusaSlicer_app_console PrusaSlicer_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer.rc)
|
||||
# Generate debug symbols even in release mode.
|
||||
if (MSVC)
|
||||
target_link_options(PrusaSlicer_app_console PUBLIC "$<$<CONFIG:RELEASE>:/DEBUG>")
|
||||
target_link_options(PrusaSlicer_app_console PUBLIC "$<$<CONFIG:RELEASE>:/DEBUG>")
|
||||
endif ()
|
||||
target_compile_definitions(PrusaSlicer_app_console PRIVATE -DSLIC3R_WRAPPER_CONSOLE)
|
||||
add_dependencies(PrusaSlicer_app_console PrusaSlicer)
|
||||
set_target_properties(PrusaSlicer_app_console PROPERTIES OUTPUT_NAME "prusa-slicer-console")
|
||||
target_link_libraries(PrusaSlicer_app_console PRIVATE boost_headeronly)
|
||||
|
||||
add_executable(PrusaSlicer_app_gcodeviewer WIN32 PrusaSlicer_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer-gcodeviewer.rc)
|
||||
# Generate debug symbols even in release mode.
|
||||
if (MSVC)
|
||||
target_link_options(PrusaSlicer_app_gcodeviewer PUBLIC "$<$<CONFIG:RELEASE>:/DEBUG>")
|
||||
endif ()
|
||||
target_compile_definitions(PrusaSlicer_app_gcodeviewer PRIVATE -DSLIC3R_WRAPPER_NOCONSOLE -DSLIC3R_WRAPPER_GCODEVIEWER)
|
||||
add_dependencies(PrusaSlicer_app_gcodeviewer PrusaSlicer)
|
||||
set_target_properties(PrusaSlicer_app_gcodeviewer PROPERTIES OUTPUT_NAME "prusa-gcodeviewer")
|
||||
target_link_libraries(PrusaSlicer_app_gcodeviewer PRIVATE boost_headeronly)
|
||||
endif ()
|
||||
|
||||
# Link the resources dir to where Slic3r GUI expects it
|
||||
|
|
|
@ -101,6 +101,7 @@ int CLI::run(int argc, char **argv)
|
|||
std::find(m_transforms.begin(), m_transforms.end(), "cut") == m_transforms.end() &&
|
||||
std::find(m_transforms.begin(), m_transforms.end(), "cut_x") == m_transforms.end() &&
|
||||
std::find(m_transforms.begin(), m_transforms.end(), "cut_y") == m_transforms.end();
|
||||
bool start_as_gcodeviewer = false;
|
||||
|
||||
const std::vector<std::string> &load_configs = m_config.option<ConfigOptionStrings>("load", true)->values;
|
||||
|
||||
|
@ -469,7 +470,11 @@ int CLI::run(int argc, char **argv)
|
|||
print->process();
|
||||
if (printer_technology == ptFFF) {
|
||||
// The outfile is processed by a PlaceholderParser.
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
outfile = fff_print.export_gcode(outfile, nullptr, nullptr);
|
||||
#else
|
||||
outfile = fff_print.export_gcode(outfile, nullptr);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
outfile_final = fff_print.print_statistics().finalize_output_path(outfile);
|
||||
} else {
|
||||
outfile = sla_print.output_filepath(outfile);
|
||||
|
@ -517,6 +522,9 @@ int CLI::run(int argc, char **argv)
|
|||
<< " (" << print.total_extruded_volume()/1000 << "cm3)" << std::endl;
|
||||
*/
|
||||
}
|
||||
} else if (opt_key == "gcodeviewer") {
|
||||
start_gui = true;
|
||||
start_as_gcodeviewer = true;
|
||||
} else {
|
||||
boost::nowide::cerr << "error: option not supported yet: " << opt_key << std::endl;
|
||||
return 1;
|
||||
|
|
|
@ -221,6 +221,11 @@ int wmain(int argc, wchar_t **argv)
|
|||
std::vector<wchar_t*> argv_extended;
|
||||
argv_extended.emplace_back(argv[0]);
|
||||
|
||||
#ifdef SLIC3R_WRAPPER_GCODEVIEWER
|
||||
wchar_t gcodeviewer_param[] = L"--gcodeviewer";
|
||||
argv_extended.emplace_back(gcodeviewer_param);
|
||||
#endif /* SLIC3R_WRAPPER_GCODEVIEWER */
|
||||
|
||||
#ifdef SLIC3R_GUI
|
||||
// Here one may push some additional parameters based on the wrapper type.
|
||||
bool force_mesa = false;
|
||||
|
|
|
@ -48,9 +48,19 @@
|
|||
#include <ostream>
|
||||
#include <functional>
|
||||
#include <assert.h>
|
||||
#include <Shiny/Shiny.h>
|
||||
#include <libslic3r/Int128.hpp>
|
||||
|
||||
// Profiling support using the Shiny intrusive profiler
|
||||
//#define CLIPPERLIB_PROFILE
|
||||
#if defined(SLIC3R_PROFILE) && defined(CLIPPERLIB_PROFILE)
|
||||
#include <Shiny/Shiny.h>
|
||||
#define CLIPPERLIB_PROFILE_FUNC() PROFILE_FUNC()
|
||||
#define CLIPPERLIB_PROFILE_BLOCK(name) PROFILE_BLOCK(name)
|
||||
#else
|
||||
#define CLIPPERLIB_PROFILE_FUNC()
|
||||
#define CLIPPERLIB_PROFILE_BLOCK(name)
|
||||
#endif
|
||||
|
||||
#ifdef use_xyz
|
||||
namespace ClipperLib_Z {
|
||||
#else /* use_xyz */
|
||||
|
@ -263,7 +273,7 @@ int PointInPolygon (const IntPoint &pt, OutPt *op)
|
|||
// This is potentially very expensive! O(n^2)!
|
||||
bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
OutPt* op = OutPt1;
|
||||
do
|
||||
{
|
||||
|
@ -714,7 +724,7 @@ TEdge* ClipperBase::ProcessBound(TEdge* E, bool NextIsForward)
|
|||
|
||||
bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
// Remove duplicate end point from a closed input path.
|
||||
// Remove duplicate points from the end of the input path.
|
||||
int highI = (int)pg.size() -1;
|
||||
|
@ -738,7 +748,7 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
|
|||
|
||||
bool ClipperBase::AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
std::vector<int> num_edges(ppg.size(), 0);
|
||||
int num_edges_total = 0;
|
||||
for (size_t i = 0; i < ppg.size(); ++ i) {
|
||||
|
@ -780,7 +790,7 @@ bool ClipperBase::AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed)
|
|||
|
||||
bool ClipperBase::AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, bool Closed, TEdge* edges)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
#ifdef use_lines
|
||||
if (!Closed && PolyTyp == ptClip)
|
||||
throw clipperException("AddPath: Open paths must be subject.");
|
||||
|
@ -954,7 +964,7 @@ bool ClipperBase::AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, b
|
|||
|
||||
void ClipperBase::Clear()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
m_MinimaList.clear();
|
||||
m_edges.clear();
|
||||
m_UseFullRange = false;
|
||||
|
@ -966,7 +976,7 @@ void ClipperBase::Clear()
|
|||
// Sort the LML entries, initialize the left / right bound edges of each Local Minima.
|
||||
void ClipperBase::Reset()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
if (m_MinimaList.empty()) return; //ie nothing to process
|
||||
std::sort(m_MinimaList.begin(), m_MinimaList.end(), [](const LocalMinimum& lm1, const LocalMinimum& lm2){ return lm1.Y < lm2.Y; });
|
||||
|
||||
|
@ -995,7 +1005,7 @@ void ClipperBase::Reset()
|
|||
// Returns (0,0,0,0) for an empty rectangle.
|
||||
IntRect ClipperBase::GetBounds()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
IntRect result;
|
||||
auto lm = m_MinimaList.begin();
|
||||
if (lm == m_MinimaList.end())
|
||||
|
@ -1056,7 +1066,7 @@ Clipper::Clipper(int initOptions) :
|
|||
|
||||
void Clipper::Reset()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
ClipperBase::Reset();
|
||||
m_Scanbeam = std::priority_queue<cInt>();
|
||||
m_Maxima.clear();
|
||||
|
@ -1071,7 +1081,7 @@ void Clipper::Reset()
|
|||
bool Clipper::Execute(ClipType clipType, Paths &solution,
|
||||
PolyFillType subjFillType, PolyFillType clipFillType)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
if (m_HasOpenPaths)
|
||||
throw clipperException("Error: PolyTree struct is needed for open path clipping.");
|
||||
solution.resize(0);
|
||||
|
@ -1089,7 +1099,7 @@ bool Clipper::Execute(ClipType clipType, Paths &solution,
|
|||
bool Clipper::Execute(ClipType clipType, PolyTree& polytree,
|
||||
PolyFillType subjFillType, PolyFillType clipFillType)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
m_SubjFillType = subjFillType;
|
||||
m_ClipFillType = clipFillType;
|
||||
m_ClipType = clipType;
|
||||
|
@ -1103,10 +1113,10 @@ bool Clipper::Execute(ClipType clipType, PolyTree& polytree,
|
|||
|
||||
bool Clipper::ExecuteInternal()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
bool succeeded = true;
|
||||
try {
|
||||
PROFILE_BLOCK(Clipper_ExecuteInternal_Process);
|
||||
CLIPPERLIB_PROFILE_BLOCK(Clipper_ExecuteInternal_Process);
|
||||
Reset();
|
||||
if (m_MinimaList.empty()) return true;
|
||||
cInt botY = m_Scanbeam.top();
|
||||
|
@ -1131,13 +1141,13 @@ bool Clipper::ExecuteInternal()
|
|||
|
||||
if (succeeded)
|
||||
{
|
||||
PROFILE_BLOCK(Clipper_ExecuteInternal_Fix);
|
||||
CLIPPERLIB_PROFILE_BLOCK(Clipper_ExecuteInternal_Fix);
|
||||
|
||||
//fix orientations ...
|
||||
//FIXME Vojtech: Does it not invalidate the loop hierarchy maintained as OutRec::FirstLeft pointers?
|
||||
//FIXME Vojtech: The area is calculated with floats, it may not be numerically stable!
|
||||
{
|
||||
PROFILE_BLOCK(Clipper_ExecuteInternal_Fix_orientations);
|
||||
CLIPPERLIB_PROFILE_BLOCK(Clipper_ExecuteInternal_Fix_orientations);
|
||||
for (OutRec *outRec : m_PolyOuts)
|
||||
if (outRec->Pts && !outRec->IsOpen && (outRec->IsHole ^ m_ReverseOutput) == (Area(*outRec) > 0))
|
||||
ReversePolyPtLinks(outRec->Pts);
|
||||
|
@ -1147,7 +1157,7 @@ bool Clipper::ExecuteInternal()
|
|||
|
||||
//unfortunately FixupOutPolygon() must be done after JoinCommonEdges()
|
||||
{
|
||||
PROFILE_BLOCK(Clipper_ExecuteInternal_Fix_fixup);
|
||||
CLIPPERLIB_PROFILE_BLOCK(Clipper_ExecuteInternal_Fix_fixup);
|
||||
for (OutRec *outRec : m_PolyOuts)
|
||||
if (outRec->Pts) {
|
||||
if (outRec->IsOpen)
|
||||
|
@ -1401,7 +1411,7 @@ bool Clipper::IsContributing(const TEdge& edge) const
|
|||
// Called from Clipper::InsertLocalMinimaIntoAEL() and Clipper::IntersectEdges().
|
||||
OutPt* Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
OutPt* result;
|
||||
TEdge *e, *prevE;
|
||||
if (IsHorizontal(*e2) || ( e1->Dx > e2->Dx ))
|
||||
|
@ -1493,7 +1503,7 @@ void Clipper::CopyAELToSEL()
|
|||
// Called from Clipper::ExecuteInternal()
|
||||
void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
while (!m_MinimaList.empty() && m_MinimaList.back().Y == botY)
|
||||
{
|
||||
TEdge* lb = m_MinimaList.back().LeftBound;
|
||||
|
@ -2043,7 +2053,7 @@ OutPt* Clipper::GetLastOutPt(TEdge *e)
|
|||
|
||||
void Clipper::ProcessHorizontals()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
TEdge* horzEdge = m_SortedEdges;
|
||||
while(horzEdge)
|
||||
{
|
||||
|
@ -2414,7 +2424,7 @@ void Clipper::UpdateEdgeIntoAEL(TEdge *&e)
|
|||
|
||||
bool Clipper::ProcessIntersections(const cInt topY)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
if( !m_ActiveEdges ) return true;
|
||||
try {
|
||||
BuildIntersectList(topY);
|
||||
|
@ -2569,7 +2579,7 @@ void Clipper::DoMaxima(TEdge *e)
|
|||
|
||||
void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
TEdge* e = m_ActiveEdges;
|
||||
while( e )
|
||||
{
|
||||
|
@ -3177,7 +3187,7 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
|
|||
// This is potentially very expensive! O(n^3)!
|
||||
void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec) const
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
//tests if NewOutRec contains the polygon before reassigning FirstLeft
|
||||
for (OutRec *outRec : m_PolyOuts)
|
||||
{
|
||||
|
@ -3201,7 +3211,7 @@ void Clipper::FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec) const
|
|||
|
||||
void Clipper::JoinCommonEdges()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
for (Join &join : m_Joins)
|
||||
{
|
||||
OutRec *outRec1 = GetOutRec(join.OutPt1->Idx);
|
||||
|
@ -3771,7 +3781,7 @@ void ClipperOffset::DoRound(int j, int k)
|
|||
// http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Classes/Clipper/Properties/StrictlySimple.htm
|
||||
void Clipper::DoSimplePolygons()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERLIB_PROFILE_FUNC();
|
||||
size_t i = 0;
|
||||
while (i < m_PolyOuts.size())
|
||||
{
|
||||
|
|
|
@ -108,17 +108,19 @@ namespace ImGui
|
|||
const char ColorMarkerEnd = 0x3; // ETX
|
||||
|
||||
// Special ASCII characters are used here as an ikons markers
|
||||
const char PrintIconMarker = 0x4;
|
||||
const char PrinterIconMarker = 0x5;
|
||||
const char PrinterSlaIconMarker = 0x6;
|
||||
const char FilamentIconMarker = 0x7;
|
||||
const char MaterialIconMarker = 0x8;
|
||||
const char CloseIconMarker = 0xB;
|
||||
const char CloseIconHoverMarker = 0xC;
|
||||
const char TimerDotMarker = 0xE;
|
||||
const char TimerDotEmptyMarker = 0xF;
|
||||
const char WarningMarker = 0x10;
|
||||
const char ErrorMarker = 0x11;
|
||||
const char PrintIconMarker = 0x4;
|
||||
const char PrinterIconMarker = 0x5;
|
||||
const char PrinterSlaIconMarker = 0x6;
|
||||
const char FilamentIconMarker = 0x7;
|
||||
const char MaterialIconMarker = 0x8;
|
||||
const char CloseIconMarker = 0xB;
|
||||
const char CloseIconHoverMarker = 0xC;
|
||||
// const char TimerDotMarker = 0xE;
|
||||
// const char TimerDotEmptyMarker = 0xF;
|
||||
const char MinimalizeMarker = 0xE;
|
||||
const char MinimalizeHoverMarker = 0xF;
|
||||
const char WarningMarker = 0x10;
|
||||
const char ErrorMarker = 0x11;
|
||||
// void MyFunction(const char* name, const MyMatrix44& v);
|
||||
|
||||
}
|
||||
|
|
|
@ -99,6 +99,8 @@ add_library(libslic3r STATIC
|
|||
GCode/ToolOrdering.hpp
|
||||
GCode/WipeTower.cpp
|
||||
GCode/WipeTower.hpp
|
||||
GCode/GCodeProcessor.cpp
|
||||
GCode/GCodeProcessor.hpp
|
||||
GCode.cpp
|
||||
GCode.hpp
|
||||
GCodeReader.cpp
|
||||
|
@ -161,6 +163,8 @@ add_library(libslic3r STATIC
|
|||
PrintConfig.hpp
|
||||
PrintObject.cpp
|
||||
PrintRegion.cpp
|
||||
PNGRead.hpp
|
||||
PNGRead.cpp
|
||||
Semver.cpp
|
||||
ShortestPath.cpp
|
||||
ShortestPath.hpp
|
||||
|
@ -308,6 +312,8 @@ target_link_libraries(libslic3r
|
|||
TBB::tbb
|
||||
libslic3r_cgal
|
||||
${CMAKE_DL_LIBS}
|
||||
PNG::PNG
|
||||
ZLIB::ZLIB
|
||||
)
|
||||
|
||||
if (TARGET OpenVDB::openvdb)
|
||||
|
|
|
@ -8,7 +8,16 @@
|
|||
#include "SVG.hpp"
|
||||
#endif /* CLIPPER_UTILS_DEBUG */
|
||||
|
||||
#include <Shiny/Shiny.h>
|
||||
// Profiling support using the Shiny intrusive profiler
|
||||
//#define CLIPPER_UTILS_PROFILE
|
||||
#if defined(SLIC3R_PROFILE) && defined(CLIPPER_UTILS_PROFILE)
|
||||
#include <Shiny/Shiny.h>
|
||||
#define CLIPPERUTILS_PROFILE_FUNC() PROFILE_FUNC()
|
||||
#define CLIPPERUTILS_PROFILE_BLOCK(name) PROFILE_BLOCK(name)
|
||||
#else
|
||||
#define CLIPPERUTILS_PROFILE_FUNC()
|
||||
#define CLIPPERUTILS_PROFILE_BLOCK(name)
|
||||
#endif
|
||||
|
||||
#define CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR (0.005f)
|
||||
|
||||
|
@ -50,7 +59,7 @@ err:
|
|||
|
||||
void scaleClipperPolygon(ClipperLib::Path &polygon)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERUTILS_PROFILE_FUNC();
|
||||
for (ClipperLib::Path::iterator pit = polygon.begin(); pit != polygon.end(); ++pit) {
|
||||
pit->X <<= CLIPPER_OFFSET_POWER_OF_2;
|
||||
pit->Y <<= CLIPPER_OFFSET_POWER_OF_2;
|
||||
|
@ -59,7 +68,7 @@ void scaleClipperPolygon(ClipperLib::Path &polygon)
|
|||
|
||||
void scaleClipperPolygons(ClipperLib::Paths &polygons)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERUTILS_PROFILE_FUNC();
|
||||
for (ClipperLib::Paths::iterator it = polygons.begin(); it != polygons.end(); ++it)
|
||||
for (ClipperLib::Path::iterator pit = (*it).begin(); pit != (*it).end(); ++pit) {
|
||||
pit->X <<= CLIPPER_OFFSET_POWER_OF_2;
|
||||
|
@ -69,7 +78,7 @@ void scaleClipperPolygons(ClipperLib::Paths &polygons)
|
|||
|
||||
void unscaleClipperPolygon(ClipperLib::Path &polygon)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERUTILS_PROFILE_FUNC();
|
||||
for (ClipperLib::Path::iterator pit = polygon.begin(); pit != polygon.end(); ++pit) {
|
||||
pit->X += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA;
|
||||
pit->Y += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA;
|
||||
|
@ -80,7 +89,7 @@ void unscaleClipperPolygon(ClipperLib::Path &polygon)
|
|||
|
||||
void unscaleClipperPolygons(ClipperLib::Paths &polygons)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERUTILS_PROFILE_FUNC();
|
||||
for (ClipperLib::Paths::iterator it = polygons.begin(); it != polygons.end(); ++it)
|
||||
for (ClipperLib::Path::iterator pit = (*it).begin(); pit != (*it).end(); ++pit) {
|
||||
pit->X += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA;
|
||||
|
@ -790,7 +799,7 @@ ExPolygons simplify_polygons_ex(const Polygons &subject, bool preserve_collinear
|
|||
|
||||
void safety_offset(ClipperLib::Paths* paths)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
CLIPPERUTILS_PROFILE_FUNC();
|
||||
|
||||
// scale input
|
||||
scaleClipperPolygons(*paths);
|
||||
|
@ -812,11 +821,11 @@ void safety_offset(ClipperLib::Paths* paths)
|
|||
if (! ccw)
|
||||
std::reverse(path.begin(), path.end());
|
||||
{
|
||||
PROFILE_BLOCK(safety_offset_AddPaths);
|
||||
CLIPPERUTILS_PROFILE_BLOCK(safety_offset_AddPaths);
|
||||
co.AddPath((*paths)[i], ClipperLib::jtMiter, ClipperLib::etClosedPolygon);
|
||||
}
|
||||
{
|
||||
PROFILE_BLOCK(safety_offset_Execute);
|
||||
CLIPPERUTILS_PROFILE_BLOCK(safety_offset_Execute);
|
||||
// offset outside by 10um
|
||||
ClipperLib::Paths out_this;
|
||||
co.Execute(out_this, ccw ? 10.f * float(CLIPPER_OFFSET_SCALE) : -10.f * float(CLIPPER_OFFSET_SCALE));
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#include "CustomGCode.hpp"
|
||||
#include "Config.hpp"
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include "GCode.hpp"
|
||||
#else
|
||||
#include "GCode/PreviewData.hpp"
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
#include "GCodeWriter.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
@ -17,8 +21,12 @@ extern void update_custom_gcode_per_print_z_from_config(Info& info, DynamicPrint
|
|||
return;
|
||||
if (info.gcodes.empty() && ! colorprint_heights->values.empty()) {
|
||||
// Convert the old colorprint_heighs only if there is no equivalent data in a new format.
|
||||
const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors();
|
||||
const auto& colorprint_values = colorprint_heights->values;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
const std::vector<std::string>& colors = ColorPrintColors::get();
|
||||
#else
|
||||
const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors();
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
const auto& colorprint_values = colorprint_heights->values;
|
||||
info.gcodes.clear();
|
||||
info.gcodes.reserve(colorprint_values.size());
|
||||
int i = 0;
|
||||
|
|
|
@ -306,7 +306,11 @@ double ExtrusionLoop::min_mm3_per_mm() const
|
|||
std::string ExtrusionEntity::role_to_string(ExtrusionRole role)
|
||||
{
|
||||
switch (role) {
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
case erNone : return L("Unknown");
|
||||
#else
|
||||
case erNone : return L("None");
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
case erPerimeter : return L("Perimeter");
|
||||
case erExternalPerimeter : return L("External perimeter");
|
||||
case erOverhangPerimeter : return L("Overhang perimeter");
|
||||
|
@ -327,4 +331,40 @@ std::string ExtrusionEntity::role_to_string(ExtrusionRole role)
|
|||
return "";
|
||||
}
|
||||
|
||||
ExtrusionRole ExtrusionEntity::string_to_role(const std::string& role)
|
||||
{
|
||||
if (role == L("Perimeter"))
|
||||
return erPerimeter;
|
||||
else if (role == L("External perimeter"))
|
||||
return erExternalPerimeter;
|
||||
else if (role == L("Overhang perimeter"))
|
||||
return erOverhangPerimeter;
|
||||
else if (role == L("Internal infill"))
|
||||
return erInternalInfill;
|
||||
else if (role == L("Solid infill"))
|
||||
return erSolidInfill;
|
||||
else if (role == L("Top solid infill"))
|
||||
return erTopSolidInfill;
|
||||
else if (role == L("Ironing"))
|
||||
return erIroning;
|
||||
else if (role == L("Bridge infill"))
|
||||
return erBridgeInfill;
|
||||
else if (role == L("Gap fill"))
|
||||
return erGapFill;
|
||||
else if (role == L("Skirt"))
|
||||
return erSkirt;
|
||||
else if (role == L("Support material"))
|
||||
return erSupportMaterial;
|
||||
else if (role == L("Support material interface"))
|
||||
return erSupportMaterialInterface;
|
||||
else if (role == L("Wipe tower"))
|
||||
return erWipeTower;
|
||||
else if (role == L("Custom"))
|
||||
return erCustom;
|
||||
else if (role == L("Mixed"))
|
||||
return erMixed;
|
||||
else
|
||||
return erNone;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -106,6 +106,7 @@ public:
|
|||
virtual double total_volume() const = 0;
|
||||
|
||||
static std::string role_to_string(ExtrusionRole role);
|
||||
static ExtrusionRole string_to_role(const std::string& role);
|
||||
};
|
||||
|
||||
typedef std::vector<ExtrusionEntity*> ExtrusionEntitiesPtr;
|
||||
|
@ -121,8 +122,8 @@ public:
|
|||
// Height of the extrusion, used for visualization purposes.
|
||||
float height;
|
||||
|
||||
ExtrusionPath(ExtrusionRole role) : mm3_per_mm(-1), width(-1), height(-1), m_role(role) {};
|
||||
ExtrusionPath(ExtrusionRole role, double mm3_per_mm, float width, float height) : mm3_per_mm(mm3_per_mm), width(width), height(height), m_role(role) {};
|
||||
ExtrusionPath(ExtrusionRole role) : mm3_per_mm(-1), width(-1), height(-1), m_role(role) {}
|
||||
ExtrusionPath(ExtrusionRole role, double mm3_per_mm, float width, float height) : mm3_per_mm(mm3_per_mm), width(width), height(height), m_role(role) {}
|
||||
ExtrusionPath(const ExtrusionPath& rhs) : polyline(rhs.polyline), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), m_role(rhs.m_role) {}
|
||||
ExtrusionPath(ExtrusionPath&& rhs) : polyline(std::move(rhs.polyline)), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), m_role(rhs.m_role) {}
|
||||
ExtrusionPath(const Polyline &polyline, const ExtrusionPath &rhs) : polyline(polyline), mm3_per_mm(rhs.mm3_per_mm), width(rhs.width), height(rhs.height), m_role(rhs.m_role) {}
|
||||
|
|
|
@ -87,6 +87,7 @@ const char* TRANSFORM_ATTR = "transform";
|
|||
const char* PRINTABLE_ATTR = "printable";
|
||||
const char* INSTANCESCOUNT_ATTR = "instances_count";
|
||||
const char* CUSTOM_SUPPORTS_ATTR = "slic3rpe:custom_supports";
|
||||
const char* CUSTOM_SEAM_ATTR = "slic3rpe:custom_seam";
|
||||
|
||||
const char* KEY_ATTR = "key";
|
||||
const char* VALUE_ATTR = "value";
|
||||
|
@ -285,6 +286,7 @@ namespace Slic3r {
|
|||
std::vector<float> vertices;
|
||||
std::vector<unsigned int> triangles;
|
||||
std::vector<std::string> custom_supports;
|
||||
std::vector<std::string> custom_seam;
|
||||
|
||||
bool empty()
|
||||
{
|
||||
|
@ -296,6 +298,7 @@ namespace Slic3r {
|
|||
vertices.clear();
|
||||
triangles.clear();
|
||||
custom_supports.clear();
|
||||
custom_seam.clear();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1114,6 +1117,15 @@ namespace Slic3r {
|
|||
float(std::atof(object_data_points[i+6].c_str())),
|
||||
float(std::atof(object_data_points[i+7].c_str())));
|
||||
}
|
||||
|
||||
// The holes are saved elevated above the mesh and deeper (bad idea indeed).
|
||||
// This is retained for compatibility.
|
||||
// Place the hole to the mesh and make it shallower to compensate.
|
||||
// The offset is 1 mm above the mesh.
|
||||
for (sla::DrainHole& hole : sla_drain_holes) {
|
||||
hole.pos += hole.normal.normalized();
|
||||
hole.height -= 1.f;
|
||||
}
|
||||
|
||||
if (!sla_drain_holes.empty())
|
||||
m_sla_drain_holes.insert(IdToSlaDrainHolesMap::value_type(object_id, sla_drain_holes));
|
||||
|
@ -1544,6 +1556,7 @@ namespace Slic3r {
|
|||
m_curr_object.geometry.triangles.push_back((unsigned int)get_attribute_value_int(attributes, num_attributes, V3_ATTR));
|
||||
|
||||
m_curr_object.geometry.custom_supports.push_back(get_attribute_value_string(attributes, num_attributes, CUSTOM_SUPPORTS_ATTR));
|
||||
m_curr_object.geometry.custom_seam.push_back(get_attribute_value_string(attributes, num_attributes, CUSTOM_SEAM_ATTR));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1877,14 +1890,18 @@ namespace Slic3r {
|
|||
volume->source.transform = Slic3r::Geometry::Transformation(volume_matrix_to_object);
|
||||
volume->calculate_convex_hull();
|
||||
|
||||
// recreate custom supports from previously loaded attribute
|
||||
// recreate custom supports and seam from previously loaded attribute
|
||||
for (unsigned i=0; i<triangles_count; ++i) {
|
||||
size_t index = src_start_id/3 + i;
|
||||
assert(index < geometry.custom_supports.size());
|
||||
assert(index < geometry.custom_seam.size());
|
||||
if (! geometry.custom_supports[index].empty())
|
||||
volume->m_supported_facets.set_triangle_from_string(i, geometry.custom_supports[index]);
|
||||
if (! geometry.custom_seam[index].empty())
|
||||
volume->m_seam_facets.set_triangle_from_string(i, geometry.custom_seam[index]);
|
||||
}
|
||||
|
||||
|
||||
// apply the remaining volume's metadata
|
||||
for (const Metadata& metadata : volume_data.metadata)
|
||||
{
|
||||
|
@ -2401,6 +2418,10 @@ namespace Slic3r {
|
|||
if (! custom_supports_data_string.empty())
|
||||
stream << CUSTOM_SUPPORTS_ATTR << "=\"" << custom_supports_data_string << "\" ";
|
||||
|
||||
std::string custom_seam_data_string = volume->m_seam_facets.get_triangle_as_string(i);
|
||||
if (! custom_seam_data_string.empty())
|
||||
stream << CUSTOM_SEAM_ATTR << "=\"" << custom_seam_data_string << "\" ";
|
||||
|
||||
stream << "/>\n";
|
||||
}
|
||||
}
|
||||
|
@ -2591,7 +2612,18 @@ namespace Slic3r {
|
|||
for (const ModelObject* object : model.objects)
|
||||
{
|
||||
++count;
|
||||
auto& drain_holes = object->sla_drain_holes;
|
||||
sla::DrainHoles drain_holes = object->sla_drain_holes;
|
||||
|
||||
// The holes were placed 1mm above the mesh in the first implementation.
|
||||
// This was a bad idea and the reference point was changed in 2.3 so
|
||||
// to be on the mesh exactly. The elevated position is still saved
|
||||
// in 3MFs for compatibility reasons.
|
||||
for (sla::DrainHole& hole : drain_holes) {
|
||||
hole.pos -= hole.normal.normalized();
|
||||
hole.height += 1.f;
|
||||
}
|
||||
|
||||
|
||||
if (!drain_holes.empty())
|
||||
{
|
||||
out += string_printf(fmt, count);
|
||||
|
|
|
@ -35,6 +35,6 @@ namespace Slic3r {
|
|||
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
|
||||
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr);
|
||||
|
||||
}; // namespace Slic3r
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_Format_3mf_hpp_ */
|
||||
|
|
|
@ -8,8 +8,316 @@
|
|||
#include "libslic3r/Zipper.hpp"
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "libslic3r/SlicesToTriangleMesh.hpp"
|
||||
#include "libslic3r/MarchingSquares.hpp"
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
#include "libslic3r/MTUtils.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/SLA/RasterBase.hpp"
|
||||
#include "libslic3r/miniz_extension.hpp"
|
||||
#include "libslic3r/PNGRead.hpp"
|
||||
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
namespace marchsq {
|
||||
|
||||
template<> struct _RasterTraits<Slic3r::png::ImageGreyscale> {
|
||||
using Rst = Slic3r::png::ImageGreyscale;
|
||||
|
||||
// The type of pixel cell in the raster
|
||||
using ValueType = uint8_t;
|
||||
|
||||
// Value at a given position
|
||||
static uint8_t get(const Rst &rst, size_t row, size_t col)
|
||||
{
|
||||
return rst.get(row, col);
|
||||
}
|
||||
|
||||
// Number of rows and cols of the raster
|
||||
static size_t rows(const Rst &rst) { return rst.rows; }
|
||||
static size_t cols(const Rst &rst) { return rst.cols; }
|
||||
};
|
||||
|
||||
} // namespace marchsq
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace {
|
||||
|
||||
struct PNGBuffer { std::vector<uint8_t> buf; std::string fname; };
|
||||
struct ArchiveData {
|
||||
boost::property_tree::ptree profile, config;
|
||||
std::vector<PNGBuffer> images;
|
||||
};
|
||||
|
||||
static const constexpr char *CONFIG_FNAME = "config.ini";
|
||||
static const constexpr char *PROFILE_FNAME = "prusaslicer.ini";
|
||||
|
||||
boost::property_tree::ptree read_ini(const mz_zip_archive_file_stat &entry,
|
||||
MZ_Archive & zip)
|
||||
{
|
||||
std::string buf(size_t(entry.m_uncomp_size), '\0');
|
||||
|
||||
if (!mz_zip_reader_extract_file_to_mem(&zip.arch, entry.m_filename,
|
||||
buf.data(), buf.size(), 0))
|
||||
throw std::runtime_error(zip.get_errorstr());
|
||||
|
||||
boost::property_tree::ptree tree;
|
||||
std::stringstream ss(buf);
|
||||
boost::property_tree::read_ini(ss, tree);
|
||||
return tree;
|
||||
}
|
||||
|
||||
PNGBuffer read_png(const mz_zip_archive_file_stat &entry,
|
||||
MZ_Archive & zip,
|
||||
const std::string & name)
|
||||
{
|
||||
std::vector<uint8_t> buf(entry.m_uncomp_size);
|
||||
|
||||
if (!mz_zip_reader_extract_file_to_mem(&zip.arch, entry.m_filename,
|
||||
buf.data(), buf.size(), 0))
|
||||
throw std::runtime_error(zip.get_errorstr());
|
||||
|
||||
return {std::move(buf), (name.empty() ? entry.m_filename : name)};
|
||||
}
|
||||
|
||||
ArchiveData extract_sla_archive(const std::string &zipfname,
|
||||
const std::string &exclude)
|
||||
{
|
||||
ArchiveData arch;
|
||||
|
||||
// Little RAII
|
||||
struct Arch: public MZ_Archive {
|
||||
Arch(const std::string &fname) {
|
||||
if (!open_zip_reader(&arch, fname))
|
||||
throw std::runtime_error(get_errorstr());
|
||||
}
|
||||
|
||||
~Arch() { close_zip_reader(&arch); }
|
||||
} zip (zipfname);
|
||||
|
||||
mz_uint num_entries = mz_zip_reader_get_num_files(&zip.arch);
|
||||
|
||||
for (mz_uint i = 0; i < num_entries; ++i)
|
||||
{
|
||||
mz_zip_archive_file_stat entry;
|
||||
|
||||
if (mz_zip_reader_file_stat(&zip.arch, i, &entry))
|
||||
{
|
||||
std::string name = entry.m_filename;
|
||||
boost::algorithm::to_lower(name);
|
||||
|
||||
if (boost::algorithm::contains(name, exclude)) continue;
|
||||
|
||||
if (name == CONFIG_FNAME) arch.config = read_ini(entry, zip);
|
||||
if (name == PROFILE_FNAME) arch.profile = read_ini(entry, zip);
|
||||
|
||||
if (boost::filesystem::path(name).extension().string() == ".png") {
|
||||
auto it = std::lower_bound(
|
||||
arch.images.begin(), arch.images.end(), PNGBuffer{{}, name},
|
||||
[](const PNGBuffer &r1, const PNGBuffer &r2) {
|
||||
return std::less<std::string>()(r1.fname, r2.fname);
|
||||
});
|
||||
|
||||
arch.images.insert(it, read_png(entry, zip, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return arch;
|
||||
}
|
||||
|
||||
ExPolygons rings_to_expolygons(const std::vector<marchsq::Ring> &rings,
|
||||
double px_w, double px_h)
|
||||
{
|
||||
ExPolygons polys; polys.reserve(rings.size());
|
||||
|
||||
for (const marchsq::Ring &ring : rings) {
|
||||
Polygon poly; Points &pts = poly.points;
|
||||
pts.reserve(ring.size());
|
||||
|
||||
for (const marchsq::Coord &crd : ring)
|
||||
pts.emplace_back(scaled(crd.c * px_w), scaled(crd.r * px_h));
|
||||
|
||||
polys.emplace_back(poly);
|
||||
}
|
||||
|
||||
// reverse the raster transformations
|
||||
return union_ex(polys);
|
||||
}
|
||||
|
||||
template<class Fn> void foreach_vertex(ExPolygon &poly, Fn &&fn)
|
||||
{
|
||||
for (auto &p : poly.contour.points) fn(p);
|
||||
for (auto &h : poly.holes)
|
||||
for (auto &p : h.points) fn(p);
|
||||
}
|
||||
|
||||
void invert_raster_trafo(ExPolygons & expolys,
|
||||
const sla::RasterBase::Trafo &trafo,
|
||||
coord_t width,
|
||||
coord_t height)
|
||||
{
|
||||
if (trafo.flipXY) std::swap(height, width);
|
||||
|
||||
for (auto &expoly : expolys) {
|
||||
if (trafo.mirror_y)
|
||||
foreach_vertex(expoly, [height](Point &p) {p.y() = height - p.y(); });
|
||||
|
||||
if (trafo.mirror_x)
|
||||
foreach_vertex(expoly, [width](Point &p) {p.x() = width - p.x(); });
|
||||
|
||||
expoly.translate(-trafo.center_x, -trafo.center_y);
|
||||
|
||||
if (trafo.flipXY)
|
||||
foreach_vertex(expoly, [](Point &p) { std::swap(p.x(), p.y()); });
|
||||
|
||||
if ((trafo.mirror_x + trafo.mirror_y + trafo.flipXY) % 2) {
|
||||
expoly.contour.reverse();
|
||||
for (auto &h : expoly.holes) h.reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RasterParams {
|
||||
sla::RasterBase::Trafo trafo; // Raster transformations
|
||||
coord_t width, height; // scaled raster dimensions (not resolution)
|
||||
double px_h, px_w; // pixel dimesions
|
||||
marchsq::Coord win; // marching squares window size
|
||||
};
|
||||
|
||||
RasterParams get_raster_params(const DynamicPrintConfig &cfg)
|
||||
{
|
||||
auto *opt_disp_cols = cfg.option<ConfigOptionInt>("display_pixels_x");
|
||||
auto *opt_disp_rows = cfg.option<ConfigOptionInt>("display_pixels_y");
|
||||
auto *opt_disp_w = cfg.option<ConfigOptionFloat>("display_width");
|
||||
auto *opt_disp_h = cfg.option<ConfigOptionFloat>("display_height");
|
||||
auto *opt_mirror_x = cfg.option<ConfigOptionBool>("display_mirror_x");
|
||||
auto *opt_mirror_y = cfg.option<ConfigOptionBool>("display_mirror_y");
|
||||
auto *opt_orient = cfg.option<ConfigOptionEnum<SLADisplayOrientation>>("display_orientation");
|
||||
|
||||
if (!opt_disp_cols || !opt_disp_rows || !opt_disp_w || !opt_disp_h ||
|
||||
!opt_mirror_x || !opt_mirror_y || !opt_orient)
|
||||
throw std::runtime_error("Invalid SL1 file");
|
||||
|
||||
RasterParams rstp;
|
||||
|
||||
rstp.px_w = opt_disp_w->value / (opt_disp_cols->value - 1);
|
||||
rstp.px_h = opt_disp_h->value / (opt_disp_rows->value - 1);
|
||||
|
||||
rstp.trafo = sla::RasterBase::Trafo{opt_orient->value == sladoLandscape ?
|
||||
sla::RasterBase::roLandscape :
|
||||
sla::RasterBase::roPortrait,
|
||||
{opt_mirror_x->value, opt_mirror_y->value}};
|
||||
|
||||
rstp.height = scaled(opt_disp_h->value);
|
||||
rstp.width = scaled(opt_disp_w->value);
|
||||
|
||||
return rstp;
|
||||
}
|
||||
|
||||
struct SliceParams { double layerh = 0., initial_layerh = 0.; };
|
||||
|
||||
SliceParams get_slice_params(const DynamicPrintConfig &cfg)
|
||||
{
|
||||
auto *opt_layerh = cfg.option<ConfigOptionFloat>("layer_height");
|
||||
auto *opt_init_layerh = cfg.option<ConfigOptionFloat>("initial_layer_height");
|
||||
|
||||
if (!opt_layerh || !opt_init_layerh)
|
||||
throw std::runtime_error("Invalid SL1 file");
|
||||
|
||||
return SliceParams{opt_layerh->getFloat(), opt_init_layerh->getFloat()};
|
||||
}
|
||||
|
||||
std::vector<ExPolygons> extract_slices_from_sla_archive(
|
||||
ArchiveData & arch,
|
||||
const RasterParams & rstp,
|
||||
std::function<bool(int)> progr)
|
||||
{
|
||||
auto jobdir = arch.config.get<std::string>("jobDir");
|
||||
for (auto &c : jobdir) c = std::tolower(c);
|
||||
|
||||
std::vector<ExPolygons> slices(arch.images.size());
|
||||
|
||||
struct Status
|
||||
{
|
||||
double incr, val, prev;
|
||||
bool stop = false;
|
||||
tbb::spin_mutex mutex;
|
||||
} st {100. / slices.size(), 0., 0.};
|
||||
|
||||
tbb::parallel_for(size_t(0), arch.images.size(),
|
||||
[&arch, &slices, &st, &rstp, progr](size_t i) {
|
||||
// Status indication guarded with the spinlock
|
||||
{
|
||||
std::lock_guard<tbb::spin_mutex> lck(st.mutex);
|
||||
if (st.stop) return;
|
||||
|
||||
st.val += st.incr;
|
||||
double curr = std::round(st.val);
|
||||
if (curr > st.prev) {
|
||||
st.prev = curr;
|
||||
st.stop = !progr(int(curr));
|
||||
}
|
||||
}
|
||||
|
||||
png::ImageGreyscale img;
|
||||
png::ReadBuf rb{arch.images[i].buf.data(), arch.images[i].buf.size()};
|
||||
if (!png::decode_png(rb, img)) return;
|
||||
|
||||
auto rings = marchsq::execute(img, 128, rstp.win);
|
||||
ExPolygons expolys = rings_to_expolygons(rings, rstp.px_w, rstp.px_h);
|
||||
|
||||
// Invert the raster transformations indicated in
|
||||
// the profile metadata
|
||||
invert_raster_trafo(expolys, rstp.trafo, rstp.width, rstp.height);
|
||||
|
||||
slices[i] = std::move(expolys);
|
||||
});
|
||||
|
||||
if (st.stop) slices = {};
|
||||
|
||||
return slices;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void import_sla_archive(const std::string &zipfname, DynamicPrintConfig &out)
|
||||
{
|
||||
ArchiveData arch = extract_sla_archive(zipfname, "png");
|
||||
out.load(arch.profile);
|
||||
}
|
||||
|
||||
void import_sla_archive(
|
||||
const std::string & zipfname,
|
||||
Vec2i windowsize,
|
||||
TriangleMesh & out,
|
||||
DynamicPrintConfig & profile,
|
||||
std::function<bool(int)> progr)
|
||||
{
|
||||
// Ensure minimum window size for marching squares
|
||||
windowsize.x() = std::max(2, windowsize.x());
|
||||
windowsize.y() = std::max(2, windowsize.y());
|
||||
|
||||
ArchiveData arch = extract_sla_archive(zipfname, "thumbnail");
|
||||
profile.load(arch.profile);
|
||||
|
||||
RasterParams rstp = get_raster_params(profile);
|
||||
rstp.win = {windowsize.y(), windowsize.x()};
|
||||
|
||||
SliceParams slicp = get_slice_params(profile);
|
||||
|
||||
std::vector<ExPolygons> slices =
|
||||
extract_slices_from_sla_archive(arch, rstp, progr);
|
||||
|
||||
if (!slices.empty())
|
||||
out = slices_to_triangle_mesh(slices, 0, slicp.layerh, slicp.initial_layerh);
|
||||
}
|
||||
|
||||
using ConfMap = std::map<std::string, std::string>;
|
||||
|
||||
namespace {
|
||||
|
|
|
@ -38,6 +38,24 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void import_sla_archive(const std::string &zipfname, DynamicPrintConfig &out);
|
||||
|
||||
void import_sla_archive(
|
||||
const std::string & zipfname,
|
||||
Vec2i windowsize,
|
||||
TriangleMesh & out,
|
||||
DynamicPrintConfig & profile,
|
||||
std::function<bool(int)> progr = [](int) { return true; });
|
||||
|
||||
inline void import_sla_archive(
|
||||
const std::string & zipfname,
|
||||
Vec2i windowsize,
|
||||
TriangleMesh & out,
|
||||
std::function<bool(int)> progr = [](int) { return true; })
|
||||
{
|
||||
DynamicPrintConfig profile;
|
||||
import_sla_archive(zipfname, windowsize, out, profile, progr);
|
||||
}
|
||||
|
||||
} // namespace Slic3r::sla
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,9 +13,13 @@
|
|||
#include "GCode/SpiralVase.hpp"
|
||||
#include "GCode/ToolOrdering.hpp"
|
||||
#include "GCode/WipeTower.hpp"
|
||||
#include "GCodeTimeEstimator.hpp"
|
||||
#include "EdgeGrid.hpp"
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include "GCode/GCodeProcessor.hpp"
|
||||
#else
|
||||
#include "GCode/Analyzer.hpp"
|
||||
#include "GCodeTimeEstimator.hpp"
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
#include "EdgeGrid.hpp"
|
||||
#include "GCode/ThumbnailData.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
@ -29,7 +33,9 @@ namespace Slic3r {
|
|||
|
||||
// Forward declarations.
|
||||
class GCode;
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
class GCodePreviewData;
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
namespace { struct Item; }
|
||||
struct PrintInstance;
|
||||
|
@ -138,6 +144,15 @@ private:
|
|||
double m_last_wipe_tower_print_z = 0.f;
|
||||
};
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
class ColorPrintColors
|
||||
{
|
||||
static const std::vector<std::string> Colors;
|
||||
public:
|
||||
static const std::vector<std::string>& get() { return Colors; }
|
||||
};
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
class GCode {
|
||||
public:
|
||||
GCode() :
|
||||
|
@ -145,21 +160,33 @@ public:
|
|||
m_enable_loop_clipping(true),
|
||||
m_enable_cooling_markers(false),
|
||||
m_enable_extrusion_role_markers(false),
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_last_processor_extrusion_role(erNone),
|
||||
#else
|
||||
m_enable_analyzer(false),
|
||||
m_last_analyzer_extrusion_role(erNone),
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
m_layer_count(0),
|
||||
m_layer_index(-1),
|
||||
m_layer(nullptr),
|
||||
m_volumetric_speed(0),
|
||||
m_last_pos_defined(false),
|
||||
m_last_extrusion_role(erNone),
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
m_last_mm3_per_mm(0.0),
|
||||
m_last_width(0.0f),
|
||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
m_last_mm3_per_mm(GCodeAnalyzer::Default_mm3_per_mm),
|
||||
m_last_width(GCodeAnalyzer::Default_Width),
|
||||
m_last_height(GCodeAnalyzer::Default_Height),
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
m_brim_done(false),
|
||||
m_second_layer_things_done(false),
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
m_normal_time_estimator(GCodeTimeEstimator::Normal),
|
||||
m_silent_time_estimator(GCodeTimeEstimator::Silent),
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
m_silent_time_estimator_enabled(false),
|
||||
m_last_obj_copy(nullptr, Point(std::numeric_limits<coord_t>::max(), std::numeric_limits<coord_t>::max()))
|
||||
{}
|
||||
|
@ -167,7 +194,11 @@ public:
|
|||
|
||||
// throws std::runtime_exception on error,
|
||||
// throws CanceledException through print->throw_if_canceled().
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
void do_export(Print* print, const char* path, GCodeProcessor::Result* result = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||
#else
|
||||
void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
|
||||
const Vec2d& origin() const { return m_origin; }
|
||||
|
@ -327,11 +358,16 @@ private:
|
|||
// Markers for the Pressure Equalizer to recognize the extrusion type.
|
||||
// The Pressure Equalizer removes the markers from the final G-code.
|
||||
bool m_enable_extrusion_role_markers;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
// Keeps track of the last extrusion role passed to the processor
|
||||
ExtrusionRole m_last_processor_extrusion_role;
|
||||
#else
|
||||
// Enableds the G-code Analyzer.
|
||||
// Extended markers will be added during G-code generation.
|
||||
// The G-code Analyzer will remove these comments from the final G-code.
|
||||
bool m_enable_analyzer;
|
||||
ExtrusionRole m_last_analyzer_extrusion_role;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
// How many times will change_layer() be called?
|
||||
// change_layer() will update the progress bar.
|
||||
unsigned int m_layer_count;
|
||||
|
@ -344,10 +380,20 @@ private:
|
|||
double m_volumetric_speed;
|
||||
// Support for the extrusion role markers. Which marker is active?
|
||||
ExtrusionRole m_last_extrusion_role;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
// Support for G-Code Processor
|
||||
float m_last_height{ 0.0f };
|
||||
float m_last_layer_z{ 0.0f };
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
double m_last_mm3_per_mm;
|
||||
float m_last_width{ 0.0f };
|
||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
#else
|
||||
// Support for G-Code Analyzer
|
||||
double m_last_mm3_per_mm;
|
||||
float m_last_width;
|
||||
float m_last_height;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
Point m_last_pos;
|
||||
bool m_last_pos_defined;
|
||||
|
@ -368,13 +414,20 @@ private:
|
|||
// Index of a last object copy extruded.
|
||||
std::pair<const PrintObject*, Point> m_last_obj_copy;
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
// Time estimators
|
||||
GCodeTimeEstimator m_normal_time_estimator;
|
||||
GCodeTimeEstimator m_silent_time_estimator;
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
bool m_silent_time_estimator_enabled;
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
// Processor
|
||||
GCodeProcessor m_processor;
|
||||
#else
|
||||
// Analyzer
|
||||
GCodeAnalyzer m_analyzer;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
// Write a string into a file.
|
||||
void _write(FILE* file, const std::string& what) { this->_write(file, what.c_str()); }
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "Analyzer.hpp"
|
||||
#include "PreviewData.hpp"
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
|
||||
static const std::string AXIS_STR = "XYZE";
|
||||
static const float MMMIN_TO_MMSEC = 1.0f / 60.0f;
|
||||
static const float INCHES_TO_MM = 25.4f;
|
||||
|
@ -350,7 +352,7 @@ void GCodeAnalyzer::_processG1(const GCodeReader::GCodeLine& line)
|
|||
if (delta_pos[E] < 0.0f)
|
||||
{
|
||||
if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f) || (delta_pos[Z] != 0.0f))
|
||||
type = GCodeMove::Move;
|
||||
type = GCodeMove::Move;
|
||||
else
|
||||
type = GCodeMove::Retract;
|
||||
}
|
||||
|
@ -651,7 +653,7 @@ bool GCodeAnalyzer::_process_tags(const GCodeReader::GCodeLine& line)
|
|||
return true;
|
||||
}
|
||||
|
||||
// color change tag
|
||||
// pause print tag
|
||||
pos = comment.find(Pause_Print_Tag);
|
||||
if (pos != comment.npos)
|
||||
{
|
||||
|
@ -659,7 +661,7 @@ bool GCodeAnalyzer::_process_tags(const GCodeReader::GCodeLine& line)
|
|||
return true;
|
||||
}
|
||||
|
||||
// color change tag
|
||||
// custom code tag
|
||||
pos = comment.find(Custom_Code_Tag);
|
||||
if (pos != comment.npos)
|
||||
{
|
||||
|
@ -667,7 +669,7 @@ bool GCodeAnalyzer::_process_tags(const GCodeReader::GCodeLine& line)
|
|||
return true;
|
||||
}
|
||||
|
||||
// color change tag
|
||||
// end pause print or custom code tag
|
||||
pos = comment.find(End_Pause_Print_Or_Custom_Code_Tag);
|
||||
if (pos != comment.npos)
|
||||
{
|
||||
|
@ -1191,3 +1193,5 @@ size_t GCodeAnalyzer::memory_used() const
|
|||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef slic3r_GCode_Analyzer_hpp_
|
||||
#define slic3r_GCode_Analyzer_hpp_
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
|
||||
#include "../libslic3r.h"
|
||||
#include "../PrintConfig.hpp"
|
||||
#include "../ExtrusionEntity.hpp"
|
||||
|
@ -302,4 +304,6 @@ private:
|
|||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
#endif /* slic3r_GCode_Analyzer_hpp_ */
|
||||
|
|
2163
src/libslic3r/GCode/GCodeProcessor.cpp
Normal file
2163
src/libslic3r/GCode/GCodeProcessor.cpp
Normal file
File diff suppressed because it is too large
Load diff
559
src/libslic3r/GCode/GCodeProcessor.hpp
Normal file
559
src/libslic3r/GCode/GCodeProcessor.hpp
Normal file
|
@ -0,0 +1,559 @@
|
|||
#ifndef slic3r_GCodeProcessor_hpp_
|
||||
#define slic3r_GCodeProcessor_hpp_
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include "libslic3r/GCodeReader.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/CustomGCode.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
enum class EMoveType : unsigned char
|
||||
{
|
||||
Noop,
|
||||
Retract,
|
||||
Unretract,
|
||||
Tool_change,
|
||||
Color_change,
|
||||
Pause_Print,
|
||||
Custom_GCode,
|
||||
Travel,
|
||||
Extrude,
|
||||
Count
|
||||
};
|
||||
|
||||
struct PrintEstimatedTimeStatistics
|
||||
{
|
||||
enum class ETimeMode : unsigned char
|
||||
{
|
||||
Normal,
|
||||
Stealth,
|
||||
Count
|
||||
};
|
||||
|
||||
struct Mode
|
||||
{
|
||||
float time;
|
||||
std::vector<std::pair<CustomGCode::Type, std::pair<float, float>>> custom_gcode_times;
|
||||
std::vector<std::pair<EMoveType, float>> moves_times;
|
||||
std::vector<std::pair<ExtrusionRole, float>> roles_times;
|
||||
std::vector<float> layers_times;
|
||||
|
||||
void reset() {
|
||||
time = 0.0f;
|
||||
custom_gcode_times.clear();
|
||||
moves_times.clear();
|
||||
roles_times.clear();
|
||||
layers_times.clear();
|
||||
}
|
||||
};
|
||||
|
||||
std::array<Mode, static_cast<size_t>(ETimeMode::Count)> modes;
|
||||
|
||||
PrintEstimatedTimeStatistics() { reset(); }
|
||||
|
||||
void reset() {
|
||||
for (auto m : modes) {
|
||||
m.reset();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class GCodeProcessor
|
||||
{
|
||||
public:
|
||||
static const std::string Extrusion_Role_Tag;
|
||||
static const std::string Height_Tag;
|
||||
static const std::string Layer_Change_Tag;
|
||||
static const std::string Color_Change_Tag;
|
||||
static const std::string Pause_Print_Tag;
|
||||
static const std::string Custom_Code_Tag;
|
||||
static const std::string First_Line_M73_Placeholder_Tag;
|
||||
static const std::string Last_Line_M73_Placeholder_Tag;
|
||||
static const std::string Estimated_Printing_Time_Placeholder_Tag;
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
static const std::string Width_Tag;
|
||||
static const std::string Mm3_Per_Mm_Tag;
|
||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
|
||||
private:
|
||||
using AxisCoords = std::array<float, 4>;
|
||||
using ExtruderColors = std::vector<unsigned char>;
|
||||
|
||||
enum class EUnits : unsigned char
|
||||
{
|
||||
Millimeters,
|
||||
Inches
|
||||
};
|
||||
|
||||
enum class EPositioningType : unsigned char
|
||||
{
|
||||
Absolute,
|
||||
Relative
|
||||
};
|
||||
|
||||
struct CachedPosition
|
||||
{
|
||||
AxisCoords position; // mm
|
||||
float feedrate; // mm/s
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
struct CpColor
|
||||
{
|
||||
unsigned char counter;
|
||||
unsigned char current;
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
public:
|
||||
struct FeedrateProfile
|
||||
{
|
||||
float entry{ 0.0f }; // mm/s
|
||||
float cruise{ 0.0f }; // mm/s
|
||||
float exit{ 0.0f }; // mm/s
|
||||
};
|
||||
|
||||
struct Trapezoid
|
||||
{
|
||||
float accelerate_until{ 0.0f }; // mm
|
||||
float decelerate_after{ 0.0f }; // mm
|
||||
float cruise_feedrate{ 0.0f }; // mm/sec
|
||||
|
||||
float acceleration_time(float entry_feedrate, float acceleration) const;
|
||||
float cruise_time() const;
|
||||
float deceleration_time(float distance, float acceleration) const;
|
||||
float cruise_distance() const;
|
||||
};
|
||||
|
||||
struct TimeBlock
|
||||
{
|
||||
struct Flags
|
||||
{
|
||||
bool recalculate{ false };
|
||||
bool nominal_length{ false };
|
||||
};
|
||||
|
||||
EMoveType move_type{ EMoveType::Noop };
|
||||
ExtrusionRole role{ erNone };
|
||||
unsigned int layer_id{ 0 };
|
||||
float distance{ 0.0f }; // mm
|
||||
float acceleration{ 0.0f }; // mm/s^2
|
||||
float max_entry_speed{ 0.0f }; // mm/s
|
||||
float safe_feedrate{ 0.0f }; // mm/s
|
||||
Flags flags;
|
||||
FeedrateProfile feedrate_profile;
|
||||
Trapezoid trapezoid;
|
||||
|
||||
// Calculates this block's trapezoid
|
||||
void calculate_trapezoid();
|
||||
|
||||
float time() const;
|
||||
};
|
||||
|
||||
private:
|
||||
struct TimeMachine
|
||||
{
|
||||
struct State
|
||||
{
|
||||
float feedrate; // mm/s
|
||||
float safe_feedrate; // mm/s
|
||||
AxisCoords axis_feedrate; // mm/s
|
||||
AxisCoords abs_axis_feedrate; // mm/s
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
struct CustomGCodeTime
|
||||
{
|
||||
bool needed;
|
||||
float cache;
|
||||
std::vector<std::pair<CustomGCode::Type, float>> times;
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
bool enabled;
|
||||
float acceleration; // mm/s^2
|
||||
// hard limit for the acceleration, to which the firmware will clamp.
|
||||
float max_acceleration; // mm/s^2
|
||||
float extrude_factor_override_percentage;
|
||||
float time; // s
|
||||
std::string line_m73_mask;
|
||||
State curr;
|
||||
State prev;
|
||||
CustomGCodeTime gcode_time;
|
||||
std::vector<TimeBlock> blocks;
|
||||
std::vector<float> g1_times_cache;
|
||||
std::array<float, static_cast<size_t>(EMoveType::Count)> moves_time;
|
||||
std::array<float, static_cast<size_t>(ExtrusionRole::erCount)> roles_time;
|
||||
std::vector<float> layers_time;
|
||||
|
||||
void reset();
|
||||
|
||||
// Simulates firmware st_synchronize() call
|
||||
void simulate_st_synchronize(float additional_time = 0.0f);
|
||||
void calculate_time(size_t keep_last_n_blocks = 0);
|
||||
};
|
||||
|
||||
struct TimeProcessor
|
||||
{
|
||||
struct Planner
|
||||
{
|
||||
// Size of the firmware planner queue. The old 8-bit Marlins usually just managed 16 trapezoidal blocks.
|
||||
// Let's be conservative and plan for newer boards with more memory.
|
||||
static constexpr size_t queue_size = 64;
|
||||
// The firmware recalculates last planner_queue_size trapezoidal blocks each time a new block is added.
|
||||
// We are not simulating the firmware exactly, we calculate a sequence of blocks once a reasonable number of blocks accumulate.
|
||||
static constexpr size_t refresh_threshold = queue_size * 4;
|
||||
};
|
||||
|
||||
// extruder_id is currently used to correctly calculate filament load / unload times into the total print time.
|
||||
// This is currently only really used by the MK3 MMU2:
|
||||
// extruder_unloaded = true means no filament is loaded yet, all the filaments are parked in the MK3 MMU2 unit.
|
||||
bool extruder_unloaded;
|
||||
// whether or not to export post-process the gcode to export lines M73 in it
|
||||
bool export_remaining_time_enabled;
|
||||
// allow to skip the lines M201/M203/M204/M205 generated by GCode::print_machine_envelope()
|
||||
bool machine_envelope_processing_enabled;
|
||||
MachineEnvelopeConfig machine_limits;
|
||||
// Additional load / unload times for a filament exchange sequence.
|
||||
std::vector<float> filament_load_times;
|
||||
std::vector<float> filament_unload_times;
|
||||
std::array<TimeMachine, static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Count)> machines;
|
||||
|
||||
void reset();
|
||||
|
||||
// post process the file with the given filename to add remaining time lines M73
|
||||
void post_process(const std::string& filename);
|
||||
};
|
||||
|
||||
public:
|
||||
struct MoveVertex
|
||||
{
|
||||
EMoveType type{ EMoveType::Noop };
|
||||
ExtrusionRole extrusion_role{ erNone };
|
||||
unsigned char extruder_id{ 0 };
|
||||
unsigned char cp_color_id{ 0 };
|
||||
Vec3f position{ Vec3f::Zero() }; // mm
|
||||
float delta_extruder{ 0.0f }; // mm
|
||||
float feedrate{ 0.0f }; // mm/s
|
||||
float width{ 0.0f }; // mm
|
||||
float height{ 0.0f }; // mm
|
||||
float mm3_per_mm{ 0.0f };
|
||||
float fan_speed{ 0.0f }; // percentage
|
||||
float time{ 0.0f }; // s
|
||||
|
||||
float volumetric_rate() const { return feedrate * mm3_per_mm; }
|
||||
};
|
||||
|
||||
struct Result
|
||||
{
|
||||
unsigned int id;
|
||||
std::vector<MoveVertex> moves;
|
||||
Pointfs bed_shape;
|
||||
std::string printer_settings_id;
|
||||
std::vector<std::string> extruder_colors;
|
||||
PrintEstimatedTimeStatistics time_statistics;
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
long long time{ 0 };
|
||||
void reset()
|
||||
{
|
||||
time = 0;
|
||||
moves = std::vector<MoveVertex>();
|
||||
bed_shape = Pointfs();
|
||||
extruder_colors = std::vector<std::string>();
|
||||
}
|
||||
#else
|
||||
void reset()
|
||||
{
|
||||
moves = std::vector<MoveVertex>();
|
||||
bed_shape = Pointfs();
|
||||
extruder_colors = std::vector<std::string>();
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
};
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
struct DataChecker
|
||||
{
|
||||
struct Error
|
||||
{
|
||||
float value;
|
||||
float tag_value;
|
||||
ExtrusionRole role;
|
||||
};
|
||||
|
||||
std::string type;
|
||||
float threshold{ 0.01f };
|
||||
float last_tag_value{ 0.0f };
|
||||
unsigned int count{ 0 };
|
||||
std::vector<Error> errors;
|
||||
|
||||
DataChecker(const std::string& type, float threshold)
|
||||
: type(type), threshold(threshold)
|
||||
{}
|
||||
|
||||
void update(float value, ExtrusionRole role) {
|
||||
++count;
|
||||
if (last_tag_value != 0.0f) {
|
||||
if (std::abs(value - last_tag_value) / last_tag_value > threshold)
|
||||
errors.push_back({ value, last_tag_value, role });
|
||||
}
|
||||
}
|
||||
|
||||
void reset() { last_tag_value = 0.0f; errors.clear(); count = 0; }
|
||||
|
||||
std::pair<float, float> get_min() const {
|
||||
float delta_min = FLT_MAX;
|
||||
float perc_min = 0.0f;
|
||||
for (const Error& e : errors) {
|
||||
if (delta_min > e.value - e.tag_value) {
|
||||
delta_min = e.value - e.tag_value;
|
||||
perc_min = 100.0f * delta_min / e.tag_value;
|
||||
}
|
||||
}
|
||||
return { delta_min, perc_min };
|
||||
}
|
||||
|
||||
std::pair<float, float> get_max() const {
|
||||
float delta_max = -FLT_MAX;
|
||||
float perc_max = 0.0f;
|
||||
for (const Error& e : errors) {
|
||||
if (delta_max < e.value - e.tag_value) {
|
||||
delta_max = e.value - e.tag_value;
|
||||
perc_max = 100.0f * delta_max / e.tag_value;
|
||||
}
|
||||
}
|
||||
return { delta_max, perc_max };
|
||||
}
|
||||
|
||||
void output() const {
|
||||
if (!errors.empty()) {
|
||||
std::cout << type << ":\n";
|
||||
std::cout << "Errors: " << errors.size() << " (" << 100.0f * float(errors.size()) / float(count) << "%)\n";
|
||||
auto [min, perc_min] = get_min();
|
||||
auto [max, perc_max] = get_max();
|
||||
std::cout << "min: " << min << "(" << perc_min << "%) - max: " << max << "(" << perc_max << "%)\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
|
||||
private:
|
||||
GCodeReader m_parser;
|
||||
|
||||
EUnits m_units;
|
||||
EPositioningType m_global_positioning_type;
|
||||
EPositioningType m_e_local_positioning_type;
|
||||
std::vector<Vec3f> m_extruder_offsets;
|
||||
GCodeFlavor m_flavor;
|
||||
|
||||
AxisCoords m_start_position; // mm
|
||||
AxisCoords m_end_position; // mm
|
||||
AxisCoords m_origin; // mm
|
||||
CachedPosition m_cached_position;
|
||||
|
||||
float m_feedrate; // mm/s
|
||||
float m_width; // mm
|
||||
float m_height; // mm
|
||||
float m_mm3_per_mm;
|
||||
float m_fan_speed; // percentage
|
||||
ExtrusionRole m_extrusion_role;
|
||||
unsigned char m_extruder_id;
|
||||
ExtruderColors m_extruder_colors;
|
||||
std::vector<float> m_filament_diameters;
|
||||
float m_extruded_last_z;
|
||||
unsigned int m_layer_id;
|
||||
CpColor m_cp_color;
|
||||
|
||||
enum class EProducer
|
||||
{
|
||||
Unknown,
|
||||
PrusaSlicer,
|
||||
Cura,
|
||||
Simplify3D,
|
||||
CraftWare,
|
||||
ideaMaker
|
||||
};
|
||||
|
||||
static const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> Producers;
|
||||
EProducer m_producer;
|
||||
bool m_producers_enabled;
|
||||
|
||||
TimeProcessor m_time_processor;
|
||||
|
||||
Result m_result;
|
||||
static unsigned int s_result_id;
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
DataChecker m_mm3_per_mm_compare{ "mm3_per_mm", 0.01f };
|
||||
DataChecker m_height_compare{ "height", 0.01f };
|
||||
DataChecker m_width_compare{ "width", 0.01f };
|
||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
|
||||
public:
|
||||
GCodeProcessor();
|
||||
|
||||
void apply_config(const PrintConfig& config);
|
||||
void apply_config(const DynamicPrintConfig& config);
|
||||
void enable_stealth_time_estimator(bool enabled);
|
||||
bool is_stealth_time_estimator_enabled() const {
|
||||
return m_time_processor.machines[static_cast<size_t>(PrintEstimatedTimeStatistics::ETimeMode::Stealth)].enabled;
|
||||
}
|
||||
void enable_machine_envelope_processing(bool enabled) { m_time_processor.machine_envelope_processing_enabled = enabled; }
|
||||
void enable_producers(bool enabled) { m_producers_enabled = enabled; }
|
||||
void reset();
|
||||
|
||||
const Result& get_result() const { return m_result; }
|
||||
Result&& extract_result() { return std::move(m_result); }
|
||||
|
||||
// Process the gcode contained in the file with the given filename
|
||||
void process_file(const std::string& filename);
|
||||
|
||||
float get_time(PrintEstimatedTimeStatistics::ETimeMode mode) const;
|
||||
std::string get_time_dhm(PrintEstimatedTimeStatistics::ETimeMode mode) const;
|
||||
std::vector<std::pair<CustomGCode::Type, std::pair<float, float>>> get_custom_gcode_times(PrintEstimatedTimeStatistics::ETimeMode mode, bool include_remaining) const;
|
||||
|
||||
std::vector<std::pair<EMoveType, float>> get_moves_time(PrintEstimatedTimeStatistics::ETimeMode mode) const;
|
||||
std::vector<std::pair<ExtrusionRole, float>> get_roles_time(PrintEstimatedTimeStatistics::ETimeMode mode) const;
|
||||
std::vector<float> get_layers_time(PrintEstimatedTimeStatistics::ETimeMode mode) const;
|
||||
|
||||
private:
|
||||
void process_gcode_line(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Process tags embedded into comments
|
||||
void process_tags(const std::string& comment);
|
||||
bool process_producers_tags(const std::string& comment);
|
||||
bool process_prusaslicer_tags(const std::string& comment);
|
||||
bool process_cura_tags(const std::string& comment);
|
||||
bool process_simplify3d_tags(const std::string& comment);
|
||||
bool process_craftware_tags(const std::string& comment);
|
||||
bool process_ideamaker_tags(const std::string& comment);
|
||||
|
||||
bool detect_producer(const std::string& comment);
|
||||
|
||||
// Move
|
||||
void process_G0(const GCodeReader::GCodeLine& line);
|
||||
void process_G1(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Retract
|
||||
void process_G10(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Unretract
|
||||
void process_G11(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set Units to Inches
|
||||
void process_G20(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set Units to Millimeters
|
||||
void process_G21(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Firmware controlled Retract
|
||||
void process_G22(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Firmware controlled Unretract
|
||||
void process_G23(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set to Absolute Positioning
|
||||
void process_G90(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set to Relative Positioning
|
||||
void process_G91(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set Position
|
||||
void process_G92(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Sleep or Conditional stop
|
||||
void process_M1(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set extruder to absolute mode
|
||||
void process_M82(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set extruder to relative mode
|
||||
void process_M83(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set fan speed
|
||||
void process_M106(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Disable fan
|
||||
void process_M107(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set tool (Sailfish)
|
||||
void process_M108(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Recall stored home offsets
|
||||
void process_M132(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set tool (MakerWare)
|
||||
void process_M135(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set max printing acceleration
|
||||
void process_M201(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set maximum feedrate
|
||||
void process_M203(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set default acceleration
|
||||
void process_M204(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Advanced settings
|
||||
void process_M205(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set extrude factor override percentage
|
||||
void process_M221(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Repetier: Store x, y and z position
|
||||
void process_M401(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Repetier: Go to stored position
|
||||
void process_M402(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Set allowable instantaneous speed change
|
||||
void process_M566(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Unload the current filament into the MK3 MMU2 unit at the end of print.
|
||||
void process_M702(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Processes T line (Select Tool)
|
||||
void process_T(const GCodeReader::GCodeLine& line);
|
||||
void process_T(const std::string& command);
|
||||
|
||||
void store_move_vertex(EMoveType type);
|
||||
|
||||
float minimum_feedrate(PrintEstimatedTimeStatistics::ETimeMode mode, float feedrate) const;
|
||||
float minimum_travel_feedrate(PrintEstimatedTimeStatistics::ETimeMode mode, float feedrate) const;
|
||||
float get_axis_max_feedrate(PrintEstimatedTimeStatistics::ETimeMode mode, Axis axis) const;
|
||||
float get_axis_max_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode, Axis axis) const;
|
||||
float get_axis_max_jerk(PrintEstimatedTimeStatistics::ETimeMode mode, Axis axis) const;
|
||||
float get_retract_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode) const;
|
||||
float get_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode) const;
|
||||
void set_acceleration(PrintEstimatedTimeStatistics::ETimeMode mode, float value);
|
||||
float get_filament_load_time(size_t extruder_id);
|
||||
float get_filament_unload_time(size_t extruder_id);
|
||||
|
||||
void process_custom_gcode_time(CustomGCode::Type code);
|
||||
|
||||
// Simulates firmware st_synchronize() call
|
||||
void simulate_st_synchronize(float additional_time = 0.0f);
|
||||
|
||||
void update_estimated_times_stats();
|
||||
};
|
||||
|
||||
} /* namespace Slic3r */
|
||||
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
#endif /* slic3r_GCodeProcessor_hpp_ */
|
||||
|
||||
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
#define L(s) (s)
|
||||
|
||||
|
@ -516,3 +518,5 @@ Color operator * (float f, const Color& color)
|
|||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef slic3r_GCode_PreviewData_hpp_
|
||||
#define slic3r_GCode_PreviewData_hpp_
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
|
||||
#include "../libslic3r.h"
|
||||
#include "../ExtrusionEntity.hpp"
|
||||
#include "../Point.hpp"
|
||||
|
@ -56,8 +58,7 @@ public:
|
|||
// Color mapping to convert a float into a smooth rainbow of 10 colors.
|
||||
class RangeBase
|
||||
{
|
||||
public:
|
||||
|
||||
public:
|
||||
virtual void reset() = 0;
|
||||
virtual bool empty() const = 0;
|
||||
virtual float min() const = 0;
|
||||
|
@ -73,7 +74,7 @@ public:
|
|||
// Color mapping converting a float in a range between a min and a max into a smooth rainbow of 10 colors.
|
||||
class Range : public RangeBase
|
||||
{
|
||||
public:
|
||||
public:
|
||||
Range();
|
||||
|
||||
// RangeBase Overrides
|
||||
|
@ -97,8 +98,7 @@ public:
|
|||
template <typename EnumRangeType>
|
||||
class MultiRange : public RangeBase
|
||||
{
|
||||
public:
|
||||
|
||||
public:
|
||||
void reset() override
|
||||
{
|
||||
bounds = decltype(bounds){};
|
||||
|
@ -160,8 +160,7 @@ public:
|
|||
mode.set(static_cast<std::size_t>(range_type_value), enable);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
// Interval bounds
|
||||
struct Bounds
|
||||
{
|
||||
|
@ -394,4 +393,6 @@ public:
|
|||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
#endif /* slic3r_GCode_PreviewData_hpp_ */
|
||||
|
|
|
@ -21,7 +21,11 @@ TODO LIST
|
|||
#include <vector>
|
||||
#include <numeric>
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include "GCodeProcessor.hpp"
|
||||
#else
|
||||
#include "Analyzer.hpp"
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
#include "BoundingBox.hpp"
|
||||
|
||||
#if defined(__linux) || defined(__GNUC__ )
|
||||
|
@ -47,36 +51,69 @@ public:
|
|||
m_extrusion_flow(0.f),
|
||||
m_preview_suppressed(false),
|
||||
m_elapsed_time(0.f),
|
||||
#if !ENABLE_GCODE_VIEWER || ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
m_default_analyzer_line_width(line_width),
|
||||
#endif // !ENABLE_GCODE_VIEWER || ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
m_gcode_flavor(flavor),
|
||||
m_filpar(filament_parameters)
|
||||
{
|
||||
// adds tag for analyzer:
|
||||
char buf[64];
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
sprintf(buf, ";%s%f\n", GCodeProcessor::Height_Tag.c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming
|
||||
m_gcode += buf;
|
||||
sprintf(buf, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erWipeTower).c_str());
|
||||
m_gcode += buf;
|
||||
#else
|
||||
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Height_Tag.c_str(), m_layer_height); // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming
|
||||
m_gcode += buf;
|
||||
sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erWipeTower);
|
||||
m_gcode += buf;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
change_analyzer_line_width(line_width);
|
||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
}
|
||||
|
||||
WipeTowerWriter& change_analyzer_line_width(float line_width) {
|
||||
// adds tag for analyzer:
|
||||
char buf[64];
|
||||
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Width_Tag.c_str(), line_width);
|
||||
m_gcode += buf;
|
||||
return *this;
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
WipeTowerWriter& change_analyzer_line_width(float line_width) {
|
||||
// adds tag for analyzer:
|
||||
char buf[64];
|
||||
sprintf(buf, ";%s%f\n", GCodeProcessor::Width_Tag.c_str(), line_width);
|
||||
m_gcode += buf;
|
||||
return *this;
|
||||
}
|
||||
|
||||
WipeTowerWriter& change_analyzer_mm3_per_mm(float len, float e) {
|
||||
static const float area = float(M_PI) * 1.75f * 1.75f / 4.f;
|
||||
float mm3_per_mm = (len == 0.f ? 0.f : area * e / len);
|
||||
// adds tag for analyzer:
|
||||
char buf[64];
|
||||
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Mm3_Per_Mm_Tag.c_str(), mm3_per_mm);
|
||||
m_gcode += buf;
|
||||
return *this;
|
||||
WipeTowerWriter& change_analyzer_mm3_per_mm(float len, float e) {
|
||||
static const float area = float(M_PI) * 1.75f * 1.75f / 4.f;
|
||||
float mm3_per_mm = (len == 0.f ? 0.f : area * e / len);
|
||||
// adds tag for processor:
|
||||
char buf[64];
|
||||
sprintf(buf, ";%s%f\n", GCodeProcessor::Mm3_Per_Mm_Tag.c_str(), mm3_per_mm);
|
||||
m_gcode += buf;
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
WipeTowerWriter& change_analyzer_line_width(float line_width) {
|
||||
// adds tag for analyzer:
|
||||
char buf[64];
|
||||
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Width_Tag.c_str(), line_width);
|
||||
m_gcode += buf;
|
||||
return *this;
|
||||
}
|
||||
|
||||
WipeTowerWriter& change_analyzer_mm3_per_mm(float len, float e) {
|
||||
static const float area = float(M_PI) * 1.75f * 1.75f / 4.f;
|
||||
float mm3_per_mm = (len == 0.f ? 0.f : area * e / len);
|
||||
// adds tag for analyzer:
|
||||
char buf[64];
|
||||
sprintf(buf, ";%s%f\n", GCodeAnalyzer::Mm3_Per_Mm_Tag.c_str(), mm3_per_mm);
|
||||
m_gcode += buf;
|
||||
return *this;
|
||||
}
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
|
||||
WipeTowerWriter& set_initial_position(const Vec2f &pos, float width = 0.f, float depth = 0.f, float internal_angle = 0.f) {
|
||||
m_wipe_tower_width = width;
|
||||
|
@ -111,8 +148,13 @@ public:
|
|||
// Suppress / resume G-code preview in Slic3r. Slic3r will have difficulty to differentiate the various
|
||||
// filament loading and cooling moves from normal extrusion moves. Therefore the writer
|
||||
// is asked to suppres output of some lines, which look like extrusions.
|
||||
WipeTowerWriter& suppress_preview() { change_analyzer_line_width(0.f); m_preview_suppressed = true; return *this; }
|
||||
WipeTowerWriter& resume_preview() { change_analyzer_line_width(m_default_analyzer_line_width); m_preview_suppressed = false; return *this; }
|
||||
#if !ENABLE_GCODE_VIEWER || ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
WipeTowerWriter& suppress_preview() { change_analyzer_line_width(0.f); m_preview_suppressed = true; return *this; }
|
||||
WipeTowerWriter& resume_preview() { change_analyzer_line_width(m_default_analyzer_line_width); m_preview_suppressed = false; return *this; }
|
||||
#else
|
||||
WipeTowerWriter& suppress_preview() { m_preview_suppressed = true; return *this; }
|
||||
WipeTowerWriter& resume_preview() { m_preview_suppressed = false; return *this; }
|
||||
#endif // !ENABLE_GCODE_VIEWER || ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
|
||||
WipeTowerWriter& feedrate(float f)
|
||||
{
|
||||
|
@ -149,8 +191,14 @@ public:
|
|||
Vec2f rot(this->rotate(Vec2f(x,y))); // this is where we want to go
|
||||
|
||||
if (! m_preview_suppressed && e > 0.f && len > 0.f) {
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
change_analyzer_mm3_per_mm(len, e);
|
||||
// Width of a squished extrusion, corrected for the roundings of the squished extrusions.
|
||||
#else
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
change_analyzer_mm3_per_mm(len, e);
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
// Width of a squished extrusion, corrected for the roundings of the squished extrusions.
|
||||
// This is left zero if it is a travel move.
|
||||
float width = e * m_filpar[0].filament_area / (len * m_layer_height);
|
||||
// Correct for the roundings of a squished extrusion.
|
||||
|
@ -411,7 +459,9 @@ private:
|
|||
float m_wipe_tower_depth = 0.f;
|
||||
unsigned m_last_fan_speed = 0;
|
||||
int current_temp = -1;
|
||||
#if !ENABLE_GCODE_VIEWER || ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
const float m_default_analyzer_line_width;
|
||||
#endif // !ENABLE_GCODE_VIEWER || ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
float m_used_filament_length = 0.f;
|
||||
GCodeFlavor m_gcode_flavor;
|
||||
const std::vector<WipeTower::FilamentParameters>& m_filpar;
|
||||
|
@ -852,8 +902,12 @@ void WipeTower::toolchange_Unload(
|
|||
const float line_width = m_perimeter_width * m_filpar[m_current_tool].ramming_line_width_multiplicator; // desired ramming line thickness
|
||||
const float y_step = line_width * m_filpar[m_current_tool].ramming_step_multiplicator * m_extra_spacing; // spacing between lines in mm
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
writer.append("; CP TOOLCHANGE UNLOAD\n")
|
||||
.change_analyzer_line_width(line_width);
|
||||
.change_analyzer_line_width(line_width);
|
||||
#else
|
||||
writer.append("; CP TOOLCHANGE UNLOAD\n");
|
||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
|
||||
unsigned i = 0; // iterates through ramming_speed
|
||||
m_left_to_right = true; // current direction of ramming
|
||||
|
@ -930,7 +984,9 @@ void WipeTower::toolchange_Unload(
|
|||
}
|
||||
}
|
||||
Vec2f end_of_ramming(writer.x(),writer.y());
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
writer.change_analyzer_line_width(m_perimeter_width); // so the next lines are not affected by ramming_line_width_multiplier
|
||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
|
||||
// Retraction:
|
||||
float old_x = writer.x();
|
||||
|
|
|
@ -115,7 +115,12 @@ void GCodeReader::parse_file(const std::string &file, callback_t callback)
|
|||
{
|
||||
std::ifstream f(file);
|
||||
std::string line;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_parsing_file = true;
|
||||
while (m_parsing_file && std::getline(f, line))
|
||||
#else
|
||||
while (std::getline(f, line))
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
this->parse_line(line, callback);
|
||||
}
|
||||
|
||||
|
|
|
@ -107,6 +107,9 @@ public:
|
|||
{ GCodeLine gline; this->parse_line(line.c_str(), gline, callback); }
|
||||
|
||||
void parse_file(const std::string &file, callback_t callback);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
void quit_parsing_file() { m_parsing_file = false; }
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
float& x() { return m_position[X]; }
|
||||
float x() const { return m_position[X]; }
|
||||
|
@ -145,6 +148,9 @@ private:
|
|||
char m_extrusion_axis;
|
||||
float m_position[NUM_AXES];
|
||||
bool m_verbose;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
bool m_parsing_file{ false };
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
};
|
||||
|
||||
} /* namespace Slic3r */
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
|
||||
static const float MMMIN_TO_MMSEC = 1.0f / 60.0f;
|
||||
static const float MILLISEC_TO_SEC = 0.001f;
|
||||
static const float INCHES_TO_MM = 25.4f;
|
||||
|
@ -1671,3 +1673,5 @@ namespace Slic3r {
|
|||
}
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
}
|
||||
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "GCodeReader.hpp"
|
||||
#include "CustomGCode.hpp"
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
|
||||
#define ENABLE_MOVE_STATS 0
|
||||
|
||||
namespace Slic3r {
|
||||
|
@ -481,4 +483,6 @@ namespace Slic3r {
|
|||
|
||||
} /* namespace Slic3r */
|
||||
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
#endif /* slic3r_GCodeTimeEstimator_hpp_ */
|
||||
|
|
|
@ -21,7 +21,9 @@
|
|||
#include "SVG.hpp"
|
||||
#include <Eigen/Dense>
|
||||
#include "GCodeWriter.hpp"
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
#include "GCode/PreviewData.hpp"
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -1007,6 +1009,7 @@ void ModelObject::convert_units(ModelObjectPtrs& new_objects, bool from_imperial
|
|||
for (ModelVolume* volume : volumes)
|
||||
{
|
||||
volume->m_supported_facets.clear();
|
||||
volume->m_seam_facets.clear();
|
||||
if (!volume->mesh().empty()) {
|
||||
TriangleMesh mesh(volume->mesh());
|
||||
mesh.require_shared_vertices();
|
||||
|
@ -1112,6 +1115,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
|||
const auto volume_matrix = volume->get_matrix();
|
||||
|
||||
volume->m_supported_facets.clear();
|
||||
volume->m_seam_facets.clear();
|
||||
|
||||
if (! volume->is_model_part()) {
|
||||
// Modifiers are not cut, but we still need to add the instance transformation
|
||||
|
@ -1831,7 +1835,7 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
|
|||
}
|
||||
|
||||
|
||||
indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, FacetSupportType type) const
|
||||
indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, EnforcerBlockerType type) const
|
||||
{
|
||||
TriangleSelector selector(mv.mesh());
|
||||
selector.deserialize(m_data);
|
||||
|
@ -1993,6 +1997,16 @@ bool model_custom_supports_data_changed(const ModelObject& mo, const ModelObject
|
|||
return false;
|
||||
}
|
||||
|
||||
bool model_custom_seam_data_changed(const ModelObject& mo, const ModelObject& mo_new) {
|
||||
assert(! model_volume_list_changed(mo, mo_new, ModelVolumeType::MODEL_PART));
|
||||
assert(mo.volumes.size() == mo_new.volumes.size());
|
||||
for (size_t i=0; i<mo.volumes.size(); ++i) {
|
||||
if (! mo_new.volumes[i]->m_seam_facets.is_same_as(mo.volumes[i]->m_seam_facets))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
extern bool model_has_multi_part_objects(const Model &model)
|
||||
{
|
||||
for (const ModelObject *model_object : model.objects)
|
||||
|
|
|
@ -394,7 +394,7 @@ enum class ModelVolumeType : int {
|
|||
SUPPORT_BLOCKER,
|
||||
};
|
||||
|
||||
enum class FacetSupportType : int8_t {
|
||||
enum class EnforcerBlockerType : int8_t {
|
||||
// Maximum is 3. The value is serialized in TriangleSelector into 2 bits!
|
||||
NONE = 0,
|
||||
ENFORCER = 1,
|
||||
|
@ -407,7 +407,7 @@ public:
|
|||
|
||||
const std::map<int, std::vector<bool>>& get_data() const { return m_data; }
|
||||
bool set(const TriangleSelector& selector);
|
||||
indexed_triangle_set get_facets(const ModelVolume& mv, FacetSupportType type) const;
|
||||
indexed_triangle_set get_facets(const ModelVolume& mv, EnforcerBlockerType type) const;
|
||||
void clear();
|
||||
std::string get_triangle_as_string(int i) const;
|
||||
void set_triangle_from_string(int triangle_id, const std::string& str);
|
||||
|
@ -464,6 +464,9 @@ public:
|
|||
// List of mesh facets to be supported/unsupported.
|
||||
FacetsAnnotation m_supported_facets;
|
||||
|
||||
// List of seam enforcers/blockers.
|
||||
FacetsAnnotation m_seam_facets;
|
||||
|
||||
// A parent object owning this modifier volume.
|
||||
ModelObject* get_object() const { return this->object; }
|
||||
ModelVolumeType type() const { return m_type; }
|
||||
|
@ -593,7 +596,7 @@ private:
|
|||
ObjectBase(other),
|
||||
name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull),
|
||||
config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation),
|
||||
m_supported_facets(other.m_supported_facets)
|
||||
m_supported_facets(other.m_supported_facets), m_seam_facets(other.m_seam_facets)
|
||||
{
|
||||
assert(this->id().valid()); assert(this->config.id().valid()); assert(this->id() != this->config.id());
|
||||
assert(this->id() == other.id() && this->config.id() == other.config.id());
|
||||
|
@ -612,6 +615,7 @@ private:
|
|||
assert(this->config.id().valid()); assert(this->config.id() != other.config.id()); assert(this->id() != this->config.id());
|
||||
|
||||
m_supported_facets.clear();
|
||||
m_seam_facets.clear();
|
||||
}
|
||||
|
||||
ModelVolume& operator=(ModelVolume &rhs) = delete;
|
||||
|
@ -625,7 +629,7 @@ private:
|
|||
template<class Archive> void load(Archive &ar) {
|
||||
bool has_convex_hull;
|
||||
ar(name, source, m_mesh, m_type, m_material_id, m_transformation,
|
||||
m_is_splittable, has_convex_hull, m_supported_facets);
|
||||
m_is_splittable, has_convex_hull, m_supported_facets, m_seam_facets);
|
||||
cereal::load_by_value(ar, config);
|
||||
assert(m_mesh);
|
||||
if (has_convex_hull) {
|
||||
|
@ -639,7 +643,7 @@ private:
|
|||
template<class Archive> void save(Archive &ar) const {
|
||||
bool has_convex_hull = m_convex_hull.get() != nullptr;
|
||||
ar(name, source, m_mesh, m_type, m_material_id, m_transformation,
|
||||
m_is_splittable, has_convex_hull, m_supported_facets);
|
||||
m_is_splittable, has_convex_hull, m_supported_facets, m_seam_facets);
|
||||
cereal::save_by_value(ar, config);
|
||||
if (has_convex_hull)
|
||||
cereal::save_optional(ar, m_convex_hull);
|
||||
|
@ -904,6 +908,10 @@ extern bool model_volume_list_changed(const ModelObject &model_object_old, const
|
|||
// The function assumes that volumes list is synchronized.
|
||||
extern bool model_custom_supports_data_changed(const ModelObject& mo, const ModelObject& mo_new);
|
||||
|
||||
// Test whether the now ModelObject has newer custom seam data than the old one.
|
||||
// The function assumes that volumes list is synchronized.
|
||||
extern bool model_custom_seam_data_changed(const ModelObject& mo, const ModelObject& mo_new);
|
||||
|
||||
// If the model has multi-part objects, then it is currently not supported by the SLA mode.
|
||||
// Either the model cannot be loaded, or a SLA printer has to be activated.
|
||||
extern bool model_has_multi_part_objects(const Model &model);
|
||||
|
|
100
src/libslic3r/PNGRead.cpp
Normal file
100
src/libslic3r/PNGRead.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
#include "PNGRead.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <cstdio>
|
||||
#include <png.h>
|
||||
|
||||
namespace Slic3r { namespace png {
|
||||
|
||||
struct PNGDescr {
|
||||
png_struct *png = nullptr; png_info *info = nullptr;
|
||||
|
||||
PNGDescr() = default;
|
||||
PNGDescr(const PNGDescr&) = delete;
|
||||
PNGDescr(PNGDescr&&) = delete;
|
||||
PNGDescr& operator=(const PNGDescr&) = delete;
|
||||
PNGDescr& operator=(PNGDescr&&) = delete;
|
||||
|
||||
~PNGDescr()
|
||||
{
|
||||
if (png && info) png_destroy_info_struct(png, &info);
|
||||
if (png) png_destroy_read_struct( &png, nullptr, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
bool is_png(const ReadBuf &rb)
|
||||
{
|
||||
static const constexpr int PNG_SIG_BYTES = 8;
|
||||
|
||||
#if PNG_LIBPNG_VER_MINOR <= 2
|
||||
// Earlier libpng versions had png_sig_cmp(png_bytep, ...) which is not
|
||||
// a const pointer. It is not possible to cast away the const qualifier from
|
||||
// the input buffer so... yes... life is challenging...
|
||||
png_byte buf[PNG_SIG_BYTES];
|
||||
auto inbuf = static_cast<const std::uint8_t *>(rb.buf);
|
||||
std::copy(inbuf, inbuf + PNG_SIG_BYTES, buf);
|
||||
#else
|
||||
auto buf = static_cast<png_const_bytep>(rb.buf);
|
||||
#endif
|
||||
|
||||
return rb.sz >= PNG_SIG_BYTES && !png_sig_cmp(buf, 0, PNG_SIG_BYTES);
|
||||
}
|
||||
|
||||
// Buffer read callback for libpng. It provides an allocated output buffer and
|
||||
// the amount of data it desires to read from the input.
|
||||
void png_read_callback(png_struct *png_ptr,
|
||||
png_bytep outBytes,
|
||||
png_size_t byteCountToRead)
|
||||
{
|
||||
// Retrieve our input buffer through the png_ptr
|
||||
auto reader = static_cast<IStream *>(png_get_io_ptr(png_ptr));
|
||||
|
||||
if (!reader || !reader->is_ok()) return;
|
||||
|
||||
reader->read(static_cast<std::uint8_t *>(outBytes), byteCountToRead);
|
||||
}
|
||||
|
||||
bool decode_png(IStream &in_buf, ImageGreyscale &out_img)
|
||||
{
|
||||
static const constexpr int PNG_SIG_BYTES = 8;
|
||||
|
||||
std::vector<png_byte> sig(PNG_SIG_BYTES, 0);
|
||||
in_buf.read(sig.data(), PNG_SIG_BYTES);
|
||||
if (!png_check_sig(sig.data(), PNG_SIG_BYTES))
|
||||
return false;
|
||||
|
||||
PNGDescr dsc;
|
||||
dsc.png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr,
|
||||
nullptr);
|
||||
|
||||
if(!dsc.png) return false;
|
||||
|
||||
dsc.info = png_create_info_struct(dsc.png);
|
||||
if(!dsc.info) return false;
|
||||
|
||||
png_set_read_fn(dsc.png, static_cast<void *>(&in_buf), png_read_callback);
|
||||
|
||||
// Tell that we have already read the first bytes to check the signature
|
||||
png_set_sig_bytes(dsc.png, PNG_SIG_BYTES);
|
||||
|
||||
png_read_info(dsc.png, dsc.info);
|
||||
|
||||
out_img.cols = png_get_image_width(dsc.png, dsc.info);
|
||||
out_img.rows = png_get_image_height(dsc.png, dsc.info);
|
||||
size_t color_type = png_get_color_type(dsc.png, dsc.info);
|
||||
size_t bit_depth = png_get_bit_depth(dsc.png, dsc.info);
|
||||
|
||||
if (color_type != PNG_COLOR_TYPE_GRAY || bit_depth != 8)
|
||||
return false;
|
||||
|
||||
out_img.buf.resize(out_img.rows * out_img.cols);
|
||||
|
||||
auto readbuf = static_cast<png_bytep>(out_img.buf.data());
|
||||
for (size_t r = 0; r < out_img.rows; ++r)
|
||||
png_read_row(dsc.png, readbuf + r * out_img.cols, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::png
|
70
src/libslic3r/PNGRead.hpp
Normal file
70
src/libslic3r/PNGRead.hpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#ifndef PNGREAD_HPP
|
||||
#define PNGREAD_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <istream>
|
||||
|
||||
namespace Slic3r { namespace png {
|
||||
|
||||
// Interface for an input stream of encoded png image data.
|
||||
struct IStream {
|
||||
virtual ~IStream() = default;
|
||||
virtual size_t read(std::uint8_t *outp, size_t amount) = 0;
|
||||
virtual bool is_ok() const = 0;
|
||||
};
|
||||
|
||||
// The output format of decode_png: a 2D pixel matrix stored continuously row
|
||||
// after row (row major layout).
|
||||
template<class PxT> struct Image {
|
||||
std::vector<PxT> buf;
|
||||
size_t rows, cols;
|
||||
PxT get(size_t row, size_t col) const { return buf[row * cols + col]; }
|
||||
};
|
||||
|
||||
using ImageGreyscale = Image<uint8_t>;
|
||||
|
||||
// Only decodes true 8 bit grayscale png images. Returns false for other formats
|
||||
// TODO (if needed): implement transformation of rgb images into grayscale...
|
||||
bool decode_png(IStream &stream, ImageGreyscale &out_img);
|
||||
|
||||
// TODO (if needed)
|
||||
// struct RGB { uint8_t r, g, b; };
|
||||
// using ImageRGB = Image<RGB>;
|
||||
// bool decode_png(IStream &stream, ImageRGB &img);
|
||||
|
||||
|
||||
// Encoded png data buffer: a simple read-only buffer and its size.
|
||||
struct ReadBuf { const void *buf = nullptr; const size_t sz = 0; };
|
||||
|
||||
bool is_png(const ReadBuf &pngbuf);
|
||||
|
||||
template<class Img> bool decode_png(const ReadBuf &in_buf, Img &out_img)
|
||||
{
|
||||
struct ReadBufStream: public IStream {
|
||||
const ReadBuf &rbuf_ref; size_t pos = 0;
|
||||
|
||||
explicit ReadBufStream(const ReadBuf &buf): rbuf_ref{buf} {}
|
||||
|
||||
size_t read(std::uint8_t *outp, size_t amount) override
|
||||
{
|
||||
if (amount > rbuf_ref.sz - pos) return 0;
|
||||
|
||||
auto buf = static_cast<const std::uint8_t *>(rbuf_ref.buf);
|
||||
std::copy(buf + pos, buf + (pos + amount), outp);
|
||||
pos += amount;
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
bool is_ok() const override { return pos < rbuf_ref.sz; }
|
||||
} stream{in_buf};
|
||||
|
||||
return decode_png(stream, out_img);
|
||||
}
|
||||
|
||||
// TODO: std::istream of FILE* could be similarly adapted in case its needed...
|
||||
|
||||
}} // namespace Slic3r::png
|
||||
|
||||
#endif // PNGREAD_HPP
|
|
@ -634,7 +634,9 @@ void PresetCollection::add_default_preset(const std::vector<std::string> &keys,
|
|||
// Throws an exception on error.
|
||||
void PresetCollection::load_presets(const std::string &dir_path, const std::string &subdir)
|
||||
{
|
||||
boost::filesystem::path dir = boost::filesystem::canonical(boost::filesystem::path(dir_path) / subdir).make_preferred();
|
||||
// Don't use boost::filesystem::canonical() on Windows, it is broken in regard to reparse points,
|
||||
// see https://github.com/prusa3d/PrusaSlicer/issues/732
|
||||
boost::filesystem::path dir = boost::filesystem::absolute(boost::filesystem::path(dir_path) / subdir).make_preferred();
|
||||
m_dir_path = dir.string();
|
||||
std::string errors_cummulative;
|
||||
// Store the loaded presets into a new vector, otherwise the binary search for already existing presets would be broken.
|
||||
|
@ -1518,7 +1520,9 @@ PhysicalPrinterCollection::PhysicalPrinterCollection( const std::vector<std::str
|
|||
// Throws an exception on error.
|
||||
void PhysicalPrinterCollection::load_printers(const std::string& dir_path, const std::string& subdir)
|
||||
{
|
||||
boost::filesystem::path dir = boost::filesystem::canonical(boost::filesystem::path(dir_path) / subdir).make_preferred();
|
||||
// Don't use boost::filesystem::canonical() on Windows, it is broken in regard to reparse points,
|
||||
// see https://github.com/prusa3d/PrusaSlicer/issues/732
|
||||
boost::filesystem::path dir = boost::filesystem::absolute(boost::filesystem::path(dir_path) / subdir).make_preferred();
|
||||
m_dir_path = dir.string();
|
||||
std::string errors_cummulative;
|
||||
// Store the loaded printers into a new vector, otherwise the binary search for already existing presets would be broken.
|
||||
|
@ -1812,6 +1816,26 @@ namespace PresetUtils {
|
|||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
std::string system_printer_bed_model(const Preset& preset)
|
||||
{
|
||||
std::string out;
|
||||
const VendorProfile::PrinterModel* pm = PresetUtils::system_printer_model(preset);
|
||||
if (pm != nullptr && !pm->bed_model.empty())
|
||||
out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_model;
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string system_printer_bed_texture(const Preset& preset)
|
||||
{
|
||||
std::string out;
|
||||
const VendorProfile::PrinterModel* pm = PresetUtils::system_printer_model(preset);
|
||||
if (pm != nullptr && !pm->bed_texture.empty())
|
||||
out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_texture;
|
||||
return out;
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
} // namespace PresetUtils
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -527,6 +527,10 @@ public:
|
|||
namespace PresetUtils {
|
||||
// PrinterModel of a system profile, from which this preset is derived, or null if it is not derived from a system profile.
|
||||
const VendorProfile::PrinterModel* system_printer_model(const Preset &preset);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
std::string system_printer_bed_model(const Preset& preset);
|
||||
std::string system_printer_bed_texture(const Preset& preset);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
} // namespace PresetUtils
|
||||
|
||||
|
||||
|
|
|
@ -404,6 +404,7 @@ static inline void model_volume_list_copy_configs(ModelObject &model_object_dst,
|
|||
mv_dst.name = mv_src.name;
|
||||
static_cast<DynamicPrintConfig&>(mv_dst.config) = static_cast<const DynamicPrintConfig&>(mv_src.config);
|
||||
mv_dst.m_supported_facets = mv_src.m_supported_facets;
|
||||
mv_dst.m_seam_facets = mv_src.m_seam_facets;
|
||||
//FIXME what to do with the materials?
|
||||
// mv_dst.m_material_id = mv_src.m_material_id;
|
||||
++ i_src;
|
||||
|
@ -867,6 +868,9 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||
model_volume_list_update_supports(model_object, model_object_new);
|
||||
}
|
||||
}
|
||||
if (model_custom_seam_data_changed(model_object, model_object_new)) {
|
||||
update_apply_status(this->invalidate_step(psGCodeExport));
|
||||
}
|
||||
if (! model_parts_differ && ! modifiers_differ) {
|
||||
// Synchronize Object's config.
|
||||
bool object_config_changed = model_object.config != model_object_new.config;
|
||||
|
@ -1632,13 +1636,21 @@ void Print::process()
|
|||
// The export_gcode may die for various reasons (fails to process output_filename_format,
|
||||
// write error into the G-code, cannot execute post-processing scripts).
|
||||
// It is up to the caller to show an error message.
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
std::string Print::export_gcode(const std::string& path_template, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#else
|
||||
std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
{
|
||||
// output everything to a G-code file
|
||||
// The following call may die if the output_filename_format template substitution fails.
|
||||
std::string path = this->output_filepath(path_template);
|
||||
std::string message;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
if (!path.empty() && result == nullptr) {
|
||||
#else
|
||||
if (! path.empty() && preview_data == nullptr) {
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
// Only show the path if preview_data is not set -> running from command line.
|
||||
message = L("Exporting G-code");
|
||||
message += " to ";
|
||||
|
@ -1649,7 +1661,11 @@ std::string Print::export_gcode(const std::string& path_template, GCodePreviewDa
|
|||
|
||||
// The following line may die for multiple reasons.
|
||||
GCode gcode;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
gcode.do_export(this, path.c_str(), result, thumbnail_cb);
|
||||
#else
|
||||
gcode.do_export(this, path.c_str(), preview_data, thumbnail_cb);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
return path.c_str();
|
||||
}
|
||||
|
||||
|
@ -2180,16 +2196,16 @@ DynamicConfig PrintStatistics::config() const
|
|||
DynamicConfig config;
|
||||
std::string normal_print_time = short_time(this->estimated_normal_print_time);
|
||||
std::string silent_print_time = short_time(this->estimated_silent_print_time);
|
||||
config.set_key_value("print_time", new ConfigOptionString(normal_print_time));
|
||||
config.set_key_value("normal_print_time", new ConfigOptionString(normal_print_time));
|
||||
config.set_key_value("silent_print_time", new ConfigOptionString(silent_print_time));
|
||||
config.set_key_value("used_filament", new ConfigOptionFloat (this->total_used_filament / 1000.));
|
||||
config.set_key_value("extruded_volume", new ConfigOptionFloat (this->total_extruded_volume));
|
||||
config.set_key_value("total_cost", new ConfigOptionFloat (this->total_cost));
|
||||
config.set_key_value("print_time", new ConfigOptionString(normal_print_time));
|
||||
config.set_key_value("normal_print_time", new ConfigOptionString(normal_print_time));
|
||||
config.set_key_value("silent_print_time", new ConfigOptionString(silent_print_time));
|
||||
config.set_key_value("used_filament", new ConfigOptionFloat(this->total_used_filament / 1000.));
|
||||
config.set_key_value("extruded_volume", new ConfigOptionFloat(this->total_extruded_volume));
|
||||
config.set_key_value("total_cost", new ConfigOptionFloat(this->total_cost));
|
||||
config.set_key_value("total_toolchanges", new ConfigOptionInt(this->total_toolchanges));
|
||||
config.set_key_value("total_weight", new ConfigOptionFloat (this->total_weight));
|
||||
config.set_key_value("total_wipe_tower_cost", new ConfigOptionFloat (this->total_wipe_tower_cost));
|
||||
config.set_key_value("total_wipe_tower_filament", new ConfigOptionFloat (this->total_wipe_tower_filament));
|
||||
config.set_key_value("total_weight", new ConfigOptionFloat(this->total_weight));
|
||||
config.set_key_value("total_wipe_tower_cost", new ConfigOptionFloat(this->total_wipe_tower_cost));
|
||||
config.set_key_value("total_wipe_tower_filament", new ConfigOptionFloat(this->total_wipe_tower_filament));
|
||||
return config;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
#include "GCode/ToolOrdering.hpp"
|
||||
#include "GCode/WipeTower.hpp"
|
||||
#include "GCode/ThumbnailData.hpp"
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include "GCode/GCodeProcessor.hpp"
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
#include "libslic3r.h"
|
||||
|
||||
|
@ -20,7 +23,9 @@ class Print;
|
|||
class PrintObject;
|
||||
class ModelObject;
|
||||
class GCode;
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
class GCodePreviewData;
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
enum class SlicingMode : uint32_t;
|
||||
class Layer;
|
||||
class SupportLayer;
|
||||
|
@ -186,10 +191,8 @@ public:
|
|||
std::vector<ExPolygons> slice_support_blockers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_BLOCKER); }
|
||||
std::vector<ExPolygons> slice_support_enforcers() const { return this->slice_support_volumes(ModelVolumeType::SUPPORT_ENFORCER); }
|
||||
|
||||
// Helpers to project custom supports on slices
|
||||
void project_and_append_custom_supports(FacetSupportType type, std::vector<ExPolygons>& expolys) const;
|
||||
void project_and_append_custom_enforcers(std::vector<ExPolygons>& enforcers) const { project_and_append_custom_supports(FacetSupportType::ENFORCER, enforcers); }
|
||||
void project_and_append_custom_blockers(std::vector<ExPolygons>& blockers) const { project_and_append_custom_supports(FacetSupportType::BLOCKER, blockers); }
|
||||
// Helpers to project custom facets on slices
|
||||
void project_and_append_custom_facets(bool seam, EnforcerBlockerType type, std::vector<ExPolygons>& expolys) const;
|
||||
|
||||
private:
|
||||
// to be called from Print only.
|
||||
|
@ -300,8 +303,10 @@ struct PrintStatistics
|
|||
PrintStatistics() { clear(); }
|
||||
std::string estimated_normal_print_time;
|
||||
std::string estimated_silent_print_time;
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
std::vector<std::pair<CustomGCode::Type, std::string>> estimated_normal_custom_gcode_print_times;
|
||||
std::vector<std::pair<CustomGCode::Type, std::string>> estimated_silent_custom_gcode_print_times;
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
double total_used_filament;
|
||||
double total_extruded_volume;
|
||||
double total_cost;
|
||||
|
@ -319,10 +324,12 @@ struct PrintStatistics
|
|||
std::string finalize_output_path(const std::string &path_in) const;
|
||||
|
||||
void clear() {
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
estimated_normal_print_time.clear();
|
||||
estimated_silent_print_time.clear();
|
||||
estimated_normal_custom_gcode_print_times.clear();
|
||||
estimated_silent_custom_gcode_print_times.clear();
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
total_used_filament = 0.;
|
||||
total_extruded_volume = 0.;
|
||||
total_cost = 0.;
|
||||
|
@ -362,7 +369,11 @@ public:
|
|||
void process() override;
|
||||
// Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file.
|
||||
// If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
std::string export_gcode(const std::string& path_template, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||
#else
|
||||
std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
// methods for handling state
|
||||
bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); }
|
||||
|
@ -417,6 +428,7 @@ public:
|
|||
const Polygon& first_layer_convex_hull() const { return m_first_layer_convex_hull; }
|
||||
|
||||
const PrintStatistics& print_statistics() const { return m_print_statistics; }
|
||||
PrintStatistics& print_statistics() { return m_print_statistics; }
|
||||
|
||||
// Wipe tower support.
|
||||
bool has_wipe_tower() const;
|
||||
|
|
|
@ -507,9 +507,9 @@ protected:
|
|||
bool set_started(PrintStepEnum step) { return m_state.set_started(step, this->state_mutex(), [this](){ this->throw_if_canceled(); }); }
|
||||
PrintStateBase::TimeStamp set_done(PrintStepEnum step) {
|
||||
std::pair<PrintStateBase::TimeStamp, bool> status = m_state.set_done(step, this->state_mutex(), [this](){ this->throw_if_canceled(); });
|
||||
if (status.second)
|
||||
this->status_update_warnings(this->id(), static_cast<int>(step), PrintStateBase::WarningLevel::NON_CRITICAL, std::string());
|
||||
return status.first;
|
||||
if (status.second)
|
||||
this->status_update_warnings(this->id(), static_cast<int>(step), PrintStateBase::WarningLevel::NON_CRITICAL, std::string());
|
||||
return status.first;
|
||||
}
|
||||
bool invalidate_step(PrintStepEnum step)
|
||||
{ return m_state.invalidate(step, this->cancel_callback()); }
|
||||
|
@ -556,9 +556,9 @@ protected:
|
|||
{ return m_state.set_started(step, PrintObjectBase::state_mutex(m_print), [this](){ this->throw_if_canceled(); }); }
|
||||
PrintStateBase::TimeStamp set_done(PrintObjectStepEnum step) {
|
||||
std::pair<PrintStateBase::TimeStamp, bool> status = m_state.set_done(step, PrintObjectBase::state_mutex(m_print), [this](){ this->throw_if_canceled(); });
|
||||
if (status.second)
|
||||
this->status_update_warnings(m_print, static_cast<int>(step), PrintStateBase::WarningLevel::NON_CRITICAL, std::string());
|
||||
return status.first;
|
||||
if (status.second)
|
||||
this->status_update_warnings(m_print, static_cast<int>(step), PrintStateBase::WarningLevel::NON_CRITICAL, std::string());
|
||||
return status.first;
|
||||
}
|
||||
|
||||
bool invalidate_step(PrintObjectStepEnum step)
|
||||
|
|
|
@ -3530,6 +3530,12 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
|||
def->cli = "export-gcode|gcode|g";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("gcodeviewer", coBool);
|
||||
def->label = L("G-code viewer");
|
||||
def->tooltip = L("Visualize an already sliced and saved G-code");
|
||||
def->cli = "gcodeviewer";
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("slice", coBool);
|
||||
def->label = L("Slice");
|
||||
def->tooltip = L("Slice the model as FFF or SLA based on the printer_technology configuration value.");
|
||||
|
|
|
@ -239,9 +239,13 @@ class DynamicPrintConfig : public DynamicConfig
|
|||
public:
|
||||
DynamicPrintConfig() {}
|
||||
DynamicPrintConfig(const DynamicPrintConfig &rhs) : DynamicConfig(rhs) {}
|
||||
DynamicPrintConfig(DynamicPrintConfig &&rhs) noexcept : DynamicConfig(std::move(rhs)) {}
|
||||
explicit DynamicPrintConfig(const StaticPrintConfig &rhs);
|
||||
explicit DynamicPrintConfig(const ConfigBase &rhs) : DynamicConfig(rhs) {}
|
||||
|
||||
DynamicPrintConfig& operator=(const DynamicPrintConfig &rhs) { DynamicConfig::operator=(rhs); return *this; }
|
||||
DynamicPrintConfig& operator=(DynamicPrintConfig &&rhs) noexcept { DynamicConfig::operator=(std::move(rhs)); return *this; }
|
||||
|
||||
static DynamicPrintConfig full_print_config();
|
||||
static DynamicPrintConfig* new_from_defaults_keys(const std::vector<std::string> &keys);
|
||||
|
||||
|
|
|
@ -2669,12 +2669,14 @@ void PrintObject::_generate_support_material()
|
|||
}
|
||||
|
||||
|
||||
void PrintObject::project_and_append_custom_supports(
|
||||
FacetSupportType type, std::vector<ExPolygons>& expolys) const
|
||||
void PrintObject::project_and_append_custom_facets(
|
||||
bool seam, EnforcerBlockerType type, std::vector<ExPolygons>& expolys) const
|
||||
{
|
||||
for (const ModelVolume* mv : this->model_object()->volumes) {
|
||||
const indexed_triangle_set custom_facets = mv->m_supported_facets.get_facets(*mv, type);
|
||||
if (custom_facets.indices.empty())
|
||||
const indexed_triangle_set custom_facets = seam
|
||||
? mv->m_seam_facets.get_facets(*mv, type)
|
||||
: mv->m_supported_facets.get_facets(*mv, type);
|
||||
if (! mv->is_model_part() || custom_facets.indices.empty())
|
||||
continue;
|
||||
|
||||
const Transform3f& tr1 = mv->get_matrix().cast<float>();
|
||||
|
@ -2721,7 +2723,7 @@ void PrintObject::project_and_append_custom_supports(
|
|||
|
||||
// Ignore triangles with upward-pointing normal. Don't forget about mirroring.
|
||||
float z_comp = (facet[1]-facet[0]).cross(facet[2]-facet[0]).z();
|
||||
if (tr_det_sign * z_comp > 0.)
|
||||
if (! seam && tr_det_sign * z_comp > 0.)
|
||||
continue;
|
||||
|
||||
// Sort the three vertices according to z-coordinate.
|
||||
|
|
|
@ -128,12 +128,13 @@ protected:
|
|||
}
|
||||
|
||||
public:
|
||||
template<class GammaFn> AGGRaster(const Resolution &res,
|
||||
template<class GammaFn>
|
||||
AGGRaster(const Resolution &res,
|
||||
const PixelDim & pd,
|
||||
const Trafo & trafo,
|
||||
const TColor & foreground,
|
||||
const TColor & background,
|
||||
GammaFn && gammafn)
|
||||
const TColor & foreground,
|
||||
const TColor & background,
|
||||
GammaFn && gammafn)
|
||||
: m_resolution(res)
|
||||
, m_pxdim_scaled(SCALING_FACTOR / pd.w_mm, SCALING_FACTOR / pd.h_mm)
|
||||
, m_buf(res.pixels())
|
||||
|
|
|
@ -58,6 +58,8 @@ struct DrainHole
|
|||
|
||||
using DrainHoles = std::vector<DrainHole>;
|
||||
|
||||
constexpr float HoleStickOutLength = 1.f;
|
||||
|
||||
std::unique_ptr<TriangleMesh> generate_interior(const TriangleMesh &mesh,
|
||||
const HollowingConfig & = {},
|
||||
const JobController &ctl = {});
|
||||
|
|
|
@ -28,15 +28,9 @@ void reproject_support_points(const IndexedMesh &mesh, std::vector<PointType> &p
|
|||
inline void reproject_points_and_holes(ModelObject *object)
|
||||
{
|
||||
bool has_sppoints = !object->sla_support_points.empty();
|
||||
bool has_holes = !object->sla_drain_holes.empty();
|
||||
|
||||
// Disabling reprojection of holes as they have a significant offset away
|
||||
// from the model body which tolerates minor geometrical changes.
|
||||
//
|
||||
// TODO: uncomment and ensure the right offset of the hole points if
|
||||
// reprojection would still be necessary.
|
||||
// bool has_holes = !object->sla_drain_holes.empty();
|
||||
|
||||
if (!object || (/*!has_holes &&*/ !has_sppoints)) return;
|
||||
if (!object || (!has_holes && !has_sppoints)) return;
|
||||
|
||||
TriangleMesh rmsh = object->raw_mesh();
|
||||
rmsh.require_shared_vertices();
|
||||
|
@ -45,8 +39,8 @@ inline void reproject_points_and_holes(ModelObject *object)
|
|||
if (has_sppoints)
|
||||
reproject_support_points(emesh, object->sla_support_points);
|
||||
|
||||
// if (has_holes)
|
||||
// reproject_support_points(emesh, object->sla_drain_holes);
|
||||
if (has_holes)
|
||||
reproject_support_points(emesh, object->sla_drain_holes);
|
||||
}
|
||||
|
||||
}}
|
||||
|
|
|
@ -1181,6 +1181,12 @@ sla::DrainHoles SLAPrintObject::transformed_drainhole_points() const
|
|||
hl.normal = Vec3f(hl.normal(0)/(sc(0)*sc(0)),
|
||||
hl.normal(1)/(sc(1)*sc(1)),
|
||||
hl.normal(2)/(sc(2)*sc(2)));
|
||||
|
||||
// Now shift the hole a bit above the object and make it deeper to
|
||||
// compensate for it. This is to avoid problems when the hole is placed
|
||||
// on (nearly) flat surface.
|
||||
hl.pos -= hl.normal.normalized() * sla::HoleStickOutLength;
|
||||
hl.height += sla::HoleStickOutLength;
|
||||
}
|
||||
|
||||
return pts;
|
||||
|
|
|
@ -972,8 +972,8 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
|
|||
std::vector<ExPolygons> blockers = object.slice_support_blockers();
|
||||
|
||||
// Append custom supports.
|
||||
object.project_and_append_custom_enforcers(enforcers);
|
||||
object.project_and_append_custom_blockers(blockers);
|
||||
object.project_and_append_custom_facets(false, EnforcerBlockerType::ENFORCER, enforcers);
|
||||
object.project_and_append_custom_facets(false, EnforcerBlockerType::BLOCKER, blockers);
|
||||
|
||||
// Output layers, sorted by top Z.
|
||||
MyLayersPtr contact_out;
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#define ENABLE_RENDER_STATISTICS 0
|
||||
// Shows an imgui dialog with camera related data
|
||||
#define ENABLE_CAMERA_STATISTICS 0
|
||||
// Render the picking pass instead of the main scene (use [T] key to toggle between regular rendering and picking pass only rendering)
|
||||
// Render the picking pass instead of the main scene (use [T] key to toggle between regular rendering and picking pass only rendering)
|
||||
#define ENABLE_RENDER_PICKING_PASS 0
|
||||
// Enable extracting thumbnails from selected gcode and save them as png files
|
||||
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG 0
|
||||
|
@ -54,5 +54,10 @@
|
|||
// Enable built-in DPI changed event handler of wxWidgets 3.1.3
|
||||
#define ENABLE_WX_3_1_3_DPI_CHANGED_EVENT (1 && ENABLE_2_3_0_ALPHA1)
|
||||
|
||||
// Enable G-Code viewer
|
||||
#define ENABLE_GCODE_VIEWER (1 && ENABLE_2_3_0_ALPHA1)
|
||||
#define ENABLE_GCODE_VIEWER_STATISTICS (0 && ENABLE_GCODE_VIEWER)
|
||||
#define ENABLE_GCODE_VIEWER_DATA_CHECKING (0 && ENABLE_GCODE_VIEWER)
|
||||
#define ENABLE_GCODE_VIEWER_TASKBAR_ICON (0 && ENABLE_GCODE_VIEWER)
|
||||
|
||||
#endif // _prusaslicer_technologies_h_
|
||||
|
|
|
@ -35,7 +35,7 @@ void TriangleSelector::Triangle::set_division(int sides_to_split, int special_si
|
|||
|
||||
void TriangleSelector::select_patch(const Vec3f& hit, int facet_start,
|
||||
const Vec3f& source, const Vec3f& dir,
|
||||
float radius, FacetSupportType new_state)
|
||||
float radius, EnforcerBlockerType new_state)
|
||||
{
|
||||
assert(facet_start < m_orig_size_indices);
|
||||
assert(is_approx(dir.norm(), 1.f));
|
||||
|
@ -77,7 +77,7 @@ void TriangleSelector::select_patch(const Vec3f& hit, int facet_start,
|
|||
// the triangle recursively, selecting just subtriangles truly inside the circle.
|
||||
// This is done by an actual recursive call. Returns false if the triangle is
|
||||
// outside the cursor.
|
||||
bool TriangleSelector::select_triangle(int facet_idx, FacetSupportType type, bool recursive_call)
|
||||
bool TriangleSelector::select_triangle(int facet_idx, EnforcerBlockerType type, bool recursive_call)
|
||||
{
|
||||
assert(facet_idx < int(m_triangles.size()));
|
||||
|
||||
|
@ -140,7 +140,7 @@ bool TriangleSelector::select_triangle(int facet_idx, FacetSupportType type, boo
|
|||
|
||||
|
||||
|
||||
void TriangleSelector::set_facet(int facet_idx, FacetSupportType state)
|
||||
void TriangleSelector::set_facet(int facet_idx, EnforcerBlockerType state)
|
||||
{
|
||||
assert(facet_idx < m_orig_size_indices);
|
||||
undivide_triangle(facet_idx);
|
||||
|
@ -157,7 +157,7 @@ void TriangleSelector::split_triangle(int facet_idx)
|
|||
|
||||
Triangle* tr = &m_triangles[facet_idx];
|
||||
|
||||
FacetSupportType old_type = tr->get_state();
|
||||
EnforcerBlockerType old_type = tr->get_state();
|
||||
|
||||
if (tr->was_split_before() != 0) {
|
||||
// This triangle is not split at the moment, but was at one point
|
||||
|
@ -323,7 +323,7 @@ void TriangleSelector::remove_useless_children(int facet_idx)
|
|||
|
||||
|
||||
// Return if a child is not leaf or two children differ in type.
|
||||
FacetSupportType first_child_type = FacetSupportType::NONE;
|
||||
EnforcerBlockerType first_child_type = EnforcerBlockerType::NONE;
|
||||
for (int child_idx=0; child_idx<=tr.number_of_split_sides(); ++child_idx) {
|
||||
if (m_triangles[tr.children[child_idx]].is_split())
|
||||
return;
|
||||
|
@ -456,7 +456,7 @@ void TriangleSelector::push_triangle(int a, int b, int c)
|
|||
}
|
||||
|
||||
|
||||
void TriangleSelector::perform_split(int facet_idx, FacetSupportType old_state)
|
||||
void TriangleSelector::perform_split(int facet_idx, EnforcerBlockerType old_state)
|
||||
{
|
||||
Triangle* tr = &m_triangles[facet_idx];
|
||||
|
||||
|
@ -520,7 +520,7 @@ void TriangleSelector::perform_split(int facet_idx, FacetSupportType old_state)
|
|||
|
||||
|
||||
|
||||
indexed_triangle_set TriangleSelector::get_facets(FacetSupportType state) const
|
||||
indexed_triangle_set TriangleSelector::get_facets(EnforcerBlockerType state) const
|
||||
{
|
||||
indexed_triangle_set out;
|
||||
for (const Triangle& tr : m_triangles) {
|
||||
|
@ -542,7 +542,7 @@ std::map<int, std::vector<bool>> TriangleSelector::serialize() const
|
|||
{
|
||||
// Each original triangle of the mesh is assigned a number encoding its state
|
||||
// or how it is split. Each triangle is encoded by 4 bits (xxyy):
|
||||
// leaf triangle: xx = FacetSupportType, yy = 0
|
||||
// leaf triangle: xx = EnforcerBlockerType, yy = 0
|
||||
// non-leaf: xx = special side, yy = number of split sides
|
||||
// These are bitwise appended and formed into one 64-bit integer.
|
||||
|
||||
|
@ -553,7 +553,7 @@ std::map<int, std::vector<bool>> TriangleSelector::serialize() const
|
|||
for (int i=0; i<m_orig_size_indices; ++i) {
|
||||
const Triangle& tr = m_triangles[i];
|
||||
|
||||
if (! tr.is_split() && tr.get_state() == FacetSupportType::NONE)
|
||||
if (! tr.is_split() && tr.get_state() == EnforcerBlockerType::NONE)
|
||||
continue; // no need to save anything, unsplit and unselected is default
|
||||
|
||||
std::vector<bool> data; // complete encoding of this mesh triangle
|
||||
|
@ -627,7 +627,7 @@ void TriangleSelector::deserialize(const std::map<int, std::vector<bool>> data)
|
|||
int num_of_split_sides = (next_code & 0b11);
|
||||
int num_of_children = num_of_split_sides != 0 ? num_of_split_sides + 1 : 0;
|
||||
bool is_split = num_of_children != 0;
|
||||
FacetSupportType state = FacetSupportType(next_code >> 2);
|
||||
EnforcerBlockerType state = EnforcerBlockerType(next_code >> 2);
|
||||
int special_side = (next_code >> 2);
|
||||
|
||||
// Take care of the first iteration separately, so handling of the others is simpler.
|
||||
|
@ -641,7 +641,7 @@ void TriangleSelector::deserialize(const std::map<int, std::vector<bool>> data)
|
|||
// then go to the next.
|
||||
parents.push_back({triangle_id, 0, num_of_children});
|
||||
m_triangles[triangle_id].set_division(num_of_children-1, special_side);
|
||||
perform_split(triangle_id, FacetSupportType::NONE);
|
||||
perform_split(triangle_id, EnforcerBlockerType::NONE);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -655,7 +655,7 @@ void TriangleSelector::deserialize(const std::map<int, std::vector<bool>> data)
|
|||
const ProcessingInfo& last = parents.back();
|
||||
int this_idx = m_triangles[last.facet_id].children[last.processed_children];
|
||||
m_triangles[this_idx].set_division(num_of_children-1, special_side);
|
||||
perform_split(this_idx, FacetSupportType::NONE);
|
||||
perform_split(this_idx, EnforcerBlockerType::NONE);
|
||||
parents.push_back({this_idx, 0, num_of_children});
|
||||
} else {
|
||||
// this triangle belongs to last split one
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
enum class FacetSupportType : int8_t;
|
||||
enum class EnforcerBlockerType : int8_t;
|
||||
|
||||
|
||||
|
||||
|
@ -29,13 +29,13 @@ public:
|
|||
const Vec3f& source, // camera position (mesh coords)
|
||||
const Vec3f& dir, // direction of the ray (mesh coords)
|
||||
float radius, // radius of the cursor
|
||||
FacetSupportType new_state); // enforcer or blocker?
|
||||
EnforcerBlockerType new_state); // enforcer or blocker?
|
||||
|
||||
// Get facets currently in the given state.
|
||||
indexed_triangle_set get_facets(FacetSupportType state) const;
|
||||
indexed_triangle_set get_facets(EnforcerBlockerType state) const;
|
||||
|
||||
// Set facet of the mesh to a given state. Only works for original triangles.
|
||||
void set_facet(int facet_idx, FacetSupportType state);
|
||||
void set_facet(int facet_idx, EnforcerBlockerType state);
|
||||
|
||||
// Clear everything and make the tree empty.
|
||||
void reset();
|
||||
|
@ -59,7 +59,7 @@ protected:
|
|||
// It increments/decrements reference counter on vertices.
|
||||
Triangle(int a, int b, int c)
|
||||
: verts_idxs{a, b, c},
|
||||
state{FacetSupportType(0)},
|
||||
state{EnforcerBlockerType(0)},
|
||||
number_of_splits{0},
|
||||
special_side_idx{0},
|
||||
old_number_of_splits{0}
|
||||
|
@ -77,8 +77,8 @@ protected:
|
|||
void set_division(int sides_to_split, int special_side_idx = -1);
|
||||
|
||||
// Get/set current state.
|
||||
void set_state(FacetSupportType type) { assert(! is_split()); state = type; }
|
||||
FacetSupportType get_state() const { assert(! is_split()); return state; }
|
||||
void set_state(EnforcerBlockerType type) { assert(! is_split()); state = type; }
|
||||
EnforcerBlockerType get_state() const { assert(! is_split()); return state; }
|
||||
|
||||
// Get info on how it's split.
|
||||
bool is_split() const { return number_of_split_sides() != 0; }
|
||||
|
@ -90,7 +90,7 @@ protected:
|
|||
private:
|
||||
int number_of_splits;
|
||||
int special_side_idx;
|
||||
FacetSupportType state;
|
||||
EnforcerBlockerType state;
|
||||
|
||||
// How many children were spawned during last split?
|
||||
// Is not reset on remerging the triangle.
|
||||
|
@ -133,7 +133,7 @@ protected:
|
|||
float m_old_cursor_radius;
|
||||
|
||||
// Private functions:
|
||||
bool select_triangle(int facet_idx, FacetSupportType type,
|
||||
bool select_triangle(int facet_idx, EnforcerBlockerType type,
|
||||
bool recursive_call = false);
|
||||
bool is_point_inside_cursor(const Vec3f& point) const;
|
||||
int vertices_inside(int facet_idx) const;
|
||||
|
@ -144,7 +144,7 @@ protected:
|
|||
bool is_pointer_in_triangle(int facet_idx) const;
|
||||
bool is_edge_inside_cursor(int facet_idx) const;
|
||||
void push_triangle(int a, int b, int c);
|
||||
void perform_split(int facet_idx, FacetSupportType old_state);
|
||||
void perform_split(int facet_idx, EnforcerBlockerType old_state);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -110,19 +110,20 @@ std::string header_slic3r_generated();
|
|||
// getpid platform wrapper
|
||||
extern unsigned get_current_pid();
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
template <typename Real>
|
||||
Real round_nearest(Real value, unsigned int decimals)
|
||||
{
|
||||
Real res = (Real)0;
|
||||
if (decimals == 0)
|
||||
res = ::round(value);
|
||||
else
|
||||
{
|
||||
else {
|
||||
Real power = ::pow((Real)10, (int)decimals);
|
||||
res = ::round(value * power + (Real)0.5) / power;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
// Compute the next highest power of 2 of 32-bit v
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html
|
||||
|
@ -337,6 +338,25 @@ inline std::string get_time_dhms(float time_in_secs)
|
|||
return buffer;
|
||||
}
|
||||
|
||||
inline std::string get_time_dhm(float time_in_secs)
|
||||
{
|
||||
int days = (int)(time_in_secs / 86400.0f);
|
||||
time_in_secs -= (float)days * 86400.0f;
|
||||
int hours = (int)(time_in_secs / 3600.0f);
|
||||
time_in_secs -= (float)hours * 3600.0f;
|
||||
int minutes = (int)(time_in_secs / 60.0f);
|
||||
|
||||
char buffer[64];
|
||||
if (days > 0)
|
||||
::sprintf(buffer, "%dd %dh %dm %ds", days, hours, minutes, (int)time_in_secs);
|
||||
else if (hours > 0)
|
||||
::sprintf(buffer, "%dh %dm %ds", hours, minutes, (int)time_in_secs);
|
||||
else if (minutes > 0)
|
||||
::sprintf(buffer, "%dm %ds", minutes, (int)time_in_secs);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#if WIN32
|
||||
|
|
25
src/platform/msw/PrusaSlicer-gcodeviewer.rc.in
Normal file
25
src/platform/msw/PrusaSlicer-gcodeviewer.rc.in
Normal file
|
@ -0,0 +1,25 @@
|
|||
1 VERSIONINFO
|
||||
FILEVERSION @SLIC3R_RC_VERSION@
|
||||
PRODUCTVERSION @SLIC3R_RC_VERSION@
|
||||
{
|
||||
BLOCK "StringFileInfo"
|
||||
{
|
||||
BLOCK "040904E4"
|
||||
{
|
||||
VALUE "CompanyName", "Prusa Research"
|
||||
VALUE "FileDescription", "@SLIC3R_APP_NAME@ G-code Viewer"
|
||||
VALUE "FileVersion", "@SLIC3R_BUILD_ID@"
|
||||
VALUE "ProductName", "@SLIC3R_APP_NAME@ G-code Viewer"
|
||||
VALUE "ProductVersion", "@SLIC3R_BUILD_ID@"
|
||||
VALUE "InternalName", "@SLIC3R_APP_NAME@ G-code Viewer"
|
||||
VALUE "LegalCopyright", "Copyright \251 2016-2020 Prusa Research, \251 2011-2018 Alessandro Ranelucci"
|
||||
VALUE "OriginalFilename", "prusa-gcodeviewer.exe"
|
||||
}
|
||||
}
|
||||
BLOCK "VarFileInfo"
|
||||
{
|
||||
VALUE "Translation", 0x409, 1252
|
||||
}
|
||||
}
|
||||
2 ICON "@SLIC3R_RESOURCES_DIR@/icons/PrusaSlicer-gcodeviewer.ico"
|
||||
1 24 "PrusaSlicer.manifest"
|
|
@ -21,6 +21,8 @@ set(SLIC3R_GUI_SOURCES
|
|||
GUI/3DScene.cpp
|
||||
GUI/3DScene.hpp
|
||||
GUI/format.hpp
|
||||
GUI/GLShadersManager.hpp
|
||||
GUI/GLShadersManager.cpp
|
||||
GUI/GLShader.cpp
|
||||
GUI/GLShader.hpp
|
||||
GUI/GLCanvas3D.hpp
|
||||
|
@ -51,12 +53,20 @@ set(SLIC3R_GUI_SOURCES
|
|||
GUI/Gizmos/GLGizmoCut.hpp
|
||||
GUI/Gizmos/GLGizmoHollow.cpp
|
||||
GUI/Gizmos/GLGizmoHollow.hpp
|
||||
GUI/Gizmos/GLGizmoPainterBase.cpp
|
||||
GUI/Gizmos/GLGizmoPainterBase.hpp
|
||||
GUI/Gizmos/GLGizmoSeam.cpp
|
||||
GUI/Gizmos/GLGizmoSeam.hpp
|
||||
GUI/GLSelectionRectangle.cpp
|
||||
GUI/GLSelectionRectangle.hpp
|
||||
GUI/GLModel.hpp
|
||||
GUI/GLModel.cpp
|
||||
GUI/GLTexture.hpp
|
||||
GUI/GLTexture.cpp
|
||||
GUI/GLToolbar.hpp
|
||||
GUI/GLToolbar.cpp
|
||||
GUI/GCodeViewer.hpp
|
||||
GUI/GCodeViewer.cpp
|
||||
GUI/Preferences.cpp
|
||||
GUI/Preferences.hpp
|
||||
GUI/PresetHints.cpp
|
||||
|
@ -185,13 +195,12 @@ set(SLIC3R_GUI_SOURCES
|
|||
Utils/Bonjour.hpp
|
||||
Utils/PresetUpdater.cpp
|
||||
Utils/PresetUpdater.hpp
|
||||
Utils/Profile.hpp
|
||||
Utils/UndoRedo.cpp
|
||||
Utils/UndoRedo.hpp
|
||||
Utils/HexFile.cpp
|
||||
Utils/HexFile.hpp
|
||||
Utils/Thread.hpp
|
||||
Utils/SLAImport.hpp
|
||||
Utils/SLAImport.cpp
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
|
|
|
@ -5,15 +5,24 @@
|
|||
#include "libslic3r/Polygon.hpp"
|
||||
#include "libslic3r/ClipperUtils.hpp"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "GLCanvas3D.hpp"
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include "3DScene.hpp"
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include <boost/log/trivial.hpp>
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
static const float GROUND_Z = -0.02f;
|
||||
|
||||
|
@ -36,10 +45,8 @@ bool GeometryBuffer::set_from_triangles(const Polygons& triangles, float z, bool
|
|||
float max_y = min_y;
|
||||
|
||||
unsigned int v_count = 0;
|
||||
for (const Polygon& t : triangles)
|
||||
{
|
||||
for (unsigned int i = 0; i < 3; ++i)
|
||||
{
|
||||
for (const Polygon& t : triangles) {
|
||||
for (unsigned int i = 0; i < 3; ++i) {
|
||||
Vertex& v = m_vertices[v_count];
|
||||
|
||||
const Point& p = t.points[i];
|
||||
|
@ -50,8 +57,7 @@ bool GeometryBuffer::set_from_triangles(const Polygons& triangles, float z, bool
|
|||
v.position[1] = y;
|
||||
v.position[2] = z;
|
||||
|
||||
if (generate_tex_coords)
|
||||
{
|
||||
if (generate_tex_coords) {
|
||||
v.tex_coords[0] = x;
|
||||
v.tex_coords[1] = y;
|
||||
|
||||
|
@ -65,17 +71,14 @@ bool GeometryBuffer::set_from_triangles(const Polygons& triangles, float z, bool
|
|||
}
|
||||
}
|
||||
|
||||
if (generate_tex_coords)
|
||||
{
|
||||
if (generate_tex_coords) {
|
||||
float size_x = max_x - min_x;
|
||||
float size_y = max_y - min_y;
|
||||
|
||||
if ((size_x != 0.0f) && (size_y != 0.0f))
|
||||
{
|
||||
if ((size_x != 0.0f) && (size_y != 0.0f)) {
|
||||
float inv_size_x = 1.0f / size_x;
|
||||
float inv_size_y = -1.0f / size_y;
|
||||
for (Vertex& v : m_vertices)
|
||||
{
|
||||
for (Vertex& v : m_vertices) {
|
||||
v.tex_coords[0] = (v.tex_coords[0] - min_x) * inv_size_x;
|
||||
v.tex_coords[1] = (v.tex_coords[1] - min_y) * inv_size_y;
|
||||
}
|
||||
|
@ -96,8 +99,7 @@ bool GeometryBuffer::set_from_lines(const Lines& lines, float z)
|
|||
m_vertices = std::vector<Vertex>(v_size, Vertex());
|
||||
|
||||
unsigned int v_count = 0;
|
||||
for (const Line& l : lines)
|
||||
{
|
||||
for (const Line& l : lines) {
|
||||
Vertex& v1 = m_vertices[v_count];
|
||||
v1.position[0] = unscale<float>(l.a(0));
|
||||
v1.position[1] = unscale<float>(l.a(1));
|
||||
|
@ -119,10 +121,24 @@ const float* GeometryBuffer::get_vertices_data() const
|
|||
return (m_vertices.size() > 0) ? (const float*)m_vertices.data() : nullptr;
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
const float Bed3D::Axes::DefaultStemRadius = 0.5f;
|
||||
const float Bed3D::Axes::DefaultStemLength = 25.0f;
|
||||
const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius;
|
||||
const float Bed3D::Axes::DefaultTipLength = 5.0f;
|
||||
#else
|
||||
const double Bed3D::Axes::Radius = 0.5;
|
||||
const double Bed3D::Axes::ArrowBaseRadius = 2.5 * Bed3D::Axes::Radius;
|
||||
const double Bed3D::Axes::ArrowLength = 5.0;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
void Bed3D::Axes::set_stem_length(float length)
|
||||
{
|
||||
m_stem_length = length;
|
||||
m_arrow.reset();
|
||||
}
|
||||
#else
|
||||
Bed3D::Axes::Axes()
|
||||
: origin(Vec3d::Zero())
|
||||
, length(25.0 * Vec3d::Ones())
|
||||
|
@ -137,9 +153,47 @@ Bed3D::Axes::~Axes()
|
|||
if (m_quadric != nullptr)
|
||||
::gluDeleteQuadric(m_quadric);
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
void Bed3D::Axes::render() const
|
||||
{
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
auto render_axis = [this](const Transform3f& transform) {
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glMultMatrixf(transform.data()));
|
||||
m_arrow.render();
|
||||
glsafe(::glPopMatrix());
|
||||
};
|
||||
|
||||
m_arrow.init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length));
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
shader->start_using();
|
||||
|
||||
// x axis
|
||||
std::array<float, 4> color = { 0.75f, 0.0f, 0.0f, 1.0f };
|
||||
shader->set_uniform("uniform_color", color);
|
||||
render_axis(Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0f }).cast<float>());
|
||||
|
||||
// y axis
|
||||
color = { 0.0f, 0.75f, 0.0f, 1.0f };
|
||||
shader->set_uniform("uniform_color", color);
|
||||
render_axis(Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0f }).cast<float>());
|
||||
|
||||
// z axis
|
||||
color = { 0.0f, 0.0f, 0.75f, 1.0f };
|
||||
shader->set_uniform("uniform_color", color);
|
||||
render_axis(Geometry::assemble_transform(m_origin).cast<float>());
|
||||
|
||||
shader->stop_using();
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
#else
|
||||
if (m_quadric == nullptr)
|
||||
return;
|
||||
|
||||
|
@ -171,8 +225,10 @@ void Bed3D::Axes::render() const
|
|||
|
||||
glsafe(::glDisable(GL_LIGHTING));
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
}
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
void Bed3D::Axes::render_axis(double length) const
|
||||
{
|
||||
::gluQuadricOrientation(m_quadric, GLU_OUTSIDE);
|
||||
|
@ -185,6 +241,7 @@ void Bed3D::Axes::render_axis(double length) const
|
|||
::gluQuadricOrientation(m_quadric, GLU_INSIDE);
|
||||
::gluDisk(m_quadric, 0.0, ArrowBaseRadius, 32, 1);
|
||||
}
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
Bed3D::Bed3D()
|
||||
: m_type(Custom)
|
||||
|
@ -193,7 +250,7 @@ Bed3D::Bed3D()
|
|||
{
|
||||
}
|
||||
|
||||
bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model)
|
||||
bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom)
|
||||
{
|
||||
auto check_texture = [](const std::string& texture) {
|
||||
return !texture.empty() && (boost::algorithm::iends_with(texture, ".png") || boost::algorithm::iends_with(texture, ".svg")) && boost::filesystem::exists(texture);
|
||||
|
@ -203,30 +260,39 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
|
|||
return !model.empty() && boost::algorithm::iends_with(model, ".stl") && boost::filesystem::exists(model);
|
||||
};
|
||||
|
||||
auto [new_type, system_model, system_texture] = detect_type(shape);
|
||||
EType type;
|
||||
std::string model;
|
||||
std::string texture;
|
||||
if (force_as_custom)
|
||||
type = Custom;
|
||||
else {
|
||||
auto [new_type, system_model, system_texture] = detect_type(shape);
|
||||
type = new_type;
|
||||
model = system_model;
|
||||
texture = system_texture;
|
||||
}
|
||||
|
||||
std::string texture_filename = custom_texture.empty() ? system_texture : custom_texture;
|
||||
std::string texture_filename = custom_texture.empty() ? texture : custom_texture;
|
||||
if (!check_texture(texture_filename))
|
||||
texture_filename.clear();
|
||||
|
||||
std::string model_filename = custom_model.empty() ? system_model : custom_model;
|
||||
std::string model_filename = custom_model.empty() ? model : custom_model;
|
||||
if (!check_model(model_filename))
|
||||
model_filename.clear();
|
||||
|
||||
if ((m_shape == shape) && (m_type == new_type) && (m_texture_filename == texture_filename) && (m_model_filename == model_filename))
|
||||
if (m_shape == shape && m_type == type && m_texture_filename == texture_filename && m_model_filename == model_filename)
|
||||
// No change, no need to update the UI.
|
||||
return false;
|
||||
|
||||
m_shape = shape;
|
||||
m_texture_filename = texture_filename;
|
||||
m_model_filename = model_filename;
|
||||
m_type = new_type;
|
||||
m_type = type;
|
||||
|
||||
calc_bounding_boxes();
|
||||
|
||||
ExPolygon poly;
|
||||
for (const Vec2d& p : m_shape)
|
||||
{
|
||||
for (const Vec2d& p : m_shape) {
|
||||
poly.contour.append(Point(scale_(p(0)), scale_(p(1))));
|
||||
}
|
||||
|
||||
|
@ -242,8 +308,13 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
|
|||
m_model.reset();
|
||||
|
||||
// Set the origin and size for rendering the coordinate system axes.
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_axes.set_origin({ 0.0, 0.0, static_cast<double>(GROUND_Z) });
|
||||
m_axes.set_stem_length(0.1f * static_cast<float>(m_bounding_box.max_size()));
|
||||
#else
|
||||
m_axes.origin = Vec3d(0.0, 0.0, (double)GROUND_Z);
|
||||
m_axes.length = 0.1 * m_bounding_box.max_size() * Vec3d::Ones();
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
// Let the calee to update the UI.
|
||||
return true;
|
||||
|
@ -282,25 +353,35 @@ void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor,
|
|||
void Bed3D::calc_bounding_boxes() const
|
||||
{
|
||||
m_bounding_box = BoundingBoxf3();
|
||||
for (const Vec2d& p : m_shape)
|
||||
{
|
||||
for (const Vec2d& p : m_shape) {
|
||||
m_bounding_box.merge(Vec3d(p(0), p(1), 0.0));
|
||||
}
|
||||
|
||||
m_extended_bounding_box = m_bounding_box;
|
||||
|
||||
// extend to contain axes
|
||||
m_extended_bounding_box.merge(m_axes.length + Axes::ArrowLength * Vec3d::Ones());
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_extended_bounding_box.merge(m_axes.get_origin() + m_axes.get_total_length() * Vec3d::Ones());
|
||||
m_extended_bounding_box.merge(m_extended_bounding_box.min + Vec3d(-Axes::DefaultTipRadius, -Axes::DefaultTipRadius, m_extended_bounding_box.max(2)));
|
||||
|
||||
// extend to contain model, if any
|
||||
BoundingBoxf3 model_bb = m_model.get_bounding_box();
|
||||
if (model_bb.defined) {
|
||||
model_bb.translate(m_model_offset);
|
||||
m_extended_bounding_box.merge(model_bb);
|
||||
}
|
||||
#else
|
||||
m_extended_bounding_box.merge(m_axes.length + Axes::ArrowLength * Vec3d::Ones());
|
||||
// extend to contain model, if any
|
||||
if (!m_model.get_filename().empty())
|
||||
m_extended_bounding_box.merge(m_model.get_transformed_bounding_box());
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
}
|
||||
|
||||
void Bed3D::calc_triangles(const ExPolygon& poly)
|
||||
{
|
||||
Polygons triangles;
|
||||
poly.triangulate(&triangles);
|
||||
poly.triangulate_p2t(&triangles);
|
||||
|
||||
if (!m_triangles.set_from_triangles(triangles, GROUND_Z, true))
|
||||
printf("Unable to create bed triangles\n");
|
||||
|
@ -309,15 +390,13 @@ void Bed3D::calc_triangles(const ExPolygon& poly)
|
|||
void Bed3D::calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox)
|
||||
{
|
||||
Polylines axes_lines;
|
||||
for (coord_t x = bed_bbox.min(0); x <= bed_bbox.max(0); x += scale_(10.0))
|
||||
{
|
||||
for (coord_t x = bed_bbox.min(0); x <= bed_bbox.max(0); x += scale_(10.0)) {
|
||||
Polyline line;
|
||||
line.append(Point(x, bed_bbox.min(1)));
|
||||
line.append(Point(x, bed_bbox.max(1)));
|
||||
axes_lines.push_back(line);
|
||||
}
|
||||
for (coord_t y = bed_bbox.min(1); y <= bed_bbox.max(1); y += scale_(10.0))
|
||||
{
|
||||
for (coord_t y = bed_bbox.min(1); y <= bed_bbox.max(1); y += scale_(10.0)) {
|
||||
Polyline line;
|
||||
line.append(Point(bed_bbox.min(0), y));
|
||||
line.append(Point(bed_bbox.max(0), y));
|
||||
|
@ -335,6 +414,7 @@ void Bed3D::calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox)
|
|||
printf("Unable to create bed grid lines\n");
|
||||
}
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
static std::string system_print_bed_model(const Preset &preset)
|
||||
{
|
||||
std::string out;
|
||||
|
@ -352,23 +432,25 @@ static std::string system_print_bed_texture(const Preset &preset)
|
|||
out = Slic3r::resources_dir() + "/profiles/" + preset.vendor->id + "/" + pm->bed_texture;
|
||||
return out;
|
||||
}
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
std::tuple<Bed3D::EType, std::string, std::string> Bed3D::detect_type(const Pointfs& shape) const
|
||||
{
|
||||
auto bundle = wxGetApp().preset_bundle;
|
||||
if (bundle != nullptr)
|
||||
{
|
||||
if (bundle != nullptr) {
|
||||
const Preset* curr = &bundle->printers.get_selected_preset();
|
||||
while (curr != nullptr)
|
||||
{
|
||||
if (curr->config.has("bed_shape"))
|
||||
{
|
||||
if (shape == dynamic_cast<const ConfigOptionPoints*>(curr->config.option("bed_shape"))->values)
|
||||
{
|
||||
while (curr != nullptr) {
|
||||
if (curr->config.has("bed_shape")) {
|
||||
if (shape == dynamic_cast<const ConfigOptionPoints*>(curr->config.option("bed_shape"))->values) {
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
std::string model_filename = PresetUtils::system_printer_bed_model(*curr);
|
||||
std::string texture_filename = PresetUtils::system_printer_bed_texture(*curr);
|
||||
#else
|
||||
std::string model_filename = system_print_bed_model(*curr);
|
||||
std::string texture_filename = system_print_bed_texture(*curr);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
if (!model_filename.empty() && !texture_filename.empty())
|
||||
return std::make_tuple(System, model_filename, texture_filename);
|
||||
return { System, model_filename, texture_filename };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -376,7 +458,7 @@ std::tuple<Bed3D::EType, std::string, std::string> Bed3D::detect_type(const Poin
|
|||
}
|
||||
}
|
||||
|
||||
return std::make_tuple(Custom, "", "");
|
||||
return { Custom, "", "" };
|
||||
}
|
||||
|
||||
void Bed3D::render_axes() const
|
||||
|
@ -396,26 +478,21 @@ void Bed3D::render_system(GLCanvas3D& canvas, bool bottom, bool show_texture) co
|
|||
|
||||
void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
||||
{
|
||||
if (m_texture_filename.empty())
|
||||
{
|
||||
if (m_texture_filename.empty()) {
|
||||
m_texture.reset();
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_texture.get_id() == 0) || (m_texture.get_source() != m_texture_filename))
|
||||
{
|
||||
if ((m_texture.get_id() == 0) || (m_texture.get_source() != m_texture_filename)) {
|
||||
m_texture.reset();
|
||||
|
||||
if (boost::algorithm::iends_with(m_texture_filename, ".svg"))
|
||||
{
|
||||
if (boost::algorithm::iends_with(m_texture_filename, ".svg")) {
|
||||
// use higher resolution images if graphic card and opengl version allow
|
||||
GLint max_tex_size = OpenGLManager::get_gl_info().get_max_tex_size();
|
||||
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != m_texture_filename))
|
||||
{
|
||||
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != m_texture_filename)) {
|
||||
// generate a temporary lower resolution texture to show while no main texture levels have been compressed
|
||||
if (!m_temp_texture.load_from_svg_file(m_texture_filename, false, false, false, max_tex_size / 8))
|
||||
{
|
||||
if (!m_temp_texture.load_from_svg_file(m_texture_filename, false, false, false, max_tex_size / 8)) {
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
|
@ -423,19 +500,15 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
|||
}
|
||||
|
||||
// starts generating the main texture, compression will run asynchronously
|
||||
if (!m_texture.load_from_svg_file(m_texture_filename, true, true, true, max_tex_size))
|
||||
{
|
||||
if (!m_texture.load_from_svg_file(m_texture_filename, true, true, true, max_tex_size)) {
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (boost::algorithm::iends_with(m_texture_filename, ".png"))
|
||||
{
|
||||
}
|
||||
else if (boost::algorithm::iends_with(m_texture_filename, ".png")) {
|
||||
// generate a temporary lower resolution texture to show while no main texture levels have been compressed
|
||||
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != m_texture_filename))
|
||||
{
|
||||
if (!m_temp_texture.load_from_file(m_texture_filename, false, GLTexture::None, false))
|
||||
{
|
||||
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != m_texture_filename)) {
|
||||
if (!m_temp_texture.load_from_file(m_texture_filename, false, GLTexture::None, false)) {
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
|
@ -443,20 +516,17 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
|||
}
|
||||
|
||||
// starts generating the main texture, compression will run asynchronously
|
||||
if (!m_texture.load_from_file(m_texture_filename, true, GLTexture::MultiThreaded, true))
|
||||
{
|
||||
if (!m_texture.load_from_file(m_texture_filename, true, GLTexture::MultiThreaded, true)) {
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (m_texture.unsent_compressed_data_available())
|
||||
{
|
||||
else if (m_texture.unsent_compressed_data_available()) {
|
||||
// sends to gpu the already available compressed levels of the main texture
|
||||
m_texture.send_compressed_data_to_gpu();
|
||||
|
||||
|
@ -468,19 +538,14 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
|||
|
||||
}
|
||||
|
||||
if (m_triangles.get_vertices_count() > 0)
|
||||
{
|
||||
if (m_shader.get_shader_program_id() == 0)
|
||||
m_shader.init("printbed.vs", "printbed.fs");
|
||||
if (m_triangles.get_vertices_count() > 0) {
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("printbed");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
shader->set_uniform("transparent_background", bottom);
|
||||
shader->set_uniform("svg_source", boost::algorithm::iends_with(m_texture.get_source(), ".svg"));
|
||||
|
||||
if (m_shader.is_initialized())
|
||||
{
|
||||
m_shader.start_using();
|
||||
m_shader.set_uniform("transparent_background", bottom);
|
||||
m_shader.set_uniform("svg_source", boost::algorithm::iends_with(m_texture.get_source(), ".svg"));
|
||||
|
||||
if (m_vbo_id == 0)
|
||||
{
|
||||
if (m_vbo_id == 0) {
|
||||
glsafe(::glGenBuffers(1, &m_vbo_id));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
|
||||
glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW));
|
||||
|
@ -498,8 +563,8 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
|||
|
||||
unsigned int stride = m_triangles.get_vertex_data_size();
|
||||
|
||||
GLint position_id = m_shader.get_attrib_location("v_position");
|
||||
GLint tex_coords_id = m_shader.get_attrib_location("v_tex_coords");
|
||||
GLint position_id = shader->get_attrib_location("v_position");
|
||||
GLint tex_coords_id = shader->get_attrib_location("v_tex_coords");
|
||||
|
||||
// show the temporary texture while no compressed data is available
|
||||
GLuint tex_id = (GLuint)m_temp_texture.get_id();
|
||||
|
@ -509,13 +574,11 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
|||
glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
|
||||
|
||||
if (position_id != -1)
|
||||
{
|
||||
if (position_id != -1) {
|
||||
glsafe(::glEnableVertexAttribArray(position_id));
|
||||
glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_position_offset()));
|
||||
}
|
||||
if (tex_coords_id != -1)
|
||||
{
|
||||
if (tex_coords_id != -1) {
|
||||
glsafe(::glEnableVertexAttribArray(tex_coords_id));
|
||||
glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_tex_coords_offset()));
|
||||
}
|
||||
|
@ -537,7 +600,7 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
|||
glsafe(::glDisable(GL_BLEND));
|
||||
glsafe(::glDepthMask(GL_TRUE));
|
||||
|
||||
m_shader.stop_using();
|
||||
shader->stop_using();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -547,29 +610,41 @@ void Bed3D::render_model() const
|
|||
if (m_model_filename.empty())
|
||||
return;
|
||||
|
||||
if ((m_model.get_filename() != m_model_filename) && m_model.init_from_file(m_model_filename))
|
||||
{
|
||||
if ((m_model.get_filename() != m_model_filename) && m_model.init_from_file(m_model_filename)) {
|
||||
// move the model so that its origin (0.0, 0.0, 0.0) goes into the bed shape center and a bit down to avoid z-fighting with the texture quad
|
||||
Vec3d shift = m_bounding_box.center();
|
||||
shift(2) = -0.03;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_model_offset = shift;
|
||||
#else
|
||||
m_model.set_offset(shift);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
// update extended bounding box
|
||||
calc_bounding_boxes();
|
||||
}
|
||||
|
||||
if (!m_model.get_filename().empty())
|
||||
{
|
||||
glsafe(::glEnable(GL_LIGHTING));
|
||||
m_model.render();
|
||||
glsafe(::glDisable(GL_LIGHTING));
|
||||
if (!m_model.get_filename().empty()) {
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
shader->set_uniform("uniform_color", m_model_color);
|
||||
::glPushMatrix();
|
||||
::glTranslated(m_model_offset(0), m_model_offset(1), m_model_offset(2));
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
m_model.render();
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
::glPopMatrix();
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
shader->stop_using();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture) const
|
||||
{
|
||||
if (m_texture_filename.empty() && m_model_filename.empty())
|
||||
{
|
||||
if (m_texture_filename.empty() && m_model_filename.empty()) {
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
|
@ -586,8 +661,7 @@ void Bed3D::render_default(bool bottom) const
|
|||
m_texture.reset();
|
||||
|
||||
unsigned int triangles_vcount = m_triangles.get_vertices_count();
|
||||
if (triangles_vcount > 0)
|
||||
{
|
||||
if (triangles_vcount > 0) {
|
||||
bool has_model = !m_model.get_filename().empty();
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
@ -596,11 +670,14 @@ void Bed3D::render_default(bool bottom) const
|
|||
|
||||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||
|
||||
if (!has_model && !bottom)
|
||||
{
|
||||
if (!has_model && !bottom) {
|
||||
// draw background
|
||||
glsafe(::glDepthMask(GL_FALSE));
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
glsafe(::glColor4fv(m_model_color.data()));
|
||||
#else
|
||||
glsafe(::glColor4f(0.35f, 0.35f, 0.35f, 0.4f));
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
glsafe(::glNormal3d(0.0f, 0.0f, 1.0f));
|
||||
glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_vertices_data()));
|
||||
glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)triangles_vcount));
|
||||
|
@ -608,11 +685,11 @@ void Bed3D::render_default(bool bottom) const
|
|||
}
|
||||
|
||||
// draw grid
|
||||
glsafe(::glLineWidth(3.0f * m_scale_factor));
|
||||
glsafe(::glLineWidth(1.5f * m_scale_factor));
|
||||
if (has_model && !bottom)
|
||||
glsafe(::glColor4f(0.75f, 0.75f, 0.75f, 1.0f));
|
||||
glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 1.0f));
|
||||
else
|
||||
glsafe(::glColor4f(0.2f, 0.2f, 0.2f, 0.4f));
|
||||
glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 0.6f));
|
||||
glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_gridlines.get_vertices_data()));
|
||||
glsafe(::glDrawArrays(GL_LINES, 0, (GLsizei)m_gridlines.get_vertices_count()));
|
||||
|
||||
|
@ -624,8 +701,7 @@ void Bed3D::render_default(bool bottom) const
|
|||
|
||||
void Bed3D::reset()
|
||||
{
|
||||
if (m_vbo_id > 0)
|
||||
{
|
||||
if (m_vbo_id > 0) {
|
||||
glsafe(::glDeleteBuffers(1, &m_vbo_id));
|
||||
m_vbo_id = 0;
|
||||
}
|
||||
|
|
|
@ -3,12 +3,19 @@
|
|||
|
||||
#include "GLTexture.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#include "GLShader.hpp"
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include "GLModel.hpp"
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
#include <tuple>
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include <array>
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
class GLUquadric;
|
||||
typedef class GLUquadric GLUquadricObj;
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
@ -45,22 +52,53 @@ public:
|
|||
|
||||
class Bed3D
|
||||
{
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
class Axes
|
||||
{
|
||||
public:
|
||||
static const float DefaultStemRadius;
|
||||
static const float DefaultStemLength;
|
||||
static const float DefaultTipRadius;
|
||||
static const float DefaultTipLength;
|
||||
|
||||
private:
|
||||
#else
|
||||
struct Axes
|
||||
{
|
||||
static const double Radius;
|
||||
static const double ArrowBaseRadius;
|
||||
static const double ArrowLength;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
Vec3d m_origin{ Vec3d::Zero() };
|
||||
float m_stem_length{ DefaultStemLength };
|
||||
mutable GLModel m_arrow;
|
||||
|
||||
public:
|
||||
#else
|
||||
Vec3d origin;
|
||||
Vec3d length;
|
||||
GLUquadricObj* m_quadric;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
Axes();
|
||||
~Axes();
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
const Vec3d& get_origin() const { return m_origin; }
|
||||
void set_origin(const Vec3d& origin) { m_origin = origin; }
|
||||
void set_stem_length(float length);
|
||||
float get_total_length() const { return m_stem_length + DefaultTipLength; }
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
void render() const;
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
private:
|
||||
void render_axis(double length) const;
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -82,10 +120,15 @@ private:
|
|||
GeometryBuffer m_triangles;
|
||||
GeometryBuffer m_gridlines;
|
||||
mutable GLTexture m_texture;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
mutable GLModel m_model;
|
||||
mutable Vec3d m_model_offset{ Vec3d::Zero() };
|
||||
std::array<float, 4> m_model_color{ 0.235f, 0.235f, 0.235f, 1.0f };
|
||||
#else
|
||||
mutable GLBed m_model;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
// temporary texture shown until the main texture has still no levels compressed
|
||||
mutable GLTexture m_temp_texture;
|
||||
mutable Shader m_shader;
|
||||
mutable unsigned int m_vbo_id;
|
||||
Axes m_axes;
|
||||
|
||||
|
@ -101,7 +144,7 @@ public:
|
|||
|
||||
const Pointfs& get_shape() const { return m_shape; }
|
||||
// Return true if the bed shape changed, so the calee will update the UI.
|
||||
bool set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model);
|
||||
bool set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom = false);
|
||||
|
||||
const BoundingBoxf3& get_bounding_box(bool extended) const {
|
||||
return extended ? m_extended_bounding_box : m_bounding_box;
|
||||
|
|
|
@ -7,19 +7,24 @@
|
|||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
|
||||
#include "3DScene.hpp"
|
||||
#if ENABLE_ENVIRONMENT_MAP
|
||||
#include "GLShader.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#if ENABLE_ENVIRONMENT_MAP
|
||||
#include "Plater.hpp"
|
||||
#endif // ENABLE_ENVIRONMENT_MAP
|
||||
|
||||
#include "libslic3r/ExtrusionEntity.hpp"
|
||||
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
#include "libslic3r/GCode/PreviewData.hpp"
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include "libslic3r/Slicing.hpp"
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
#include "libslic3r/GCode/Analyzer.hpp"
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
#include "slic3r/GUI/BitmapCache.hpp"
|
||||
#include "libslic3r/Format/STL.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
|
@ -442,7 +447,6 @@ BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box(const Transform3d &
|
|||
bounding_box().transformed(trafo);
|
||||
}
|
||||
|
||||
|
||||
void GLVolume::set_range(double min_z, double max_z)
|
||||
{
|
||||
this->qverts_range.first = 0;
|
||||
|
@ -747,6 +751,10 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo
|
|||
|
||||
void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func) const
|
||||
{
|
||||
GLShaderProgram* shader = GUI::wxGetApp().get_current_shader();
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
|
||||
|
@ -757,80 +765,32 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
|
|||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
|
||||
|
||||
GLint current_program_id;
|
||||
glsafe(::glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id));
|
||||
GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1;
|
||||
GLint z_range_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "z_range") : -1;
|
||||
GLint clipping_plane_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "clipping_plane") : -1;
|
||||
|
||||
GLint print_box_min_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.min") : -1;
|
||||
GLint print_box_max_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.max") : -1;
|
||||
GLint print_box_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.actived") : -1;
|
||||
GLint print_box_worldmatrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_world_matrix") : -1;
|
||||
|
||||
shader->set_uniform("print_box.min", m_print_box_min, 3);
|
||||
shader->set_uniform("print_box.max", m_print_box_max, 3);
|
||||
shader->set_uniform("z_range", m_z_range, 2);
|
||||
shader->set_uniform("clipping_plane", m_clipping_plane, 4);
|
||||
#if ENABLE_SLOPE_RENDERING
|
||||
GLint slope_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.actived") : -1;
|
||||
GLint slope_normal_matrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.volume_world_normal_matrix") : -1;
|
||||
GLint slope_z_range_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.z_range") : -1;
|
||||
#endif // ENABLE_SLOPE_RENDERING
|
||||
|
||||
#if ENABLE_ENVIRONMENT_MAP
|
||||
GLint use_environment_tex_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "use_environment_tex") : -1;
|
||||
#endif // ENABLE_ENVIRONMENT_MAP
|
||||
glcheck();
|
||||
|
||||
if (print_box_min_id != -1)
|
||||
glsafe(::glUniform3fv(print_box_min_id, 1, (const GLfloat*)m_print_box_min));
|
||||
|
||||
if (print_box_max_id != -1)
|
||||
glsafe(::glUniform3fv(print_box_max_id, 1, (const GLfloat*)m_print_box_max));
|
||||
|
||||
if (z_range_id != -1)
|
||||
glsafe(::glUniform2fv(z_range_id, 1, (const GLfloat*)m_z_range));
|
||||
|
||||
if (clipping_plane_id != -1)
|
||||
glsafe(::glUniform4fv(clipping_plane_id, 1, (const GLfloat*)m_clipping_plane));
|
||||
|
||||
#if ENABLE_SLOPE_RENDERING
|
||||
if (slope_z_range_id != -1)
|
||||
glsafe(::glUniform2fv(slope_z_range_id, 1, (const GLfloat*)m_slope.z_range.data()));
|
||||
shader->set_uniform("slope.z_range", m_slope.z_range);
|
||||
#endif // ENABLE_SLOPE_RENDERING
|
||||
|
||||
#if ENABLE_ENVIRONMENT_MAP
|
||||
unsigned int environment_texture_id = GUI::wxGetApp().plater()->get_environment_texture_id();
|
||||
bool use_environment_texture = current_program_id > 0 && environment_texture_id > 0 && GUI::wxGetApp().app_config->get("use_environment_map") == "1";
|
||||
|
||||
if (use_environment_tex_id != -1)
|
||||
{
|
||||
glsafe(::glUniform1i(use_environment_tex_id, use_environment_texture ? 1 : 0));
|
||||
if (use_environment_texture)
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, environment_texture_id));
|
||||
}
|
||||
bool use_environment_texture = environment_texture_id > 0 && GUI::wxGetApp().app_config->get("use_environment_map") == "1";
|
||||
shader->set_uniform("use_environment_tex", use_environment_texture);
|
||||
if (use_environment_texture)
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, environment_texture_id));
|
||||
#endif // ENABLE_ENVIRONMENT_MAP
|
||||
glcheck();
|
||||
|
||||
GLVolumeWithIdAndZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func);
|
||||
for (GLVolumeWithIdAndZ& volume : to_render) {
|
||||
volume.first->set_render_color();
|
||||
#if ENABLE_SLOPE_RENDERING
|
||||
if (color_id >= 0)
|
||||
glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)volume.first->render_color));
|
||||
else
|
||||
glsafe(::glColor4fv(volume.first->render_color));
|
||||
|
||||
if (print_box_active_id != -1)
|
||||
glsafe(::glUniform1i(print_box_active_id, volume.first->shader_outside_printer_detection_enabled ? 1 : 0));
|
||||
|
||||
if (print_box_worldmatrix_id != -1)
|
||||
glsafe(::glUniformMatrix4fv(print_box_worldmatrix_id, 1, GL_FALSE, (const GLfloat*)volume.first->world_matrix().cast<float>().data()));
|
||||
|
||||
if (slope_active_id != -1)
|
||||
glsafe(::glUniform1i(slope_active_id, m_slope.active && !volume.first->is_modifier && !volume.first->is_wipe_tower ? 1 : 0));
|
||||
|
||||
if (slope_normal_matrix_id != -1)
|
||||
{
|
||||
Matrix3f normal_matrix = volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>();
|
||||
glsafe(::glUniformMatrix3fv(slope_normal_matrix_id, 1, GL_FALSE, (const GLfloat*)normal_matrix.data()));
|
||||
}
|
||||
shader->set_uniform("uniform_color", volume.first->render_color, 4);
|
||||
shader->set_uniform("print_box.actived", volume.first->shader_outside_printer_detection_enabled);
|
||||
shader->set_uniform("print_box.volume_world_matrix", volume.first->world_matrix());
|
||||
shader->set_uniform("slope.actived", m_slope.active && !volume.first->is_modifier && !volume.first->is_wipe_tower);
|
||||
shader->set_uniform("slope.volume_world_normal_matrix", static_cast<Matrix3f>(volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>()));
|
||||
|
||||
volume.first->render();
|
||||
#else
|
||||
|
@ -839,7 +799,7 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
|
|||
}
|
||||
|
||||
#if ENABLE_ENVIRONMENT_MAP
|
||||
if (use_environment_tex_id != -1 && use_environment_texture)
|
||||
if (use_environment_texture)
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||
#endif // ENABLE_ENVIRONMENT_MAP
|
||||
|
||||
|
@ -1057,6 +1017,7 @@ bool GLVolumeCollection::has_toolpaths_to_export() const
|
|||
return false;
|
||||
}
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
void GLVolumeCollection::export_toolpaths_to_obj(const char* filename) const
|
||||
{
|
||||
if (filename == nullptr)
|
||||
|
@ -1338,6 +1299,7 @@ void GLVolumeCollection::export_toolpaths_to_obj(const char* filename) const
|
|||
|
||||
fclose(fp);
|
||||
}
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
// caller is responsible for supplying NO lines with zero length
|
||||
static void thick_lines_to_indexed_vertex_array(
|
||||
|
@ -1985,6 +1947,7 @@ void _3DScene::point3_to_verts(const Vec3crd& point, double width, double height
|
|||
thick_point_to_verts(point, width, height, volume);
|
||||
}
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
GLModel::GLModel()
|
||||
: m_filename("")
|
||||
{
|
||||
|
@ -2040,6 +2003,10 @@ void GLModel::reset()
|
|||
|
||||
void GLModel::render() const
|
||||
{
|
||||
GLShaderProgram* shader = GUI::wxGetApp().get_current_shader();
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
|
||||
|
@ -2047,17 +2014,8 @@ void GLModel::render() const
|
|||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
|
||||
|
||||
GLint current_program_id;
|
||||
glsafe(::glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id));
|
||||
GLint color_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "uniform_color") : -1;
|
||||
glcheck();
|
||||
|
||||
#if ENABLE_SLOPE_RENDERING
|
||||
if (color_id >= 0)
|
||||
glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)m_volume.render_color));
|
||||
else
|
||||
glsafe(::glColor4fv(m_volume.render_color));
|
||||
|
||||
shader->set_uniform("uniform_color", m_volume.render_color, 4);
|
||||
m_volume.render();
|
||||
#else
|
||||
m_volume.render(color_id, -1, -1);
|
||||
|
@ -2274,5 +2232,6 @@ bool GLBed::on_init_from_file(const std::string& filename)
|
|||
|
||||
return true;
|
||||
}
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -26,12 +26,6 @@
|
|||
#endif // HAS_GLSAFE
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
class Bed3D;
|
||||
struct Camera;
|
||||
class GLToolbar;
|
||||
} // namespace GUI
|
||||
|
||||
class SLAPrintObject;
|
||||
enum SLAPrintObjectStep : unsigned int;
|
||||
class DynamicPrintConfig;
|
||||
|
@ -603,8 +597,10 @@ public:
|
|||
std::string log_memory_info() const;
|
||||
|
||||
bool has_toolpaths_to_export() const;
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
// Export the geometry of the GLVolumes toolpaths of this collection into the file with the given path, in obj format
|
||||
void export_toolpaths_to_obj(const char* filename) const;
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
private:
|
||||
GLVolumeCollection(const GLVolumeCollection &other);
|
||||
|
@ -613,6 +609,7 @@ private:
|
|||
|
||||
GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = nullptr);
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
class GLModel
|
||||
{
|
||||
protected:
|
||||
|
@ -672,6 +669,7 @@ class GLBed : public GLModel
|
|||
protected:
|
||||
bool on_init_from_file(const std::string& filename) override;
|
||||
};
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
struct _3DScene
|
||||
{
|
||||
|
|
|
@ -19,7 +19,9 @@
|
|||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/GCode/PostProcessor.hpp"
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
#include "libslic3r/GCode/PreviewData.hpp"
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
#include "libslic3r/Format/SL1.hpp"
|
||||
#include "libslic3r/libslic3r.h"
|
||||
|
||||
|
@ -92,7 +94,11 @@ void BackgroundSlicingProcess::process_fff()
|
|||
wxCommandEvent evt(m_event_slicing_completed_id);
|
||||
evt.SetInt((int)(m_fff_print->step_state_with_timestamp(PrintStep::psBrim).timestamp));
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt.Clone());
|
||||
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data, m_thumbnail_cb);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_fff_print->export_gcode(m_temp_output_path, m_gcode_result, m_thumbnail_cb);
|
||||
#else
|
||||
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data, m_thumbnail_cb);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
if (this->set_step_started(bspsGCodeFinalize)) {
|
||||
if (! m_export_path.empty()) {
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
|
||||
|
@ -382,6 +388,17 @@ Print::ApplyStatus BackgroundSlicingProcess::apply(const Model &model, const Dyn
|
|||
assert(m_print != nullptr);
|
||||
assert(config.opt_enum<PrinterTechnology>("printer_technology") == m_print->technology());
|
||||
Print::ApplyStatus invalidated = m_print->apply(model, config);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
if ((invalidated & PrintBase::APPLY_STATUS_INVALIDATED) != 0 && m_print->technology() == ptFFF &&
|
||||
!this->m_fff_print->is_step_done(psGCodeExport))
|
||||
{
|
||||
// Some FFF status was invalidated, and the G-code was not exported yet.
|
||||
// Let the G-code preview UI know that the final G-code preview is not valid.
|
||||
// In addition, this early memory deallocation reduces memory footprint.
|
||||
if (m_gcode_result != nullptr)
|
||||
m_gcode_result->reset();
|
||||
}
|
||||
#else
|
||||
if ((invalidated & PrintBase::APPLY_STATUS_INVALIDATED) != 0 && m_print->technology() == ptFFF &&
|
||||
m_gcode_preview_data != nullptr && ! this->m_fff_print->is_step_done(psGCodeExport)) {
|
||||
// Some FFF status was invalidated, and the G-code was not exported yet.
|
||||
|
@ -389,6 +406,7 @@ Print::ApplyStatus BackgroundSlicingProcess::apply(const Model &model, const Dyn
|
|||
// In addition, this early memory deallocation reduces memory footprint.
|
||||
m_gcode_preview_data->reset();
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
#include "libslic3r/GCode/ThumbnailData.hpp"
|
||||
#include "libslic3r/Format/SL1.hpp"
|
||||
#include "slic3r/Utils/PrintHost.hpp"
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
|
||||
namespace boost { namespace filesystem { class path; } }
|
||||
|
@ -18,7 +21,9 @@ namespace boost { namespace filesystem { class path; } }
|
|||
namespace Slic3r {
|
||||
|
||||
class DynamicPrintConfig;
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
class GCodePreviewData;
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
class Model;
|
||||
class SLAPrint;
|
||||
|
||||
|
@ -50,8 +55,12 @@ public:
|
|||
|
||||
void set_fff_print(Print *print) { m_fff_print = print; }
|
||||
void set_sla_print(SLAPrint *print) { m_sla_print = print; m_sla_print->set_printer(&m_sla_archive); }
|
||||
void set_gcode_preview_data(GCodePreviewData *gpd) { m_gcode_preview_data = gpd; }
|
||||
void set_thumbnail_cb(ThumbnailsGeneratorCallback cb) { m_thumbnail_cb = cb; }
|
||||
void set_thumbnail_cb(ThumbnailsGeneratorCallback cb) { m_thumbnail_cb = cb; }
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
void set_gcode_result(GCodeProcessor::Result* result) { m_gcode_result = result; }
|
||||
#else
|
||||
void set_gcode_preview_data(GCodePreviewData* gpd) { m_gcode_preview_data = gpd; }
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
// The following wxCommandEvent will be sent to the UI thread / Plater window, when the slicing is finished
|
||||
// and the background processing will transition into G-code export.
|
||||
|
@ -157,12 +166,17 @@ private:
|
|||
// Non-owned pointers to Print instances.
|
||||
Print *m_fff_print = nullptr;
|
||||
SLAPrint *m_sla_print = nullptr;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
// Data structure, to which the G-code export writes its annotations.
|
||||
GCodeProcessor::Result *m_gcode_result = nullptr;
|
||||
#else
|
||||
// Data structure, to which the G-code export writes its annotations.
|
||||
GCodePreviewData *m_gcode_preview_data = nullptr;
|
||||
// Callback function, used to write thumbnails into gcode.
|
||||
ThumbnailsGeneratorCallback m_thumbnail_cb = nullptr;
|
||||
SL1Archive m_sla_archive;
|
||||
// Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID.
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
// Callback function, used to write thumbnails into gcode.
|
||||
ThumbnailsGeneratorCallback m_thumbnail_cb = nullptr;
|
||||
SL1Archive m_sla_archive;
|
||||
// Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID.
|
||||
std::string m_temp_output_path;
|
||||
// Output path provided by the user. The output path may be set even if the slicing is running,
|
||||
// but once set, it cannot be re-set.
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
#include "libslic3r/Utils.hpp"
|
||||
#include "../Utils/MacDarkMode.hpp"
|
||||
#include "GUI.hpp"
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include "GUI_Utils.hpp"
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
|
@ -355,6 +358,7 @@ wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsi
|
|||
}
|
||||
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
static inline int hex_digit_to_int(const char c)
|
||||
{
|
||||
return
|
||||
|
@ -362,6 +366,7 @@ static inline int hex_digit_to_int(const char c)
|
|||
(c >= 'A' && c <= 'F') ? int(c - 'A') + 10 :
|
||||
(c >= 'a' && c <= 'f') ? int(c - 'a') + 10 : -1;
|
||||
}
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
bool BitmapCache::parse_color(const std::string& scolor, unsigned char* rgb_out)
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "GUI_App.hpp"
|
||||
#if ENABLE_CAMERA_STATISTICS
|
||||
#include "Mouse3DController.hpp"
|
||||
#include "Plater.hpp"
|
||||
#endif // ENABLE_CAMERA_STATISTICS
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
|
|
@ -84,6 +84,7 @@ public:
|
|||
|
||||
double get_near_z() const { return m_frustrum_zs.first; }
|
||||
double get_far_z() const { return m_frustrum_zs.second; }
|
||||
const std::pair<double, double>& get_z_range() const { return m_frustrum_zs; }
|
||||
|
||||
double get_fov() const;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <boost/format.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
|
||||
#include <wx/settings.h>
|
||||
#include <wx/stattext.h>
|
||||
|
@ -561,30 +562,37 @@ const std::string PageMaterials::EMPTY;
|
|||
PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxString title, wxString shortname, wxString list1name)
|
||||
: ConfigWizardPage(parent, std::move(title), std::move(shortname))
|
||||
, materials(materials)
|
||||
, list_l1(new StringList(this))
|
||||
, list_l2(new StringList(this))
|
||||
, list_l3(new PresetList(this))
|
||||
, list_printer(new StringList(this, wxLB_MULTIPLE))
|
||||
, list_type(new StringList(this))
|
||||
, list_vendor(new StringList(this))
|
||||
, list_profile(new PresetList(this))
|
||||
, compatible_printers(new wxStaticText(this, wxID_ANY, _(L(""))))
|
||||
{
|
||||
append_spacer(VERTICAL_SPACING);
|
||||
|
||||
const int em = parent->em_unit();
|
||||
const int list_h = 30*em;
|
||||
|
||||
list_l1->SetMinSize(wxSize(8*em, list_h));
|
||||
list_l2->SetMinSize(wxSize(13*em, list_h));
|
||||
list_l3->SetMinSize(wxSize(25*em, list_h));
|
||||
list_printer->SetWindowStyle(wxLB_EXTENDED);
|
||||
|
||||
auto *grid = new wxFlexGridSizer(3, em/2, em);
|
||||
grid->AddGrowableCol(2, 1);
|
||||
list_printer->SetMinSize(wxSize(23*em, list_h));
|
||||
list_type->SetMinSize(wxSize(8*em, list_h));
|
||||
list_vendor->SetMinSize(wxSize(13*em, list_h));
|
||||
list_profile->SetMinSize(wxSize(23*em, list_h));
|
||||
|
||||
grid = new wxFlexGridSizer(4, em/2, em);
|
||||
grid->AddGrowableCol(3, 1);
|
||||
grid->AddGrowableRow(1, 1);
|
||||
|
||||
grid->Add(new wxStaticText(this, wxID_ANY, _(L("Printer:"))));
|
||||
grid->Add(new wxStaticText(this, wxID_ANY, list1name));
|
||||
grid->Add(new wxStaticText(this, wxID_ANY, _(L("Vendor:"))));
|
||||
grid->Add(new wxStaticText(this, wxID_ANY, _(L("Profile:"))));
|
||||
|
||||
grid->Add(list_l1, 0, wxEXPAND);
|
||||
grid->Add(list_l2, 0, wxEXPAND);
|
||||
grid->Add(list_l3, 1, wxEXPAND);
|
||||
grid->Add(list_printer, 0, wxEXPAND);
|
||||
grid->Add(list_type, 0, wxEXPAND);
|
||||
grid->Add(list_vendor, 0, wxEXPAND);
|
||||
grid->Add(list_profile, 1, wxEXPAND);
|
||||
|
||||
auto *btn_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto *sel_all = new wxButton(this, wxID_ANY, _(L("All")));
|
||||
|
@ -592,121 +600,342 @@ PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxStrin
|
|||
btn_sizer->Add(sel_all, 0, wxRIGHT, em / 2);
|
||||
btn_sizer->Add(sel_none);
|
||||
|
||||
|
||||
grid->Add(new wxBoxSizer(wxHORIZONTAL));
|
||||
grid->Add(new wxBoxSizer(wxHORIZONTAL));
|
||||
grid->Add(btn_sizer, 0, wxALIGN_RIGHT);
|
||||
|
||||
auto* notes_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
notes_sizer->Add(compatible_printers);
|
||||
grid->Add(notes_sizer);
|
||||
|
||||
|
||||
append(grid, 1, wxEXPAND);
|
||||
|
||||
list_l1->Bind(wxEVT_LISTBOX, [this](wxCommandEvent &) {
|
||||
update_lists(list_l1->GetSelection(), list_l2->GetSelection());
|
||||
list_printer->Bind(wxEVT_LISTBOX, [this](wxCommandEvent& evt) {
|
||||
update_lists(evt.GetInt(), list_type->GetSelection(), list_vendor->GetSelection());
|
||||
});
|
||||
list_type->Bind(wxEVT_LISTBOX, [this](wxCommandEvent &) {
|
||||
update_lists(list_printer->GetSelection(), list_type->GetSelection(), list_vendor->GetSelection());
|
||||
});
|
||||
list_l2->Bind(wxEVT_LISTBOX, [this](wxCommandEvent &) {
|
||||
update_lists(list_l1->GetSelection(), list_l2->GetSelection());
|
||||
list_vendor->Bind(wxEVT_LISTBOX, [this](wxCommandEvent &) {
|
||||
update_lists(list_printer->GetSelection(), list_type->GetSelection(), list_vendor->GetSelection());
|
||||
});
|
||||
|
||||
list_l3->Bind(wxEVT_CHECKLISTBOX, [this](wxCommandEvent &evt) { select_material(evt.GetInt()); });
|
||||
list_profile->Bind(wxEVT_CHECKLISTBOX, [this](wxCommandEvent &evt) { select_material(evt.GetInt()); });
|
||||
list_profile->Bind(wxEVT_LISTBOX, [this](wxCommandEvent& evt) { on_material_highlighted(evt.GetInt()); });
|
||||
|
||||
sel_all->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { select_all(true); });
|
||||
sel_none->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { select_all(false); });
|
||||
|
||||
Bind(wxEVT_PAINT, [this](wxPaintEvent& evt) {on_paint();});
|
||||
|
||||
list_profile->Bind(wxEVT_MOTION, [this](wxMouseEvent& evt) { on_mouse_move_on_profiles(evt); });
|
||||
list_profile->Bind(wxEVT_ENTER_WINDOW, [this](wxMouseEvent& evt) { on_mouse_enter_profiles(evt); });
|
||||
list_profile->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& evt) { on_mouse_leave_profiles(evt); });
|
||||
|
||||
reload_presets();
|
||||
}
|
||||
|
||||
void PageMaterials::on_paint()
|
||||
{
|
||||
if (first_paint) {
|
||||
first_paint = false;
|
||||
prepare_compatible_printers_label();
|
||||
}
|
||||
}
|
||||
void PageMaterials::on_mouse_move_on_profiles(wxMouseEvent& evt)
|
||||
{
|
||||
const wxClientDC dc(list_profile);
|
||||
const wxPoint pos = evt.GetLogicalPosition(dc);
|
||||
int item = list_profile->HitTest(pos);
|
||||
BOOST_LOG_TRIVIAL(error) << "hit test: " << item;
|
||||
on_material_hovered(item);
|
||||
}
|
||||
void PageMaterials::on_mouse_enter_profiles(wxMouseEvent& evt)
|
||||
{}
|
||||
void PageMaterials::on_mouse_leave_profiles(wxMouseEvent& evt)
|
||||
{
|
||||
on_material_hovered(-1);
|
||||
}
|
||||
void PageMaterials::reload_presets()
|
||||
{
|
||||
clear();
|
||||
|
||||
list_l1->append(_(L("(All)")), &EMPTY);
|
||||
list_printer->append(_(L("(All)")), &EMPTY);
|
||||
list_printer->SetLabelMarkup("<b>bald</b>");
|
||||
for (const Preset* printer : materials->printers) {
|
||||
list_printer->append(printer->name, &printer->name);
|
||||
}
|
||||
|
||||
for (const std::string &type : materials->types) {
|
||||
list_l1->append(type, &type);
|
||||
}
|
||||
|
||||
if (list_l1->GetCount() > 0) {
|
||||
list_l1->SetSelection(0);
|
||||
sel1_prev = wxNOT_FOUND;
|
||||
sel2_prev = wxNOT_FOUND;
|
||||
update_lists(0, 0);
|
||||
if (list_printer->GetCount() > 0) {
|
||||
list_printer->SetSelection(0);
|
||||
sel_printer_prev = wxNOT_FOUND;
|
||||
sel_type_prev = wxNOT_FOUND;
|
||||
sel_vendor_prev = wxNOT_FOUND;
|
||||
update_lists(0, 0, 0);
|
||||
}
|
||||
|
||||
presets_loaded = true;
|
||||
}
|
||||
|
||||
void PageMaterials::update_lists(int sel1, int sel2)
|
||||
void PageMaterials::prepare_compatible_printers_label()
|
||||
{
|
||||
wxWindowUpdateLocker freeze_guard(this);
|
||||
(void)freeze_guard;
|
||||
|
||||
if (sel1 != sel1_prev) {
|
||||
// Refresh the second list
|
||||
|
||||
// XXX: The vendor list is created with quadratic complexity here,
|
||||
// but the number of vendors is going to be very small this shouldn't be a problem.
|
||||
|
||||
list_l2->Clear();
|
||||
list_l2->append(_(L("(All)")), &EMPTY);
|
||||
if (sel1 != wxNOT_FOUND) {
|
||||
const std::string &type = list_l1->get_data(sel1);
|
||||
|
||||
materials->filter_presets(type, EMPTY, [this](const Preset *p) {
|
||||
const std::string &vendor = this->materials->get_vendor(p);
|
||||
|
||||
if (list_l2->find(vendor) == wxNOT_FOUND) {
|
||||
list_l2->append(vendor, &vendor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sel1_prev = sel1;
|
||||
sel2 = 0;
|
||||
sel2_prev = wxNOT_FOUND;
|
||||
list_l2->SetSelection(sel2);
|
||||
list_l3->Clear();
|
||||
assert(grid->GetColWidths().size() == 4);
|
||||
compatible_printers_width = grid->GetColWidths()[3];
|
||||
empty_printers_label = "Compatible printers:";
|
||||
for (const Preset* printer : materials->printers) {
|
||||
empty_printers_label += "\n";
|
||||
}
|
||||
clear_compatible_printers_label();
|
||||
}
|
||||
|
||||
if (sel2 != sel2_prev) {
|
||||
// Refresh the third list
|
||||
void PageMaterials::clear_compatible_printers_label()
|
||||
{
|
||||
compatible_printers->SetLabel(boost::nowide::widen(empty_printers_label));
|
||||
compatible_printers->Wrap(compatible_printers_width);
|
||||
Layout();
|
||||
}
|
||||
|
||||
list_l3->Clear();
|
||||
if (sel1 != wxNOT_FOUND && sel2 != wxNOT_FOUND) {
|
||||
const std::string &type = list_l1->get_data(sel1);
|
||||
const std::string &vendor = list_l2->get_data(sel2);
|
||||
|
||||
materials->filter_presets(type, vendor, [this](const Preset *p) {
|
||||
bool was_checked = false;
|
||||
|
||||
int cur_i = list_l3->find(p->alias);
|
||||
if (cur_i == wxNOT_FOUND)
|
||||
cur_i = list_l3->append(p->alias, &p->alias);
|
||||
void PageMaterials::on_material_hovered(int sel_material)
|
||||
{
|
||||
if ( sel_material == last_hovered_item)
|
||||
return;
|
||||
if (sel_material == -1) {
|
||||
clear_compatible_printers_label();
|
||||
return;
|
||||
}
|
||||
last_hovered_item = sel_material;
|
||||
std::string compatible_printers_label = "compatible printers:\n";
|
||||
//selected material string
|
||||
std::string material_name = list_profile->get_data(sel_material);
|
||||
// get material preset
|
||||
const std::vector<const Preset*> matching_materials = materials->get_presets_by_alias(material_name);
|
||||
if (matching_materials.empty())
|
||||
{
|
||||
clear_compatible_printers_label();
|
||||
return;
|
||||
}
|
||||
//find matching printers
|
||||
bool first = true;
|
||||
for (const Preset* printer : materials->printers) {
|
||||
bool compatible = false;
|
||||
for (const Preset* material : matching_materials) {
|
||||
if (is_compatible_with_printer(PresetWithVendorProfile(*material, material->vendor), PresetWithVendorProfile(*printer, printer->vendor))) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
was_checked = list_l3->IsChecked(cur_i);
|
||||
|
||||
const std::string& section = materials->appconfig_section();
|
||||
|
||||
const bool checked = wizard_p()->appconfig_new.has(section, p->name);
|
||||
list_l3->Check(cur_i, checked | was_checked);
|
||||
|
||||
/* Update preset selection in config.
|
||||
* If one preset from aliases bundle is selected,
|
||||
* than mark all presets with this aliases as selected
|
||||
* */
|
||||
if (checked && !was_checked)
|
||||
wizard_p()->update_presets_in_config(section, p->alias, true);
|
||||
else if (!checked && was_checked)
|
||||
wizard_p()->appconfig_new.set(section, p->name, "1");
|
||||
} );
|
||||
compatible_printers_label += "\n";//", ";
|
||||
compatible_printers_label += printer->name;
|
||||
compatible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sel2_prev = sel2;
|
||||
}
|
||||
this->compatible_printers->SetLabel(boost::nowide::widen(compatible_printers_label));
|
||||
this->compatible_printers->Wrap(compatible_printers_width);
|
||||
}
|
||||
|
||||
void PageMaterials::on_material_highlighted(int sel_material)
|
||||
{
|
||||
wxWindowUpdateLocker freeze_guard(this);
|
||||
(void)freeze_guard;
|
||||
|
||||
//std::string compatible_printers_label = "compatible printers:\n";
|
||||
//std::string empty_suplement = std::string();
|
||||
//unselect all printers
|
||||
list_printer->SetSelection(wxNOT_FOUND);
|
||||
//selected material string
|
||||
std::string material_name = list_profile->get_data(sel_material);
|
||||
// get material preset
|
||||
const std::vector<const Preset*> matching_materials = materials->get_presets_by_alias(material_name);
|
||||
if (matching_materials.empty())
|
||||
return;
|
||||
//find matching printers
|
||||
//bool first = true;
|
||||
for (const Preset* printer : materials->printers) {
|
||||
bool compatible = false;
|
||||
for (const Preset* material : matching_materials) {
|
||||
if (is_compatible_with_printer(PresetWithVendorProfile(*material, material->vendor), PresetWithVendorProfile(*printer, printer->vendor))) {
|
||||
//select printer
|
||||
int index = list_printer->find(printer->name);
|
||||
list_printer->SetSelection(index);
|
||||
/*if (first)
|
||||
first = false;
|
||||
else
|
||||
compatible_printers_label += "\n";//", ";
|
||||
compatible_printers_label += printer->name;
|
||||
compatible = true;
|
||||
break;*/
|
||||
}
|
||||
}
|
||||
//if(!compatible)
|
||||
// empty_suplement += std::string(printer->name.length() + 2, ' ');
|
||||
}
|
||||
// fill rest of label with blanks so it maintains legth
|
||||
//compatible_printers_label += empty_suplement;
|
||||
|
||||
update_lists(0,0,0);
|
||||
list_profile->SetSelection(list_profile->find(material_name));
|
||||
|
||||
//this->compatible_printers->SetLabel(boost::nowide::widen(compatible_printers_label));
|
||||
//this->compatible_printers->Wrap(compatible_printers_width);
|
||||
//Refresh();
|
||||
}
|
||||
|
||||
void PageMaterials::update_lists(int sel_printer, int sel_type, int sel_vendor)
|
||||
{
|
||||
wxWindowUpdateLocker freeze_guard(this);
|
||||
(void)freeze_guard;
|
||||
|
||||
wxArrayInt sel_printers;
|
||||
int sel_printers_count = list_printer->GetSelections(sel_printers);
|
||||
|
||||
if (sel_printers_count != sel_printer_prev) {
|
||||
// Refresh type list
|
||||
list_type->Clear();
|
||||
list_type->append(_(L("(All)")), &EMPTY);
|
||||
if (sel_printers_count > 0) {
|
||||
// If all is selected with other printers
|
||||
// unselect "all" or all printers depending on last value
|
||||
if (sel_printers[0] == 0 && sel_printers_count > 1) {
|
||||
if (sel_printer == 0) {
|
||||
list_printer->SetSelection(wxNOT_FOUND);
|
||||
list_printer->SetSelection(0);
|
||||
} else {
|
||||
list_printer->SetSelection(0, false);
|
||||
sel_printers_count = list_printer->GetSelections(sel_printers);
|
||||
}
|
||||
}
|
||||
if (sel_printers[0] != 0) {
|
||||
for (size_t i = 0; i < sel_printers_count; i++) {
|
||||
const std::string& printer_name = list_printer->get_data(sel_printers[i]);
|
||||
const Preset* printer = nullptr;
|
||||
for (const Preset* it : materials->printers) {
|
||||
if (it->name == printer_name) {
|
||||
printer = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
materials->filter_presets(printer, EMPTY, EMPTY, [this](const Preset* p) {
|
||||
const std::string& type = this->materials->get_type(p);
|
||||
if (list_type->find(type) == wxNOT_FOUND) {
|
||||
list_type->append(type, &type);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
//clear selection except "ALL"
|
||||
list_printer->SetSelection(wxNOT_FOUND);
|
||||
list_printer->SetSelection(0);
|
||||
|
||||
materials->filter_presets(nullptr, EMPTY, EMPTY, [this](const Preset* p) {
|
||||
const std::string& type = this->materials->get_type(p);
|
||||
if (list_type->find(type) == wxNOT_FOUND) {
|
||||
list_type->append(type, &type);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sel_printer_prev = sel_printers_count;
|
||||
sel_type = 0;
|
||||
sel_type_prev = wxNOT_FOUND;
|
||||
list_type->SetSelection(sel_type);
|
||||
list_profile->Clear();
|
||||
}
|
||||
|
||||
if (sel_type != sel_type_prev) {
|
||||
// Refresh vendor list
|
||||
|
||||
// XXX: The vendor list is created with quadratic complexity here,
|
||||
// but the number of vendors is going to be very small this shouldn't be a problem.
|
||||
|
||||
list_vendor->Clear();
|
||||
list_vendor->append(_(L("(All)")), &EMPTY);
|
||||
if (sel_printers_count != 0 && sel_type != wxNOT_FOUND) {
|
||||
const std::string& type = list_type->get_data(sel_type);
|
||||
// find printer preset
|
||||
for (size_t i = 0; i < sel_printers_count; i++) {
|
||||
const std::string& printer_name = list_printer->get_data(sel_printers[i]);
|
||||
const Preset* printer = nullptr;
|
||||
for (const Preset* it : materials->printers) {
|
||||
if (it->name == printer_name) {
|
||||
printer = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
materials->filter_presets(printer, type, EMPTY, [this](const Preset* p) {
|
||||
const std::string& vendor = this->materials->get_vendor(p);
|
||||
if (list_vendor->find(vendor) == wxNOT_FOUND) {
|
||||
list_vendor->append(vendor, &vendor);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
sel_type_prev = sel_type;
|
||||
sel_vendor = 0;
|
||||
sel_vendor_prev = wxNOT_FOUND;
|
||||
list_vendor->SetSelection(sel_vendor);
|
||||
list_profile->Clear();
|
||||
}
|
||||
|
||||
if (sel_vendor != sel_vendor_prev) {
|
||||
// Refresh material list
|
||||
|
||||
list_profile->Clear();
|
||||
clear_compatible_printers_label();
|
||||
if (sel_printers_count != 0 && sel_type != wxNOT_FOUND && sel_vendor != wxNOT_FOUND) {
|
||||
const std::string& type = list_type->get_data(sel_type);
|
||||
const std::string& vendor = list_vendor->get_data(sel_vendor);
|
||||
// finst printer preset
|
||||
for (size_t i = 0; i < sel_printers_count; i++) {
|
||||
const std::string& printer_name = list_printer->get_data(sel_printers[i]);
|
||||
const Preset* printer = nullptr;
|
||||
for (const Preset* it : materials->printers) {
|
||||
if (it->name == printer_name) {
|
||||
printer = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
materials->filter_presets(printer, type, vendor, [this](const Preset* p) {
|
||||
bool was_checked = false;
|
||||
//size_t printer_counter = materials->get_printer_counter(p);
|
||||
int cur_i = list_profile->find(p->alias);
|
||||
if (cur_i == wxNOT_FOUND)
|
||||
//cur_i = list_profile->append(p->alias + " " + std::to_string(printer_counter)/*+ (omnipresent ? "" : " ONLY SOME PRINTERS")*/, &p->alias);
|
||||
cur_i = list_profile->append(p->alias + (materials->get_omnipresent(p) ? "" : " *"), &p->alias);
|
||||
else
|
||||
was_checked = list_profile->IsChecked(cur_i);
|
||||
|
||||
const std::string& section = materials->appconfig_section();
|
||||
|
||||
const bool checked = wizard_p()->appconfig_new.has(section, p->name);
|
||||
list_profile->Check(cur_i, checked | was_checked);
|
||||
|
||||
/* Update preset selection in config.
|
||||
* If one preset from aliases bundle is selected,
|
||||
* than mark all presets with this aliases as selected
|
||||
* */
|
||||
if (checked && !was_checked)
|
||||
wizard_p()->update_presets_in_config(section, p->alias, true);
|
||||
else if (!checked && was_checked)
|
||||
wizard_p()->appconfig_new.set(section, p->name, "1");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
sel_vendor_prev = sel_vendor;
|
||||
}
|
||||
}
|
||||
|
||||
void PageMaterials::select_material(int i)
|
||||
{
|
||||
const bool checked = list_l3->IsChecked(i);
|
||||
const bool checked = list_profile->IsChecked(i);
|
||||
|
||||
const std::string& alias_key = list_l3->get_data(i);
|
||||
const std::string& alias_key = list_profile->get_data(i);
|
||||
wizard_p()->update_presets_in_config(materials->appconfig_section(), alias_key, checked);
|
||||
}
|
||||
|
||||
|
@ -715,10 +944,10 @@ void PageMaterials::select_all(bool select)
|
|||
wxWindowUpdateLocker freeze_guard(this);
|
||||
(void)freeze_guard;
|
||||
|
||||
for (unsigned i = 0; i < list_l3->GetCount(); i++) {
|
||||
const bool current = list_l3->IsChecked(i);
|
||||
for (unsigned i = 0; i < list_profile->GetCount(); i++) {
|
||||
const bool current = list_profile->IsChecked(i);
|
||||
if (current != select) {
|
||||
list_l3->Check(i, select);
|
||||
list_profile->Check(i, select);
|
||||
select_material(i);
|
||||
}
|
||||
}
|
||||
|
@ -726,11 +955,13 @@ void PageMaterials::select_all(bool select)
|
|||
|
||||
void PageMaterials::clear()
|
||||
{
|
||||
list_l1->Clear();
|
||||
list_l2->Clear();
|
||||
list_l3->Clear();
|
||||
sel1_prev = wxNOT_FOUND;
|
||||
sel2_prev = wxNOT_FOUND;
|
||||
list_printer->Clear();
|
||||
list_type->Clear();
|
||||
list_vendor->Clear();
|
||||
list_profile->Clear();
|
||||
sel_printer_prev = wxNOT_FOUND;
|
||||
sel_type_prev = wxNOT_FOUND;
|
||||
sel_vendor_prev = wxNOT_FOUND;
|
||||
presets_loaded = false;
|
||||
}
|
||||
|
||||
|
@ -740,6 +971,7 @@ void PageMaterials::on_activate()
|
|||
wizard_p()->update_materials(materials->technology);
|
||||
reload_presets();
|
||||
}
|
||||
first_paint = true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1314,16 +1546,22 @@ const std::string Materials::UNKNOWN = "(Unknown)";
|
|||
|
||||
void Materials::push(const Preset *preset)
|
||||
{
|
||||
presets.push_back(preset);
|
||||
presets.emplace_back(preset, 0);
|
||||
types.insert(technology & T_FFF
|
||||
? Materials::get_filament_type(preset)
|
||||
: Materials::get_material_type(preset));
|
||||
}
|
||||
|
||||
void Materials::add_printer(const Preset* preset)
|
||||
{
|
||||
printers.insert(preset);
|
||||
}
|
||||
|
||||
void Materials::clear()
|
||||
{
|
||||
presets.clear();
|
||||
types.clear();
|
||||
printers.clear();
|
||||
}
|
||||
|
||||
const std::string& Materials::appconfig_section() const
|
||||
|
@ -1373,7 +1611,6 @@ const std::string& Materials::get_material_vendor(const Preset *preset)
|
|||
return opt != nullptr ? opt->value : UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
// priv
|
||||
|
||||
static const std::unordered_map<std::string, std::pair<std::string, std::string>> legacy_preset_map {{
|
||||
|
@ -1601,26 +1838,28 @@ void ConfigWizard::priv::update_materials(Technology technology)
|
|||
if (any_fff_selected && (technology & T_FFF)) {
|
||||
filaments.clear();
|
||||
aliases_fff.clear();
|
||||
|
||||
// Iterate filaments in all bundles
|
||||
for (const auto &pair : bundles) {
|
||||
for (const auto &filament : pair.second.preset_bundle->filaments) {
|
||||
// Check if filament is already added
|
||||
if (filaments.containts(&filament))
|
||||
continue;
|
||||
if (filaments.containts(&filament))
|
||||
continue;
|
||||
// Iterate printers in all bundles
|
||||
// For now, we only allow the profiles to be compatible with another profiles inside the same bundle.
|
||||
// for (const auto &pair : bundles)
|
||||
for (const auto &printer : pair.second.preset_bundle->printers)
|
||||
// Filter out inapplicable printers
|
||||
if (printer.is_visible && printer.printer_technology() == ptFFF &&
|
||||
is_compatible_with_printer(PresetWithVendorProfile(filament, nullptr), PresetWithVendorProfile(printer, nullptr)) &&
|
||||
// Check if filament is already added
|
||||
! filaments.containts(&filament)) {
|
||||
filaments.push(&filament);
|
||||
if (!filament.alias.empty())
|
||||
aliases_fff[filament.alias].insert(filament.name);
|
||||
}
|
||||
for (const auto &printer : pair.second.preset_bundle->printers) {
|
||||
if (!printer.is_visible || printer.printer_technology() != ptFFF)
|
||||
continue;
|
||||
// Filter out inapplicable printers
|
||||
if (is_compatible_with_printer(PresetWithVendorProfile(filament, filament.vendor), PresetWithVendorProfile(printer, printer.vendor))) {
|
||||
if (!filaments.containts(&filament)) {
|
||||
filaments.push(&filament);
|
||||
if (!filament.alias.empty())
|
||||
aliases_fff[filament.alias].insert(filament.name);
|
||||
}
|
||||
filaments.add_printer_counter(&filament);
|
||||
filaments.add_printer(&printer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1637,17 +1876,21 @@ void ConfigWizard::priv::update_materials(Technology technology)
|
|||
continue;
|
||||
// Iterate printers in all bundles
|
||||
// For now, we only allow the profiles to be compatible with another profiles inside the same bundle.
|
||||
// for (const auto &pair : bundles)
|
||||
for (const auto &printer : pair.second.preset_bundle->printers)
|
||||
// Filter out inapplicable printers
|
||||
if (printer.is_visible && printer.printer_technology() == ptSLA &&
|
||||
is_compatible_with_printer(PresetWithVendorProfile(material, nullptr), PresetWithVendorProfile(printer, nullptr)) &&
|
||||
// Check if material is already added
|
||||
! sla_materials.containts(&material)) {
|
||||
for (const auto& printer : pair.second.preset_bundle->printers) {
|
||||
if(!printer.is_visible || printer.printer_technology() != ptSLA)
|
||||
continue;
|
||||
// Filter out inapplicable printers
|
||||
if (is_compatible_with_printer(PresetWithVendorProfile(material, nullptr), PresetWithVendorProfile(printer, nullptr))) {
|
||||
// Check if material is already added
|
||||
if(!sla_materials.containts(&material)) {
|
||||
sla_materials.push(&material);
|
||||
if (!material.alias.empty())
|
||||
aliases_sla[material.alias].insert(material.name);
|
||||
}
|
||||
sla_materials.add_printer_counter(&material);
|
||||
sla_materials.add_printer(&printer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/panel.h>
|
||||
|
@ -57,32 +58,98 @@ enum Technology {
|
|||
T_ANY = ~0,
|
||||
};
|
||||
|
||||
struct Bundle
|
||||
{
|
||||
std::unique_ptr<PresetBundle> preset_bundle;
|
||||
VendorProfile* vendor_profile{ nullptr };
|
||||
bool is_in_resources{ false };
|
||||
bool is_prusa_bundle{ false };
|
||||
|
||||
Bundle() = default;
|
||||
Bundle(Bundle&& other);
|
||||
|
||||
// Returns false if not loaded. Reason for that is logged as boost::log error.
|
||||
bool load(fs::path source_path, bool is_in_resources, bool is_prusa_bundle = false);
|
||||
|
||||
const std::string& vendor_id() const { return vendor_profile->id; }
|
||||
};
|
||||
|
||||
struct BundleMap : std::unordered_map<std::string /* = vendor ID */, Bundle>
|
||||
{
|
||||
static BundleMap load();
|
||||
|
||||
Bundle& prusa_bundle();
|
||||
const Bundle& prusa_bundle() const;
|
||||
};
|
||||
|
||||
struct Materials
|
||||
{
|
||||
Technology technology;
|
||||
// use vector for the presets to purpose of save of presets sorting in the bundle
|
||||
std::vector<const Preset*> presets;
|
||||
// bool is true if material is present in all printers (omnipresent)
|
||||
// size_t is counter of printers compatible with material
|
||||
std::vector<std::pair<const Preset*, size_t>> presets;
|
||||
std::set<std::string> types;
|
||||
std::set<const Preset*> printers;
|
||||
|
||||
Materials(Technology technology) : technology(technology) {}
|
||||
|
||||
void push(const Preset *preset);
|
||||
void add_printer(const Preset* preset);
|
||||
void clear();
|
||||
bool containts(const Preset *preset) const {
|
||||
return std::find(presets.begin(), presets.end(), preset) != presets.end();
|
||||
//return std::find(presets.begin(), presets.end(), preset) != presets.end();
|
||||
return std::find_if(presets.begin(), presets.end(),
|
||||
[preset](const std::pair<const Preset*, bool>& element) { return element.first == preset; }) != presets.end();
|
||||
|
||||
}
|
||||
|
||||
bool get_omnipresent(const Preset* preset) {
|
||||
return get_printer_counter(preset) == printers.size();
|
||||
}
|
||||
|
||||
const std::vector<const Preset*> get_presets_by_alias(const std::string name) {
|
||||
std::vector<const Preset*> ret_vec;
|
||||
for (auto it = presets.begin(); it != presets.end(); ++it) {
|
||||
if ((*it).first->alias == name)
|
||||
ret_vec.push_back((*it).first);
|
||||
}
|
||||
return ret_vec;
|
||||
}
|
||||
|
||||
void add_printer_counter(const Preset* preset) {
|
||||
for (auto it = presets.begin(); it != presets.end(); ++it) {
|
||||
if ((*it).first->alias == preset->alias)
|
||||
(*it).second += 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t get_printer_counter(const Preset* preset) {
|
||||
size_t highest = 0;
|
||||
for (auto it : presets) {
|
||||
if (it.first->alias == preset->alias && it.second > highest)
|
||||
highest = it.second;
|
||||
}
|
||||
return highest;
|
||||
}
|
||||
|
||||
const std::string& appconfig_section() const;
|
||||
const std::string& get_type(const Preset *preset) const;
|
||||
const std::string& get_vendor(const Preset *preset) const;
|
||||
|
||||
|
||||
template<class F> void filter_presets(const std::string &type, const std::string &vendor, F cb) {
|
||||
for (const Preset *preset : presets) {
|
||||
if ((type.empty() || get_type(preset) == type) && (vendor.empty() || get_vendor(preset) == vendor)) {
|
||||
cb(preset);
|
||||
}
|
||||
}
|
||||
}
|
||||
template<class F> void filter_presets(const Preset* printer, const std::string& type, const std::string& vendor, F cb) {
|
||||
for (auto preset : presets) {
|
||||
const Preset& prst = *(preset.first);
|
||||
const Preset& prntr = *printer;
|
||||
if ((printer == nullptr || is_compatible_with_printer(PresetWithVendorProfile(prst, prst.vendor), PresetWithVendorProfile(prntr, prntr.vendor))) &&
|
||||
(type.empty() || get_type(preset.first) == type) &&
|
||||
(vendor.empty() || get_vendor(preset.first) == vendor)) {
|
||||
|
||||
cb(preset.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const std::string UNKNOWN;
|
||||
static const std::string& get_filament_type(const Preset *preset);
|
||||
|
@ -91,33 +158,9 @@ struct Materials
|
|||
static const std::string& get_material_vendor(const Preset *preset);
|
||||
};
|
||||
|
||||
struct Bundle
|
||||
{
|
||||
std::unique_ptr<PresetBundle> preset_bundle;
|
||||
VendorProfile *vendor_profile { nullptr };
|
||||
bool is_in_resources { false };
|
||||
bool is_prusa_bundle { false };
|
||||
|
||||
Bundle() = default;
|
||||
Bundle(Bundle &&other);
|
||||
|
||||
// Returns false if not loaded. Reason for that is logged as boost::log error.
|
||||
bool load(fs::path source_path, bool is_in_resources, bool is_prusa_bundle = false);
|
||||
|
||||
const std::string& vendor_id() const { return vendor_profile->id; }
|
||||
};
|
||||
|
||||
struct BundleMap: std::unordered_map<std::string /* = vendor ID */, Bundle>
|
||||
{
|
||||
static BundleMap load();
|
||||
|
||||
Bundle& prusa_bundle();
|
||||
const Bundle& prusa_bundle() const;
|
||||
};
|
||||
|
||||
struct PrinterPickerEvent;
|
||||
|
||||
|
||||
// GUI elements
|
||||
|
||||
typedef std::function<bool(const VendorProfile::PrinterModel&)> ModelFilter;
|
||||
|
@ -225,6 +268,7 @@ struct PagePrinters: ConfigWizardPage
|
|||
template<class T, class D> struct DataList : public T
|
||||
{
|
||||
DataList(wxWindow *parent) : T(parent, wxID_ANY) {}
|
||||
DataList(wxWindow* parent, int style) : T(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, style) {}
|
||||
|
||||
// Note: We're _not_ using wxLB_SORT here because it doesn't do the right thing,
|
||||
// eg. "ABS" is sorted before "(All)"
|
||||
|
@ -252,6 +296,25 @@ template<class T, class D> struct DataList : public T
|
|||
}
|
||||
|
||||
int size() { return this->GetCount(); }
|
||||
|
||||
void on_mouse_move(const wxPoint& position) {
|
||||
int item = T::HitTest(position);
|
||||
|
||||
if(item == wxHitTest::wxHT_WINDOW_INSIDE)
|
||||
BOOST_LOG_TRIVIAL(error) << "hit test wxHT_WINDOW_INSIDE";
|
||||
else if (item == wxHitTest::wxHT_WINDOW_OUTSIDE)
|
||||
BOOST_LOG_TRIVIAL(error) << "hit test wxHT_WINDOW_OUTSIDE";
|
||||
else if(item == wxHitTest::wxHT_WINDOW_CORNER)
|
||||
BOOST_LOG_TRIVIAL(error) << "hit test wxHT_WINDOW_CORNER";
|
||||
else if (item == wxHitTest::wxHT_WINDOW_VERT_SCROLLBAR)
|
||||
BOOST_LOG_TRIVIAL(error) << "hit test wxHT_WINDOW_VERT_SCROLLBAR";
|
||||
else if (item == wxHitTest::wxHT_NOWHERE)
|
||||
BOOST_LOG_TRIVIAL(error) << "hit test wxHT_NOWHERE";
|
||||
else if (item == wxHitTest::wxHT_MAX)
|
||||
BOOST_LOG_TRIVIAL(error) << "hit test wxHT_MAX";
|
||||
else
|
||||
BOOST_LOG_TRIVIAL(error) << "hit test: " << item;
|
||||
}
|
||||
};
|
||||
|
||||
typedef DataList<wxListBox, std::string> StringList;
|
||||
|
@ -260,21 +323,35 @@ typedef DataList<wxCheckListBox, std::string> PresetList;
|
|||
struct PageMaterials: ConfigWizardPage
|
||||
{
|
||||
Materials *materials;
|
||||
StringList *list_l1, *list_l2;
|
||||
PresetList *list_l3;
|
||||
int sel1_prev, sel2_prev;
|
||||
StringList *list_printer, *list_type, *list_vendor;
|
||||
PresetList *list_profile;
|
||||
int sel_printer_prev, sel_type_prev, sel_vendor_prev;
|
||||
bool presets_loaded;
|
||||
|
||||
wxFlexGridSizer *grid;
|
||||
wxStaticText *compatible_printers;
|
||||
int compatible_printers_width = { 100 };
|
||||
std::string empty_printers_label;
|
||||
bool first_paint = { false };
|
||||
static const std::string EMPTY;
|
||||
int last_hovered_item = { -1 } ;
|
||||
|
||||
PageMaterials(ConfigWizard *parent, Materials *materials, wxString title, wxString shortname, wxString list1name);
|
||||
|
||||
void reload_presets();
|
||||
void update_lists(int sel1, int sel2);
|
||||
void update_lists(int sel1, int sel2, int sel3);
|
||||
void on_material_highlighted(int sel_material);
|
||||
void on_material_hovered(int sel_material);
|
||||
void select_material(int i);
|
||||
void select_all(bool select);
|
||||
void clear();
|
||||
void prepare_compatible_printers_label();
|
||||
void clear_compatible_printers_label();
|
||||
|
||||
void on_paint();
|
||||
void on_mouse_move_on_profiles(wxMouseEvent& evt);
|
||||
void on_mouse_enter_profiles(wxMouseEvent& evt);
|
||||
void on_mouse_leave_profiles(wxMouseEvent& evt);
|
||||
virtual void on_activate() override;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
#include "libslic3r/libslic3r.h"
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include "DoubleSlider.hpp"
|
||||
#include "libslic3r/GCode.hpp"
|
||||
#else
|
||||
#include "wxExtensions.hpp"
|
||||
#include "libslic3r/GCode/PreviewData.hpp"
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
#include "GUI.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "Plater.hpp"
|
||||
|
@ -15,7 +21,9 @@
|
|||
#include <wx/bmpcbox.h>
|
||||
#include <wx/statline.h>
|
||||
#include <wx/dcclient.h>
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
#include <wx/numformatter.h>
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
#include <wx/colordlg.h>
|
||||
|
||||
#include <cmath>
|
||||
|
@ -72,8 +80,13 @@ Control::Control( wxWindow *parent,
|
|||
if (!is_osx)
|
||||
SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
m_bmp_thumb_higher = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "thumb_right") : ScalableBitmap(this, "thumb_up"));
|
||||
m_bmp_thumb_lower = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "thumb_left") : ScalableBitmap(this, "thumb_down"));
|
||||
#else
|
||||
m_bmp_thumb_higher = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "right_half_circle.png") : ScalableBitmap(this, "thumb_up"));
|
||||
m_bmp_thumb_lower = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "left_half_circle.png" ) : ScalableBitmap(this, "thumb_down"));
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
m_thumb_size = m_bmp_thumb_lower.GetBmpSize();
|
||||
|
||||
m_bmp_add_tick_on = ScalableBitmap(this, "colorchange_add");
|
||||
|
@ -275,14 +288,14 @@ wxCoord Control::get_position_from_value(const int value)
|
|||
return wxCoord(SLIDER_MARGIN + int(val*step + 0.5));
|
||||
}
|
||||
|
||||
wxSize Control::get_size()
|
||||
wxSize Control::get_size() const
|
||||
{
|
||||
int w, h;
|
||||
get_size(&w, &h);
|
||||
return wxSize(w, h);
|
||||
}
|
||||
|
||||
void Control::get_size(int *w, int *h)
|
||||
void Control::get_size(int* w, int* h) const
|
||||
{
|
||||
GetSize(w, h);
|
||||
is_horizontal() ? *w -= m_lock_icon_dim : *h -= m_lock_icon_dim;
|
||||
|
@ -302,14 +315,22 @@ double Control::get_double_value(const SelectedSlider& selection)
|
|||
Info Control::GetTicksValues() const
|
||||
{
|
||||
Info custom_gcode_per_print_z;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
std::vector<CustomGCode::Item>& values = custom_gcode_per_print_z.gcodes;
|
||||
#else
|
||||
std::vector<Item>& values = custom_gcode_per_print_z.gcodes;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
const int val_size = m_values.size();
|
||||
if (!m_values.empty())
|
||||
for (const TickCode& tick : m_ticks.ticks) {
|
||||
if (tick.tick > val_size)
|
||||
break;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
values.emplace_back(CustomGCode::Item{ m_values[tick.tick], tick.type, tick.extruder, tick.color, tick.extra });
|
||||
#else
|
||||
values.emplace_back(Item{m_values[tick.tick], tick.type, tick.extruder, tick.color, tick.extra});
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
}
|
||||
|
||||
if (m_force_mode_apply)
|
||||
|
@ -329,7 +350,11 @@ void Control::SetTicksValues(const Info& custom_gcode_per_print_z)
|
|||
const bool was_empty = m_ticks.empty();
|
||||
|
||||
m_ticks.ticks.clear();
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
const std::vector<CustomGCode::Item>& heights = custom_gcode_per_print_z.gcodes;
|
||||
#else
|
||||
const std::vector<Item>& heights = custom_gcode_per_print_z.gcodes;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
for (auto h : heights) {
|
||||
auto it = std::lower_bound(m_values.begin(), m_values.end(), h.print_z - epsilon());
|
||||
|
||||
|
@ -401,7 +426,15 @@ void Control::draw_focus_rect()
|
|||
|
||||
void Control::render()
|
||||
{
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#ifdef _WIN32
|
||||
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||
#else
|
||||
SetBackgroundColour(GetParent()->GetBackgroundColour());
|
||||
#endif // _WIN32
|
||||
#else
|
||||
SetBackgroundColour(GetParent()->GetBackgroundColour());
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
draw_focus_rect();
|
||||
|
||||
wxPaintDC dc(this);
|
||||
|
@ -417,22 +450,22 @@ void Control::render()
|
|||
// draw line
|
||||
draw_scroll_line(dc, lower_pos, higher_pos);
|
||||
|
||||
//draw color print ticks
|
||||
// draw color print ticks
|
||||
draw_ticks(dc);
|
||||
|
||||
// draw both sliders
|
||||
draw_thumbs(dc, lower_pos, higher_pos);
|
||||
|
||||
//draw lock/unlock
|
||||
// draw lock/unlock
|
||||
draw_one_layer_icon(dc);
|
||||
|
||||
//draw revert bitmap (if it's shown)
|
||||
// draw revert bitmap (if it's shown)
|
||||
draw_revert_icon(dc);
|
||||
|
||||
//draw cog bitmap (if it's shown)
|
||||
// draw cog bitmap (if it's shown)
|
||||
draw_cog_icon(dc);
|
||||
|
||||
//draw mouse position
|
||||
// draw mouse position
|
||||
draw_tick_on_mouse_position(dc);
|
||||
}
|
||||
|
||||
|
@ -544,10 +577,21 @@ wxString Control::get_label(int tick) const
|
|||
if (value >= m_values.size())
|
||||
return "ErrVal";
|
||||
|
||||
const wxString str = m_values.empty() ?
|
||||
wxNumberFormatter::ToString(m_label_koef*value, 2, wxNumberFormatter::Style_None) :
|
||||
wxNumberFormatter::ToString(m_values[value], 2, wxNumberFormatter::Style_None);
|
||||
return format_wxstr("%1%\n(%2%)", str, m_values.empty() ? value : value+1);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
if (m_draw_mode == dmSequentialGCodeView)
|
||||
return wxString::Format("%d", static_cast<unsigned int>(m_values[value]));
|
||||
else {
|
||||
const wxString str = m_values.empty() ?
|
||||
wxString::Format("%.*f", 2, m_label_koef * value) :
|
||||
wxString::Format("%.*f", 2, m_values[value]);
|
||||
return format_wxstr("%1%\n(%2%)", str, m_values.empty() ? value : value + 1);
|
||||
}
|
||||
#else
|
||||
const wxString str = m_values.empty() ?
|
||||
wxNumberFormatter::ToString(m_label_koef * value, 2, wxNumberFormatter::Style_None) :
|
||||
wxNumberFormatter::ToString(m_values[value], 2, wxNumberFormatter::Style_None);
|
||||
return format_wxstr("%1%\n(%2%)", str, m_values.empty() ? value : value + 1);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
}
|
||||
|
||||
void Control::draw_tick_text(wxDC& dc, const wxPoint& pos, int tick, bool right_side/*=true*/) const
|
||||
|
@ -556,13 +600,36 @@ void Control::draw_tick_text(wxDC& dc, const wxPoint& pos, int tick, bool right_
|
|||
const wxString label = get_label(tick);
|
||||
dc.GetMultiLineTextExtent(label, &text_width, &text_height);
|
||||
wxPoint text_pos;
|
||||
if (right_side)
|
||||
text_pos = is_horizontal() ? wxPoint(pos.x + 1, pos.y + m_thumb_size.x) :
|
||||
wxPoint(pos.x + m_thumb_size.x+1, pos.y - 0.5*text_height - 1);
|
||||
else
|
||||
text_pos = is_horizontal() ? wxPoint(pos.x - text_width - 1, pos.y - m_thumb_size.x - text_height) :
|
||||
wxPoint(pos.x - text_width - 1 - m_thumb_size.x, pos.y - 0.5*text_height + 1);
|
||||
dc.DrawText(label, text_pos);
|
||||
if (right_side) {
|
||||
if (is_horizontal()) {
|
||||
int width;
|
||||
int height;
|
||||
get_size(&width, &height);
|
||||
|
||||
int x_right = pos.x + 1 + text_width;
|
||||
int xx = (x_right < width) ? pos.x + 1 : pos.x - text_width - 1;
|
||||
text_pos = wxPoint(xx, pos.y + m_thumb_size.x / 2 + 1);
|
||||
}
|
||||
else
|
||||
text_pos = wxPoint(pos.x + m_thumb_size.x + 1, pos.y - 0.5 * text_height - 1);
|
||||
|
||||
// update text rectangle
|
||||
m_rect_lower_thumb_text = wxRect(text_pos, wxSize(text_width, text_height));
|
||||
}
|
||||
else {
|
||||
if (is_horizontal()) {
|
||||
int x = pos.x - text_width - 1;
|
||||
int xx = (x > 0) ? x : pos.x + 1;
|
||||
text_pos = wxPoint(xx, pos.y - m_thumb_size.x / 2 - text_height - 1);
|
||||
}
|
||||
else
|
||||
text_pos = wxPoint(pos.x - text_width - 1 - m_thumb_size.x, pos.y - 0.5 * text_height + 1);
|
||||
|
||||
// update text rectangle
|
||||
m_rect_higher_thumb_text = wxRect(text_pos, wxSize(text_width, text_height));
|
||||
}
|
||||
|
||||
dc.DrawText(label, text_pos);
|
||||
}
|
||||
|
||||
void Control::draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const
|
||||
|
@ -572,6 +639,10 @@ void Control::draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider
|
|||
|
||||
void Control::draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection)
|
||||
{
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
wxCoord x_draw = pos.x - int(0.5 * m_thumb_size.x);
|
||||
wxCoord y_draw = pos.y - int(0.5 * m_thumb_size.y);
|
||||
#else
|
||||
wxCoord x_draw, y_draw;
|
||||
if (selection == ssLower) {
|
||||
if (is_horizontal()) {
|
||||
|
@ -583,7 +654,7 @@ void Control::draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider
|
|||
y_draw = pos.y - int(0.5*m_thumb_size.y);
|
||||
}
|
||||
}
|
||||
else{
|
||||
else {
|
||||
if (is_horizontal()) {
|
||||
x_draw = pos.x;
|
||||
y_draw = pos.y - int(0.5*m_thumb_size.y);
|
||||
|
@ -593,6 +664,7 @@ void Control::draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider
|
|||
y_draw = pos.y - int(0.5*m_thumb_size.y);
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
dc.DrawBitmap(selection == ssLower ? m_bmp_thumb_lower.bmp() : m_bmp_thumb_higher.bmp(), x_draw, y_draw);
|
||||
|
||||
// Update thumb rect
|
||||
|
@ -756,7 +828,15 @@ void Control::draw_colored_band(wxDC& dc)
|
|||
// don't color a band for MultiExtruder mode
|
||||
if (m_ticks.empty() || m_mode == MultiExtruder)
|
||||
{
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#ifdef _WIN32
|
||||
draw_band(dc, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW), main_band);
|
||||
#else
|
||||
draw_band(dc, GetParent()->GetBackgroundColour(), main_band);
|
||||
#endif // _WIN32
|
||||
#else
|
||||
draw_band(dc, GetParent()->GetBackgroundColour(), main_band);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -788,6 +868,11 @@ void Control::draw_colored_band(wxDC& dc)
|
|||
|
||||
void Control::draw_one_layer_icon(wxDC& dc)
|
||||
{
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
if (m_draw_mode == dmSequentialGCodeView)
|
||||
return;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
const wxBitmap& icon = m_is_one_layer ?
|
||||
m_focus == fiOneLayerIcon ? m_bmp_one_layer_lock_off.bmp() : m_bmp_one_layer_lock_on.bmp() :
|
||||
m_focus == fiOneLayerIcon ? m_bmp_one_layer_unlock_off.bmp() : m_bmp_one_layer_unlock_on.bmp();
|
||||
|
@ -829,8 +914,20 @@ void Control::draw_cog_icon(wxDC& dc)
|
|||
get_size(&width, &height);
|
||||
|
||||
wxCoord x_draw, y_draw;
|
||||
is_horizontal() ? x_draw = width-2 : x_draw = width - m_cog_icon_dim - 2;
|
||||
is_horizontal() ? y_draw = height - m_cog_icon_dim - 2 : y_draw = height-2;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
if (m_draw_mode == dmSequentialGCodeView)
|
||||
{
|
||||
is_horizontal() ? x_draw = width - 2 : x_draw = 0.5 * width - 0.5 * m_cog_icon_dim;
|
||||
is_horizontal() ? y_draw = 0.5 * height - 0.5 * m_cog_icon_dim : y_draw = height - 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
is_horizontal() ? x_draw = width - 2 : x_draw = width - m_cog_icon_dim - 2;
|
||||
is_horizontal() ? y_draw = height - m_cog_icon_dim - 2 : y_draw = height - 2;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
dc.DrawBitmap(m_bmp_cog.bmp(), x_draw, y_draw);
|
||||
|
||||
|
@ -838,9 +935,12 @@ void Control::draw_cog_icon(wxDC& dc)
|
|||
m_rect_cog_icon = wxRect(x_draw, y_draw, m_cog_icon_dim, m_cog_icon_dim);
|
||||
}
|
||||
|
||||
void Control::update_thumb_rect(const wxCoord& begin_x, const wxCoord& begin_y, const SelectedSlider& selection)
|
||||
void Control::update_thumb_rect(const wxCoord begin_x, const wxCoord begin_y, const SelectedSlider& selection)
|
||||
{
|
||||
const wxRect& rect = wxRect(begin_x, begin_y + (selection == ssLower ? int(m_thumb_size.y * 0.5) : 0), m_thumb_size.x, int(m_thumb_size.y*0.5));
|
||||
const wxRect rect = is_horizontal() ?
|
||||
wxRect(begin_x + (selection == ssHigher ? m_thumb_size.x / 2 : 0), begin_y, m_thumb_size.x / 2, m_thumb_size.y) :
|
||||
wxRect(begin_x, begin_y + (selection == ssLower ? m_thumb_size.y / 2 : 0), m_thumb_size.x, m_thumb_size.y / 2);
|
||||
|
||||
if (selection == ssLower)
|
||||
m_rect_lower_thumb = rect;
|
||||
else
|
||||
|
@ -968,10 +1068,19 @@ wxString Control::get_tooltip(int tick/*=-1*/)
|
|||
if (m_focus == fiRevertIcon)
|
||||
return _L("Discard all custom changes");
|
||||
if (m_focus == fiCogIcon)
|
||||
return m_mode == MultiAsSingle ?
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
{
|
||||
if (m_draw_mode == dmSequentialGCodeView)
|
||||
return _L("Jump to move") + " (Shift + G)";
|
||||
else
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
return m_mode == MultiAsSingle ?
|
||||
GUI::from_u8((boost::format(_u8L("Jump to height %s or "
|
||||
"Set extruder sequence for the entire print")) % " (Shift + G)\n").str()) :
|
||||
_L("Jump to height") + " (Shift + G)";
|
||||
"Set extruder sequence for the entire print")) % " (Shift + G)\n").str()) :
|
||||
_L("Jump to height") + " (Shift + G)";
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
if (m_focus == fiColorBand)
|
||||
return m_mode != SingleExtruder ? "" :
|
||||
_L("Edit current color - Right click the colored slider segment");
|
||||
|
@ -1099,6 +1208,14 @@ void Control::OnMotion(wxMouseEvent& event)
|
|||
else if (m_mode == SingleExtruder && is_point_in_rect(pos, get_colored_band_rect()) &&
|
||||
get_edited_tick_for_position(pos) >= 0 )
|
||||
m_focus = fiColorBand;
|
||||
else if (is_point_in_rect(pos, m_rect_lower_thumb))
|
||||
m_focus = fiLowerThumb;
|
||||
else if (is_point_in_rect(pos, m_rect_higher_thumb))
|
||||
m_focus = fiHigherThumb;
|
||||
else if (is_point_in_rect(pos, m_rect_lower_thumb_text))
|
||||
m_focus = fiLowerThumbText;
|
||||
else if (is_point_in_rect(pos, m_rect_higher_thumb_text))
|
||||
m_focus = fiHigherThumbText;
|
||||
else {
|
||||
m_focus = fiTick;
|
||||
tick = get_tick_near_point(pos);
|
||||
|
@ -1223,7 +1340,11 @@ void Control::OnLeftUp(wxMouseEvent& event)
|
|||
if (m_mode == MultiAsSingle && m_draw_mode == dmRegular)
|
||||
show_cog_icon_context_menu();
|
||||
else
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
jump_to_value();
|
||||
#else
|
||||
jump_to_print_z();
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
break;
|
||||
case maOneLayerIconClick:
|
||||
switch_one_layer_mode();
|
||||
|
@ -1262,6 +1383,15 @@ void Control::move_current_thumb(const bool condition)
|
|||
if (is_horizontal())
|
||||
delta *= -1;
|
||||
|
||||
// accelerators
|
||||
int accelerator = 0;
|
||||
if (wxGetKeyState(WXK_SHIFT))
|
||||
accelerator += 5;
|
||||
if (wxGetKeyState(WXK_CONTROL))
|
||||
accelerator += 5;
|
||||
if (accelerator > 0)
|
||||
delta *= accelerator;
|
||||
|
||||
if (m_selection == ssLower) {
|
||||
m_lower_value -= delta;
|
||||
correct_lower_value();
|
||||
|
@ -1295,12 +1425,32 @@ void Control::OnWheel(wxMouseEvent& event)
|
|||
ssLower : ssHigher;
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
move_current_thumb((m_draw_mode == dmSequentialGCodeView) ? event.GetWheelRotation() < 0 : event.GetWheelRotation() > 0);
|
||||
#else
|
||||
move_current_thumb(event.GetWheelRotation() > 0);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
}
|
||||
|
||||
void Control::OnKeyDown(wxKeyEvent &event)
|
||||
{
|
||||
const int key = event.GetKeyCode();
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
if (m_draw_mode != dmSequentialGCodeView && key == WXK_NUMPAD_ADD) {
|
||||
// OnChar() is called immediately after OnKeyDown(), which can cause call of add_tick() twice.
|
||||
// To avoid this case we should suppress second add_tick() call.
|
||||
m_ticks.suppress_plus(true);
|
||||
add_current_tick(true);
|
||||
}
|
||||
else if (m_draw_mode != dmSequentialGCodeView && (key == WXK_NUMPAD_SUBTRACT || key == WXK_DELETE || key == WXK_BACK)) {
|
||||
// OnChar() is called immediately after OnKeyDown(), which can cause call of delete_tick() twice.
|
||||
// To avoid this case we should suppress second delete_tick() call.
|
||||
m_ticks.suppress_minus(true);
|
||||
delete_current_tick();
|
||||
}
|
||||
else if (m_draw_mode != dmSequentialGCodeView && event.GetKeyCode() == WXK_SHIFT)
|
||||
UseDefaultColors(false);
|
||||
#else
|
||||
if (key == WXK_NUMPAD_ADD) {
|
||||
// OnChar() is called immediately after OnKeyDown(), which can cause call of add_tick() twice.
|
||||
// To avoid this case we should suppress second add_tick() call.
|
||||
|
@ -1315,22 +1465,37 @@ void Control::OnKeyDown(wxKeyEvent &event)
|
|||
}
|
||||
else if (event.GetKeyCode() == WXK_SHIFT)
|
||||
UseDefaultColors(false);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
else if (is_horizontal())
|
||||
{
|
||||
if (key == WXK_LEFT || key == WXK_RIGHT)
|
||||
move_current_thumb(key == WXK_LEFT);
|
||||
else if (key == WXK_UP || key == WXK_DOWN) {
|
||||
m_selection = key == WXK_UP ? ssHigher : ssLower;
|
||||
Refresh();
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
if (m_is_focused)
|
||||
{
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
if (key == WXK_LEFT || key == WXK_RIGHT)
|
||||
move_current_thumb(key == WXK_LEFT);
|
||||
else if (key == WXK_UP || key == WXK_DOWN) {
|
||||
m_selection = key == WXK_UP ? ssHigher : ssLower;
|
||||
Refresh();
|
||||
}
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (key == WXK_LEFT || key == WXK_RIGHT) {
|
||||
m_selection = key == WXK_LEFT ? ssHigher : ssLower;
|
||||
Refresh();
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
if (m_is_focused)
|
||||
{
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
if (key == WXK_LEFT || key == WXK_RIGHT) {
|
||||
m_selection = key == WXK_LEFT ? ssHigher : ssLower;
|
||||
Refresh();
|
||||
}
|
||||
else if (key == WXK_UP || key == WXK_DOWN)
|
||||
move_current_thumb(key == WXK_UP);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
}
|
||||
else if (key == WXK_UP || key == WXK_DOWN)
|
||||
move_current_thumb(key == WXK_UP);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
}
|
||||
|
||||
event.Skip(); // !Needed to have EVT_CHAR generated as well
|
||||
|
@ -1351,16 +1516,27 @@ void Control::OnKeyUp(wxKeyEvent &event)
|
|||
void Control::OnChar(wxKeyEvent& event)
|
||||
{
|
||||
const int key = event.GetKeyCode();
|
||||
if (key == '+' && !m_ticks.suppressed_plus()) {
|
||||
add_current_tick(true);
|
||||
m_ticks.suppress_plus(false);
|
||||
}
|
||||
else if (key == '-' && !m_ticks.suppressed_minus()) {
|
||||
delete_current_tick();
|
||||
m_ticks.suppress_minus(false);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
if (m_draw_mode != dmSequentialGCodeView)
|
||||
{
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
if (key == '+' && !m_ticks.suppressed_plus()) {
|
||||
add_current_tick(true);
|
||||
m_ticks.suppress_plus(false);
|
||||
}
|
||||
else if (key == '-' && !m_ticks.suppressed_minus()) {
|
||||
delete_current_tick();
|
||||
m_ticks.suppress_minus(false);
|
||||
}
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
if (key == 'G')
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
jump_to_value();
|
||||
#else
|
||||
jump_to_print_z();
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
}
|
||||
|
||||
void Control::OnRightDown(wxMouseEvent& event)
|
||||
|
@ -1550,7 +1726,11 @@ void Control::show_cog_icon_context_menu()
|
|||
wxMenu menu;
|
||||
|
||||
append_menu_item(&menu, wxID_ANY, _(L("Jump to height")) + " (Shift+G)", "",
|
||||
[this](wxCommandEvent&) { jump_to_print_z(); }, "", &menu);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
[this](wxCommandEvent&) { jump_to_value(); }, "", & menu);
|
||||
#else
|
||||
[this](wxCommandEvent&) { jump_to_print_z(); }, "", &menu);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
append_menu_item(&menu, wxID_ANY, _(L("Set extruder sequence for the entire print")), "",
|
||||
[this](wxCommandEvent&) { edit_extruder_sequence(); }, "", &menu);
|
||||
|
@ -1670,11 +1850,21 @@ static std::string get_pause_print_msg(const std::string& msg_in, double height)
|
|||
return into_u8(dlg.GetValue());
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
static double get_value_to_jump(double active_value, double min_z, double max_z, DrawMode mode)
|
||||
#else
|
||||
static double get_print_z_to_jump(double active_print_z, double min_z, double max_z)
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
{
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
wxString msg_text = (mode == dmSequentialGCodeView) ? _L("Enter the move you want to jump to") + ":" : _L("Enter the height you want to jump to") + ":";
|
||||
wxString msg_header = (mode == dmSequentialGCodeView) ? _L("Jump to move") : _L("Jump to height");
|
||||
wxString msg_in = GUI::double_to_string(active_value);
|
||||
#else
|
||||
wxString msg_text = _(L("Enter the height you want to jump to")) + ":";
|
||||
wxString msg_header = _(L("Jump to height"));
|
||||
wxString msg_in = GUI::double_to_string(active_print_z);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
// get custom gcode
|
||||
wxTextEntryDialog dlg(nullptr, msg_text, msg_header, msg_in, wxTextEntryDialogStyle);
|
||||
|
@ -1883,6 +2073,23 @@ void Control::edit_extruder_sequence()
|
|||
post_ticks_changed_event(ToolChange);
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
void Control::jump_to_value()
|
||||
{
|
||||
double value = get_value_to_jump(m_values[m_selection == ssLower ? m_lower_value : m_higher_value],
|
||||
m_values[m_min_value], m_values[m_max_value], m_draw_mode);
|
||||
if (value < 0.0)
|
||||
return;
|
||||
|
||||
auto it = std::lower_bound(m_values.begin(), m_values.end(), value - epsilon());
|
||||
int tick_value = it - m_values.begin();
|
||||
|
||||
if (m_selection == ssLower)
|
||||
SetLowerValue(tick_value);
|
||||
else
|
||||
SetHigherValue(tick_value);
|
||||
}
|
||||
#else
|
||||
void Control::jump_to_print_z()
|
||||
{
|
||||
double print_z = get_print_z_to_jump(m_values[m_selection == ssLower ? m_lower_value : m_higher_value],
|
||||
|
@ -1898,6 +2105,7 @@ void Control::jump_to_print_z()
|
|||
else
|
||||
SetHigherValue(tick_value);
|
||||
}
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
void Control::post_ticks_changed_event(Type type /*= Custom*/)
|
||||
{
|
||||
|
@ -1968,7 +2176,11 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int
|
|||
{
|
||||
if (mode == SingleExtruder && type == ColorChange && m_use_default_colors)
|
||||
{
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
const std::vector<std::string>& colors = ColorPrintColors::get();
|
||||
#else
|
||||
const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors();
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
if (ticks.empty())
|
||||
return colors[0];
|
||||
m_default_color_idx++;
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
#include "libslic3r/CustomGCode.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
#include <wx/wx.h>
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
#include <wx/window.h>
|
||||
#include <wx/control.h>
|
||||
#include <wx/dc.h>
|
||||
|
@ -42,6 +44,10 @@ enum FocusedItem {
|
|||
fiCogIcon,
|
||||
fiColorBand,
|
||||
fiActionIcon,
|
||||
fiLowerThumb,
|
||||
fiHigherThumb,
|
||||
fiLowerThumbText,
|
||||
fiHigherThumbText,
|
||||
fiTick
|
||||
};
|
||||
|
||||
|
@ -73,6 +79,9 @@ enum DrawMode
|
|||
dmRegular,
|
||||
dmSlaPrint,
|
||||
dmSequentialFffPrint,
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
dmSequentialGCodeView,
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
};
|
||||
|
||||
struct TickCode
|
||||
|
@ -210,6 +219,9 @@ public:
|
|||
void SetTicksValues(const Info &custom_gcode_per_print_z);
|
||||
|
||||
void SetDrawMode(bool is_sla_print, bool is_sequential_print);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
void SetDrawMode(DrawMode mode) { m_draw_mode = mode; }
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
void SetManipulationMode(Mode mode) { m_mode = mode; }
|
||||
Mode GetManipulationMode() const { return m_mode; }
|
||||
|
@ -222,7 +234,7 @@ public:
|
|||
bool is_higher_at_max() const { return m_higher_value == m_max_value; }
|
||||
bool is_full_span() const { return this->is_lower_at_min() && this->is_higher_at_max(); }
|
||||
|
||||
void OnPaint(wxPaintEvent& ) { render();}
|
||||
void OnPaint(wxPaintEvent& ) { render(); }
|
||||
void OnLeftDown(wxMouseEvent& event);
|
||||
void OnMotion(wxMouseEvent& event);
|
||||
void OnLeftUp(wxMouseEvent& event);
|
||||
|
@ -246,7 +258,11 @@ public:
|
|||
void discard_all_thicks();
|
||||
void move_current_thumb_to_pos(wxPoint pos);
|
||||
void edit_extruder_sequence();
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
void jump_to_value();
|
||||
#else
|
||||
void jump_to_print_z();
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
void show_add_context_menu();
|
||||
void show_edit_context_menu();
|
||||
void show_cog_icon_context_menu();
|
||||
|
@ -272,7 +288,7 @@ protected:
|
|||
void draw_tick_text(wxDC& dc, const wxPoint& pos, int tick, bool right_side = true) const;
|
||||
void draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const;
|
||||
|
||||
void update_thumb_rect(const wxCoord& begin_x, const wxCoord& begin_y, const SelectedSlider& selection);
|
||||
void update_thumb_rect(const wxCoord begin_x, const wxCoord begin_y, const SelectedSlider& selection);
|
||||
bool detect_selected_slider(const wxPoint& pt);
|
||||
void correct_lower_value();
|
||||
void correct_higher_value();
|
||||
|
@ -290,8 +306,8 @@ private:
|
|||
int get_value_from_position(const wxCoord x, const wxCoord y);
|
||||
int get_value_from_position(const wxPoint pos) { return get_value_from_position(pos.x, pos.y); }
|
||||
wxCoord get_position_from_value(const int value);
|
||||
wxSize get_size();
|
||||
void get_size(int *w, int *h);
|
||||
wxSize get_size() const;
|
||||
void get_size(int* w, int* h) const;
|
||||
double get_double_value(const SelectedSlider& selection);
|
||||
wxString get_tooltip(int tick = -1);
|
||||
int get_edited_tick_for_position(wxPoint pos, Type type = ColorChange);
|
||||
|
@ -348,6 +364,8 @@ private:
|
|||
|
||||
wxRect m_rect_lower_thumb;
|
||||
wxRect m_rect_higher_thumb;
|
||||
mutable wxRect m_rect_lower_thumb_text;
|
||||
mutable wxRect m_rect_higher_thumb_text;
|
||||
wxRect m_rect_tick_action;
|
||||
wxRect m_rect_one_layer_icon;
|
||||
wxRect m_rect_revert_icon;
|
||||
|
|
2359
src/slic3r/GUI/GCodeViewer.cpp
Normal file
2359
src/slic3r/GUI/GCodeViewer.cpp
Normal file
File diff suppressed because it is too large
Load diff
477
src/slic3r/GUI/GCodeViewer.hpp
Normal file
477
src/slic3r/GUI/GCodeViewer.hpp
Normal file
|
@ -0,0 +1,477 @@
|
|||
#ifndef slic3r_GCodeViewer_hpp_
|
||||
#define slic3r_GCodeViewer_hpp_
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include "3DScene.hpp"
|
||||
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
||||
#include "GLModel.hpp"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Print;
|
||||
class TriangleMesh;
|
||||
|
||||
namespace GUI {
|
||||
|
||||
class GCodeViewer
|
||||
{
|
||||
using Color = std::array<float, 3>;
|
||||
static const std::vector<Color> Extrusion_Role_Colors;
|
||||
static const std::vector<Color> Options_Colors;
|
||||
static const std::vector<Color> Travel_Colors;
|
||||
static const std::vector<Color> Range_Colors;
|
||||
|
||||
enum class EOptionsColors : unsigned char
|
||||
{
|
||||
Retractions,
|
||||
Unretractions,
|
||||
ToolChanges,
|
||||
ColorChanges,
|
||||
PausePrints,
|
||||
CustomGCodes
|
||||
};
|
||||
|
||||
// vbo buffer containing vertices data used to rendder a specific toolpath type
|
||||
struct VBuffer
|
||||
{
|
||||
enum class EFormat : unsigned char
|
||||
{
|
||||
// vertex format: 3 floats -> position.x|position.y|position.z
|
||||
Position,
|
||||
// vertex format: 4 floats -> position.x|position.y|position.z|normal.x
|
||||
PositionNormal1,
|
||||
// vertex format: 6 floats -> position.x|position.y|position.z|normal.x|normal.y|normal.z
|
||||
PositionNormal3
|
||||
};
|
||||
|
||||
EFormat format{ EFormat::Position };
|
||||
// vbo id
|
||||
unsigned int id{ 0 };
|
||||
// count of vertices, updated after data are sent to gpu
|
||||
size_t count{ 0 };
|
||||
|
||||
size_t data_size_bytes() const { return count * vertex_size_bytes(); }
|
||||
|
||||
size_t vertex_size_floats() const { return position_size_floats() + normal_size_floats(); }
|
||||
size_t vertex_size_bytes() const { return vertex_size_floats() * sizeof(float); }
|
||||
|
||||
size_t position_offset_floats() const { return 0; }
|
||||
size_t position_offset_size() const { return position_offset_floats() * sizeof(float); }
|
||||
size_t position_size_floats() const
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case EFormat::Position:
|
||||
case EFormat::PositionNormal3: { return 3; }
|
||||
case EFormat::PositionNormal1: { return 4; }
|
||||
default: { return 0; }
|
||||
}
|
||||
}
|
||||
size_t position_size_bytes() const { return position_size_floats() * sizeof(float); }
|
||||
|
||||
size_t normal_offset_floats() const
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case EFormat::Position:
|
||||
case EFormat::PositionNormal1: { return 0; }
|
||||
case EFormat::PositionNormal3: { return 3; }
|
||||
default: { return 0; }
|
||||
}
|
||||
}
|
||||
size_t normal_offset_size() const { return normal_offset_floats() * sizeof(float); }
|
||||
size_t normal_size_floats() const {
|
||||
switch (format)
|
||||
{
|
||||
default:
|
||||
case EFormat::Position:
|
||||
case EFormat::PositionNormal1: { return 0; }
|
||||
case EFormat::PositionNormal3: { return 3; }
|
||||
}
|
||||
}
|
||||
size_t normal_size_bytes() const { return normal_size_floats() * sizeof(float); }
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
// ibo buffer containing indices data (lines/triangles) used to render a specific toolpath type
|
||||
struct IBuffer
|
||||
{
|
||||
// ibo id
|
||||
unsigned int id{ 0 };
|
||||
// count of indices, updated after data are sent to gpu
|
||||
size_t count{ 0 };
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
// Used to identify different toolpath sub-types inside a IBuffer
|
||||
struct Path
|
||||
{
|
||||
struct Endpoint
|
||||
{
|
||||
// index into the indices buffer
|
||||
unsigned int i_id{ 0u };
|
||||
// sequential id
|
||||
unsigned int s_id{ 0u };
|
||||
Vec3f position{ Vec3f::Zero() };
|
||||
};
|
||||
|
||||
EMoveType type{ EMoveType::Noop };
|
||||
ExtrusionRole role{ erNone };
|
||||
Endpoint first;
|
||||
Endpoint last;
|
||||
float delta_extruder{ 0.0f };
|
||||
float height{ 0.0f };
|
||||
float width{ 0.0f };
|
||||
float feedrate{ 0.0f };
|
||||
float fan_speed{ 0.0f };
|
||||
float volumetric_rate{ 0.0f };
|
||||
unsigned char extruder_id{ 0 };
|
||||
unsigned char cp_color_id{ 0 };
|
||||
|
||||
bool matches(const GCodeProcessor::MoveVertex& move) const;
|
||||
size_t vertices_count() const { return last.s_id - first.s_id + 1; }
|
||||
bool contains(unsigned int id) const { return first.s_id <= id && id <= last.s_id; }
|
||||
};
|
||||
|
||||
// Used to batch the indices needed to render paths
|
||||
struct RenderPath
|
||||
{
|
||||
Color color;
|
||||
size_t path_id;
|
||||
std::vector<unsigned int> sizes;
|
||||
std::vector<size_t> offsets; // use size_t because we need the pointer's size (used in the call glMultiDrawElements())
|
||||
};
|
||||
|
||||
// buffer containing data for rendering a specific toolpath type
|
||||
struct TBuffer
|
||||
{
|
||||
enum class ERenderPrimitiveType : unsigned char
|
||||
{
|
||||
Point,
|
||||
Line,
|
||||
Triangle
|
||||
};
|
||||
|
||||
ERenderPrimitiveType render_primitive_type;
|
||||
VBuffer vertices;
|
||||
IBuffer indices;
|
||||
|
||||
std::string shader;
|
||||
std::vector<Path> paths;
|
||||
std::vector<RenderPath> render_paths;
|
||||
bool visible{ false };
|
||||
|
||||
void reset();
|
||||
void add_path(const GCodeProcessor::MoveVertex& move, unsigned int i_id, unsigned int s_id);
|
||||
unsigned int indices_per_segment() const {
|
||||
switch (render_primitive_type)
|
||||
{
|
||||
case ERenderPrimitiveType::Point: { return 1; }
|
||||
case ERenderPrimitiveType::Line: { return 2; }
|
||||
case ERenderPrimitiveType::Triangle: { return 42; } // 3 indices x 14 triangles
|
||||
default: { return 0; }
|
||||
}
|
||||
}
|
||||
unsigned int start_segment_vertex_offset() const {
|
||||
switch (render_primitive_type)
|
||||
{
|
||||
case ERenderPrimitiveType::Point:
|
||||
case ERenderPrimitiveType::Line:
|
||||
case ERenderPrimitiveType::Triangle:
|
||||
default: { return 0; }
|
||||
}
|
||||
}
|
||||
unsigned int end_segment_vertex_offset() const {
|
||||
switch (render_primitive_type)
|
||||
{
|
||||
case ERenderPrimitiveType::Point: { return 0; }
|
||||
case ERenderPrimitiveType::Line: { return 1; }
|
||||
case ERenderPrimitiveType::Triangle: { return 36; } // 1 vertex of 13th triangle
|
||||
default: { return 0; }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// helper to render shells
|
||||
struct Shells
|
||||
{
|
||||
GLVolumeCollection volumes;
|
||||
bool visible{ false };
|
||||
};
|
||||
|
||||
// helper to render extrusion paths
|
||||
struct Extrusions
|
||||
{
|
||||
struct Range
|
||||
{
|
||||
float min;
|
||||
float max;
|
||||
unsigned int count;
|
||||
|
||||
Range() { reset(); }
|
||||
|
||||
void update_from(const float value) {
|
||||
if (value != max && value != min)
|
||||
++count;
|
||||
min = std::min(min, value);
|
||||
max = std::max(max, value);
|
||||
}
|
||||
void reset() { min = FLT_MAX; max = -FLT_MAX; count = 0; }
|
||||
|
||||
float step_size() const { return (max - min) / (static_cast<float>(Range_Colors.size()) - 1.0f); }
|
||||
Color get_color_at(float value) const;
|
||||
};
|
||||
|
||||
struct Ranges
|
||||
{
|
||||
// Color mapping by layer height.
|
||||
Range height;
|
||||
// Color mapping by extrusion width.
|
||||
Range width;
|
||||
// Color mapping by feedrate.
|
||||
Range feedrate;
|
||||
// Color mapping by fan speed.
|
||||
Range fan_speed;
|
||||
// Color mapping by volumetric extrusion rate.
|
||||
Range volumetric_rate;
|
||||
|
||||
void reset() {
|
||||
height.reset();
|
||||
width.reset();
|
||||
feedrate.reset();
|
||||
fan_speed.reset();
|
||||
volumetric_rate.reset();
|
||||
}
|
||||
};
|
||||
|
||||
unsigned int role_visibility_flags{ 0 };
|
||||
Ranges ranges;
|
||||
|
||||
void reset_role_visibility_flags() {
|
||||
role_visibility_flags = 0;
|
||||
for (unsigned int i = 0; i < erCount; ++i) {
|
||||
role_visibility_flags |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
void reset_ranges() { ranges.reset(); }
|
||||
};
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
struct Statistics
|
||||
{
|
||||
// times
|
||||
long long results_time{ 0 };
|
||||
long long load_time{ 0 };
|
||||
long long refresh_time{ 0 };
|
||||
long long refresh_paths_time{ 0 };
|
||||
// opengl calls
|
||||
long long gl_multi_points_calls_count{ 0 };
|
||||
long long gl_multi_lines_calls_count{ 0 };
|
||||
long long gl_multi_triangles_calls_count{ 0 };
|
||||
// memory
|
||||
long long results_size{ 0 };
|
||||
long long vertices_gpu_size{ 0 };
|
||||
long long indices_gpu_size{ 0 };
|
||||
long long paths_size{ 0 };
|
||||
long long render_paths_size{ 0 };
|
||||
// others
|
||||
long long travel_segments_count{ 0 };
|
||||
long long extrude_segments_count{ 0 };
|
||||
|
||||
void reset_all() {
|
||||
reset_times();
|
||||
reset_opengl();
|
||||
reset_sizes();
|
||||
reset_counters();
|
||||
}
|
||||
|
||||
void reset_times() {
|
||||
results_time = 0;
|
||||
load_time = 0;
|
||||
refresh_time = 0;
|
||||
refresh_paths_time = 0;
|
||||
}
|
||||
|
||||
void reset_opengl() {
|
||||
gl_multi_points_calls_count = 0;
|
||||
gl_multi_lines_calls_count = 0;
|
||||
gl_multi_triangles_calls_count = 0;
|
||||
}
|
||||
|
||||
void reset_sizes() {
|
||||
results_size = 0;
|
||||
vertices_gpu_size = 0;
|
||||
indices_gpu_size = 0;
|
||||
paths_size = 0;
|
||||
render_paths_size = 0;
|
||||
}
|
||||
|
||||
void reset_counters() {
|
||||
travel_segments_count = 0;
|
||||
extrude_segments_count = 0;
|
||||
}
|
||||
};
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
|
||||
public:
|
||||
struct SequentialView
|
||||
{
|
||||
class Marker
|
||||
{
|
||||
GLModel m_model;
|
||||
Vec3f m_world_position;
|
||||
Transform3f m_world_transform;
|
||||
float m_z_offset{ 0.5f };
|
||||
std::array<float, 4> m_color{ 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
bool m_visible{ false };
|
||||
|
||||
public:
|
||||
void init();
|
||||
|
||||
const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); }
|
||||
|
||||
void set_world_position(const Vec3f& position);
|
||||
void set_color(const std::array<float, 4>& color) { m_color = color; }
|
||||
|
||||
bool is_visible() const { return m_visible; }
|
||||
void set_visible(bool visible) { m_visible = visible; }
|
||||
|
||||
void render() const;
|
||||
};
|
||||
|
||||
struct Endpoints
|
||||
{
|
||||
unsigned int first{ 0 };
|
||||
unsigned int last{ 0 };
|
||||
};
|
||||
|
||||
Endpoints endpoints;
|
||||
Endpoints current;
|
||||
Vec3f current_position{ Vec3f::Zero() };
|
||||
Marker marker;
|
||||
};
|
||||
|
||||
enum class EViewType : unsigned char
|
||||
{
|
||||
FeatureType,
|
||||
Height,
|
||||
Width,
|
||||
Feedrate,
|
||||
FanSpeed,
|
||||
VolumetricRate,
|
||||
Tool,
|
||||
ColorPrint,
|
||||
Count
|
||||
};
|
||||
|
||||
private:
|
||||
unsigned int m_last_result_id{ 0 };
|
||||
size_t m_vertices_count{ 0 };
|
||||
mutable std::vector<TBuffer> m_buffers{ static_cast<size_t>(EMoveType::Extrude) };
|
||||
// bounding box of toolpaths
|
||||
BoundingBoxf3 m_paths_bounding_box;
|
||||
// bounding box of toolpaths + marker tools
|
||||
BoundingBoxf3 m_max_bounding_box;
|
||||
std::vector<Color> m_tool_colors;
|
||||
std::vector<double> m_layers_zs;
|
||||
std::array<double, 2> m_layers_z_range;
|
||||
std::vector<ExtrusionRole> m_roles;
|
||||
std::vector<unsigned char> m_extruder_ids;
|
||||
mutable Extrusions m_extrusions;
|
||||
mutable SequentialView m_sequential_view;
|
||||
Shells m_shells;
|
||||
EViewType m_view_type{ EViewType::FeatureType };
|
||||
bool m_legend_enabled{ true };
|
||||
PrintEstimatedTimeStatistics m_time_statistics;
|
||||
mutable PrintEstimatedTimeStatistics::ETimeMode m_time_estimate_mode{ PrintEstimatedTimeStatistics::ETimeMode::Normal };
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
mutable Statistics m_statistics;
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
std::array<float, 2> m_detected_point_sizes = { 0.0f, 0.0f };
|
||||
|
||||
public:
|
||||
GCodeViewer() = default;
|
||||
~GCodeViewer() { reset(); }
|
||||
|
||||
bool init();
|
||||
|
||||
// extract rendering data from the given parameters
|
||||
void load(const GCodeProcessor::Result& gcode_result, const Print& print, bool initialized);
|
||||
// recalculate ranges in dependence of what is visible and sets tool/print colors
|
||||
void refresh(const GCodeProcessor::Result& gcode_result, const std::vector<std::string>& str_tool_colors);
|
||||
|
||||
void reset();
|
||||
void render() const;
|
||||
|
||||
bool has_data() const { return !m_roles.empty(); }
|
||||
|
||||
const BoundingBoxf3& get_paths_bounding_box() const { return m_paths_bounding_box; }
|
||||
const BoundingBoxf3& get_max_bounding_box() const { return m_max_bounding_box; }
|
||||
const std::vector<double>& get_layers_zs() const { return m_layers_zs; };
|
||||
|
||||
const SequentialView& get_sequential_view() const { return m_sequential_view; }
|
||||
void update_sequential_view_current(unsigned int first, unsigned int last)
|
||||
{
|
||||
m_sequential_view.current.first = first;
|
||||
m_sequential_view.current.last = last;
|
||||
refresh_render_paths(true, true);
|
||||
}
|
||||
|
||||
EViewType get_view_type() const { return m_view_type; }
|
||||
void set_view_type(EViewType type) {
|
||||
if (type == EViewType::Count)
|
||||
type = EViewType::FeatureType;
|
||||
|
||||
m_view_type = type;
|
||||
}
|
||||
|
||||
bool is_toolpath_move_type_visible(EMoveType type) const;
|
||||
void set_toolpath_move_type_visible(EMoveType type, bool visible);
|
||||
unsigned int get_toolpath_role_visibility_flags() const { return m_extrusions.role_visibility_flags; }
|
||||
void set_toolpath_role_visibility_flags(unsigned int flags) { m_extrusions.role_visibility_flags = flags; }
|
||||
unsigned int get_options_visibility_flags() const;
|
||||
void set_options_visibility_from_flags(unsigned int flags);
|
||||
void set_layers_z_range(const std::array<double, 2>& layers_z_range);
|
||||
|
||||
bool is_legend_enabled() const { return m_legend_enabled; }
|
||||
void enable_legend(bool enable) { m_legend_enabled = enable; }
|
||||
|
||||
void export_toolpaths_to_obj(const char* filename) const;
|
||||
|
||||
private:
|
||||
void init_shaders();
|
||||
void load_toolpaths(const GCodeProcessor::Result& gcode_result);
|
||||
void load_shells(const Print& print, bool initialized);
|
||||
void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const;
|
||||
void render_toolpaths() const;
|
||||
void render_shells() const;
|
||||
void render_legend() const;
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
void render_statistics() const;
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
bool is_visible(ExtrusionRole role) const {
|
||||
return role < erCount && (m_extrusions.role_visibility_flags & (1 << role)) != 0;
|
||||
}
|
||||
bool is_visible(const Path& path) const { return is_visible(path.role); }
|
||||
bool is_in_z_range(const Path& path) const {
|
||||
auto in_z_range = [this](double z) {
|
||||
return z > m_layers_z_range[0] - EPSILON && z < m_layers_z_range[1] + EPSILON;
|
||||
};
|
||||
|
||||
return in_z_range(path.first.position[2]) || in_z_range(path.last.position[2]);
|
||||
}
|
||||
bool is_travel_in_z_range(size_t id) const;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
#endif // slic3r_GCodeViewer_hpp_
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -6,13 +6,16 @@
|
|||
#include <chrono>
|
||||
|
||||
#include "GLToolbar.hpp"
|
||||
#include "GLShader.hpp"
|
||||
#include "Event.hpp"
|
||||
#include "Selection.hpp"
|
||||
#include "Gizmos/GLGizmosManager.hpp"
|
||||
#include "GUI_ObjectLayers.hpp"
|
||||
#include "GLSelectionRectangle.hpp"
|
||||
#include "MeshUtils.hpp"
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
||||
#include "GCodeViewer.hpp"
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
#include "libslic3r/Slicing.hpp"
|
||||
|
||||
|
@ -36,7 +39,9 @@ namespace Slic3r {
|
|||
|
||||
struct Camera;
|
||||
class BackgroundSlicingProcess;
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
class GCodePreviewData;
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
struct ThumbnailData;
|
||||
class ModelObject;
|
||||
class ModelInstance;
|
||||
|
@ -103,7 +108,11 @@ wxDECLARE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent);
|
|||
wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_BED_SHAPE, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_TAB, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_RESETGIZMOS, SimpleEvent);
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_MOVE_LAYERS_SLIDER, wxKeyEvent);
|
||||
#else
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
|
||||
|
@ -118,6 +127,7 @@ class GLCanvas3D
|
|||
static const double DefaultCameraZoomToBoxMarginFactor;
|
||||
|
||||
public:
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
struct GCodePreviewVolumeIndex
|
||||
{
|
||||
enum EType
|
||||
|
@ -144,6 +154,7 @@ public:
|
|||
|
||||
void reset() { first_volumes.clear(); }
|
||||
};
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
private:
|
||||
class LayersEditing
|
||||
|
@ -161,7 +172,6 @@ private:
|
|||
private:
|
||||
|
||||
bool m_enabled;
|
||||
Shader m_shader;
|
||||
unsigned int m_z_texture_id;
|
||||
// Not owned by LayersEditing.
|
||||
const DynamicPrintConfig *m_config;
|
||||
|
@ -208,8 +218,9 @@ private:
|
|||
LayersEditing();
|
||||
~LayersEditing();
|
||||
|
||||
bool init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename);
|
||||
void set_config(const DynamicPrintConfig* config);
|
||||
void init();
|
||||
|
||||
void set_config(const DynamicPrintConfig* config);
|
||||
void select_object(const Model &model, int object_id);
|
||||
|
||||
bool is_allowed() const;
|
||||
|
@ -339,6 +350,7 @@ private:
|
|||
bool generate(const std::string& msg, const GLCanvas3D& canvas, bool compress, bool red_colored = false);
|
||||
};
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
class LegendTexture : public GUI::GLTexture
|
||||
{
|
||||
static const int Px_Title_Offset = 5;
|
||||
|
@ -365,6 +377,7 @@ private:
|
|||
|
||||
void render(const GLCanvas3D& canvas) const;
|
||||
};
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
#if ENABLE_RENDER_STATISTICS
|
||||
struct RenderStats
|
||||
|
@ -443,11 +456,12 @@ private:
|
|||
std::unique_ptr<RetinaHelper> m_retina_helper;
|
||||
#endif
|
||||
bool m_in_render;
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
LegendTexture m_legend_texture;
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
WarningTexture m_warning_texture;
|
||||
wxTimer m_timer;
|
||||
LayersEditing m_layers_editing;
|
||||
Shader m_shader;
|
||||
Mouse m_mouse;
|
||||
mutable GLGizmosManager m_gizmos;
|
||||
mutable GLToolbar m_main_toolbar;
|
||||
|
@ -462,6 +476,10 @@ private:
|
|||
bool m_extra_frame_requested;
|
||||
|
||||
mutable GLVolumeCollection m_volumes;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
GCodeViewer m_gcode_viewer;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
Selection m_selection;
|
||||
const DynamicPrintConfig* m_config;
|
||||
Model* m_model;
|
||||
|
@ -472,7 +490,9 @@ private:
|
|||
bool m_initialized;
|
||||
bool m_apply_zoom_to_volumes_filter;
|
||||
mutable std::vector<int> m_hover_volume_idxs;
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
bool m_legend_texture_enabled;
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
bool m_picking_enabled;
|
||||
bool m_moving_enabled;
|
||||
bool m_dynamic_background_enabled;
|
||||
|
@ -490,7 +510,9 @@ private:
|
|||
|
||||
bool m_reload_delayed;
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
GCodePreviewVolumeIndex m_gcode_preview_volume_index;
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
#if ENABLE_RENDER_PICKING_PASS
|
||||
bool m_show_picking_texture;
|
||||
|
@ -532,6 +554,12 @@ public:
|
|||
void reset_volumes();
|
||||
int check_volumes_outside_state() const;
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
void reset_gcode_toolpaths() { m_gcode_viewer.reset(); }
|
||||
const GCodeViewer::SequentialView& get_gcode_sequential_view() const { return m_gcode_viewer.get_sequential_view(); }
|
||||
void update_gcode_sequential_view_current(unsigned int first, unsigned int last) { m_gcode_viewer.update_sequential_view_current(first, last); }
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
|
||||
void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
|
||||
void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
|
||||
void update_instance_printable_state_for_object(size_t obj_idx);
|
||||
|
@ -564,7 +592,6 @@ public:
|
|||
void set_color_by(const std::string& value);
|
||||
|
||||
void refresh_camera_scene_box();
|
||||
const Shader& get_shader() const { return m_shader; }
|
||||
|
||||
BoundingBoxf3 volumes_bounding_box() const;
|
||||
BoundingBoxf3 scene_bounding_box() const;
|
||||
|
@ -597,6 +624,9 @@ public:
|
|||
void zoom_to_bed();
|
||||
void zoom_to_volumes();
|
||||
void zoom_to_selection();
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
void zoom_to_gcode();
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
void select_view(const std::string& direction);
|
||||
|
||||
void update_volumes_colors_by_extruder();
|
||||
|
@ -613,7 +643,20 @@ public:
|
|||
void delete_selected();
|
||||
void ensure_on_bed(unsigned int object_idx);
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
bool is_gcode_legend_enabled() const { return m_gcode_viewer.is_legend_enabled(); }
|
||||
GCodeViewer::EViewType get_gcode_view_type() const { return m_gcode_viewer.get_view_type(); }
|
||||
const std::vector<double>& get_gcode_layers_zs() const;
|
||||
std::vector<double> get_volumes_print_zs(bool active_only) const;
|
||||
unsigned int get_gcode_options_visibility_flags() const { return m_gcode_viewer.get_options_visibility_flags(); }
|
||||
void set_gcode_options_visibility_from_flags(unsigned int flags);
|
||||
unsigned int get_toolpath_role_visibility_flags() const { return m_gcode_viewer.get_toolpath_role_visibility_flags(); }
|
||||
void set_toolpath_role_visibility_flags(unsigned int flags);
|
||||
void set_toolpath_view_type(GCodeViewer::EViewType type);
|
||||
void set_toolpaths_z_range(const std::array<double, 2>& range);
|
||||
#else
|
||||
std::vector<double> get_current_print_zs(bool active_only) const;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
void set_toolpaths_range(double low, double high);
|
||||
|
||||
std::vector<int> load_object(const ModelObject& model_object, int obj_idx, std::vector<int> instance_idxs);
|
||||
|
@ -623,7 +666,14 @@ public:
|
|||
|
||||
void reload_scene(bool refresh_immediately, bool force_full_scene_refresh = false);
|
||||
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
void load_gcode_preview(const GCodeProcessor::Result& gcode_result);
|
||||
void refresh_gcode_preview(const GCodeProcessor::Result& gcode_result, const std::vector<std::string>& str_tool_colors);
|
||||
void set_gcode_view_preview_type(GCodeViewer::EViewType type) { return m_gcode_viewer.set_view_type(type); }
|
||||
GCodeViewer::EViewType get_gcode_view_preview_type() const { return m_gcode_viewer.get_view_type(); }
|
||||
#else
|
||||
void load_gcode_preview(const GCodePreviewData& preview_data, const std::vector<std::string>& str_tool_colors);
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
void load_sla_preview();
|
||||
void load_preview(const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values);
|
||||
void bind_event_handlers();
|
||||
|
@ -642,7 +692,9 @@ public:
|
|||
Size get_canvas_size() const;
|
||||
Vec2d get_local_mouse_position() const;
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
void reset_legend_texture();
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
void set_tooltip(const std::string& tooltip) const;
|
||||
|
||||
|
@ -744,6 +796,9 @@ private:
|
|||
void _render_background() const;
|
||||
void _render_bed(bool bottom, bool show_axes) const;
|
||||
void _render_objects() const;
|
||||
#if ENABLE_GCODE_VIEWER
|
||||
void _render_gcode() const;
|
||||
#endif // ENABLE_GCODE_VIEWER
|
||||
void _render_selection() const;
|
||||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
void _render_selection_center() const;
|
||||
|
@ -751,7 +806,9 @@ private:
|
|||
void _check_and_update_toolbar_icon_scale() const;
|
||||
void _render_overlays() const;
|
||||
void _render_warning_texture() const;
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
void _render_legend_texture() const;
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
void _render_volumes_for_picking() const;
|
||||
void _render_current_gizmo() const;
|
||||
void _render_gizmos_overlay() const;
|
||||
|
@ -799,22 +856,28 @@ private:
|
|||
// Create 3D thick extrusion lines for wipe tower extrusions
|
||||
void _load_wipe_tower_toolpaths(const std::vector<std::string>& str_tool_colors);
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
// generates gcode extrusion paths geometry
|
||||
void _load_gcode_extrusion_paths(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
|
||||
// generates gcode travel paths geometry
|
||||
void _load_gcode_travel_paths(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
|
||||
// generates objects and wipe tower geometry
|
||||
void _load_fff_shells();
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
// Load SLA objects and support structures for objects, for which the slaposSliceSupports step has been finished.
|
||||
void _load_sla_shells();
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
// sets gcode geometry visibility according to user selection
|
||||
void _update_gcode_volumes_visibility(const GCodePreviewData& preview_data);
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
void _update_toolpath_volumes_outside_state();
|
||||
void _update_sla_shells_outside_state();
|
||||
void _show_warning_texture_if_needed(WarningTexture::Warning warning);
|
||||
|
||||
#if !ENABLE_GCODE_VIEWER
|
||||
// generates the legend texture in dependence of the current shown view type
|
||||
void _generate_legend_texture(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors);
|
||||
#endif // !ENABLE_GCODE_VIEWER
|
||||
|
||||
// generates a warning texture containing the given message
|
||||
void _set_warning_texture(WarningTexture::Warning warning, bool state);
|
||||
|
|
531
src/slic3r/GUI/GLModel.cpp
Normal file
531
src/slic3r/GUI/GLModel.cpp
Normal file
|
@ -0,0 +1,531 @@
|
|||
#include "libslic3r/libslic3r.h"
|
||||
#include "GLModel.hpp"
|
||||
|
||||
#include "3DScene.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
void GLModel::init_from(const GLModelInitializationData& data)
|
||||
{
|
||||
assert(!data.positions.empty() && !data.triangles.empty());
|
||||
assert(data.positions.size() == data.normals.size());
|
||||
|
||||
if (m_vbo_id > 0) // call reset() if you want to reuse this model
|
||||
return;
|
||||
|
||||
// vertices/normals data
|
||||
std::vector<float> vertices(6 * data.positions.size());
|
||||
for (size_t i = 0; i < data.positions.size(); ++i) {
|
||||
size_t offset = i * 6;
|
||||
::memcpy(static_cast<void*>(&vertices[offset]), static_cast<const void*>(data.positions[i].data()), 3 * sizeof(float));
|
||||
::memcpy(static_cast<void*>(&vertices[3 + offset]), static_cast<const void*>(data.normals[i].data()), 3 * sizeof(float));
|
||||
}
|
||||
|
||||
// indices data
|
||||
std::vector<unsigned int> indices(3 * data.triangles.size());
|
||||
for (size_t i = 0; i < data.triangles.size(); ++i) {
|
||||
for (size_t j = 0; j < 3; ++j) {
|
||||
indices[i * 3 + j] = static_cast<unsigned int>(data.triangles[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
m_indices_count = static_cast<unsigned int>(indices.size());
|
||||
m_bounding_box = BoundingBoxf3();
|
||||
for (size_t i = 0; i < data.positions.size(); ++i) {
|
||||
m_bounding_box.merge(data.positions[i].cast<double>());
|
||||
}
|
||||
|
||||
send_to_gpu(vertices, indices);
|
||||
}
|
||||
|
||||
void GLModel::init_from(const TriangleMesh& mesh)
|
||||
{
|
||||
if (m_vbo_id > 0) // call reset() if you want to reuse this model
|
||||
return;
|
||||
|
||||
std::vector<float> vertices = std::vector<float>(18 * mesh.stl.stats.number_of_facets);
|
||||
std::vector<unsigned int> indices = std::vector<unsigned int>(3 * mesh.stl.stats.number_of_facets);
|
||||
|
||||
unsigned int vertices_count = 0;
|
||||
for (uint32_t i = 0; i < mesh.stl.stats.number_of_facets; ++i) {
|
||||
const stl_facet& facet = mesh.stl.facet_start[i];
|
||||
for (uint32_t j = 0; j < 3; ++j) {
|
||||
uint32_t offset = i * 18 + j * 6;
|
||||
::memcpy(static_cast<void*>(&vertices[offset]), static_cast<const void*>(facet.vertex[j].data()), 3 * sizeof(float));
|
||||
::memcpy(static_cast<void*>(&vertices[3 + offset]), static_cast<const void*>(facet.normal.data()), 3 * sizeof(float));
|
||||
}
|
||||
for (uint32_t j = 0; j < 3; ++j) {
|
||||
indices[i * 3 + j] = vertices_count + j;
|
||||
}
|
||||
vertices_count += 3;
|
||||
}
|
||||
|
||||
m_indices_count = static_cast<unsigned int>(indices.size());
|
||||
m_bounding_box = mesh.bounding_box();
|
||||
|
||||
send_to_gpu(vertices, indices);
|
||||
}
|
||||
|
||||
bool GLModel::init_from_file(const std::string& filename)
|
||||
{
|
||||
if (!boost::filesystem::exists(filename))
|
||||
return false;
|
||||
|
||||
if (!boost::algorithm::iends_with(filename, ".stl"))
|
||||
return false;
|
||||
|
||||
Model model;
|
||||
try
|
||||
{
|
||||
model = Model::read_from_file(filename);
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
init_from(model.mesh());
|
||||
|
||||
m_filename = filename;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLModel::reset()
|
||||
{
|
||||
// release gpu memory
|
||||
if (m_ibo_id > 0) {
|
||||
glsafe(::glDeleteBuffers(1, &m_ibo_id));
|
||||
m_ibo_id = 0;
|
||||
}
|
||||
|
||||
if (m_vbo_id > 0) {
|
||||
glsafe(::glDeleteBuffers(1, &m_vbo_id));
|
||||
m_vbo_id = 0;
|
||||
}
|
||||
|
||||
m_indices_count = 0;
|
||||
m_bounding_box = BoundingBoxf3();
|
||||
m_filename = std::string();
|
||||
}
|
||||
|
||||
void GLModel::render() const
|
||||
{
|
||||
if (m_vbo_id == 0 || m_ibo_id == 0)
|
||||
return;
|
||||
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
|
||||
glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)0));
|
||||
glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float))));
|
||||
|
||||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
|
||||
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo_id));
|
||||
glsafe(::glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_indices_count), GL_UNSIGNED_INT, (const void*)0));
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
|
||||
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
|
||||
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
|
||||
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
}
|
||||
|
||||
void GLModel::send_to_gpu(const std::vector<float>& vertices, const std::vector<unsigned int>& indices)
|
||||
{
|
||||
// vertex data -> send to gpu
|
||||
glsafe(::glGenBuffers(1, &m_vbo_id));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
|
||||
glsafe(::glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
|
||||
// indices data -> send to gpu
|
||||
glsafe(::glGenBuffers(1, &m_ibo_id));
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo_id));
|
||||
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW));
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
}
|
||||
|
||||
GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float tip_height, float stem_radius, float stem_height)
|
||||
{
|
||||
auto append_vertex = [](GLModelInitializationData& data, const Vec3f& position, const Vec3f& normal) {
|
||||
data.positions.emplace_back(position);
|
||||
data.normals.emplace_back(normal);
|
||||
};
|
||||
|
||||
resolution = std::max(4, resolution);
|
||||
|
||||
GLModelInitializationData data;
|
||||
|
||||
const float angle_step = 2.0f * M_PI / static_cast<float>(resolution);
|
||||
std::vector<float> cosines(resolution);
|
||||
std::vector<float> sines(resolution);
|
||||
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
float angle = angle_step * static_cast<float>(i);
|
||||
cosines[i] = ::cos(angle);
|
||||
sines[i] = -::sin(angle);
|
||||
}
|
||||
|
||||
const float total_height = tip_height + stem_height;
|
||||
|
||||
// tip vertices/normals
|
||||
append_vertex(data, { 0.0f, 0.0f, total_height }, Vec3f::UnitZ());
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
append_vertex(data, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f });
|
||||
}
|
||||
|
||||
// tip triangles
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
int v3 = (i < resolution - 1) ? i + 2 : 1;
|
||||
data.triangles.emplace_back(0, i + 1, v3);
|
||||
}
|
||||
|
||||
// tip cap outer perimeter vertices
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
append_vertex(data, { tip_radius * sines[i], tip_radius * cosines[i], stem_height }, -Vec3f::UnitZ());
|
||||
}
|
||||
|
||||
// tip cap inner perimeter vertices
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, -Vec3f::UnitZ());
|
||||
}
|
||||
|
||||
// tip cap triangles
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
int v2 = (i < resolution - 1) ? i + resolution + 2 : resolution + 1;
|
||||
int v3 = (i < resolution - 1) ? i + 2 * resolution + 2 : 2 * resolution + 1;
|
||||
data.triangles.emplace_back(i + resolution + 1, v3, v2);
|
||||
data.triangles.emplace_back(i + resolution + 1, i + 2 * resolution + 1, v3);
|
||||
}
|
||||
|
||||
// stem bottom vertices
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], stem_height }, { sines[i], cosines[i], 0.0f });
|
||||
}
|
||||
|
||||
// stem top vertices
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, { sines[i], cosines[i], 0.0f });
|
||||
}
|
||||
|
||||
// stem triangles
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
int v2 = (i < resolution - 1) ? i + 3 * resolution + 2 : 3 * resolution + 1;
|
||||
int v3 = (i < resolution - 1) ? i + 4 * resolution + 2 : 4 * resolution + 1;
|
||||
data.triangles.emplace_back(i + 3 * resolution + 1, v3, v2);
|
||||
data.triangles.emplace_back(i + 3 * resolution + 1, i + 4 * resolution + 1, v3);
|
||||
}
|
||||
|
||||
// stem cap vertices
|
||||
append_vertex(data, Vec3f::Zero(), -Vec3f::UnitZ());
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
append_vertex(data, { stem_radius * sines[i], stem_radius * cosines[i], 0.0f }, -Vec3f::UnitZ());
|
||||
}
|
||||
|
||||
// stem cap triangles
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
int v3 = (i < resolution - 1) ? i + 5 * resolution + 3 : 5 * resolution + 2;
|
||||
data.triangles.emplace_back(5 * resolution + 1, v3, i + 5 * resolution + 2);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
GLModelInitializationData circular_arrow(int resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness)
|
||||
{
|
||||
auto append_vertex = [](GLModelInitializationData& data, const Vec3f& position, const Vec3f& normal) {
|
||||
data.positions.emplace_back(position);
|
||||
data.normals.emplace_back(normal);
|
||||
};
|
||||
|
||||
resolution = std::max(2, resolution);
|
||||
|
||||
GLModelInitializationData data;
|
||||
|
||||
const float half_thickness = 0.5f * thickness;
|
||||
const float half_stem_width = 0.5f * stem_width;
|
||||
const float half_tip_width = 0.5f * tip_width;
|
||||
|
||||
const float outer_radius = radius + half_stem_width;
|
||||
const float inner_radius = radius - half_stem_width;
|
||||
const float step_angle = 0.5f * PI / static_cast<float>(resolution);
|
||||
|
||||
// tip
|
||||
// top face vertices
|
||||
append_vertex(data, { 0.0f, outer_radius, half_thickness }, Vec3f::UnitZ());
|
||||
append_vertex(data, { 0.0f, radius + half_tip_width, half_thickness }, Vec3f::UnitZ());
|
||||
append_vertex(data, { -tip_height, radius, half_thickness }, Vec3f::UnitZ());
|
||||
append_vertex(data, { 0.0f, radius - half_tip_width, half_thickness }, Vec3f::UnitZ());
|
||||
append_vertex(data, { 0.0f, inner_radius, half_thickness }, Vec3f::UnitZ());
|
||||
|
||||
// top face triangles
|
||||
data.triangles.emplace_back(0, 1, 2);
|
||||
data.triangles.emplace_back(0, 2, 4);
|
||||
data.triangles.emplace_back(4, 2, 3);
|
||||
|
||||
// bottom face vertices
|
||||
append_vertex(data, { 0.0f, outer_radius, -half_thickness }, -Vec3f::UnitZ());
|
||||
append_vertex(data, { 0.0f, radius + half_tip_width, -half_thickness }, -Vec3f::UnitZ());
|
||||
append_vertex(data, { -tip_height, radius, -half_thickness }, -Vec3f::UnitZ());
|
||||
append_vertex(data, { 0.0f, radius - half_tip_width, -half_thickness }, -Vec3f::UnitZ());
|
||||
append_vertex(data, { 0.0f, inner_radius, -half_thickness }, -Vec3f::UnitZ());
|
||||
|
||||
// bottom face triangles
|
||||
data.triangles.emplace_back(5, 7, 6);
|
||||
data.triangles.emplace_back(5, 9, 7);
|
||||
data.triangles.emplace_back(9, 8, 7);
|
||||
|
||||
// side faces vertices
|
||||
append_vertex(data, { 0.0f, outer_radius, -half_thickness }, Vec3f::UnitX());
|
||||
append_vertex(data, { 0.0f, radius + half_tip_width, -half_thickness }, Vec3f::UnitX());
|
||||
append_vertex(data, { 0.0f, outer_radius, half_thickness }, Vec3f::UnitX());
|
||||
append_vertex(data, { 0.0f, radius + half_tip_width, half_thickness }, Vec3f::UnitX());
|
||||
|
||||
Vec3f normal(-half_tip_width, tip_height, 0.0f);
|
||||
normal.normalize();
|
||||
append_vertex(data, { 0.0f, radius + half_tip_width, -half_thickness }, normal);
|
||||
append_vertex(data, { -tip_height, radius, -half_thickness }, normal);
|
||||
append_vertex(data, { 0.0f, radius + half_tip_width, half_thickness }, normal);
|
||||
append_vertex(data, { -tip_height, radius, half_thickness }, normal);
|
||||
|
||||
normal = Vec3f(-half_tip_width, -tip_height, 0.0f);
|
||||
normal.normalize();
|
||||
append_vertex(data, { -tip_height, radius, -half_thickness }, normal);
|
||||
append_vertex(data, { 0.0f, radius - half_tip_width, -half_thickness }, normal);
|
||||
append_vertex(data, { -tip_height, radius, half_thickness }, normal);
|
||||
append_vertex(data, { 0.0f, radius - half_tip_width, half_thickness }, normal);
|
||||
|
||||
append_vertex(data, { 0.0f, radius - half_tip_width, -half_thickness }, Vec3f::UnitX());
|
||||
append_vertex(data, { 0.0f, inner_radius, -half_thickness }, Vec3f::UnitX());
|
||||
append_vertex(data, { 0.0f, radius - half_tip_width, half_thickness }, Vec3f::UnitX());
|
||||
append_vertex(data, { 0.0f, inner_radius, half_thickness }, Vec3f::UnitX());
|
||||
|
||||
// side face triangles
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
int ii = i * 4;
|
||||
data.triangles.emplace_back(10 + ii, 11 + ii, 13 + ii);
|
||||
data.triangles.emplace_back(10 + ii, 13 + ii, 12 + ii);
|
||||
}
|
||||
|
||||
// stem
|
||||
// top face vertices
|
||||
for (int i = 0; i <= resolution; ++i)
|
||||
{
|
||||
float angle = static_cast<float>(i) * step_angle;
|
||||
append_vertex(data, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ());
|
||||
}
|
||||
|
||||
for (int i = 0; i <= resolution; ++i)
|
||||
{
|
||||
float angle = static_cast<float>(i) * step_angle;
|
||||
append_vertex(data, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), half_thickness }, Vec3f::UnitZ());
|
||||
}
|
||||
|
||||
// top face triangles
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
data.triangles.emplace_back(26 + i, 27 + i, 27 + resolution + i);
|
||||
data.triangles.emplace_back(27 + i, 28 + resolution + i, 27 + resolution + i);
|
||||
}
|
||||
|
||||
// bottom face vertices
|
||||
for (int i = 0; i <= resolution; ++i)
|
||||
{
|
||||
float angle = static_cast<float>(i) * step_angle;
|
||||
append_vertex(data, { inner_radius * ::sin(angle), inner_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ());
|
||||
}
|
||||
|
||||
for (int i = 0; i <= resolution; ++i)
|
||||
{
|
||||
float angle = static_cast<float>(i) * step_angle;
|
||||
append_vertex(data, { outer_radius * ::sin(angle), outer_radius * ::cos(angle), -half_thickness }, -Vec3f::UnitZ());
|
||||
}
|
||||
|
||||
// bottom face triangles
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
data.triangles.emplace_back(28 + 2 * resolution + i, 29 + 3 * resolution + i, 29 + 2 * resolution + i);
|
||||
data.triangles.emplace_back(29 + 2 * resolution + i, 29 + 3 * resolution + i, 30 + 3 * resolution + i);
|
||||
}
|
||||
|
||||
// side faces vertices and triangles
|
||||
for (int i = 0; i <= resolution; ++i)
|
||||
{
|
||||
float angle = static_cast<float>(i) * step_angle;
|
||||
float c = ::cos(angle);
|
||||
float s = ::sin(angle);
|
||||
append_vertex(data, { inner_radius * s, inner_radius * c, -half_thickness }, { -s, -c, 0.0f });
|
||||
}
|
||||
|
||||
for (int i = 0; i <= resolution; ++i)
|
||||
{
|
||||
float angle = static_cast<float>(i) * step_angle;
|
||||
float c = ::cos(angle);
|
||||
float s = ::sin(angle);
|
||||
append_vertex(data, { inner_radius * s, inner_radius * c, half_thickness }, { -s, -c, 0.0f });
|
||||
}
|
||||
|
||||
int first_id = 26 + 4 * (resolution + 1);
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
int ii = first_id + i;
|
||||
data.triangles.emplace_back(ii, ii + 1, ii + resolution + 2);
|
||||
data.triangles.emplace_back(ii, ii + resolution + 2, ii + resolution + 1);
|
||||
}
|
||||
|
||||
append_vertex(data, { inner_radius, 0.0f, -half_thickness }, -Vec3f::UnitY());
|
||||
append_vertex(data, { outer_radius, 0.0f, -half_thickness }, -Vec3f::UnitY());
|
||||
append_vertex(data, { inner_radius, 0.0f, half_thickness }, -Vec3f::UnitY());
|
||||
append_vertex(data, { outer_radius, 0.0f, half_thickness }, -Vec3f::UnitY());
|
||||
|
||||
first_id = 26 + 6 * (resolution + 1);
|
||||
data.triangles.emplace_back(first_id, first_id + 1, first_id + 3);
|
||||
data.triangles.emplace_back(first_id, first_id + 3, first_id + 2);
|
||||
|
||||
for (int i = resolution; i >= 0; --i)
|
||||
{
|
||||
float angle = static_cast<float>(i) * step_angle;
|
||||
float c = ::cos(angle);
|
||||
float s = ::sin(angle);
|
||||
append_vertex(data, { outer_radius * s, outer_radius * c, -half_thickness }, { s, c, 0.0f });
|
||||
}
|
||||
|
||||
for (int i = resolution; i >= 0; --i)
|
||||
{
|
||||
float angle = static_cast<float>(i) * step_angle;
|
||||
float c = ::cos(angle);
|
||||
float s = ::sin(angle);
|
||||
append_vertex(data, { outer_radius * s, outer_radius * c, +half_thickness }, { s, c, 0.0f });
|
||||
}
|
||||
|
||||
first_id = 30 + 6 * (resolution + 1);
|
||||
for (int i = 0; i < resolution; ++i)
|
||||
{
|
||||
int ii = first_id + i;
|
||||
data.triangles.emplace_back(ii, ii + 1, ii + resolution + 2);
|
||||
data.triangles.emplace_back(ii, ii + resolution + 2, ii + resolution + 1);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
GLModelInitializationData straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness)
|
||||
{
|
||||
auto append_vertex = [](GLModelInitializationData& data, const Vec3f& position, const Vec3f& normal) {
|
||||
data.positions.emplace_back(position);
|
||||
data.normals.emplace_back(normal);
|
||||
};
|
||||
|
||||
GLModelInitializationData data;
|
||||
|
||||
const float half_thickness = 0.5f * thickness;
|
||||
const float half_stem_width = 0.5f * stem_width;
|
||||
const float half_tip_width = 0.5f * tip_width;
|
||||
const float total_height = tip_height + stem_height;
|
||||
|
||||
// top face vertices
|
||||
append_vertex(data, { half_stem_width, 0.0, half_thickness }, Vec3f::UnitZ());
|
||||
append_vertex(data, { half_stem_width, stem_height, half_thickness }, Vec3f::UnitZ());
|
||||
append_vertex(data, { half_tip_width, stem_height, half_thickness }, Vec3f::UnitZ());
|
||||
append_vertex(data, { 0.0, total_height, half_thickness }, Vec3f::UnitZ());
|
||||
append_vertex(data, { -half_tip_width, stem_height, half_thickness }, Vec3f::UnitZ());
|
||||
append_vertex(data, { -half_stem_width, stem_height, half_thickness }, Vec3f::UnitZ());
|
||||
append_vertex(data, { -half_stem_width, 0.0, half_thickness }, Vec3f::UnitZ());
|
||||
|
||||
// top face triangles
|
||||
data.triangles.emplace_back(0, 1, 6);
|
||||
data.triangles.emplace_back(6, 1, 5);
|
||||
data.triangles.emplace_back(4, 5, 3);
|
||||
data.triangles.emplace_back(5, 1, 3);
|
||||
data.triangles.emplace_back(1, 2, 3);
|
||||
|
||||
// bottom face vertices
|
||||
append_vertex(data, { half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitZ());
|
||||
append_vertex(data, { half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitZ());
|
||||
append_vertex(data, { half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitZ());
|
||||
append_vertex(data, { 0.0, total_height, -half_thickness }, -Vec3f::UnitZ());
|
||||
append_vertex(data, { -half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitZ());
|
||||
append_vertex(data, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitZ());
|
||||
append_vertex(data, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitZ());
|
||||
|
||||
// bottom face triangles
|
||||
data.triangles.emplace_back(7, 13, 8);
|
||||
data.triangles.emplace_back(13, 12, 8);
|
||||
data.triangles.emplace_back(12, 11, 10);
|
||||
data.triangles.emplace_back(8, 12, 10);
|
||||
data.triangles.emplace_back(9, 8, 10);
|
||||
|
||||
// side faces vertices
|
||||
append_vertex(data, { half_stem_width, 0.0, -half_thickness }, Vec3f::UnitX());
|
||||
append_vertex(data, { half_stem_width, stem_height, -half_thickness }, Vec3f::UnitX());
|
||||
append_vertex(data, { half_stem_width, 0.0, half_thickness }, Vec3f::UnitX());
|
||||
append_vertex(data, { half_stem_width, stem_height, half_thickness }, Vec3f::UnitX());
|
||||
|
||||
append_vertex(data, { half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitY());
|
||||
append_vertex(data, { half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitY());
|
||||
append_vertex(data, { half_stem_width, stem_height, half_thickness }, -Vec3f::UnitY());
|
||||
append_vertex(data, { half_tip_width, stem_height, half_thickness }, -Vec3f::UnitY());
|
||||
|
||||
Vec3f normal(tip_height, half_tip_width, 0.0f);
|
||||
normal.normalize();
|
||||
append_vertex(data, { half_tip_width, stem_height, -half_thickness }, normal);
|
||||
append_vertex(data, { 0.0, total_height, -half_thickness }, normal);
|
||||
append_vertex(data, { half_tip_width, stem_height, half_thickness }, normal);
|
||||
append_vertex(data, { 0.0, total_height, half_thickness }, normal);
|
||||
|
||||
normal = Vec3f(-tip_height, half_tip_width, 0.0f);
|
||||
normal.normalize();
|
||||
append_vertex(data, { 0.0, total_height, -half_thickness }, normal);
|
||||
append_vertex(data, { -half_tip_width, stem_height, -half_thickness }, normal);
|
||||
append_vertex(data, { 0.0, total_height, half_thickness }, normal);
|
||||
append_vertex(data, { -half_tip_width, stem_height, half_thickness }, normal);
|
||||
|
||||
append_vertex(data, { -half_tip_width, stem_height, -half_thickness }, -Vec3f::UnitY());
|
||||
append_vertex(data, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitY());
|
||||
append_vertex(data, { -half_tip_width, stem_height, half_thickness }, -Vec3f::UnitY());
|
||||
append_vertex(data, { -half_stem_width, stem_height, half_thickness }, -Vec3f::UnitY());
|
||||
|
||||
append_vertex(data, { -half_stem_width, stem_height, -half_thickness }, -Vec3f::UnitX());
|
||||
append_vertex(data, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitX());
|
||||
append_vertex(data, { -half_stem_width, stem_height, half_thickness }, -Vec3f::UnitX());
|
||||
append_vertex(data, { -half_stem_width, 0.0, half_thickness }, -Vec3f::UnitX());
|
||||
|
||||
append_vertex(data, { -half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitY());
|
||||
append_vertex(data, { half_stem_width, 0.0, -half_thickness }, -Vec3f::UnitY());
|
||||
append_vertex(data, { -half_stem_width, 0.0, half_thickness }, -Vec3f::UnitY());
|
||||
append_vertex(data, { half_stem_width, 0.0, half_thickness }, -Vec3f::UnitY());
|
||||
|
||||
// side face triangles
|
||||
for (int i = 0; i < 7; ++i)
|
||||
{
|
||||
int ii = i * 4;
|
||||
data.triangles.emplace_back(14 + ii, 15 + ii, 17 + ii);
|
||||
data.triangles.emplace_back(14 + ii, 17 + ii, 16 + ii);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
68
src/slic3r/GUI/GLModel.hpp
Normal file
68
src/slic3r/GUI/GLModel.hpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
#ifndef slic3r_GLModel_hpp_
|
||||
#define slic3r_GLModel_hpp_
|
||||
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/BoundingBox.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class TriangleMesh;
|
||||
|
||||
namespace GUI {
|
||||
|
||||
struct GLModelInitializationData
|
||||
{
|
||||
std::vector<Vec3f> positions;
|
||||
std::vector<Vec3f> normals;
|
||||
std::vector<Vec3i> triangles;
|
||||
};
|
||||
|
||||
class GLModel
|
||||
{
|
||||
unsigned int m_vbo_id{ 0 };
|
||||
unsigned int m_ibo_id{ 0 };
|
||||
size_t m_indices_count{ 0 };
|
||||
|
||||
BoundingBoxf3 m_bounding_box;
|
||||
std::string m_filename;
|
||||
|
||||
public:
|
||||
virtual ~GLModel() { reset(); }
|
||||
|
||||
void init_from(const GLModelInitializationData& data);
|
||||
void init_from(const TriangleMesh& mesh);
|
||||
bool init_from_file(const std::string& filename);
|
||||
void reset();
|
||||
void render() const;
|
||||
|
||||
const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; }
|
||||
|
||||
const std::string& get_filename() const { return m_filename; }
|
||||
|
||||
private:
|
||||
void send_to_gpu(const std::vector<float>& vertices, const std::vector<unsigned int>& indices);
|
||||
};
|
||||
|
||||
|
||||
// create an arrow with cylindrical stem and conical tip, with the given dimensions and resolution
|
||||
// the origin of the arrow is in the center of the stem cap
|
||||
// the arrow has its axis of symmetry along the Z axis and is pointing upward
|
||||
GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float tip_height, float stem_radius, float stem_height);
|
||||
|
||||
// create an arrow whose stem is a quarter of circle, with the given dimensions and resolution
|
||||
// the origin of the arrow is in the center of the circle
|
||||
// the arrow is contained in the 1st quadrant of the XY plane and is pointing counterclockwise
|
||||
GLModelInitializationData circular_arrow(int resolution, float radius, float tip_height, float tip_width, float stem_width, float thickness);
|
||||
|
||||
// create an arrow with the given dimensions
|
||||
// the origin of the arrow is in the center of the stem cap
|
||||
// the arrow is contained in XY plane and has its main axis along the Y axis
|
||||
GLModelInitializationData straight_arrow(float tip_width, float tip_height, float stem_width, float stem_height, float thickness);
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_GLModel_hpp_
|
||||
|
|
@ -1,366 +1,348 @@
|
|||
#include <GL/glew.h>
|
||||
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "GLShader.hpp"
|
||||
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include "libslic3r/Utils.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <assert.h>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <GL/glew.h>
|
||||
#include <cassert>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
GLShader::~GLShader()
|
||||
GLShaderProgram::~GLShaderProgram()
|
||||
{
|
||||
assert(fragment_program_id == 0);
|
||||
assert(vertex_program_id == 0);
|
||||
assert(shader_program_id == 0);
|
||||
if (m_id > 0)
|
||||
glsafe(::glDeleteProgram(m_id));
|
||||
}
|
||||
|
||||
// A safe wrapper around glGetString to report a "N/A" string in case glGetString returns nullptr.
|
||||
inline std::string gl_get_string_safe(GLenum param)
|
||||
bool GLShaderProgram::init_from_files(const std::string& name, const ShaderFilenames& filenames)
|
||||
{
|
||||
const char *value = (const char*)glGetString(param);
|
||||
return std::string(value ? value : "N/A");
|
||||
auto load_from_file = [](const std::string& filename) {
|
||||
std::string path = resources_dir() + "/shaders/" + filename;
|
||||
boost::nowide::ifstream s(path, boost::nowide::ifstream::binary);
|
||||
if (!s.good()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Couldn't open file: '" << path << "'";
|
||||
return std::string();
|
||||
}
|
||||
|
||||
s.seekg(0, s.end);
|
||||
int file_length = static_cast<int>(s.tellg());
|
||||
s.seekg(0, s.beg);
|
||||
std::string source(file_length, '\0');
|
||||
s.read(source.data(), file_length);
|
||||
if (!s.good()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error while loading file: '" << path << "'";
|
||||
return std::string();
|
||||
}
|
||||
|
||||
s.close();
|
||||
return source;
|
||||
};
|
||||
|
||||
ShaderSources sources = {};
|
||||
for (size_t i = 0; i < static_cast<size_t>(EShaderType::Count); ++i) {
|
||||
sources[i] = filenames[i].empty() ? std::string() : load_from_file(filenames[i]);
|
||||
}
|
||||
|
||||
bool valid = !sources[static_cast<size_t>(EShaderType::Vertex)].empty() && !sources[static_cast<size_t>(EShaderType::Fragment)].empty() && sources[static_cast<size_t>(EShaderType::Compute)].empty();
|
||||
valid |= !sources[static_cast<size_t>(EShaderType::Compute)].empty() && sources[static_cast<size_t>(EShaderType::Vertex)].empty() && sources[static_cast<size_t>(EShaderType::Fragment)].empty() &&
|
||||
sources[static_cast<size_t>(EShaderType::Geometry)].empty() && sources[static_cast<size_t>(EShaderType::TessEvaluation)].empty() && sources[static_cast<size_t>(EShaderType::TessControl)].empty();
|
||||
|
||||
return valid ? init_from_texts(name, sources) : false;
|
||||
}
|
||||
|
||||
bool GLShader::load_from_text(const char *fragment_shader, const char *vertex_shader)
|
||||
bool GLShaderProgram::init_from_texts(const std::string& name, const ShaderSources& sources)
|
||||
{
|
||||
std::string gl_version = gl_get_string_safe(GL_VERSION);
|
||||
int major = atoi(gl_version.c_str());
|
||||
//int minor = atoi(gl_version.c_str() + gl_version.find('.') + 1);
|
||||
if (major < 2) {
|
||||
// Cannot create a shader object on OpenGL 1.x.
|
||||
// Form an error message.
|
||||
std::string gl_vendor = gl_get_string_safe(GL_VENDOR);
|
||||
std::string gl_renderer = gl_get_string_safe(GL_RENDERER);
|
||||
std::string glsl_version = gl_get_string_safe(GL_SHADING_LANGUAGE_VERSION);
|
||||
last_error = "Your computer does not support OpenGL shaders.\n";
|
||||
#ifdef _WIN32
|
||||
if (gl_vendor == "Microsoft Corporation" && gl_renderer == "GDI Generic") {
|
||||
last_error = "Windows is using a software OpenGL renderer.\n"
|
||||
"You are either connected over remote desktop,\n"
|
||||
"or a hardware acceleration is not available.\n";
|
||||
auto shader_type_as_string = [](EShaderType type) {
|
||||
switch (type)
|
||||
{
|
||||
case EShaderType::Vertex: { return "vertex"; }
|
||||
case EShaderType::Fragment: { return "fragment"; }
|
||||
case EShaderType::Geometry: { return "geometry"; }
|
||||
case EShaderType::TessEvaluation: { return "tesselation evaluation"; }
|
||||
case EShaderType::TessControl: { return "tesselation control"; }
|
||||
case EShaderType::Compute: { return "compute"; }
|
||||
default: { return "unknown"; }
|
||||
}
|
||||
#endif
|
||||
last_error += "GL version: " + gl_version + "\n";
|
||||
last_error += "vendor: " + gl_vendor + "\n";
|
||||
last_error += "renderer: " + gl_renderer + "\n";
|
||||
last_error += "GLSL version: " + glsl_version + "\n";
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if (fragment_shader != nullptr) {
|
||||
this->fragment_program_id = ::glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glcheck();
|
||||
if (this->fragment_program_id == 0) {
|
||||
last_error = "glCreateShader(GL_FRAGMENT_SHADER) failed.";
|
||||
return false;
|
||||
auto create_shader = [](EShaderType type) {
|
||||
GLuint id = 0;
|
||||
switch (type)
|
||||
{
|
||||
case EShaderType::Vertex: { id = ::glCreateShader(GL_VERTEX_SHADER); glcheck(); break; }
|
||||
case EShaderType::Fragment: { id = ::glCreateShader(GL_FRAGMENT_SHADER); glcheck(); break; }
|
||||
case EShaderType::Geometry: { id = ::glCreateShader(GL_GEOMETRY_SHADER); glcheck(); break; }
|
||||
case EShaderType::TessEvaluation: { id = ::glCreateShader(GL_TESS_EVALUATION_SHADER); glcheck(); break; }
|
||||
case EShaderType::TessControl: { id = ::glCreateShader(GL_TESS_CONTROL_SHADER); glcheck(); break; }
|
||||
case EShaderType::Compute: { id = ::glCreateShader(GL_COMPUTE_SHADER); glcheck(); break; }
|
||||
default: { break; }
|
||||
}
|
||||
GLint len = (GLint)strlen(fragment_shader);
|
||||
glsafe(::glShaderSource(this->fragment_program_id, 1, &fragment_shader, &len));
|
||||
glsafe(::glCompileShader(this->fragment_program_id));
|
||||
GLint params;
|
||||
glsafe(::glGetShaderiv(this->fragment_program_id, GL_COMPILE_STATUS, ¶ms));
|
||||
if (params == GL_FALSE) {
|
||||
// Compilation failed. Get the log.
|
||||
glsafe(::glGetShaderiv(this->fragment_program_id, GL_INFO_LOG_LENGTH, ¶ms));
|
||||
std::vector<char> msg(params);
|
||||
glsafe(::glGetShaderInfoLog(this->fragment_program_id, params, ¶ms, msg.data()));
|
||||
this->last_error = std::string("Fragment shader compilation failed:\n") + msg.data();
|
||||
this->release();
|
||||
return false;
|
||||
|
||||
return (id == 0) ? std::make_pair(false, GLuint(0)) : std::make_pair(true, id);
|
||||
};
|
||||
|
||||
auto release_shaders = [](const std::array<GLuint, static_cast<size_t>(EShaderType::Count)>& shader_ids) {
|
||||
for (size_t i = 0; i < static_cast<size_t>(EShaderType::Count); ++i) {
|
||||
if (shader_ids[i] > 0)
|
||||
glsafe(::glDeleteShader(shader_ids[i]));
|
||||
}
|
||||
};
|
||||
|
||||
assert(m_id == 0);
|
||||
|
||||
m_name = name;
|
||||
|
||||
std::array<GLuint, static_cast<size_t>(EShaderType::Count)> shader_ids = { 0 };
|
||||
|
||||
for (size_t i = 0; i < static_cast<size_t>(EShaderType::Count); ++i) {
|
||||
const std::string& source = sources[i];
|
||||
if (!source.empty())
|
||||
{
|
||||
EShaderType type = static_cast<EShaderType>(i);
|
||||
auto [result, id] = create_shader(type);
|
||||
if (result)
|
||||
shader_ids[i] = id;
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << "glCreateShader() failed for " << shader_type_as_string(type) << " shader of shader program '" << name << "'";
|
||||
|
||||
// release shaders
|
||||
release_shaders(shader_ids);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* source_ptr = source.c_str();
|
||||
glsafe(::glShaderSource(id, 1, &source_ptr, nullptr));
|
||||
glsafe(::glCompileShader(id));
|
||||
GLint params;
|
||||
glsafe(::glGetShaderiv(id, GL_COMPILE_STATUS, ¶ms));
|
||||
if (params == GL_FALSE) {
|
||||
// Compilation failed.
|
||||
glsafe(::glGetShaderiv(id, GL_INFO_LOG_LENGTH, ¶ms));
|
||||
std::vector<char> msg(params);
|
||||
glsafe(::glGetShaderInfoLog(id, params, ¶ms, msg.data()));
|
||||
BOOST_LOG_TRIVIAL(error) << "Unable to compile " << shader_type_as_string(type) << " shader of shader program '" << name << "':\n" << msg.data();
|
||||
|
||||
// release shaders
|
||||
release_shaders(shader_ids);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vertex_shader != nullptr) {
|
||||
this->vertex_program_id = ::glCreateShader(GL_VERTEX_SHADER);
|
||||
glcheck();
|
||||
if (this->vertex_program_id == 0) {
|
||||
last_error = "glCreateShader(GL_VERTEX_SHADER) failed.";
|
||||
this->release();
|
||||
return false;
|
||||
}
|
||||
GLint len = (GLint)strlen(vertex_shader);
|
||||
glsafe(::glShaderSource(this->vertex_program_id, 1, &vertex_shader, &len));
|
||||
glsafe(::glCompileShader(this->vertex_program_id));
|
||||
GLint params;
|
||||
glsafe(::glGetShaderiv(this->vertex_program_id, GL_COMPILE_STATUS, ¶ms));
|
||||
if (params == GL_FALSE) {
|
||||
// Compilation failed. Get the log.
|
||||
glsafe(::glGetShaderiv(this->vertex_program_id, GL_INFO_LOG_LENGTH, ¶ms));
|
||||
std::vector<char> msg(params);
|
||||
glsafe(::glGetShaderInfoLog(this->vertex_program_id, params, ¶ms, msg.data()));
|
||||
this->last_error = std::string("Vertex shader compilation failed:\n") + msg.data();
|
||||
this->release();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Link shaders
|
||||
this->shader_program_id = ::glCreateProgram();
|
||||
m_id = ::glCreateProgram();
|
||||
glcheck();
|
||||
if (this->shader_program_id == 0) {
|
||||
last_error = "glCreateProgram() failed.";
|
||||
this->release();
|
||||
if (m_id == 0) {
|
||||
BOOST_LOG_TRIVIAL(error) << "glCreateProgram() failed for shader program '" << name << "'";
|
||||
|
||||
// release shaders
|
||||
release_shaders(shader_ids);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->fragment_program_id)
|
||||
glsafe(::glAttachShader(this->shader_program_id, this->fragment_program_id));
|
||||
if (this->vertex_program_id)
|
||||
glsafe(::glAttachShader(this->shader_program_id, this->vertex_program_id));
|
||||
glsafe(::glLinkProgram(this->shader_program_id));
|
||||
for (size_t i = 0; i < static_cast<size_t>(EShaderType::Count); ++i) {
|
||||
if (shader_ids[i] > 0)
|
||||
glsafe(::glAttachShader(m_id, shader_ids[i]));
|
||||
}
|
||||
|
||||
glsafe(::glLinkProgram(m_id));
|
||||
GLint params;
|
||||
glsafe(::glGetProgramiv(this->shader_program_id, GL_LINK_STATUS, ¶ms));
|
||||
glsafe(::glGetProgramiv(m_id, GL_LINK_STATUS, ¶ms));
|
||||
if (params == GL_FALSE) {
|
||||
// Linking failed. Get the log.
|
||||
glsafe(::glGetProgramiv(this->shader_program_id, GL_INFO_LOG_LENGTH, ¶ms));
|
||||
// Linking failed.
|
||||
glsafe(::glGetProgramiv(m_id, GL_INFO_LOG_LENGTH, ¶ms));
|
||||
std::vector<char> msg(params);
|
||||
glsafe(::glGetProgramInfoLog(this->shader_program_id, params, ¶ms, msg.data()));
|
||||
this->last_error = std::string("Shader linking failed:\n") + msg.data();
|
||||
this->release();
|
||||
glsafe(::glGetProgramInfoLog(m_id, params, ¶ms, msg.data()));
|
||||
BOOST_LOG_TRIVIAL(error) << "Unable to link shader program '" << name << "':\n" << msg.data();
|
||||
|
||||
// release shaders
|
||||
release_shaders(shader_ids);
|
||||
|
||||
// release shader program
|
||||
glsafe(::glDeleteProgram(m_id));
|
||||
m_id = 0;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
last_error.clear();
|
||||
// release shaders, they are no more needed
|
||||
release_shaders(shader_ids);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GLShader::load_from_file(const char* fragment_shader_filename, const char* vertex_shader_filename)
|
||||
void GLShaderProgram::start_using() const
|
||||
{
|
||||
const std::string& path = resources_dir() + "/shaders/";
|
||||
|
||||
boost::nowide::ifstream vs(path + std::string(vertex_shader_filename), boost::nowide::ifstream::binary);
|
||||
if (!vs.good())
|
||||
return false;
|
||||
|
||||
vs.seekg(0, vs.end);
|
||||
int file_length = (int)vs.tellg();
|
||||
vs.seekg(0, vs.beg);
|
||||
std::string vertex_shader(file_length, '\0');
|
||||
vs.read(vertex_shader.data(), file_length);
|
||||
if (!vs.good())
|
||||
return false;
|
||||
|
||||
vs.close();
|
||||
|
||||
boost::nowide::ifstream fs(path + std::string(fragment_shader_filename), boost::nowide::ifstream::binary);
|
||||
if (!fs.good())
|
||||
return false;
|
||||
|
||||
fs.seekg(0, fs.end);
|
||||
file_length = (int)fs.tellg();
|
||||
fs.seekg(0, fs.beg);
|
||||
std::string fragment_shader(file_length, '\0');
|
||||
fs.read(fragment_shader.data(), file_length);
|
||||
if (!fs.good())
|
||||
return false;
|
||||
|
||||
fs.close();
|
||||
|
||||
return load_from_text(fragment_shader.c_str(), vertex_shader.c_str());
|
||||
assert(m_id > 0);
|
||||
glsafe(::glUseProgram(m_id));
|
||||
}
|
||||
|
||||
void GLShader::release()
|
||||
{
|
||||
if (this->shader_program_id) {
|
||||
if (this->vertex_program_id)
|
||||
glsafe(::glDetachShader(this->shader_program_id, this->vertex_program_id));
|
||||
if (this->fragment_program_id)
|
||||
glsafe(::glDetachShader(this->shader_program_id, this->fragment_program_id));
|
||||
glsafe(::glDeleteProgram(this->shader_program_id));
|
||||
this->shader_program_id = 0;
|
||||
}
|
||||
|
||||
if (this->vertex_program_id) {
|
||||
glsafe(::glDeleteShader(this->vertex_program_id));
|
||||
this->vertex_program_id = 0;
|
||||
}
|
||||
if (this->fragment_program_id) {
|
||||
glsafe(::glDeleteShader(this->fragment_program_id));
|
||||
this->fragment_program_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GLShader::enable() const
|
||||
{
|
||||
glsafe(::glUseProgram(this->shader_program_id));
|
||||
}
|
||||
|
||||
void GLShader::disable() const
|
||||
void GLShaderProgram::stop_using() const
|
||||
{
|
||||
glsafe(::glUseProgram(0));
|
||||
}
|
||||
|
||||
// Return shader vertex attribute ID
|
||||
int GLShader::get_attrib_location(const char *name) const
|
||||
{
|
||||
return this->shader_program_id ? glGetAttribLocation(this->shader_program_id, name) : -1;
|
||||
}
|
||||
|
||||
// Return shader uniform variable ID
|
||||
int GLShader::get_uniform_location(const char *name) const
|
||||
{
|
||||
return this->shader_program_id ? glGetUniformLocation(this->shader_program_id, name) : -1;
|
||||
}
|
||||
|
||||
bool GLShader::set_uniform(const char *name, float value) const
|
||||
{
|
||||
int id = this->get_uniform_location(name);
|
||||
if (id >= 0) {
|
||||
glsafe(::glUniform1fARB(id, value));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLShader::set_uniform(const char* name, const float* matrix) const
|
||||
bool GLShaderProgram::set_uniform(const char* name, int value) const
|
||||
{
|
||||
int id = get_uniform_location(name);
|
||||
if (id >= 0)
|
||||
{
|
||||
glsafe(::glUniformMatrix4fv(id, 1, GL_FALSE, (const GLfloat*)matrix));
|
||||
if (id >= 0) {
|
||||
glsafe(::glUniform1i(id, static_cast<GLint>(value)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLShader::set_uniform(const char* name, int value) const
|
||||
bool GLShaderProgram::set_uniform(const char* name, bool value) const
|
||||
{
|
||||
return set_uniform(name, value ? 1 : 0);
|
||||
}
|
||||
|
||||
bool GLShaderProgram::set_uniform(const char* name, float value) const
|
||||
{
|
||||
int id = get_uniform_location(name);
|
||||
if (id >= 0)
|
||||
{
|
||||
glsafe(::glUniform1i(id, value));
|
||||
if (id >= 0) {
|
||||
glsafe(::glUniform1f(id, static_cast<GLfloat>(value)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
# Set shader vector
|
||||
sub SetVector
|
||||
bool GLShaderProgram::set_uniform(const char* name, double value) const
|
||||
{
|
||||
my($self,$var,@values) = @_;
|
||||
|
||||
my $id = $self->Map($var);
|
||||
return 'Unable to map $var' if (!defined($id));
|
||||
|
||||
my $count = scalar(@values);
|
||||
eval('glUniform'.$count.'fARB($id,@values)');
|
||||
|
||||
return '';
|
||||
return set_uniform(name, static_cast<float>(value));
|
||||
}
|
||||
|
||||
# Set shader 4x4 matrix
|
||||
sub SetMatrix
|
||||
bool GLShaderProgram::set_uniform(const char* name, const std::array<int, 2>& value) const
|
||||
{
|
||||
my($self,$var,$oga) = @_;
|
||||
|
||||
my $id = $self->Map($var);
|
||||
return 'Unable to map $var' if (!defined($id));
|
||||
|
||||
glUniformMatrix4fvARB_c($id,1,0,$oga->ptr());
|
||||
return '';
|
||||
}
|
||||
*/
|
||||
|
||||
Shader::Shader()
|
||||
: m_shader(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Shader::~Shader()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
bool Shader::init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename)
|
||||
{
|
||||
if (is_initialized())
|
||||
int id = get_uniform_location(name);
|
||||
if (id >= 0) {
|
||||
glsafe(::glUniform2iv(id, 1, static_cast<const GLint*>(value.data())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
m_shader = new GLShader();
|
||||
if (m_shader != nullptr)
|
||||
{
|
||||
if (!m_shader->load_from_file(fragment_shader_filename.c_str(), vertex_shader_filename.c_str()))
|
||||
{
|
||||
std::cout << "Compilaton of shader failed:" << std::endl;
|
||||
std::cout << m_shader->last_error << std::endl;
|
||||
reset();
|
||||
return false;
|
||||
bool GLShaderProgram::set_uniform(const char* name, const std::array<int, 3>& value) const
|
||||
{
|
||||
int id = get_uniform_location(name);
|
||||
if (id >= 0) {
|
||||
glsafe(::glUniform3iv(id, 1, static_cast<const GLint*>(value.data())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLShaderProgram::set_uniform(const char* name, const std::array<int, 4>& value) const
|
||||
{
|
||||
int id = get_uniform_location(name);
|
||||
if (id >= 0) {
|
||||
glsafe(::glUniform4iv(id, 1, static_cast<const GLint*>(value.data())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLShaderProgram::set_uniform(const char* name, const std::array<float, 2>& value) const
|
||||
{
|
||||
int id = get_uniform_location(name);
|
||||
if (id >= 0) {
|
||||
glsafe(::glUniform2fv(id, 1, static_cast<const GLfloat*>(value.data())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLShaderProgram::set_uniform(const char* name, const std::array<float, 3>& value) const
|
||||
{
|
||||
int id = get_uniform_location(name);
|
||||
if (id >= 0) {
|
||||
glsafe(::glUniform3fv(id, 1, static_cast<const GLfloat*>(value.data())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLShaderProgram::set_uniform(const char* name, const std::array<float, 4>& value) const
|
||||
{
|
||||
int id = get_uniform_location(name);
|
||||
if (id >= 0) {
|
||||
glsafe(::glUniform4fv(id, 1, static_cast<const GLfloat*>(value.data())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLShaderProgram::set_uniform(const char* name, const float* value, size_t size) const
|
||||
{
|
||||
if (size == 1)
|
||||
return set_uniform(name, value[0]);
|
||||
else if (size < 5) {
|
||||
int id = get_uniform_location(name);
|
||||
if (id >= 0) {
|
||||
if (size == 2)
|
||||
glsafe(::glUniform2fv(id, 1, static_cast<const GLfloat*>(value)));
|
||||
else if (size == 3)
|
||||
glsafe(::glUniform3fv(id, 1, static_cast<const GLfloat*>(value)));
|
||||
else
|
||||
glsafe(::glUniform4fv(id, 1, static_cast<const GLfloat*>(value)));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Shader::is_initialized() const
|
||||
bool GLShaderProgram::set_uniform(const char* name, const Transform3f& value) const
|
||||
{
|
||||
return (m_shader != nullptr);
|
||||
}
|
||||
|
||||
bool Shader::start_using() const
|
||||
{
|
||||
if (is_initialized())
|
||||
{
|
||||
m_shader->enable();
|
||||
int id = get_uniform_location(name);
|
||||
if (id >= 0) {
|
||||
glsafe(::glUniformMatrix4fv(id, 1, GL_FALSE, static_cast<const GLfloat*>(value.matrix().data())));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Shader::stop_using() const
|
||||
bool GLShaderProgram::set_uniform(const char* name, const Transform3d& value) const
|
||||
{
|
||||
if (m_shader != nullptr)
|
||||
m_shader->disable();
|
||||
return set_uniform(name, value.cast<float>());
|
||||
}
|
||||
|
||||
int Shader::get_attrib_location(const std::string& name) const
|
||||
bool GLShaderProgram::set_uniform(const char* name, const Matrix3f& value) const
|
||||
{
|
||||
return (m_shader != nullptr) ? m_shader->get_attrib_location(name.c_str()) : -1;
|
||||
}
|
||||
|
||||
int Shader::get_uniform_location(const std::string& name) const
|
||||
{
|
||||
return (m_shader != nullptr) ? m_shader->get_uniform_location(name.c_str()) : -1;
|
||||
}
|
||||
|
||||
void Shader::set_uniform(const std::string& name, float value) const
|
||||
{
|
||||
if (m_shader != nullptr)
|
||||
m_shader->set_uniform(name.c_str(), value);
|
||||
}
|
||||
|
||||
void Shader::set_uniform(const std::string& name, const float* matrix) const
|
||||
{
|
||||
if (m_shader != nullptr)
|
||||
m_shader->set_uniform(name.c_str(), matrix);
|
||||
}
|
||||
|
||||
void Shader::set_uniform(const std::string& name, bool value) const
|
||||
{
|
||||
if (m_shader != nullptr)
|
||||
m_shader->set_uniform(name.c_str(), value ? 1 : 0);
|
||||
}
|
||||
|
||||
unsigned int Shader::get_shader_program_id() const
|
||||
{
|
||||
return (m_shader != nullptr) ? m_shader->shader_program_id : 0;
|
||||
}
|
||||
|
||||
void Shader::reset()
|
||||
{
|
||||
if (m_shader != nullptr)
|
||||
{
|
||||
m_shader->release();
|
||||
delete m_shader;
|
||||
m_shader = nullptr;
|
||||
int id = get_uniform_location(name);
|
||||
if (id >= 0) {
|
||||
glsafe(::glUniformMatrix3fv(id, 1, GL_FALSE, static_cast<const GLfloat*>(value.data())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLShaderProgram::set_uniform(const char* name, const Vec3f& value) const
|
||||
{
|
||||
int id = get_uniform_location(name);
|
||||
if (id >= 0) {
|
||||
glsafe(::glUniform3fv(id, 1, static_cast<const GLfloat*>(value.data())));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLShaderProgram::set_uniform(const char* name, const Vec3d& value) const
|
||||
{
|
||||
return set_uniform(name, static_cast<Vec3f>(value.cast<float>()));
|
||||
}
|
||||
|
||||
int GLShaderProgram::get_attrib_location(const char* name) const
|
||||
{
|
||||
return (m_id > 0) ? ::glGetAttribLocation(m_id, name) : -1;
|
||||
}
|
||||
|
||||
int GLShaderProgram::get_uniform_location(const char* name) const
|
||||
{
|
||||
return (m_id > 0) ? ::glGetUniformLocation(m_id, name) : -1;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -1,71 +1,69 @@
|
|||
#ifndef slic3r_GLShader_hpp_
|
||||
#define slic3r_GLShader_hpp_
|
||||
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#include "libslic3r/Point.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class GLShader
|
||||
class GLShaderProgram
|
||||
{
|
||||
public:
|
||||
GLShader() :
|
||||
fragment_program_id(0),
|
||||
vertex_program_id(0),
|
||||
shader_program_id(0)
|
||||
{}
|
||||
~GLShader();
|
||||
enum class EShaderType
|
||||
{
|
||||
Vertex,
|
||||
Fragment,
|
||||
Geometry,
|
||||
TessEvaluation,
|
||||
TessControl,
|
||||
Compute,
|
||||
Count
|
||||
};
|
||||
|
||||
bool load_from_text(const char *fragment_shader, const char *vertex_shader);
|
||||
bool load_from_file(const char* fragment_shader_filename, const char* vertex_shader_filename);
|
||||
|
||||
void release();
|
||||
|
||||
int get_attrib_location(const char *name) const;
|
||||
int get_uniform_location(const char *name) const;
|
||||
|
||||
bool set_uniform(const char *name, float value) const;
|
||||
bool set_uniform(const char* name, const float* matrix) const;
|
||||
bool set_uniform(const char* name, int value) const;
|
||||
|
||||
void enable() const;
|
||||
void disable() const;
|
||||
|
||||
unsigned int fragment_program_id;
|
||||
unsigned int vertex_program_id;
|
||||
unsigned int shader_program_id;
|
||||
std::string last_error;
|
||||
};
|
||||
|
||||
class Shader
|
||||
{
|
||||
GLShader* m_shader;
|
||||
|
||||
public:
|
||||
Shader();
|
||||
~Shader();
|
||||
|
||||
bool init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename);
|
||||
|
||||
bool is_initialized() const;
|
||||
|
||||
bool start_using() const;
|
||||
void stop_using() const;
|
||||
|
||||
int get_attrib_location(const std::string& name) const;
|
||||
int get_uniform_location(const std::string& name) const;
|
||||
|
||||
void set_uniform(const std::string& name, float value) const;
|
||||
void set_uniform(const std::string& name, const float* matrix) const;
|
||||
void set_uniform(const std::string& name, bool value) const;
|
||||
|
||||
const GLShader* get_shader() const { return m_shader; }
|
||||
unsigned int get_shader_program_id() const;
|
||||
typedef std::array<std::string, static_cast<size_t>(EShaderType::Count)> ShaderFilenames;
|
||||
typedef std::array<std::string, static_cast<size_t>(EShaderType::Count)> ShaderSources;
|
||||
|
||||
private:
|
||||
void reset();
|
||||
std::string m_name;
|
||||
unsigned int m_id{ 0 };
|
||||
|
||||
public:
|
||||
~GLShaderProgram();
|
||||
|
||||
bool init_from_files(const std::string& name, const ShaderFilenames& filenames);
|
||||
bool init_from_texts(const std::string& name, const ShaderSources& sources);
|
||||
|
||||
const std::string& get_name() const { return m_name; }
|
||||
unsigned int get_id() const { return m_id; }
|
||||
|
||||
void start_using() const;
|
||||
void stop_using() const;
|
||||
|
||||
bool set_uniform(const char* name, int value) const;
|
||||
bool set_uniform(const char* name, bool value) const;
|
||||
bool set_uniform(const char* name, float value) const;
|
||||
bool set_uniform(const char* name, double value) const;
|
||||
bool set_uniform(const char* name, const std::array<int, 2>& value) const;
|
||||
bool set_uniform(const char* name, const std::array<int, 3>& value) const;
|
||||
bool set_uniform(const char* name, const std::array<int, 4>& value) const;
|
||||
bool set_uniform(const char* name, const std::array<float, 2>& value) const;
|
||||
bool set_uniform(const char* name, const std::array<float, 3>& value) const;
|
||||
bool set_uniform(const char* name, const std::array<float, 4>& value) const;
|
||||
bool set_uniform(const char* name, const float* value, size_t size) const;
|
||||
bool set_uniform(const char* name, const Transform3f& value) const;
|
||||
bool set_uniform(const char* name, const Transform3d& value) const;
|
||||
bool set_uniform(const char* name, const Matrix3f& value) const;
|
||||
bool set_uniform(const char* name, const Vec3f& value) const;
|
||||
bool set_uniform(const char* name, const Vec3d& value) const;
|
||||
|
||||
// returns -1 if not found
|
||||
int get_attrib_location(const char* name) const;
|
||||
// returns -1 if not found
|
||||
int get_uniform_location(const char* name) const;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_GLShader_hpp_ */
|
||||
|
|
75
src/slic3r/GUI/GLShadersManager.cpp
Normal file
75
src/slic3r/GUI/GLShadersManager.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
#include "libslic3r/libslic3r.h"
|
||||
#include "GLShadersManager.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
std::pair<bool, std::string> GLShadersManager::init()
|
||||
{
|
||||
std::string error;
|
||||
|
||||
auto append_shader = [this, &error](const std::string& name, const GLShaderProgram::ShaderFilenames& filenames) {
|
||||
m_shaders.push_back(std::make_unique<GLShaderProgram>());
|
||||
if (!m_shaders.back()->init_from_files(name, filenames)) {
|
||||
error += name + "\n";
|
||||
// if any error happens while initializating the shader, we remove it from the list
|
||||
m_shaders.pop_back();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
assert(m_shaders.empty());
|
||||
|
||||
bool valid = true;
|
||||
|
||||
// used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells
|
||||
valid &= append_shader("gouraud_light", { "gouraud_light.vs", "gouraud_light.fs" });
|
||||
// used to render printbed
|
||||
valid &= append_shader("printbed", { "printbed.vs", "printbed.fs" });
|
||||
// used to render options in gcode preview
|
||||
valid &= append_shader("options_110", { "options_110.vs", "options_110.fs" });
|
||||
if (GUI::wxGetApp().is_glsl_version_greater_or_equal_to(1, 20))
|
||||
valid &= append_shader("options_120", { "options_120.vs", "options_120.fs" });
|
||||
// used to render extrusion and travel paths as lines in gcode preview
|
||||
valid &= append_shader("toolpaths_lines", { "toolpaths_lines.vs", "toolpaths_lines.fs" });
|
||||
// used to render objects in 3d editor
|
||||
valid &= append_shader("gouraud", { "gouraud.vs", "gouraud.fs" });
|
||||
// used to render variable layers heights in 3d editor
|
||||
valid &= append_shader("variable_layer_height", { "variable_layer_height.vs", "variable_layer_height.fs" });
|
||||
|
||||
return { valid, error };
|
||||
}
|
||||
|
||||
void GLShadersManager::shutdown()
|
||||
{
|
||||
for (std::unique_ptr<GLShaderProgram>& shader : m_shaders) {
|
||||
shader.reset();
|
||||
}
|
||||
}
|
||||
|
||||
GLShaderProgram* GLShadersManager::get_shader(const std::string& shader_name)
|
||||
{
|
||||
auto it = std::find_if(m_shaders.begin(), m_shaders.end(), [shader_name](std::unique_ptr<GLShaderProgram>& p) { return p->get_name() == shader_name; });
|
||||
return (it != m_shaders.end()) ? it->get() : nullptr;
|
||||
}
|
||||
|
||||
GLShaderProgram* GLShadersManager::get_current_shader()
|
||||
{
|
||||
GLint id = 0;
|
||||
glsafe(::glGetIntegerv(GL_CURRENT_PROGRAM, &id));
|
||||
if (id == 0)
|
||||
return nullptr;
|
||||
|
||||
auto it = std::find_if(m_shaders.begin(), m_shaders.end(), [id](std::unique_ptr<GLShaderProgram>& p) { return static_cast<GLint>(p->get_id()) == id; });
|
||||
return (it != m_shaders.end()) ? it->get() : nullptr;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
30
src/slic3r/GUI/GLShadersManager.hpp
Normal file
30
src/slic3r/GUI/GLShadersManager.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef slic3r_GLShadersManager_hpp_
|
||||
#define slic3r_GLShadersManager_hpp_
|
||||
|
||||
#include "GLShader.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class GLShadersManager
|
||||
{
|
||||
std::vector<std::unique_ptr<GLShaderProgram>> m_shaders;
|
||||
|
||||
public:
|
||||
std::pair<bool, std::string> init();
|
||||
// call this method before to release the OpenGL context
|
||||
void shutdown();
|
||||
|
||||
// returns nullptr if not found
|
||||
GLShaderProgram* get_shader(const std::string& shader_name);
|
||||
|
||||
// returns currently active shader, nullptr if none
|
||||
GLShaderProgram* get_current_shader();
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_GLShadersManager_hpp_
|
|
@ -230,24 +230,13 @@ void GLToolbar::set_icons_size(float size)
|
|||
|
||||
void GLToolbar::set_scale(float scale)
|
||||
{
|
||||
if (m_layout.scale != scale)
|
||||
{
|
||||
if (m_layout.scale != scale) {
|
||||
m_layout.scale = scale;
|
||||
m_layout.dirty = true;
|
||||
m_icons_texture_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool GLToolbar::is_enabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
void GLToolbar::set_enabled(bool enable)
|
||||
{
|
||||
m_enabled = enable;//true; etFIXME
|
||||
}
|
||||
|
||||
bool GLToolbar::add_item(const GLToolbarItem::Data& data)
|
||||
{
|
||||
GLToolbarItem* item = new GLToolbarItem(GLToolbarItem::Action, data);
|
||||
|
|
|
@ -276,8 +276,8 @@ public:
|
|||
void set_icons_size(float size);
|
||||
void set_scale(float scale);
|
||||
|
||||
bool is_enabled() const;
|
||||
void set_enabled(bool enable);
|
||||
bool is_enabled() const { return m_enabled; }
|
||||
void set_enabled(bool enable) { m_enabled = enable; }
|
||||
|
||||
bool add_item(const GLToolbarItem::Data& data);
|
||||
bool add_separator();
|
||||
|
|
|
@ -255,7 +255,7 @@ void warning_catcher(wxWindow* parent, const wxString& message)
|
|||
msg.ShowModal();
|
||||
}
|
||||
|
||||
void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string items, bool initial_value)
|
||||
void create_combochecklist(wxComboCtrl* comboCtrl, const std::string& text, const std::string& items)
|
||||
{
|
||||
if (comboCtrl == nullptr)
|
||||
return;
|
||||
|
@ -266,41 +266,59 @@ void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string
|
|||
// On the other side, with this line the combo box popup cannot be closed by clicking on the combo button on Windows 10.
|
||||
comboCtrl->UseAltPopupWindow();
|
||||
|
||||
int max_width = 0;
|
||||
|
||||
// the following line messes up the popup size the first time it is shown on wxWidgets 3.1.3
|
||||
// comboCtrl->EnablePopupAnimation(false);
|
||||
comboCtrl->SetPopupControl(popup);
|
||||
popup->SetStringValue(from_u8(text));
|
||||
popup->Bind(wxEVT_CHECKLISTBOX, [popup](wxCommandEvent& evt) { popup->OnCheckListBox(evt); });
|
||||
popup->Bind(wxEVT_LISTBOX, [popup](wxCommandEvent& evt) { popup->OnListBoxSelection(evt); });
|
||||
wxString title = from_u8(text);
|
||||
max_width = std::max(max_width, 60 + comboCtrl->GetTextExtent(title).x);
|
||||
popup->SetStringValue(title);
|
||||
popup->Bind(wxEVT_CHECKLISTBOX, [popup](wxCommandEvent& evt) { popup->OnCheckListBox(evt); });
|
||||
popup->Bind(wxEVT_LISTBOX, [popup](wxCommandEvent& evt) { popup->OnListBoxSelection(evt); });
|
||||
popup->Bind(wxEVT_KEY_DOWN, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); });
|
||||
popup->Bind(wxEVT_KEY_UP, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); });
|
||||
|
||||
std::vector<std::string> items_str;
|
||||
boost::split(items_str, items, boost::is_any_of("|"), boost::token_compress_off);
|
||||
|
||||
for (const std::string& item : items_str) {
|
||||
popup->Append(from_u8(item));
|
||||
}
|
||||
// each item must be composed by 2 parts
|
||||
assert(items_str.size() %2 == 0);
|
||||
|
||||
for (unsigned int i = 0; i < popup->GetCount(); ++i) {
|
||||
popup->Check(i, initial_value);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < items_str.size(); i += 2) {
|
||||
wxString label = from_u8(items_str[i]);
|
||||
max_width = std::max(max_width, 60 + popup->GetTextExtent(label).x);
|
||||
popup->Append(label);
|
||||
popup->Check(i / 2, items_str[i + 1] == "1");
|
||||
}
|
||||
|
||||
comboCtrl->SetMinClientSize(wxSize(max_width, -1));
|
||||
}
|
||||
}
|
||||
|
||||
int combochecklist_get_flags(wxComboCtrl* comboCtrl)
|
||||
unsigned int combochecklist_get_flags(wxComboCtrl* comboCtrl)
|
||||
{
|
||||
int flags = 0;
|
||||
unsigned int flags = 0;
|
||||
|
||||
wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup);
|
||||
if (popup != nullptr) {
|
||||
for (unsigned int i = 0; i < popup->GetCount(); ++i) {
|
||||
if (popup->IsChecked(i))
|
||||
flags |= 1 << i;
|
||||
}
|
||||
}
|
||||
wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup);
|
||||
if (popup != nullptr) {
|
||||
for (unsigned int i = 0; i < popup->GetCount(); ++i) {
|
||||
if (popup->IsChecked(i))
|
||||
flags |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
return flags;
|
||||
return flags;
|
||||
}
|
||||
|
||||
void combochecklist_set_flags(wxComboCtrl* comboCtrl, unsigned int flags)
|
||||
{
|
||||
wxCheckListBoxComboPopup* popup = wxDynamicCast(comboCtrl->GetPopupControl(), wxCheckListBoxComboPopup);
|
||||
if (popup != nullptr) {
|
||||
for (unsigned int i = 0; i < popup->GetCount(); ++i) {
|
||||
popup->Check(i, (flags & (1 << i)) != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AppConfig* get_app_config()
|
||||
|
|
|
@ -49,13 +49,17 @@ inline void show_info(wxWindow* parent, const std::string& message,const std::st
|
|||
void warning_catcher(wxWindow* parent, const wxString& message);
|
||||
|
||||
// Creates a wxCheckListBoxComboPopup inside the given wxComboCtrl, filled with the given text and items.
|
||||
// Items are all initialized to the given value.
|
||||
// Items must be separated by '|', for example "Item1|Item2|Item3", and so on.
|
||||
void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string items, bool initial_value);
|
||||
// Items data must be separated by '|', and contain the item name to be shown followed by its initial value (0 for false, 1 for true).
|
||||
// For example "Item1|0|Item2|1|Item3|0", and so on.
|
||||
void create_combochecklist(wxComboCtrl* comboCtrl, const std::string& text, const std::string& items);
|
||||
|
||||
// Returns the current state of the items listed in the wxCheckListBoxComboPopup contained in the given wxComboCtrl,
|
||||
// encoded inside an int.
|
||||
int combochecklist_get_flags(wxComboCtrl* comboCtrl);
|
||||
// encoded inside an unsigned int.
|
||||
unsigned int combochecklist_get_flags(wxComboCtrl* comboCtrl);
|
||||
|
||||
// Sets the current state of the items listed in the wxCheckListBoxComboPopup contained in the given wxComboCtrl,
|
||||
// with the flags encoded in the given unsigned int.
|
||||
void combochecklist_set_flags(wxComboCtrl* comboCtrl, unsigned int flags);
|
||||
|
||||
// wxString conversions:
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue