diff --git a/.gitignore b/.gitignore index d56825aca..efeaa91b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ Build Build.bat +/build/ MYMETA.json MYMETA.yml _build @@ -11,3 +12,5 @@ xs/MANIFEST.bak xs/assertlib* .init_bundle.ini local-lib +/src/TAGS +/.vscode/ diff --git a/CMakeLists.txt b/CMakeLists.txt index b8b9add60..268380dc2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -389,10 +389,13 @@ find_package(CURL REQUIRED) add_library(libcurl INTERFACE) target_link_libraries(libcurl INTERFACE CURL::libcurl) +# Fixing curl's cmake config script bugs if (NOT WIN32) # Required by libcurl find_package(ZLIB REQUIRED) target_link_libraries(libcurl INTERFACE ZLIB::ZLIB) +else() + target_link_libraries(libcurl INTERFACE crypt32) endif() if (SLIC3R_STATIC) diff --git a/build_win.bat b/build_win.bat index dac590811..600d6d6e6 100644 --- a/build_win.bat +++ b/build_win.bat @@ -2,67 +2,79 @@ @IF "%PS_ECHO_ON%" NEQ "" (echo on) ELSE (echo off) @GOTO :MAIN :HELP +@ECHO. @ECHO Performs initial build or rebuild of the app (build) and deps (build/deps). @ECHO Default options are determined from build directories and system state. @ECHO. @ECHO Usage: build_win [-ARCH ^] [-CONFIG ^] [-DESTDIR ^] @ECHO [-STEPS ^] +@ECHO [-RUN ^] @ECHO. -@ECHO -a -ARCH Target processor architecture -@ECHO Default: %PS_ARCH_HOST% -@ECHO -c -CONFIG MSVC project config -@ECHO Default: %PS_CONFIG_DEFAULT% -@ECHO -s -STEPS Performs only the specified build steps: -@ECHO all - clean and build deps and app -@ECHO all-dirty - build deps and app without cleaning -@ECHO app - build main project/application -@ECHO app-dirty - does not build main project/application -@ECHO deps - clean and build deps -@ECHO deps-dirty - build deps without cleaning -@ECHO Default: %PS_STEPS_DEFAULT% -@ECHO -d -DESTDIR Deps destination directory (ignored on dirty builds) -@ECHO %PS_DESTDIR_DEFAULT_MSG% +@ECHO -a -ARCH Target processor architecture +@ECHO Default: %PS_ARCH_HOST% +@ECHO -c -CONFIG MSVC project config +@ECHO Default: %PS_CONFIG_DEFAULT% +@ECHO -s -STEPS Performs only the specified build steps: +@ECHO all - clean and build deps and app +@ECHO all-dirty - build deps and app without cleaning +@ECHO app - clean and build main applications +@ECHO app-dirty - build main applications without cleaning +@ECHO deps - clean and build deps +@ECHO deps-dirty - build deps without cleaning +@ECHO Default: %PS_STEPS_DEFAULT% +@ECHO -r -RUN Specifies what to perform at the run step: +@ECHO console - run and wait on prusa-slicer-console.exe +@ECHO custom - run and wait on your custom build/%PS_CUSTOM_RUN_FILE% +@ECHO ide - open project in Visual Studio if not open (no wait) +@ECHO none - run step does nothing +@ECHO viewer - run prusa-gcodeviewer.exe (no wait) +@ECHO window - run prusa-slicer.exe (no wait) +@ECHO Default: none +@ECHO -d -DESTDIR Deps destination directory +@ECHO Warning: Changing destdir path will not delete the old destdir. +@ECHO Default: %PS_DESTDIR_DEFAULT_MSG% @ECHO. -@ECHO Example usage: -@ECHO First build: build_win -d "c:\src\PrusaSlicer-deps" -@ECHO Deps change: build_win -s all -@ECHO App rebuild: build_win +@ECHO Examples: +@ECHO. +@ECHO Initial build: build_win -d "c:\src\PrusaSlicer-deps" +@ECHO Build post deps change: build_win -s all +@ECHO App dirty build: build_win +@ECHO App dirty build ^& run: build_win -r console +@ECHO All clean build ^& run: build_win -s all -r console -d "deps\build\out_deps" @ECHO. GOTO :END :MAIN +REM Script constants SET START_TIME=%TIME% SET PS_START_DIR=%CD% +SET PS_SOLUTION_NAME=PrusaSlicer +SET PS_CHOICE_TIMEOUT=30 +SET PS_CUSTOM_RUN_FILE=custom_run.bat +SET PS_DEPS_PATH_FILE_NAME=.DEPS_PATH.txt +SET PS_DEPS_PATH_FILE=%~dp0deps\build\%PS_DEPS_PATH_FILE_NAME% +SET PS_CONFIG_LIST="Debug;MinSizeRel;Release;RelWithDebInfo" + +REM Probe build directories and system state for reasonable default arguments pushd %~dp0 -REM Probe build directories and sytem state for reasonable default arguments SET PS_CONFIG=RelWithDebInfo -SET PS_ARCH=%PROCESSOR_ARCHITECTURE% +SET PS_ARCH=%PROCESSOR_ARCHITECTURE:amd64=x64% CALL :TOLOWER PS_ARCH -SET PS_DEPS_PATH_FILE=%~dp0deps\build\.DEPS_PATH.txt +SET PS_RUN=none SET PS_DESTDIR= -IF EXIST %PS_DEPS_PATH_FILE% ( - FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE%") DO SET PS_DESTDIR=%%I - IF EXIST build/ALL_BUILD.vcxproj ( - SET PS_STEPS=app-dirty - ) ELSE SET PS_STEPS=app -) ELSE SET PS_STEPS=all -SET PS_DESTDIR_CACHED=%PS_DESTDIR% +CALL :RESOLVE_DESTDIR_CACHE REM Set up parameters used by help menu SET PS_CONFIG_DEFAULT=%PS_CONFIG% SET PS_ARCH_HOST=%PS_ARCH% -SET PS_STEPS_DEFAULT=%PS_STEPS% -IF "%PS_DESTDIR%" NEQ "" ( - SET PS_DESTDIR_DEFAULT_MSG=Default: %PS_DESTDIR% -) ELSE ( - SET PS_DESTDIR_DEFAULT_MSG=Argument required ^(no default available^) -) +(echo " -help /help -h /h -? /? ")| findstr /I /C:" %~1 ">nul && GOTO :HELP REM Parse arguments SET EXIT_STATUS=1 +SET PS_CURRENT_STEP=arguments SET PARSER_STATE= SET PARSER_FAIL= -FOR %%I in (%*) DO CALL :PARSE_OPTION "ARCH CONFIG DESTDIR STEPS" PARSER_STATE "%%~I" +FOR %%I in (%*) DO CALL :PARSE_OPTION "ARCH CONFIG DESTDIR STEPS RUN" PARSER_STATE "%%~I" IF "%PARSER_FAIL%" NEQ "" ( @ECHO ERROR: Invalid switch: %PARSER_FAIL% 1>&2 GOTO :HELP @@ -72,46 +84,71 @@ IF "%PARSER_FAIL%" NEQ "" ( ) REM Validate arguments -SET PS_STEPS_SAVED=%PS_STEPS% -CALL :PARSE_OPTION_NAME "all all-dirty deps-dirty deps app-dirty app" PS_STEPS -%PS_STEPS% -IF "%PS_STEPS%" EQU "" ( - @ECHO ERROR: Invalid parameter: steps=%PS_STEPS_SAVED% 1>&2 - GOTO :HELP -) ELSE SET PS_STEPS_SAVED= -(echo %PS_STEPS%)| findstr /I /C:"dirty">nul && SET PS_STEPS_DIRTY=1 -CALL :TOLOWER PS_STEPS +SET PS_ASK_TO_CONTINUE= CALL :TOLOWER PS_ARCH -CALL :CANONICALIZE_PATH PS_DESTDIR "%PS_START_DIR%" +SET PS_ARCH=%PS_ARCH:amd64=x64% +CALL :PARSE_OPTION_VALUE %PS_CONFIG_LIST:;= % PS_CONFIG +IF "%PS_CONFIG%" EQU "" GOTO :HELP +REM RESOLVE_DESTDIR_CACHE must go after PS_ARCH and PS_CONFIG, but before PS STEPS +CALL :RESOLVE_DESTDIR_CACHE +IF "%PS_STEPS%" EQU "" SET PS_STEPS=%PS_STEPS_DEFAULT% +CALL :PARSE_OPTION_VALUE "all all-dirty deps-dirty deps app-dirty app app-cmake" PS_STEPS +IF "%PS_STEPS%" EQU "" GOTO :HELP +(echo %PS_STEPS%)| findstr /I /C:"dirty">nul && SET PS_STEPS_DIRTY=1 || SET PS_STEPS_DIRTY= +IF "%PS_STEPS%" EQU "app-cmake" SET PS_STEPS_DIRTY=1 +IF "%PS_DESTDIR%" EQU "" SET PS_DESTDIR=%PS_DESTDIR_CACHED% IF "%PS_DESTDIR%" EQU "" ( - IF "%PS_STEPS_DIRTY%" EQU "" ( - @ECHO ERROR: Parameter required: destdir 1>&2 - GOTO :HELP - ) -) ELSE IF "%PS_DESTDIR%" NEQ "%PS_DESTDIR_CACHED%" ( - IF "%PS_STEPS_DIRTY%" NEQ "" ( - @ECHO WARNING: Parameter ignored: destdir - ) ELSE (echo "all deps")| findstr /I /C:"%PS_STEPS%">nul || ( - @ECHO WARNING: Conflict with cached parameter: 1>&2 - @ECHO WARNING: -destdir=%PS_DESTDIR% 1>&2 - @ECHO WARNING: cached=%PS_DESTDIR_CACHED% 1>&2 + @ECHO ERROR: Parameter required: -DESTDIR 1>&2 + GOTO :HELP +) +CALL :CANONICALIZE_PATH PS_DESTDIR "%PS_START_DIR%" +IF "%PS_DESTDIR%" NEQ "%PS_DESTDIR_CACHED%" ( + (echo "all deps all-dirty deps-dirty")| findstr /I /C:"%PS_STEPS%">nul || ( + IF EXIST "%PS_DESTDIR%" ( + @ECHO WARNING: DESTDIR does not match cache: 1>&2 + @ECHO WARNING: new: %PS_DESTDIR% 1>&2 + @ECHO WARNING: old: %PS_DESTDIR_CACHED% 1>&2 + SET PS_ASK_TO_CONTINUE=1 + ) ELSE ( + @ECHO ERROR: Invalid parameter: DESTDIR=%PS_DESTDIR% 1>&2 + GOTO :HELP + ) ) ) SET PS_DESTDIR_DEFAULT_MSG= +CALL :PARSE_OPTION_VALUE "console custom ide none viewer window" PS_RUN +IF "%PS_RUN%" EQU "" GOTO :HELP +IF "%PS_RUN%" NEQ "none" IF "%PS_STEPS:~0,4%" EQU "deps" ( + @ECHO ERROR: RUN=%PS_RUN% specified with STEPS=%PS_STEPS% + @ECHO ERROR: RUN=none is the only valid option for STEPS "deps" or "deps-dirty" + GOTO :HELP +) +REM Give the user a chance to cancel if we found something odd. +IF "%PS_ASK_TO_CONTINUE%" EQU "" GOTO :BUILD_ENV +@ECHO. +@ECHO Unexpected parameters detected. Build paused for %PS_CHOICE_TIMEOUT% seconds. +choice /T %PS_CHOICE_TIMEOUT% /C YN /D N /M "Continue" +IF %ERRORLEVEL% NEQ 1 GOTO :HELP REM Set up MSVC environment +:BUILD_ENV SET EXIT_STATUS=2 +SET PS_CURRENT_STEP=environment @ECHO ********************************************************************** @ECHO ** Build Config: %PS_CONFIG% @ECHO ** Target Arch: %PS_ARCH% @ECHO ** Build Steps: %PS_STEPS% +@ECHO ** Run App: %PS_RUN% @ECHO ** Deps path: %PS_DESTDIR% @ECHO ** Using Microsoft Visual Studio installation found at: -SET VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -IF NOT EXIST %VSWHERE% SET VSWHERE="%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe" -FOR /F "tokens=* USEBACKQ" %%I IN (`%VSWHERE% -nologo -property installationPath`) DO SET MSVC_DIR=%%I +SET VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe +IF NOT EXIST "%VSWHERE%" SET VSWHERE=%ProgramFiles%\Microsoft Visual Studio\Installer\vswhere.exe +FOR /F "tokens=* USEBACKQ" %%I IN (`"%VSWHERE%" -nologo -property installationPath`) DO SET MSVC_DIR=%%I @ECHO ** %MSVC_DIR% CALL "%MSVC_DIR%\Common7\Tools\vsdevcmd.bat" -arch=%PS_ARCH% -host_arch=%PS_ARCH_HOST% -app_platform=Desktop -IF "%ERRORLEVEL%" NEQ "0" GOTO :END +IF %ERRORLEVEL% NEQ 0 GOTO :END +REM Need to reset the echo state after vsdevcmd.bat clobbers it. +@IF "%PS_ECHO_ON%" NEQ "" (echo on) ELSE (echo off) IF "%PS_DRY_RUN_ONLY%" NEQ "" ( @ECHO Script terminated early because PS_DRY_RUN_ONLY is set. 1>&2 GOTO :END @@ -121,36 +158,132 @@ IF /I "%PS_STEPS:~0,3%" EQU "app" GOTO :BUILD_APP REM Build deps :BUILD_DEPS SET EXIT_STATUS=3 -IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY deps\build +SET PS_CURRENT_STEP=deps +IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY deps\build "%PS_DEPS_PATH_FILE_NAME%" cd deps\build || GOTO :END -IF "%PS_STEPS_DIRTY%" EQU "" cmake.exe .. -DDESTDIR="%PS_DESTDIR%" || GOTO :END +cmake.exe .. -DDESTDIR="%PS_DESTDIR%" || GOTO :END (echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE%" msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% || GOTO :END cd ..\.. -IF /I "%PS_STEPS:~0,4%" EQU "deps" GOTO :PROLOGUE +IF /I "%PS_STEPS:~0,4%" EQU "deps" GOTO :RUN_APP REM Build app :BUILD_APP SET EXIT_STATUS=4 -IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY build +SET PS_CURRENT_STEP=app +IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY build "%PS_CUSTOM_RUN_FILE%" cd build || GOTO :END -IF "%PS_STEPS_DIRTY%" EQU "" cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" || GOTO :END -msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% || GOTO :END +REM Make sure we have a custom batch file skeleton for the run stage +set PS_CUSTOM_BAT=%PS_CUSTOM_RUN_FILE% +CALL :CANONICALIZE_PATH PS_CUSTOM_BAT +IF NOT EXIST %PS_CUSTOM_BAT% CALL :WRITE_CUSTOM_SCRIPT_SKELETON %PS_CUSTOM_BAT% +SET PS_PROJECT_IS_OPEN= +FOR /F "tokens=2 delims=," %%I in ( + 'tasklist /V /FI "IMAGENAME eq devenv.exe " /NH /FO CSV ^| find "%PS_SOLUTION_NAME%"' +) do SET PS_PROJECT_IS_OPEN=%%~I +cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST% || GOTO :END +REM Skip the build step if we're using the undocumented app-cmake to regenerate the full config from inside devenv +IF "%PS_STEPS%" NEQ "app-cmake" msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% || GOTO :END +(echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE_FOR_CONFIG%" + +REM Run app +:RUN_APP +REM All build steps complete. +CALL :DIFF_TIME ELAPSED_TIME %START_TIME% %TIME% +IF "%PS_CURRENT_STEP%" NEQ "arguments" ( + @ECHO. + @ECHO Total Build Time Elapsed %ELAPSED_TIME% +) +SET EXIT_STATUS=5 +SET PS_CURRENT_STEP=run +cd src\%PS_CONFIG% || GOTO :END +IF "%PS_RUN%" EQU "none" GOTO :PROLOGUE +SET PS_PROJECT_IS_OPEN= +FOR /F "tokens=2 delims=," %%I in ( + 'tasklist /V /FI "IMAGENAME eq devenv.exe " /NH /FO CSV ^| find "%PS_SOLUTION_NAME%"' +) do SET PS_PROJECT_IS_OPEN=%%~I +@ECHO. +@ECHO Running %PS_RUN% application... +@REM icacls below is just a hack for file-not-found error handling +IF "%PS_RUN%" EQU "console" ( + icacls prusa-slicer-console.exe >nul || GOTO :END + start /wait /b prusa-slicer-console.exe +) ELSE IF "%PS_RUN%" EQU "window" ( + icacls prusa-slicer.exe >nul || GOTO :END + start prusa-slicer.exe +) ELSE IF "%PS_RUN%" EQU "viewer" ( + icacls prusa-gcodeviewer.exe >nul || GOTO :END + start prusa-gcodeviewer.exe +) ELSE IF "%PS_RUN%" EQU "custom" ( + icacls %PS_CUSTOM_BAT% >nul || GOTO :END + CALL %PS_CUSTOM_BAT% +) ELSE IF "%PS_RUN%" EQU "ide" ( + IF "%PS_PROJECT_IS_OPEN%" NEQ "" ( + @ECHO WARNING: Solution is already open in Visual Studio. Skipping ide run step. 1>&2 + ) ELSE ( + @ECHO Preparing to run Visual Studio... + cd ..\.. || GOTO :END + REM This hack generates a single config for MSVS, guaranteeing it gets set as the active config. + cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG% > nul 2> nul || GOTO :END + REM Now launch devenv with the single config (setting it active) and a /command switch to re-run cmake and generate the full config list + start devenv.exe %PS_SOLUTION_NAME%.sln /command ^"shell /o ^^^"%~f0^^^" -d ^^^"%PS_DESTDIR%^^^" -c %PS_CONFIG% -a %PS_ARCH% -r none -s app-cmake^" + REM If devenv fails to launch just directly regenerate the full config list. + IF %ERRORLEVEL% NEQ 0 ( + cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST% 2> nul 1> nul || GOTO :END + ) + ) +) + +@REM ********** DON'T ADD ANY CODE BETWEEN THESE TWO SECTIONS ********** +@REM RUN_APP may hand off control, so let exit codes fall through to PROLOGUE. :PROLOGUE SET EXIT_STATUS=%ERRORLEVEL% :END @IF "%PS_ECHO_ON%%PS_DRY_RUN_ONLY%" NEQ "" ( - @ECHO Script Parameters: + @ECHO ********************************************************************** + @ECHO ** Script Parameters: + @ECHO ********************************************************************** @SET PS_ ) -@ECHO Script started at %START_TIME% and completed at %TIME%. +IF "%EXIT_STATUS%" NEQ "0" ( + IF "%PS_CURRENT_STEP%" NEQ "arguments" ( + @ECHO. + @ECHO ERROR: *** Build process failed at %PS_CURRENT_STEP% step. *** 1>&2 + ) +) ELSE ( + @ECHO All steps completed successfully. +) popd exit /B %EXIT_STATUS% GOTO :EOF REM Functions and stubs start here. +:RESOLVE_DESTDIR_CACHE +@REM Resolves all DESTDIR cache values and sets PS_STEPS_DEFAULT +@REM Note: This just sets global variableq, so it doesn't use setlocal. +SET PS_DEPS_PATH_FILE_FOR_CONFIG=%~dp0build\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME% +CALL :CANONICALIZE_PATH PS_DEPS_PATH_FILE_FOR_CONFIG +IF EXIST "%PS_DEPS_PATH_FILE_FOR_CONFIG%" ( + FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE_FOR_CONFIG%") DO ( + SET PS_DESTDIR_CACHED=%%I + SET PS_DESTDIR_DEFAULT_MSG=%%I + ) + SET PS_STEPS_DEFAULT=app-dirty +) ELSE IF EXIST "%PS_DEPS_PATH_FILE%" ( + FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE%") DO ( + SET PS_DESTDIR_CACHED=%%I + SET PS_DESTDIR_DEFAULT_MSG=%%I + ) + SET PS_STEPS_DEFAULT=app +) ELSE ( + SET PS_DESTDIR_CACHED= + SET PS_DESTDIR_DEFAULT_MSG=Cache missing. Argument required. + SET PS_STEPS_DEFAULT=all +) +GOTO :EOF + :PARSE_OPTION @REM Argument parser called for each argument @REM %1 - Valid option list @@ -179,12 +312,27 @@ IF "%LAST_ARG%%ARG_TYPE%" EQU "NAME" SET PARSER_FAIL=%~3 ) GOTO :EOF +:PARSE_OPTION_VALUE +setlocal disableDelayedExpansion +@REM Parses value and verifies it is within the supplied list +@REM %1 - Valid option list +@REM %2 - In/out variable name; unset on error +CALL SET NAME=%~2 +CALL SET SAVED_VALUE=%%%NAME%%% +CALL :PARSE_OPTION_NAME %1 %NAME% -%SAVED_VALUE% +CALL SET NEW_VALUE=%%%NAME%%% +IF "%NEW_VALUE%" EQU "" ( + @ECHO ERROR: Invalid parameter: %NAME:~3%=%SAVED_VALUE% 1>&2 +) +endlocal & SET %NAME%=%NEW_VALUE% +GOTO :EOF + :PARSE_OPTION_NAME @REM Parses an option name @REM %1 - Valid option list @REM %2 - Out variable name; unset on error @REM %3 - Current argument value -@REM $4 - Boolean indicating single character switches are valid +@REM %4 - Boolean indicating single character switches are valid @REM Note: Delayed expansion safe because ! character is invalid in option name setlocal enableDelayedExpansion IF "%4" NEQ "" FOR %%I IN (%~1) DO @( @@ -201,6 +349,7 @@ IF "%4" NEQ "" ( ) @(echo %OPTION_NAME%)| findstr /R /C:".[ ][ ]*.">nul && GOTO :PARSE_OPTION_NAME_FAIL @(echo %~1 )| findstr /I /C:" %OPTION_NAME% ">nul || GOTO :PARSE_OPTION_NAME_FAIL +FOR %%I IN (%~1) DO SET OPTION_NAME=!OPTION_NAME:%%~I=%%~I! endlocal & SET %~2=%OPTION_NAME% GOTO :EOF :PARSE_OPTION_NAME_FAIL @@ -210,14 +359,28 @@ GOTO :EOF :MAKE_OR_CLEAN_DIRECTORY @REM Create directory if it doesn't exist or clean it if it does @REM %1 - Directory path to clean or create +@REM %* - Optional list of files/dirs to keep (in the base directory only) setlocal disableDelayedExpansion IF NOT EXIST "%~1" ( - ECHO Creating %~1 - mkdir "%~1" && GOTO :EOF + @ECHO Creating %~1 + mkdir "%~1" && ( + endlocal + GOTO :EOF + ) +) +@ECHO Cleaning %~1 ... +SET KEEP_LIST= +:MAKE_OR_CLEAN_DIRECTORY_ARG_LOOP +IF "%~2" NEQ "" ( + SET KEEP_LIST=%KEEP_LIST% "%~2" + SHIFT /2 + GOTO :MAKE_OR_CLEAN_DIRECTORY_ARG_LOOP ) -ECHO Cleaning %~1 ... for /F "usebackq delims=" %%I in (`dir /a /b "%~1"`) do ( - (rmdir /s /q "%~1\%%I" 2>nul ) || del /q /f "%~1\%%I") + (echo %KEEP_LIST%)| findstr /I /L /C:"\"%%I\"">nul || ( + rmdir /s /q "%~1\%%I" 2>nul ) || del /q /f "%~1\%%I" +) +endlocal GOTO :EOF :TOLOWER @@ -239,7 +402,51 @@ CALL :CANONICALIZE_PATH_INNER %1 %%%~1%% %2 endlocal & SET %~1=%OUTPUT% GOTO :EOF :CANONICALIZE_PATH_INNER -if "%~3" NEQ "" (pushd %~3 || GOTO :EOF) +if "%~3" NEQ "" (pushd %3 || GOTO :EOF) SET OUTPUT=%~f2 -if "%~3" NEQ "" popd %~3 +if "%~3" NEQ "" popd +GOTO :EOF + +:DIFF_TIME +@REM Calculates elapsed time between two timestamps (TIME environment variable format) +@REM %1 - Output variable +@REM %2 - Start time +@REM %3 - End time +setlocal EnableDelayedExpansion +set START_ARG=%2 +set END_ARG=%3 +set END=!END_ARG:%TIME:~8,1%=%%100)*100+1! +set START=!START_ARG:%TIME:~8,1%=%%100)*100+1! +set /A DIFF=((((10!END:%TIME:~2,1%=%%100)*60+1!%%100)-((((10!START:%TIME:~2,1%=%%100)*60+1!%%100), DIFF-=(DIFF^>^>31)*24*60*60*100 +set /A CC=DIFF%%100+100,DIFF/=100,SS=DIFF%%60+100,DIFF/=60,MM=DIFF%%60+100,HH=DIFF/60+100 +@endlocal & set %1=%HH:~1%%TIME:~2,1%%MM:~1%%TIME:~2,1%%SS:~1%%TIME:~8,1%%CC:~1% +@GOTO :EOF + +:WRITE_CUSTOM_SCRIPT_SKELETON +@REM Writes the following text to the supplied file +@REM %1 - Output filename +setlocal +@( +ECHO @ECHO. +ECHO @ECHO ******************************************************************************** +ECHO @ECHO ** This is a custom run script skeleton. +ECHO @ECHO ******************************************************************************** +ECHO @ECHO. +ECHO @ECHO ******************************************************************************** +ECHO @ECHO ** The working directory is: +ECHO @ECHO ******************************************************************************** +ECHO dir +ECHO @ECHO. +ECHO @ECHO ******************************************************************************** +ECHO @ECHO ** The environment is: +ECHO @ECHO ******************************************************************************** +ECHO set +ECHO @ECHO. +ECHO @ECHO ******************************************************************************** +ECHO @ECHO ** Edit or replace this script to run custom steps after a successful build: +ECHO @ECHO ** %~1 +ECHO @ECHO ******************************************************************************** +ECHO @ECHO. +) > "%~1" +endlocal GOTO :EOF diff --git a/cmake/modules/FindOpenVDB.cmake b/cmake/modules/FindOpenVDB.cmake index 3b60ac9d3..4fde5fa4a 100644 --- a/cmake/modules/FindOpenVDB.cmake +++ b/cmake/modules/FindOpenVDB.cmake @@ -347,7 +347,7 @@ macro(just_fail msg) return() endmacro() -find_package(IlmBase QUIET COMPONENTS Half) +find_package(IlmBase QUIET) if(NOT IlmBase_FOUND) pkg_check_modules(IlmBase QUIET IlmBase) endif() diff --git a/deps/Blosc/Blosc.cmake b/deps/Blosc/Blosc.cmake new file mode 100644 index 000000000..45c45c7c9 --- /dev/null +++ b/deps/Blosc/Blosc.cmake @@ -0,0 +1,28 @@ +if(BUILD_SHARED_LIBS) + set(_build_shared ON) + set(_build_static OFF) +else() + set(_build_shared OFF) + set(_build_static ON) +endif() + +prusaslicer_add_cmake_project(Blosc + #URL https://github.com/Blosc/c-blosc/archive/refs/tags/v1.17.0.zip + #URL_HASH SHA256=7463a1df566704f212263312717ab2c36b45d45cba6cd0dccebf91b2cc4b4da9 + URL https://github.com/tamasmeszaros/c-blosc/archive/refs/heads/v1.17.0_tm.zip + URL_HASH SHA256=dcb48bf43a672fa3de6a4b1de2c4c238709dad5893d1e097b8374ad84b1fc3b3 + DEPENDS ${ZLIB_PKG} + # Patching upstream does not work this way with git version 2.28 installed on mac worker + # PATCH_COMMAND ${GIT_EXECUTABLE} apply --ignore-space-change --whitespace=fix ${CMAKE_CURRENT_LIST_DIR}/blosc-mods.patch + CMAKE_ARGS + -DCMAKE_POSITION_INDEPENDENT_CODE=ON + -DBUILD_SHARED=${_build_shared} + -DBUILD_STATIC=${_build_static} + -DBUILD_TESTS=OFF + -DBUILD_BENCHMARKS=OFF + -DPREFER_EXTERNAL_ZLIB=ON +) + +if (MSVC) + add_debug_dep(dep_Blosc) +endif () \ No newline at end of file diff --git a/deps/blosc-mods.patch b/deps/Blosc/blosc-mods.patch similarity index 100% rename from deps/blosc-mods.patch rename to deps/Blosc/blosc-mods.patch diff --git a/deps/Boost/Boost.cmake b/deps/Boost/Boost.cmake new file mode 100644 index 000000000..ae2bd9646 --- /dev/null +++ b/deps/Boost/Boost.cmake @@ -0,0 +1,150 @@ +include(ExternalProject) + +if (WIN32) + set(_bootstrap_cmd bootstrap.bat) + set(_build_cmd b2.exe) +else() + set(_bootstrap_cmd ./bootstrap.sh) + set(_build_cmd ./b2) +endif() + +set(_patch_command ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_DIR}/common.jam ./tools/build/src/tools/common.jam) + +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + configure_file(${CMAKE_CURRENT_LIST_DIR}/user-config.jam boost-user-config.jam) + set(_boost_toolset gcc) + set(_patch_command ${_patch_command} && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/boost-user-config.jam ./tools/build/src/tools/user-config.jam) +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + # https://cmake.org/cmake/help/latest/variable/MSVC_VERSION.html + if (MSVC_VERSION EQUAL 1800) + # 1800 = VS 12.0 (v120 toolset) + set(_boost_toolset "msvc-12.0") + elseif (MSVC_VERSION EQUAL 1900) + # 1900 = VS 14.0 (v140 toolset) + set(_boost_toolset "msvc-14.0") + elseif (MSVC_VERSION LESS 1920) + # 1910-1919 = VS 15.0 (v141 toolset) + set(_boost_toolset "msvc-14.1") + elseif (MSVC_VERSION LESS 1930) + # 1920-1929 = VS 16.0 (v142 toolset) + set(_boost_toolset "msvc-14.2") + else () + message(FATAL_ERROR "Unsupported MSVC version") + endif () +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if (WIN32) + set(_boost_toolset "clang-win") + else() + set(_boost_toolset "clang") + endif() +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + set(_boost_toolset "intel") +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + set(_boost_toolset "clang") +endif() + +message(STATUS "Deduced boost toolset: ${_boost_toolset} based on ${CMAKE_CXX_COMPILER_ID} compiler") + +set(_libs "") +foreach(_comp ${DEP_Boost_COMPONENTS}) + list(APPEND _libs "--with-${_comp}") +endforeach() + +if (BUILD_SHARED_LIBS) + set(_link shared) +else() + set(_link static) +endif() + +set(_bits "") +if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + set(_bits 64) +elseif ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") + set(_bits 32) +endif () + +include(ProcessorCount) +ProcessorCount(NPROC) +file(TO_NATIVE_PATH ${DESTDIR}/usr/local/ _prefix) + +set(_boost_flags "") +if (UNIX) + set(_boost_flags "cflags=-fPIC;cxxflags=-fPIC") +elseif(APPLE) + set(_boost_flags + "cflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET};" + "cxxflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET};" + "mflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET};" + "mmflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET}") +endif() + +set(_boost_variants "") +if(CMAKE_BUILD_TYPE) + list(APPEND CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE}) + list(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES) +endif() +list(FIND CMAKE_CONFIGURATION_TYPES "Release" _cfg_rel) +list(FIND CMAKE_CONFIGURATION_TYPES "RelWithDebInfo" _cfg_relwdeb) +list(FIND CMAKE_CONFIGURATION_TYPES "MinSizeRel" _cfg_minsizerel) +list(FIND CMAKE_CONFIGURATION_TYPES "Debug" _cfg_deb) + +if (_cfg_rel GREATER -1 OR _cfg_relwdeb GREATER -1 OR _cfg_minsizerel GREATER -1) + list(APPEND _boost_variants release) +endif() + +if (_cfg_deb GREATER -1 OR (MSVC AND ${DEP_DEBUG}) ) + list(APPEND _boost_variants debug) +endif() + +if (NOT _boost_variants) + set(_boost_variants release) +endif() + +set(_build_cmd ${_build_cmd} + ${_boost_flags} + -j${NPROC} + ${_libs} + --layout=versioned + --debug-configuration + toolset=${_boost_toolset} + address-model=${_bits} + link=${_link} + threading=multi + boost.locale.icu=off + --disable-icu + ${_boost_variants} + stage) + +set(_install_cmd ${_build_cmd} --prefix=${_prefix} install) + +ExternalProject_Add( + dep_Boost + URL "https://boostorg.jfrog.io/artifactory/main/release/1.75.0/source/boost_1_75_0.tar.gz" + URL_HASH SHA256=aeb26f80e80945e82ee93e5939baebdca47b9dee80a07d3144be1e1a6a66dd6a + DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/Boost + CONFIGURE_COMMAND "${_bootstrap_cmd}" + PATCH_COMMAND ${_patch_command} + BUILD_COMMAND "${_build_cmd}" + BUILD_IN_SOURCE ON + INSTALL_COMMAND "${_install_cmd}" +) + +if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") + # Patch the boost::polygon library with a custom one. + ExternalProject_Add(dep_boost_polygon + EXCLUDE_FROM_ALL ON + # GIT_REPOSITORY "https://github.com/prusa3d/polygon" + # GIT_TAG prusaslicer_gmp + URL https://github.com/prusa3d/polygon/archive/refs/heads/prusaslicer_gmp.zip + URL_HASH SHA256=abeb9710f0a7069fb9b22181ae5c56f6066002f125db210e7ffb27032aed6824 + DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/boost_polygon + DEPENDS dep_Boost + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory + "${CMAKE_CURRENT_BINARY_DIR}/dep_boost_polygon-prefix/src/dep_boost_polygon/include/boost/polygon" + "${DESTDIR}/usr/local/include/boost/polygon" + ) + # Only override boost::Polygon Voronoi implementation with Vojtech's GMP hacks on 64bit platforms. + list(APPEND _dep_list "dep_boost_polygon") +endif () \ No newline at end of file diff --git a/deps/Boost/common.jam b/deps/Boost/common.jam new file mode 100644 index 000000000..75d995aa1 --- /dev/null +++ b/deps/Boost/common.jam @@ -0,0 +1,1095 @@ +# Copyright 2003, 2005 Dave Abrahams +# Copyright 2005, 2006 Rene Rivera +# Copyright 2005 Toon Knapen +# Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# Provides actions common to all toolsets, such as creating directories and +# removing files. + +import os ; +import modules ; +import utility ; +import print ; +import type ; +import feature ; +import errors ; +import path ; +import sequence ; +import toolset ; +import virtual-target ; +import numbers ; + +if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] +{ + .debug-configuration = true ; +} +if [ MATCH (--show-configuration) : [ modules.peek : ARGV ] ] +{ + .show-configuration = true ; +} + +# Configurations +# +# The following class helps to manage toolset configurations. Each configuration +# has a unique ID and one or more parameters. A typical example of a unique ID +# is a condition generated by 'common.check-init-parameters' rule. Other kinds +# of IDs can be used. Parameters may include any details about the configuration +# like 'command', 'path', etc. +# +# A toolset configuration may be in one of the following states: +# +# - registered +# Configuration has been registered (e.g. explicitly or by auto-detection +# code) but has not yet been marked as used, i.e. 'toolset.using' rule has +# not yet been called for it. +# - used +# Once called 'toolset.using' rule marks the configuration as 'used'. +# +# The main difference between the states above is that while a configuration is +# 'registered' its options can be freely changed. This is useful in particular +# for autodetection code - all detected configurations may be safely overwritten +# by user code. + +class configurations +{ + import errors ; + + rule __init__ ( ) + { + } + + # Registers a configuration. + # + # Returns 'true' if the configuration has been added and an empty value if + # it already exists. Reports an error if the configuration is 'used'. + # + rule register ( id ) + { + if $(id) in $(self.used) + { + errors.error "common: the configuration '$(id)' is in use" ; + } + + local retval ; + + if ! $(id) in $(self.all) + { + self.all += $(id) ; + + # Indicate that a new configuration has been added. + retval = true ; + } + + return $(retval) ; + } + + # Mark a configuration as 'used'. + # + # Returns 'true' if the state of the configuration has been changed to + # 'used' and an empty value if it the state has not been changed. Reports an + # error if the configuration is not known. + # + rule use ( id ) + { + if ! $(id) in $(self.all) + { + errors.error "common: the configuration '$(id)' is not known" ; + } + + local retval ; + + if ! $(id) in $(self.used) + { + self.used += $(id) ; + + # Indicate that the configuration has been marked as 'used'. + retval = true ; + } + + return $(retval) ; + } + + # Return all registered configurations. + # + rule all ( ) + { + return $(self.all) ; + } + + # Return all used configurations. + # + rule used ( ) + { + return $(self.used) ; + } + + # Returns the value of a configuration parameter. + # + rule get ( id : param ) + { + return $(self.$(param).$(id)) ; + } + + # Sets the value of a configuration parameter. + # + rule set ( id : param : value * ) + { + self.$(param).$(id) = $(value) ; + } +} + + +# The rule for checking toolset parameters. Trailing parameters should all be +# parameter name/value pairs. The rule will check that each parameter either has +# a value in each invocation or has no value in each invocation. Also, the rule +# will check that the combination of all parameter values is unique in all +# invocations. +# +# Each parameter name corresponds to a subfeature. This rule will declare a +# subfeature the first time a non-empty parameter value is passed and will +# extend it with all the values. +# +# The return value from this rule is a condition to be used for flags settings. +# +rule check-init-parameters ( toolset requirement * : * ) +{ + local sig = $(toolset) ; + local condition = $(toolset) ; + local subcondition ; + for local index in 2 3 4 5 6 7 8 9 + { + local name = $($(index)[1]) ; + local value = $($(index)[2]) ; + + if $(value)-is-not-empty + { + condition = $(condition)-$(value) ; + if $(.had-unspecified-value.$(toolset).$(name)) + { + errors.user-error + "$(toolset) initialization: parameter '$(name)'" + "inconsistent" : "no value was specified in earlier" + "initialization" : "an explicit value is specified now" ; + } + # The below logic is for intel compiler. It calls this rule with + # 'intel-linux' and 'intel-win' as toolset, so we need to get the + # base part of toolset name. We can not pass 'intel' as toolset + # because in that case it will be impossible to register versionless + # intel-linux and intel-win toolsets of a specific version. + local t = $(toolset) ; + local m = [ MATCH "([^-]*)-" : $(toolset) ] ; + if $(m) + { + t = $(m[1]) ; + } + if ! $(.had-value.$(toolset).$(name)) + { + if ! $(.declared-subfeature.$(t).$(name)) + { + feature.subfeature toolset $(t) : $(name) : : propagated ; + .declared-subfeature.$(t).$(name) = true ; + } + .had-value.$(toolset).$(name) = true ; + } + feature.extend-subfeature toolset $(t) : $(name) : $(value) ; + subcondition += $(value) ; + } + else + { + if $(.had-value.$(toolset).$(name)) + { + errors.user-error + "$(toolset) initialization: parameter '$(name)'" + "inconsistent" : "an explicit value was specified in an" + "earlier initialization" : "no value is specified now" ; + } + .had-unspecified-value.$(toolset).$(name) = true ; + } + sig = $(sig)$(value:E="")- ; + } + # We also need to consider requirements on the toolset as we can + # configure the same toolset multiple times with different options that + # are selected with the requirements. + if $(requirement) + { + sig = $(sig)$(requirement:J=,) ; + } + if $(sig) in $(.all-signatures) + { + local message = + "duplicate initialization of $(toolset) with the following parameters: " ; + for local index in 2 3 4 5 6 7 8 9 + { + local p = $($(index)) ; + if $(p) + { + message += "$(p[1]) = $(p[2]:E=)" ; + } + } + message += "previous initialization at $(.init-loc.$(sig))" ; + errors.user-error + $(message[1]) : $(message[2]) : $(message[3]) : $(message[4]) : + $(message[5]) : $(message[6]) : $(message[7]) : $(message[8]) ; + } + .all-signatures += $(sig) ; + .init-loc.$(sig) = [ errors.nearest-user-location ] ; + + # If we have a requirement, this version should only be applied under that + # condition. To accomplish this we add a toolset requirement that imposes + # the toolset subcondition, which encodes the version. + if $(requirement) + { + local r = $(toolset) $(requirement) ; + r = $(r:J=,) ; + toolset.add-requirements "$(r):$(subcondition)" ; + } + + # We add the requirements, if any, to the condition to scope the toolset + # variables and options to this specific version. + condition += $(requirement) ; + + if $(.show-configuration) + { + ECHO "notice:" $(condition) ; + } + return $(condition:J=/) ; +} + + +# A helper rule to get the command to invoke some tool. If +# 'user-provided-command' is not given, tries to find binary named 'tool' in +# PATH and in the passed 'additional-path'. Otherwise, verifies that the first +# element of 'user-provided-command' is an existing program. +# +# This rule returns the command to be used when invoking the tool. If we can not +# find the tool, a warning is issued. If 'path-last' is specified, PATH is +# checked after 'additional-paths' when searching for 'tool'. +# +rule get-invocation-command-nodefault ( toolset : tool : + user-provided-command * : additional-paths * : path-last ? ) +{ + local command ; + if ! $(user-provided-command) + { + command = [ find-tool $(tool) : $(additional-paths) : $(path-last) ] ; + if ! $(command) && $(.debug-configuration) + { + ECHO "warning:" toolset $(toolset) "initialization:" can not find tool + $(tool) ; + ECHO "warning:" initialized from [ errors.nearest-user-location ] ; + } + } + else + { + command = [ check-tool $(user-provided-command) ] ; + if ! $(command) && $(.debug-configuration) + { + ECHO "warning:" toolset $(toolset) "initialization:" ; + ECHO "warning:" can not find user-provided command + '$(user-provided-command)' ; + ECHO "warning:" initialized from [ errors.nearest-user-location ] ; + } + } + + return $(command) ; +} + + +# Same as get-invocation-command-nodefault, except that if no tool is found, +# returns either the user-provided-command, if present, or the 'tool' parameter. +# +rule get-invocation-command ( toolset : tool : user-provided-command * : + additional-paths * : path-last ? ) +{ + local result = [ get-invocation-command-nodefault $(toolset) : $(tool) : + $(user-provided-command) : $(additional-paths) : $(path-last) ] ; + + if ! $(result) + { + if $(user-provided-command) + { + result = $(user-provided-command) ; + } + else + { + result = $(tool) ; + } + } + return $(result) ; +} + + +# Given an invocation command return the absolute path to the command. This +# works even if command has no path element and was found on the PATH. +# +rule get-absolute-tool-path ( command ) +{ + if $(command:D) + { + return $(command:D) ; + } + else + { + local m = [ GLOB [ modules.peek : PATH Path path ] : $(command) + $(command).exe ] ; + return $(m[1]:D) ; + } +} + + +# Attempts to find tool (binary) named 'name' in PATH and in 'additional-paths'. +# If found in PATH, returns 'name' and if found in additional paths, returns +# absolute name. If the tool is found in several directories, returns the first +# path found. Otherwise, returns an empty string. If 'path-last' is specified, +# PATH is searched after 'additional-paths'. +# +rule find-tool ( name : additional-paths * : path-last ? ) +{ + if $(name:D) + { + return [ check-tool-aux $(name) ] ; + } + local path = [ path.programs-path ] ; + local match = [ path.glob $(path) : $(name) $(name).exe ] ; + local additional-match = [ path.glob $(additional-paths) : $(name) + $(name).exe ] ; + + local result ; + if $(path-last) + { + result = $(additional-match) ; + if ! $(result) && $(match) + { + result = $(name) ; + } + } + else + { + if $(match) + { + result = $(name) ; + } + else + { + result = $(additional-match) ; + } + } + if $(result) + { + return [ path.native $(result[1]) ] ; + } +} + +# Checks if 'command' can be found either in path or is a full name to an +# existing file. +# +local rule check-tool-aux ( command ) +{ + if $(command:D) + { + if [ path.exists $(command) ] + # Both NT and Cygwin will run .exe files by their unqualified names. + || ( [ os.on-windows ] && [ path.exists $(command).exe ] ) + # Only NT will run .bat & .cmd files by their unqualified names. + || ( ( [ os.name ] = NT ) && ( [ path.exists $(command).bat ] || + [ path.exists $(command).cmd ] ) ) + { + return $(command) ; + } + } + else + { + if [ GLOB [ modules.peek : PATH Path path ] : $(command) ] + { + return $(command) ; + } + } +} + + +# Checks that a tool can be invoked by 'command'. If command is not an absolute +# path, checks if it can be found in 'path'. If command is an absolute path, +# check that it exists. Returns 'command' if ok or empty string otherwise. +# +local rule check-tool ( xcommand + ) +{ + if [ check-tool-aux $(xcommand[1]) ] || + [ check-tool-aux $(xcommand[-1]) ] + { + return $(xcommand) ; + } +} + + +# Handle common options for toolset, specifically sets the following flag +# variables: +# - CONFIG_COMMAND to $(command) +# - OPTIONS for compile to the value of in $(options) +# - OPTIONS for compile.c to the value of in $(options) +# - OPTIONS for compile.c++ to the value of in $(options) +# - OPTIONS for compile.asm to the value of in $(options) +# - OPTIONS for compile.fortran to the value of in $(options) +# - OPTIONS for link to the value of in $(options) +# +rule handle-options ( toolset : condition * : command * : options * ) +{ + if $(.debug-configuration) + { + ECHO "notice:" will use '$(command)' for $(toolset), condition + $(condition:E=(empty)) ; + } + + # The last parameter ('unchecked') says it is OK to set flags for another + # module. + toolset.flags $(toolset) CONFIG_COMMAND $(condition) : $(command) + : unchecked ; + + toolset.flags $(toolset).compile OPTIONS $(condition) : + [ feature.get-values : $(options) ] : unchecked ; + + toolset.flags $(toolset).compile.c OPTIONS $(condition) : + [ feature.get-values : $(options) ] : unchecked ; + + toolset.flags $(toolset).compile.c++ OPTIONS $(condition) : + [ feature.get-values : $(options) ] : unchecked ; + + toolset.flags $(toolset).compile.asm OPTIONS $(condition) : + [ feature.get-values : $(options) ] : unchecked ; + + toolset.flags $(toolset).compile.fortran OPTIONS $(condition) : + [ feature.get-values : $(options) ] : unchecked ; + + toolset.flags $(toolset).link OPTIONS $(condition) : + [ feature.get-values : $(options) ] : unchecked ; +} + + +# Returns the location of the "program files" directory on a Windows platform. +# +rule get-program-files-dir ( ) +{ + local ProgramFiles = [ modules.peek : ProgramFiles ] ; + if $(ProgramFiles) + { + ProgramFiles = "$(ProgramFiles:J= )" ; + } + else + { + ProgramFiles = "c:\\Program Files" ; + } + return $(ProgramFiles) ; +} + + +if [ os.name ] = NT +{ + NULL_DEVICE = "NUL" ; + IGNORE = "2>$(NULL_DEVICE) >$(NULL_DEVICE) & setlocal" ; + RM = del /f /q ; + CP = copy /b ; + LN ?= $(CP) ; + # Ugly hack to convince copy to set the timestamp of the destination to the + # current time by concatenating the source with a nonexistent file. Note + # that this requires /b (binary) as the default when concatenating files is + # /a (ascii). + WINDOWS-CP-HACK = "+ this-file-does-not-exist-A698EE7806899E69" ; +} +else if [ os.name ] = VMS +{ + NULL_DEVICE = "NL:" ; + PIPE = PIPE ; + IGNORE = "2>$(NULL_DEVICE) >$(NULL_DEVICE)" ; + RM = DELETE /NOCONF ; + CP = COPY /OVERWRITE ; + LN = $(CP) ; +} +else +{ + NULL_DEVICE = "/dev/null" ; + IGNORE = "2>$(NULL_DEVICE) >$(NULL_DEVICE)" ; + RM = rm -f ; + CP = cp ; + LN = ln ; +} + +NULL_OUT = ">$(NULL_DEVICE)" ; + +rule null-device ( ) +{ + return $(NULL_DEVICE) ; +} + + +rule rm-command ( ) +{ + return $(RM) ; +} + + +rule copy-command ( ) +{ + return $(CP) ; +} + + +if "\n" = "n" +{ + # Escape characters not supported so use ugly hacks. Will not work on Cygwin + # - see below. + nl = " +" ; + q = "" ; +} +else +{ + nl = "\n" ; + q = "\"" ; +} + + +rule newline-char ( ) +{ + return $(nl) ; +} + + +# Returns the command needed to set an environment variable on the current +# platform. The variable setting persists through all following commands and is +# visible in the environment seen by subsequently executed commands. In other +# words, on Unix systems, the variable is exported, which is consistent with the +# only possible behavior on Windows systems. +# +rule variable-setting-command ( variable : value ) +{ + if [ os.name ] = NT + { + return "set $(variable)=$(value)$(nl)" ; + } + else if [ os.name ] = VMS + { + return "$(variable) == $(q)$(value)$(q)$(nl)" ; + } + else + { + # If we do not have escape character support in bjam, the cod below + # blows up on CYGWIN, since the $(nl) variable holds a Windows new-line + # \r\n sequence that messes up the executed export command which then + # reports that the passed variable name is incorrect. + # But we have a check for cygwin in kernel/bootstrap.jam already. + return "$(variable)=$(q)$(value)$(q)$(nl)export $(variable)$(nl)" ; + } +} + + +# Returns a command to sets a named shell path variable to the given NATIVE +# paths on the current platform. +# +rule path-variable-setting-command ( variable : paths * ) +{ + local sep = [ os.path-separator ] ; + return [ variable-setting-command $(variable) : $(paths:J=$(sep)) ] ; +} + + +# Returns a command that prepends the given paths to the named path variable on +# the current platform. +# +rule prepend-path-variable-command ( variable : paths * ) +{ + return [ path-variable-setting-command $(variable) + : $(paths) [ os.expand-variable $(variable) ] ] ; +} + + +# Return a command which can create a file. If 'r' is result of invocation, then +# 'r foobar' will create foobar with unspecified content. What happens if file +# already exists is unspecified. +# +rule file-creation-command ( ) +{ + if [ os.name ] = NT + { + # A few alternative implementations on Windows: + # + # 'type NUL >> ' + # That would construct an empty file instead of a file containing + # a space and an end-of-line marker but it would also not change + # the target's timestamp in case the file already exists. + # + # 'type NUL > ' + # That would construct an empty file instead of a file containing + # a space and an end-of-line marker but it would also destroy an + # already existing file by overwriting it with an empty one. + # + # I guess the best solution would be to allow Boost Jam to define + # built-in functions such as 'create a file', 'touch a file' or 'copy a + # file' which could be used from inside action code. That would allow + # completely portable operations without this kind of kludge. + # (22.02.2009.) (Jurko) + return "echo. > " ; + } + else if [ os.name ] = VMS + { + return "APPEND /NEW NL: " ; + } + else + { + return "touch " ; + } +} + + +# Returns a command that may be used for 'touching' files. It is not a real +# 'touch' command on NT because it adds an empty line at the end of file but it +# works with source files. +# +rule file-touch-command ( ) +{ + if [ os.name ] = NT + { + return "echo. >> " ; + } + else if [ os.name ] = VMS + { + return "APPEND /NEW NL: " ; + } + else + { + return "touch " ; + } +} + + +rule MkDir +{ + # If dir exists, do not update it. Do this even for $(DOT). + NOUPDATE $(<) ; + + if $(<) != $(DOT) && ! $($(<)-mkdir) + { + # Cheesy gate to prevent multiple invocations on same dir. + $(<)-mkdir = true ; + + # Schedule the mkdir build action. + common.mkdir $(<) ; + + # Prepare a Jam 'dirs' target that can be used to make the build only + # construct all the target directories. + DEPENDS dirs : $(<) ; + + # Recursively create parent directories. $(<:P) = $(<)'s parent & we + # recurse until root. + + local s = $(<:P) ; + if [ os.name ] = NT + { + switch $(s) + { + case "*:" : s = ; + case "*:\\" : s = ; + } + } + + if $(s) + { + if $(s) != $(<) + { + DEPENDS $(<) : $(s) ; + MkDir $(s) ; + } + else + { + NOTFILE $(s) ; + } + } + } +} + + +#actions MkDir1 +#{ +# mkdir "$(<)" +#} + +# The following quick-fix actions should be replaced using the original MkDir1 +# action once Boost Jam gets updated to correctly detect different paths leading +# up to the same filesystem target and triggers their build action only once. +# (todo) (04.07.2008.) (Jurko) + +if [ os.name ] = NT +{ + actions quietly mkdir + { + if not exist "$(<)\\" mkdir "$(<)" + } +} +else +{ + actions quietly mkdir + { + mkdir -p "$(<)" + } +} + + +actions piecemeal together existing Clean +{ + $(RM) "$(>)" +} + + +rule copy +{ +} + + +actions copy +{ + $(CP) "$(>)" $(WINDOWS-CP-HACK) "$(<)" +} + + +rule RmTemps +{ +} + + +actions quietly updated piecemeal together RmTemps +{ + $(RM) "$(>)" $(IGNORE) +} + + +actions hard-link +{ + $(RM) "$(<)" 2$(NULL_OUT) $(NULL_OUT) + $(LN) "$(>)" "$(<)" $(NULL_OUT) +} + + +if [ os.name ] = VMS +{ + actions mkdir + { + IF F$PARSE("$(<:W)") .EQS. "" THEN CREATE /DIR $(<:W) + } + + actions piecemeal together existing Clean + { + $(RM) $(>:WJ=;*,);* + } + + actions copy + { + $(CP) $(>:WJ=,) $(<:W) + } + + actions quietly updated piecemeal together RmTemps + { + $(PIPE) $(RM) $(>:WJ=;*,);* $(IGNORE) + } + + actions hard-link + { + $(PIPE) $(RM) $(>[1]:W);* $(IGNORE) + $(PIPE) $(LN) $(>[1]:W) $(<:W) $(NULL_OUT) + } +} + +# Given a target, as given to a custom tag rule, returns a string formatted +# according to the passed format. Format is a list of properties that is +# represented in the result. For each element of format the corresponding target +# information is obtained and added to the result string. For all, but the +# literal, the format value is taken as the as string to prepend to the output +# to join the item to the rest of the result. If not given "-" is used as a +# joiner. +# +# The format options can be: +# +# [joiner] +# :: The basename of the target name. +# [joiner] +# :: The abbreviated toolset tag being used to build the target. +# [joiner] +# :: Indication of a multi-threaded build. +# [joiner] +# :: Collective tag of the build runtime. +# [joiner] +# :: Short version tag taken from the given "version-feature" in the +# build properties. Or if not present, the literal value as the +# version number. +# [joiner] +# :: Direct lookup of the given property-name value in the build +# properties. /property-name/ is a regular expression. E.g. +# will match every toolset. +# /otherwise/ +# :: The literal value of the format argument. +# +# For example this format: +# +# boost_ +# +# Might return: +# +# boost_thread-vc80-mt-gd-1_33.dll, or +# boost_regex-vc80-gd-1_33.dll +# +# The returned name also has the target type specific prefix and suffix which +# puts it in a ready form to use as the value from a custom tag rule. +# +rule format-name ( format * : name : type ? : property-set ) +{ + local result = "" ; + for local f in $(format) + { + switch $(f:G) + { + case : + result += $(name:B) ; + + case : + result += [ join-tag $(f:G=) : [ toolset-tag $(name) : $(type) : + $(property-set) ] ] ; + + case : + result += [ join-tag $(f:G=) : [ threading-tag $(name) : $(type) + : $(property-set) ] ] ; + + case : + result += [ join-tag $(f:G=) : [ runtime-tag $(name) : $(type) : + $(property-set) ] ] ; + + case : + result += [ join-tag $(f:G=) : [ qt-tag $(name) : $(type) : + $(property-set) ] ] ; + + case : + result += [ join-tag $(f:G=) : [ address-model-tag $(name) : + $(type) : $(property-set) ] ] ; + + case : + result += [ join-tag $(f:G=) : [ arch-and-model-tag $(name) : + $(type) : $(property-set) ] ] ; + + case : + local key = [ MATCH : $(f:G) ] ; + local version = [ $(property-set).get <$(key)> ] ; + version ?= $(key) ; + version = [ MATCH "^([^.]+)[.]([^.]+)[.]?([^.]*)" : $(version) ] ; + result += [ join-tag $(f:G=) : $(version[1])_$(version[2]) ] ; + + case : + local key = [ MATCH : $(f:G) ] ; + local p0 = [ MATCH <($(key))> : [ $(property-set).raw ] ] ; + if $(p0) + { + local p = [ $(property-set).get <$(p0)> ] ; + if $(p) + { + result += [ join-tag $(f:G=) : $(p) ] ; + } + } + + case * : + result += $(f:G=) ; + } + } + return [ virtual-target.add-prefix-and-suffix $(result:J=) : $(type) : + $(property-set) ] ; +} + + +local rule join-tag ( joiner ? : tag ? ) +{ + if ! $(joiner) { joiner = - ; } + return $(joiner)$(tag) ; +} + + +local rule toolset-tag ( name : type ? : property-set ) +{ + local tag = ; + + local properties = [ $(property-set).raw ] ; + switch [ $(property-set).get ] + { + case borland* : tag += bcb ; + case clang* : + { + switch [ $(property-set).get ] + { + case darwin : tag += clang-darwin ; + case linux : tag += clang ; + case win : tag += clangw ; + } + } + case como* : tag += como ; + case cw : tag += cw ; + case darwin* : tag += xgcc ; + case edg* : tag += edg ; + case gcc* : + { + switch [ $(property-set).get ] + { + case *windows* : tag += mgw ; + case * : tag += gcc ; + } + } + case intel : + if [ $(property-set).get ] = win + { + tag += iw ; + } + else + { + tag += il ; + } + case kcc* : tag += kcc ; + case kylix* : tag += bck ; + #case metrowerks* : tag += cw ; + #case mingw* : tag += mgw ; + case mipspro* : tag += mp ; + case msvc* : tag += vc ; + case qcc* : tag += qcc ; + case sun* : tag += sw ; + case tru64cxx* : tag += tru ; + case vacpp* : tag += xlc ; + } + local version = [ MATCH "([0123456789]+)[.]?([0123456789]*)" + : $(properties) ] ; + # For historical reasons, vc6.0 and vc7.0 use different naming. + if $(tag) = vc + { + if $(version[1]) = 6 + { + # Cancel minor version. + version = 6 ; + } + else if $(version[1]) = 7 && $(version[2]) = 0 + { + version = 7 ; + } + } + + # From GCC 5, versioning changes and minor becomes patch + if ( $(tag) = gcc || $(tag) = mgw ) && [ numbers.less 4 $(version[1]) ] + { + version = $(version[1]) ; + } + + # Ditto, from Clang 4 + if ( $(tag) = clang || $(tag) = clangw ) && [ numbers.less 3 $(version[1]) ] + { + version = $(version[1]) ; + } + + # On intel, version is not added, because it does not matter and it is the + # version of vc used as backend that matters. Ideally, we should encode the + # backend version but that would break compatibility with V1. + if $(tag) = iw + { + version = ; + } + + # On borland, version is not added for compatibility with V1. + if $(tag) = bcb + { + version = ; + } + + tag += $(version) ; + + return $(tag:J=) ; +} + + +local rule threading-tag ( name : type ? : property-set ) +{ + if multi in [ $(property-set).raw ] + { + return mt ; + } +} + + +local rule runtime-tag ( name : type ? : property-set ) +{ + local tag = ; + + local properties = [ $(property-set).raw ] ; + if static in $(properties) { tag += s ; } + + # This is an ugly thing. In V1, there is code to automatically detect which + # properties affect a target. So, if does not affect gcc + # toolset, the tag rules will not even see . Similar + # functionality in V2 is not implemented yet, so we just check for toolsets + # known to care about runtime debugging. + if ( msvc in $(properties) ) || + ( stlport in $(properties) ) || + ( win in $(properties) ) + { + if on in $(properties) { tag += g ; } + } + + if on in $(properties) { tag += y ; } + if debug in $(properties) { tag += d ; } + if stlport in $(properties) { tag += p ; } + if hostios in $(properties) { tag += n ; } + + return $(tag:J=) ; +} + + +# Create a tag for the Qt library version +# "4.6.0" will result in tag "qt460" +local rule qt-tag ( name : type ? : property-set ) +{ + local v = [ MATCH "([0123456789]+)[.]?([0123456789]*)[.]?([0123456789]*)" : + [ $(property-set).get ] ] ; + return qt$(v:J=) ; +} + + +# Create a tag for the address-model +# 64 will simply generate "64" +local rule address-model-tag ( name : type ? : property-set ) +{ + return [ $(property-set).get ] ; +} + +# Create a tag for the architecture and model +# x86 32 would generate "x32" +# This relies on the fact that all architectures start with +# unique letters. +local rule arch-and-model-tag ( name : type ? : property-set ) +{ + local architecture = [ $(property-set).get ] ; + local address-model = [ $(property-set).get ] ; + + local arch = [ MATCH ^(.) : $(architecture) ] ; + + return $(arch)$(address-model) ; +} + +rule __test__ ( ) +{ + import assert ; + + local save-os = [ modules.peek os : .name ] ; + + modules.poke os : .name : LINUX ; + assert.result "PATH=\"foo:bar:baz\"\nexport PATH\n" + : path-variable-setting-command PATH : foo bar baz ; + assert.result "PATH=\"foo:bar:$PATH\"\nexport PATH\n" + : prepend-path-variable-command PATH : foo bar ; + + modules.poke os : .name : NT ; + assert.result "set PATH=foo;bar;baz\n" + : path-variable-setting-command PATH : foo bar baz ; + assert.result "set PATH=foo;bar;%PATH%\n" + : prepend-path-variable-command PATH : foo bar ; + + modules.poke os : .name : $(save-os) ; +} diff --git a/deps/Boost/user-config.jam b/deps/Boost/user-config.jam new file mode 100644 index 000000000..eff13db28 --- /dev/null +++ b/deps/Boost/user-config.jam @@ -0,0 +1 @@ +using gcc : : @CMAKE_CXX_COMPILER@ ; \ No newline at end of file diff --git a/deps/CGAL/CGAL.cmake b/deps/CGAL/CGAL.cmake index fa88fc29e..b43467b53 100644 --- a/deps/CGAL/CGAL.cmake +++ b/deps/CGAL/CGAL.cmake @@ -1,11 +1,11 @@ prusaslicer_add_cmake_project( CGAL - GIT_REPOSITORY https://github.com/CGAL/cgal.git - GIT_TAG bec70a6d52d8aacb0b3d82a7b4edc3caa899184b # releases/CGAL-5.0 + # GIT_REPOSITORY https://github.com/CGAL/cgal.git + # GIT_TAG bec70a6d52d8aacb0b3d82a7b4edc3caa899184b # releases/CGAL-5.0 # For whatever reason, this keeps downloading forever (repeats downloads if finished) - # URL https://github.com/CGAL/cgal/archive/releases/CGAL-5.0.zip - # URL_HASH SHA256=bd9327be903ab7ee379a8a7a0609eba0962f5078d2497cf8e13e8e1598584154 - DEPENDS dep_boost dep_GMP dep_MPFR + URL https://github.com/CGAL/cgal/archive/releases/CGAL-5.0.zip + URL_HASH SHA256=c2b035bd078687b6d8c0fb6371a7443adcdb647856af9969532c4050cd5f48e5 + DEPENDS dep_Boost dep_GMP dep_MPFR ) include(GNUInstallDirs) diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index 718945828..3ce6b88a9 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -32,6 +32,7 @@ if (NPROC EQUAL 0) endif () set(DESTDIR "${CMAKE_CURRENT_BINARY_DIR}/destdir" CACHE PATH "Destination directory") +set(DEP_DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR} CACHE PATH "Path for downloaded source packages.") option(DEP_DEBUG "Build debug variants (only applicable on Windows)" ON) @@ -46,10 +47,14 @@ endif() # option(DEP_BUILD_IGL_STATIC "Build IGL as a static library. Might cause link errors and increase binary size." OFF) message(STATUS "PrusaSlicer deps DESTDIR: ${DESTDIR}") +message(STATUS "PrusaSlicer dowload dir for source packages: ${DEP_DOWNLOAD_DIR}") message(STATUS "PrusaSlicer deps debug build: ${DEP_DEBUG}") find_package(Git REQUIRED) +# The default command line for patching. Only works for newer +set(PATCH_CMD ${GIT_EXECUTABLE} apply --verbose --ignore-space-change --whitespace=fix) + get_property(_is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) function(prusaslicer_add_cmake_project projectname) @@ -71,6 +76,7 @@ function(prusaslicer_add_cmake_project projectname) dep_${projectname} EXCLUDE_FROM_ALL ON INSTALL_DIR ${DESTDIR}/usr/local + DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/${projectname} ${_gen} CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:STRING=${DESTDIR}/usr/local @@ -79,6 +85,7 @@ function(prusaslicer_add_cmake_project projectname) -DCMAKE_DEBUG_POSTFIX:STRING=d -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER} + -DCMAKE_TOOLCHAIN_FILE:STRING=${CMAKE_TOOLCHAIN_FILE} -DBUILD_SHARED_LIBS:BOOL=OFF "${_configs_line}" ${DEP_CMAKE_OPTS} @@ -145,27 +152,42 @@ if (NOT EXPAT_FOUND) set(EXPAT_PKG dep_EXPAT) endif () +set(DEP_Boost_COMPONENTS system iostreams filesystem thread log locale regex date_time) +include(Boost/Boost.cmake) + +# The order of includes respects the dependencies between libraries +include(Cereal/Cereal.cmake) +include(Qhull/Qhull.cmake) include(GLEW/GLEW.cmake) include(OpenCSG/OpenCSG.cmake) + +include(TBB/TBB.cmake) + +include(Blosc/Blosc.cmake) +include(OpenEXR/OpenEXR.cmake) +include(OpenVDB/OpenVDB.cmake) + include(GMP/GMP.cmake) include(MPFR/MPFR.cmake) include(CGAL/CGAL.cmake) + +include(NLopt/NLopt.cmake) + +include(OpenSSL/OpenSSL.cmake) +include(CURL/CURL.cmake) + +include(JPEG/JPEG.cmake) +include(TIFF/TIFF.cmake) include(wxWidgets/wxWidgets.cmake) -if (NOT "${ZLIB_PKG}" STREQUAL "") - add_dependencies(dep_blosc ${ZLIB_PKG}) - add_dependencies(dep_openexr ${ZLIB_PKG}) -endif () - set(_dep_list - dep_boost - dep_tbb - dep_libcurl + dep_Boost + dep_TBB + dep_CURL dep_wxWidgets - dep_gtest - dep_cereal - dep_nlopt - dep_openvdb + dep_Cereal + dep_NLopt + dep_OpenVDB dep_OpenCSG dep_CGAL ${PNG_PKG} @@ -173,28 +195,11 @@ set(_dep_list ${EXPAT_PKG} ) -if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") - # Patch the boost::polygon library with a custom one. - ExternalProject_Add(dep_boost_polygon - EXCLUDE_FROM_ALL ON - GIT_REPOSITORY "https://github.com/prusa3d/polygon" - GIT_TAG prusaslicer_gmp - DEPENDS dep_boost - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory - "${CMAKE_CURRENT_BINARY_DIR}/dep_boost_polygon-prefix/src/dep_boost_polygon/include/boost/polygon" - "${DESTDIR}/usr/local/include/boost/polygon" - ) - # Only override boost::Polygon Voronoi implementation with Vojtech's GMP hacks on 64bit platforms. - list(APPEND _dep_list "dep_boost_polygon") -endif () - if (MSVC) # Experimental #list(APPEND _dep_list "dep_qhull") else() - list(APPEND _dep_list "dep_qhull") + list(APPEND _dep_list "dep_Qhull") # Not working, static build has different Eigen #list(APPEND _dep_list "dep_libigl") endif() diff --git a/deps/CURL/CURL.cmake b/deps/CURL/CURL.cmake new file mode 100644 index 000000000..a05a4e97e --- /dev/null +++ b/deps/CURL/CURL.cmake @@ -0,0 +1,78 @@ +set(_curl_platform_flags + -DENABLE_IPV6:BOOL=ON + -DENABLE_VERSIONED_SYMBOLS:BOOL=ON + -DENABLE_THREADED_RESOLVER:BOOL=ON + + # -DCURL_DISABLE_LDAP:BOOL=ON + # -DCURL_DISABLE_LDAPS:BOOL=ON + -DENABLE_MANUAL:BOOL=OFF + # -DCURL_DISABLE_RTSP:BOOL=ON + # -DCURL_DISABLE_DICT:BOOL=ON + # -DCURL_DISABLE_TELNET:BOOL=ON + # -DCURL_DISABLE_POP3:BOOL=ON + # -DCURL_DISABLE_IMAP:BOOL=ON + # -DCURL_DISABLE_SMB:BOOL=ON + # -DCURL_DISABLE_SMTP:BOOL=ON + # -DCURL_DISABLE_GOPHER:BOOL=ON + -DHTTP_ONLY=ON + + -DCMAKE_USE_GSSAPI:BOOL=OFF + -DCMAKE_USE_LIBSSH2:BOOL=OFF + -DUSE_RTMP:BOOL=OFF + -DUSE_NGHTTP2:BOOL=OFF + -DUSE_MBEDTLS:BOOL=OFF +) + +if (WIN32) + set(_curl_platform_flags ${_curl_platform_flags} -DCMAKE_USE_SCHANNEL=ON) +elseif (APPLE) + set(_curl_platform_flags + + ${_curl_platform_flags} + + -DCMAKE_USE_SECTRANSP:BOOL=ON + -DCMAKE_USE_OPENSSL:BOOL=OFF + + -DCURL_CA_PATH:STRING=none + ) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(_curl_platform_flags + + ${_curl_platform_flags} + + -DCMAKE_USE_OPENSSL:BOOL=ON + + -DCURL_CA_PATH:STRING=none + -DCURL_CA_BUNDLE:STRING=none + -DCURL_CA_FALLBACK:BOOL=ON + ) +endif () + +if (BUILD_SHARED_LIBS) + set(_curl_static OFF) +else() + set(_curl_static ON) +endif() + +prusaslicer_add_cmake_project(CURL + # GIT_REPOSITORY https://github.com/curl/curl.git + # GIT_TAG curl-7_75_0 + URL https://github.com/curl/curl/archive/refs/tags/curl-7_75_0.zip + URL_HASH SHA256=a63ae025bb0a14f119e73250f2c923f4bf89aa93b8d4fafa4a9f5353a96a765a + DEPENDS ${ZLIB_PKG} + # PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && + # ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_LIST_DIR}/curl-mods.patch + CMAKE_ARGS + -DBUILD_TESTING:BOOL=OFF + -DCMAKE_POSITION_INDEPENDENT_CODE=ON + -DCURL_STATICLIB=${_curl_static} + ${_curl_platform_flags} +) + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + add_dependencies(dep_CURL dep_OpenSSL) +endif () + +if (MSVC) + add_debug_dep(dep_CURL) +endif () diff --git a/deps/Cereal/Cereal.cmake b/deps/Cereal/Cereal.cmake new file mode 100644 index 000000000..28912ff4f --- /dev/null +++ b/deps/Cereal/Cereal.cmake @@ -0,0 +1,6 @@ +prusaslicer_add_cmake_project(Cereal + URL "https://github.com/USCiLab/cereal/archive/v1.2.2.tar.gz" + URL_HASH SHA256=1921f26d2e1daf9132da3c432e2fd02093ecaedf846e65d7679ddf868c7289c4 + CMAKE_ARGS + -DJUST_INSTALL_CEREAL=on +) \ No newline at end of file diff --git a/deps/GMP/GMP.cmake b/deps/GMP/GMP.cmake index a7fe19355..6b0f97085 100644 --- a/deps/GMP/GMP.cmake +++ b/deps/GMP/GMP.cmake @@ -36,11 +36,18 @@ else () set(_gmp_build_tgt "") # let it guess endif() + set(_cross_compile_arg "") + if (CMAKE_CROSSCOMPILING) + # TOOLCHAIN_PREFIX should be defined in the toolchain file + set(_cross_compile_arg --host=${TOOLCHAIN_PREFIX}) + endif () + ExternalProject_Add(dep_GMP - # URL https://gmplib.org/download/gmp/gmp-6.1.2.tar.bz2 URL https://gmplib.org/download/gmp/gmp-6.2.1.tar.bz2 + URL_HASH SHA256=eae9326beb4158c386e39a356818031bd28f3124cf915f8c5b1dc4c7a36b4d7c + DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/GMP BUILD_IN_SOURCE ON - CONFIGURE_COMMAND env "CFLAGS=${_gmp_ccflags}" "CXXFLAGS=${_gmp_ccflags}" ./configure --enable-shared=no --enable-cxx=yes --enable-static=yes "--prefix=${DESTDIR}/usr/local" ${_gmp_build_tgt} + CONFIGURE_COMMAND env "CFLAGS=${_gmp_ccflags}" "CXXFLAGS=${_gmp_ccflags}" ./configure ${_cross_compile_arg} --enable-shared=no --enable-cxx=yes --enable-static=yes "--prefix=${DESTDIR}/usr/local" ${_gmp_build_tgt} BUILD_COMMAND make -j INSTALL_COMMAND make install ) diff --git a/deps/JPEG/JPEG.cmake b/deps/JPEG/JPEG.cmake new file mode 100644 index 000000000..4c8c0307e --- /dev/null +++ b/deps/JPEG/JPEG.cmake @@ -0,0 +1,8 @@ +prusaslicer_add_cmake_project(JPEG + URL https://github.com/libjpeg-turbo/libjpeg-turbo/archive/refs/tags/2.0.6.zip + URL_HASH SHA256=017bdc33ff3a72e11301c0feb4657cb27719d7f97fa67a78ed506c594218bbf1 + DEPENDS ${ZLIB_PKG} + CMAKE_ARGS + -DENABLE_SHARED=OFF + -DENABLE_STATIC=ON +) diff --git a/deps/MPFR/MPFR.cmake b/deps/MPFR/MPFR.cmake index ddbb178d8..c29bb39ad 100644 --- a/deps/MPFR/MPFR.cmake +++ b/deps/MPFR/MPFR.cmake @@ -18,10 +18,19 @@ if (MSVC) add_custom_target(dep_MPFR SOURCES ${_output}) else () + + set(_cross_compile_arg "") + if (CMAKE_CROSSCOMPILING) + # TOOLCHAIN_PREFIX should be defined in the toolchain file + set(_cross_compile_arg --host=${TOOLCHAIN_PREFIX}) + endif () + ExternalProject_Add(dep_MPFR URL http://ftp.vim.org/ftp/gnu/mpfr/mpfr-3.1.6.tar.bz2 https://www.mpfr.org/mpfr-3.1.6/mpfr-3.1.6.tar.bz2 # mirrors are allowed + URL_HASH SHA256=cf4f4b2d80abb79e820e78c8077b6725bbbb4e8f41896783c899087be0e94068 + DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/MPFR BUILD_IN_SOURCE ON - CONFIGURE_COMMAND env "CFLAGS=${_gmp_ccflags}" "CXXFLAGS=${_gmp_ccflags}" ./configure --prefix=${DESTDIR}/usr/local --enable-shared=no --enable-static=yes --with-gmp=${DESTDIR}/usr/local ${_gmp_build_tgt} + CONFIGURE_COMMAND env "CFLAGS=${_gmp_ccflags}" "CXXFLAGS=${_gmp_ccflags}" ./configure ${_cross_compile_arg} --prefix=${DESTDIR}/usr/local --enable-shared=no --enable-static=yes --with-gmp=${DESTDIR}/usr/local ${_gmp_build_tgt} BUILD_COMMAND make -j INSTALL_COMMAND make install DEPENDS dep_GMP diff --git a/deps/NLopt/NLopt.cmake b/deps/NLopt/NLopt.cmake new file mode 100644 index 000000000..db638c897 --- /dev/null +++ b/deps/NLopt/NLopt.cmake @@ -0,0 +1,15 @@ +prusaslicer_add_cmake_project(NLopt + URL "https://github.com/stevengj/nlopt/archive/v2.5.0.tar.gz" + URL_HASH SHA256=c6dd7a5701fff8ad5ebb45a3dc8e757e61d52658de3918e38bab233e7fd3b4ae + CMAKE_ARGS + -DNLOPT_PYTHON:BOOL=OFF + -DNLOPT_OCTAVE:BOOL=OFF + -DNLOPT_MATLAB:BOOL=OFF + -DNLOPT_GUILE:BOOL=OFF + -DNLOPT_SWIG:BOOL=OFF + -DNLOPT_TESTS:BOOL=OFF +) + +if (MSVC) + add_debug_dep(dep_NLopt) +endif () diff --git a/deps/OpenCSG/OpenCSG.cmake b/deps/OpenCSG/OpenCSG.cmake index fda74cd45..4d980fecd 100644 --- a/deps/OpenCSG/OpenCSG.cmake +++ b/deps/OpenCSG/OpenCSG.cmake @@ -1,7 +1,9 @@ prusaslicer_add_cmake_project(OpenCSG - GIT_REPOSITORY https://github.com/floriankirsch/OpenCSG.git - GIT_TAG 83e274457b46c9ad11a4ee599203250b1618f3b9 #v1.4.2 + # GIT_REPOSITORY https://github.com/floriankirsch/OpenCSG.git + # GIT_TAG 83e274457b46c9ad11a4ee599203250b1618f3b9 #v1.4.2 + URL https://github.com/floriankirsch/OpenCSG/archive/refs/tags/opencsg-1-4-2-release.zip + URL_HASH SHA256=51afe0db79af8386e2027d56d685177135581e0ee82ade9d7f2caff8deab5ec5 PATCH_COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in ./CMakeLists.txt DEPENDS dep_GLEW ) diff --git a/deps/OpenEXR/OpenEXR.cmake b/deps/OpenEXR/OpenEXR.cmake new file mode 100644 index 000000000..046223fed --- /dev/null +++ b/deps/OpenEXR/OpenEXR.cmake @@ -0,0 +1,17 @@ +prusaslicer_add_cmake_project(OpenEXR + # GIT_REPOSITORY https://github.com/openexr/openexr.git + URL https://github.com/AcademySoftwareFoundation/openexr/archive/refs/tags/v2.5.5.zip + URL_HASH SHA256=0307a3d7e1fa1e77e9d84d7e9a8694583fbbbfd50bdc6884e2c96b8ef6b902de + DEPENDS ${ZLIB_PKG} + GIT_TAG v2.5.5 + CMAKE_ARGS + -DCMAKE_POSITION_INDEPENDENT_CODE=ON + -DBUILD_TESTING=OFF + -DPYILMBASE_ENABLE:BOOL=OFF + -DOPENEXR_VIEWERS_ENABLE:BOOL=OFF + -DOPENEXR_BUILD_UTILS:BOOL=OFF +) + +if (MSVC) + add_debug_dep(dep_OpenEXR) +endif () \ No newline at end of file diff --git a/deps/OpenSSL/OpenSSL.cmake b/deps/OpenSSL/OpenSSL.cmake new file mode 100644 index 000000000..347b30d05 --- /dev/null +++ b/deps/OpenSSL/OpenSSL.cmake @@ -0,0 +1,35 @@ + +include(ProcessorCount) +ProcessorCount(NPROC) + +set(_conf_cmd "./config") +set(_cross_arch "") +set(_cross_comp_prefix_line "") +if (CMAKE_CROSSCOMPILING) + set(_conf_cmd "./Configure") + set(_cross_comp_prefix_line "--cross-compile-prefix=${TOOLCHAIN_PREFIX}-") + + if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64") + set(_cross_arch "linux-aarch64") + elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armhf") # For raspbian + # TODO: verify + set(_cross_arch "linux-armv4") + endif () +endif () + +ExternalProject_Add(dep_OpenSSL + EXCLUDE_FROM_ALL ON + URL "https://github.com/openssl/openssl/archive/OpenSSL_1_1_0l.tar.gz" + URL_HASH SHA256=e2acf0cf58d9bff2b42f2dc0aee79340c8ffe2c5e45d3ca4533dd5d4f5775b1d + DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/OpenSSL + BUILD_IN_SOURCE ON + CONFIGURE_COMMAND ${_conf_cmd} ${_cross_arch} + "--prefix=${DESTDIR}/usr/local" + ${_cross_comp_prefix_line} + no-shared + no-ssl3-method + no-dynamic-engine + -Wa,--noexecstack + BUILD_COMMAND make depend && make "-j${NPROC}" + INSTALL_COMMAND make install_sw +) \ No newline at end of file diff --git a/deps/OpenVDB/OpenVDB.cmake b/deps/OpenVDB/OpenVDB.cmake new file mode 100644 index 000000000..10dc2d916 --- /dev/null +++ b/deps/OpenVDB/OpenVDB.cmake @@ -0,0 +1,36 @@ +if(BUILD_SHARED_LIBS) + set(_build_shared ON) + set(_build_static OFF) +else() + set(_build_shared OFF) + set(_build_static ON) +endif() + +prusaslicer_add_cmake_project(OpenVDB + URL https://github.com/tamasmeszaros/openvdb/archive/refs/tags/v6.2.1-prusa3d.zip #v6.2.1 patched + URL_HASH SHA256=caf9f0c91976722883ff9cb32420ef142af22f7e625fc643b91c23d6e4172f62 + DEPENDS dep_TBB dep_Blosc dep_OpenEXR dep_Boost + CMAKE_ARGS + -DCMAKE_POSITION_INDEPENDENT_CODE=ON + -DOPENVDB_BUILD_PYTHON_MODULE=OFF + -DUSE_BLOSC=ON + -DOPENVDB_CORE_SHARED=${_build_shared} + -DOPENVDB_CORE_STATIC=${_build_static} + -DOPENVDB_ENABLE_RPATH:BOOL=OFF + -DTBB_STATIC=${_build_static} + -DOPENVDB_BUILD_VDB_PRINT=ON + -DDISABLE_DEPENDENCY_VERSION_CHECKS=ON # Centos6 has old zlib +) + +if (MSVC) + if (${DEP_DEBUG}) + ExternalProject_Get_Property(dep_OpenVDB BINARY_DIR) + ExternalProject_Add_Step(dep_OpenVDB build_debug + DEPENDEES build + DEPENDERS install + COMMAND ${CMAKE_COMMAND} ../dep_OpenVDB -DOPENVDB_BUILD_VDB_PRINT=OFF + COMMAND msbuild /m /P:Configuration=Debug INSTALL.vcxproj + WORKING_DIRECTORY "${BINARY_DIR}" + ) + endif () +endif () \ No newline at end of file diff --git a/deps/PNG/PNG.cmake b/deps/PNG/PNG.cmake index e07afec6d..f97ebb4e0 100644 --- a/deps/PNG/PNG.cmake +++ b/deps/PNG/PNG.cmake @@ -5,10 +5,18 @@ else () set(_disable_neon_extension "") endif () +set(_patch_step "") +if (APPLE) + set(_patch_step PATCH_COMMAND ${PATCH_CMD} ${CMAKE_CURRENT_LIST_DIR}/PNG.patch) +endif () + prusaslicer_add_cmake_project(PNG - GIT_REPOSITORY https://github.com/glennrp/libpng.git - GIT_TAG v1.6.35 + # GIT_REPOSITORY https://github.com/glennrp/libpng.git + # GIT_TAG v1.6.35 + URL https://github.com/glennrp/libpng/archive/refs/tags/v1.6.35.zip + URL_HASH SHA256=3d22d46c566b1761a0e15ea397589b3a5f36ac09b7c785382e6470156c04247f DEPENDS ${ZLIB_PKG} + "${_patch_step}" CMAKE_ARGS -DPNG_SHARED=OFF -DPNG_STATIC=ON diff --git a/deps/PNG/PNG.patch b/deps/PNG/PNG.patch new file mode 100644 index 000000000..3e6a70d51 --- /dev/null +++ b/deps/PNG/PNG.patch @@ -0,0 +1,26 @@ +Common subdirectories: ../libpng-1.6.35-orig/arm and ./arm +Common subdirectories: ../libpng-1.6.35-orig/contrib and ./contrib +Common subdirectories: ../libpng-1.6.35-orig/intel and ./intel +Common subdirectories: ../libpng-1.6.35-orig/mips and ./mips +Only in ./: PNG.patch +diff -u ../libpng-1.6.35-orig/pngrutil.c ./pngrutil.c +--- ../libpng-1.6.35-orig/pngrutil.c 2018-07-15 20:58:00.000000000 +0200 ++++ ./pngrutil.c 2021-03-24 15:59:38.687108444 +0100 +@@ -422,13 +422,6 @@ + png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; + } + +-#if ZLIB_VERNUM >= 0x1290 && \ +- defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_IGNORE_ADLER32) +- if (((png_ptr->options >> PNG_IGNORE_ADLER32) & 3) == PNG_OPTION_ON) +- /* Turn off validation of the ADLER32 checksum in IDAT chunks */ +- ret = inflateValidate(&png_ptr->zstream, 0); +-#endif +- + if (ret == Z_OK) + png_ptr->zowner = owner; + +Common subdirectories: ../libpng-1.6.35-orig/powerpc and ./powerpc +Common subdirectories: ../libpng-1.6.35-orig/projects and ./projects +Common subdirectories: ../libpng-1.6.35-orig/scripts and ./scripts +Common subdirectories: ../libpng-1.6.35-orig/tests and ./tests diff --git a/deps/Qhull/Qhull.cmake b/deps/Qhull/Qhull.cmake new file mode 100644 index 000000000..fedec550c --- /dev/null +++ b/deps/Qhull/Qhull.cmake @@ -0,0 +1,11 @@ +include(GNUInstallDirs) +prusaslicer_add_cmake_project(Qhull + URL "https://github.com/qhull/qhull/archive/v8.0.1.zip" + URL_HASH SHA256=5287f5edd6a0372588f5d6640799086a4033d89d19711023ef8229dd9301d69b + CMAKE_ARGS + -DINCLUDE_INSTALL_DIR=${CMAKE_INSTALL_INCLUDEDIR} +) + +if (MSVC) + add_debug_dep(dep_Qhull) +endif () \ No newline at end of file diff --git a/deps/TBB/TBB.cmake b/deps/TBB/TBB.cmake new file mode 100644 index 000000000..7315716e0 --- /dev/null +++ b/deps/TBB/TBB.cmake @@ -0,0 +1,17 @@ +prusaslicer_add_cmake_project( + TBB + URL "https://github.com/wjakob/tbb/archive/a0dc9bf76d0120f917b641ed095360448cabc85b.tar.gz" + URL_HASH SHA256=0545cb6033bd1873fcae3ea304def720a380a88292726943ae3b9b207f322efe + CMAKE_ARGS + -DTBB_BUILD_SHARED=OFF + -DTBB_BUILD_TESTS=OFF + -DTBB_BUILD_TESTS=OFF + -DCMAKE_POSITION_INDEPENDENT_CODE=ON + -DCMAKE_DEBUG_POSTFIX=_debug +) + +if (MSVC) + add_debug_dep(dep_TBB) +endif () + + diff --git a/deps/TIFF/TIFF.cmake b/deps/TIFF/TIFF.cmake new file mode 100644 index 000000000..f92dd0811 --- /dev/null +++ b/deps/TIFF/TIFF.cmake @@ -0,0 +1,13 @@ +find_package(OpenGL QUIET REQUIRED) + +prusaslicer_add_cmake_project(TIFF + URL https://gitlab.com/libtiff/libtiff/-/archive/v4.1.0/libtiff-v4.1.0.zip + URL_HASH SHA256=c56edfacef0a60c0de3e6489194fcb2f24c03dbb550a8a7de5938642d045bd32 + DEPENDS ${ZLIB_PKG} ${PNG_PKG} dep_JPEG + CMAKE_ARGS + -Dlzma:BOOL=OFF + -Dwebp:BOOL=OFF + -Djbig:BOOL=OFF + -Dzstd:BOOL=OFF + -Dpixarlog:BOOL=OFF +) diff --git a/deps/ZLIB/0001-Respect-BUILD_SHARED_LIBS.patch b/deps/ZLIB/0001-Respect-BUILD_SHARED_LIBS.patch index e65ec0e65..f176ce287 100644 --- a/deps/ZLIB/0001-Respect-BUILD_SHARED_LIBS.patch +++ b/deps/ZLIB/0001-Respect-BUILD_SHARED_LIBS.patch @@ -1,17 +1,8 @@ -From 0c64e33bc2e4e7c011f5a64f5d9c7571a434cc86 Mon Sep 17 00:00:00 2001 -From: tamasmeszaros -Date: Sat, 16 Nov 2019 13:43:17 +0100 -Subject: [PATCH] Respect BUILD_SHARED_LIBS - ---- - CMakeLists.txt | 14 ++++++++------ - 1 file changed, 8 insertions(+), 6 deletions(-) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 0fe939d..01dfea1 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -183,10 +183,12 @@ if(MINGW) +Common subdirectories: ../zlib-1.2.11/amiga and ./amiga +diff -u ../zlib-1.2.11/CMakeLists.txt ./CMakeLists.txt +--- ../zlib-1.2.11/CMakeLists.txt 2017-01-15 09:29:40.000000000 +0100 ++++ ./CMakeLists.txt 2021-03-24 15:24:48.190291072 +0100 +@@ -183,10 +183,12 @@ set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) endif(MINGW) @@ -28,7 +19,7 @@ index 0fe939d..01dfea1 100644 if(NOT CYGWIN) # This property causes shared libraries on Linux to have the full version -@@ -201,7 +203,7 @@ endif() +@@ -201,7 +203,7 @@ if(UNIX) # On unix-like platforms the library is almost always called libz @@ -37,7 +28,7 @@ index 0fe939d..01dfea1 100644 if(NOT APPLE) set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"") endif() -@@ -211,7 +213,7 @@ elseif(BUILD_SHARED_LIBS AND WIN32) +@@ -211,7 +213,7 @@ endif() if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) @@ -46,6 +37,15 @@ index 0fe939d..01dfea1 100644 RUNTIME DESTINATION "${INSTALL_BIN_DIR}" ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" LIBRARY DESTINATION "${INSTALL_LIB_DIR}" ) --- -2.16.2.windows.1 - +Common subdirectories: ../zlib-1.2.11/contrib and ./contrib +Common subdirectories: ../zlib-1.2.11/doc and ./doc +Common subdirectories: ../zlib-1.2.11/examples and ./examples +Common subdirectories: ../zlib-1.2.11/msdos and ./msdos +Common subdirectories: ../zlib-1.2.11/nintendods and ./nintendods +Common subdirectories: ../zlib-1.2.11/old and ./old +Common subdirectories: ../zlib-1.2.11/os400 and ./os400 +Common subdirectories: ../zlib-1.2.11/qnx and ./qnx +Common subdirectories: ../zlib-1.2.11/test and ./test +Common subdirectories: ../zlib-1.2.11/watcom and ./watcom +Common subdirectories: ../zlib-1.2.11/win32 and ./win32 +Only in ./: ZLIB.patch diff --git a/deps/ZLIB/ZLIB.cmake b/deps/ZLIB/ZLIB.cmake index 574f5b134..916f3318b 100644 --- a/deps/ZLIB/ZLIB.cmake +++ b/deps/ZLIB/ZLIB.cmake @@ -1,8 +1,9 @@ prusaslicer_add_cmake_project(ZLIB - GIT_REPOSITORY https://github.com/madler/zlib.git - GIT_TAG v1.2.11 - PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && - ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_LIST_DIR}/0001-Respect-BUILD_SHARED_LIBS.patch + # GIT_REPOSITORY https://github.com/madler/zlib.git + # GIT_TAG v1.2.11 + URL https://github.com/madler/zlib/archive/refs/tags/v1.2.11.zip + URL_HASH SHA256=f5cc4ab910db99b2bdbba39ebbdc225ffc2aa04b4057bc2817f1b94b6978cfc3 + PATCH_COMMAND ${PATCH_CMD} ${CMAKE_CURRENT_LIST_DIR}/0001-Respect-BUILD_SHARED_LIBS.patch CMAKE_ARGS -DSKIP_INSTALL_FILES=ON # Prevent installation of man pages et al. -DCMAKE_POSITION_INDEPENDENT_CODE=ON diff --git a/deps/deps-linux.cmake b/deps/deps-linux.cmake index c81d6785d..fbe7b711b 100644 --- a/deps/deps-linux.cmake +++ b/deps/deps-linux.cmake @@ -7,98 +7,4 @@ 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 () - -#TODO UDEV - -ExternalProject_Add(dep_boost - EXCLUDE_FROM_ALL 1 - URL "https://boostorg.jfrog.io/artifactory/main/release/1.75.0/source/boost_1_75_0.tar.gz" - URL_HASH SHA256=aeb26f80e80945e82ee93e5939baebdca47b9dee80a07d3144be1e1a6a66dd6a - BUILD_IN_SOURCE 1 - CONFIGURE_COMMAND ./bootstrap.sh - --with-libraries=system,iostreams,filesystem,thread,log,locale,regex,date_time - "--prefix=${DESTDIR}/usr/local" - BUILD_COMMAND ./b2 - -j ${NPROC} - --reconfigure - link=static - variant=release - threading=multi - boost.locale.icu=off - --disable-icu - cflags=-fPIC - cxxflags=-fPIC - install - INSTALL_COMMAND "" # b2 does that already -) - -ExternalProject_Add(dep_libopenssl - EXCLUDE_FROM_ALL 1 - URL "https://github.com/openssl/openssl/archive/OpenSSL_1_1_0l.tar.gz" - URL_HASH SHA256=e2acf0cf58d9bff2b42f2dc0aee79340c8ffe2c5e45d3ca4533dd5d4f5775b1d - BUILD_IN_SOURCE 1 - CONFIGURE_COMMAND ./config - "--prefix=${DESTDIR}/usr/local" - "--libdir=lib" - no-shared - no-ssl3-method - no-dynamic-engine - -Wa,--noexecstack - BUILD_COMMAND make depend && make "-j${NPROC}" - INSTALL_COMMAND make install_sw -) - -ExternalProject_Add(dep_libcurl - EXCLUDE_FROM_ALL 1 - DEPENDS dep_libopenssl - URL "https://curl.haxx.se/download/curl-7.58.0.tar.gz" - URL_HASH SHA256=cc245bf9a1a42a45df491501d97d5593392a03f7b4f07b952793518d97666115 - BUILD_IN_SOURCE 1 - CONFIGURE_COMMAND ./configure - --enable-static - --disable-shared - "--with-ssl=${DESTDIR}/usr/local" - --with-pic - --enable-ipv6 - --enable-versioned-symbols - --enable-threaded-resolver - --with-random=/dev/urandom - - # CA root certificate paths will be set for openssl at runtime. - --without-ca-bundle - --without-ca-path - --with-ca-fallback # to look for the ssl backend's ca store - - --disable-ldap - --disable-ldaps - --disable-manual - --disable-rtsp - --disable-dict - --disable-telnet - --disable-pop3 - --disable-imap - --disable-smb - --disable-smtp - --disable-gopher - --without-gssapi - --without-libpsl - --without-libidn2 - --without-gnutls - --without-polarssl - --without-mbedtls - --without-cyassl - --without-nss - --without-axtls - --without-brotli - --without-libmetalink - --without-libssh - --without-libssh2 - --without-librtmp - --without-nghttp2 - --without-zsh-functions-dir - BUILD_COMMAND make "-j${NPROC}" - INSTALL_COMMAND make install "DESTDIR=${DESTDIR}" -) -add_dependencies(dep_openvdb dep_boost) - +# endif () \ No newline at end of file diff --git a/deps/deps-macos.cmake b/deps/deps-macos.cmake index de77dafa8..42afc623d 100644 --- a/deps/deps-macos.cmake +++ b/deps/deps-macos.cmake @@ -16,76 +16,76 @@ set(DEP_CMAKE_OPTS include("deps-unix-common.cmake") -ExternalProject_Add(dep_boost - EXCLUDE_FROM_ALL 1 - URL "https://boostorg.jfrog.io/artifactory/main/release/1.75.0/source/boost_1_75_0.tar.gz" - URL_HASH SHA256=aeb26f80e80945e82ee93e5939baebdca47b9dee80a07d3144be1e1a6a66dd6a - BUILD_IN_SOURCE 1 - CONFIGURE_COMMAND ./bootstrap.sh - --with-toolset=clang - --with-libraries=system,iostreams,filesystem,thread,log,locale,regex,date_time - "--prefix=${DESTDIR}/usr/local" - BUILD_COMMAND ./b2 - -j ${NPROC} - --reconfigure - toolset=clang - link=static - variant=release - threading=multi - boost.locale.icu=off - --disable-icu - "cflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET}" - "cxxflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET}" - "mflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET}" - "mmflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET}" - install - INSTALL_COMMAND "" # b2 does that already -) +# ExternalProject_Add(dep_boost +# EXCLUDE_FROM_ALL 1 +# URL "https://dl.bintray.com/boostorg/release/1.75.0/source/boost_1_75_0.tar.gz" +# URL_HASH SHA256=aeb26f80e80945e82ee93e5939baebdca47b9dee80a07d3144be1e1a6a66dd6a +# BUILD_IN_SOURCE 1 +# CONFIGURE_COMMAND ./bootstrap.sh +# --with-toolset=clang +# --with-libraries=system,iostreams,filesystem,thread,log,locale,regex,date_time +# "--prefix=${DESTDIR}/usr/local" +# BUILD_COMMAND ./b2 +# -j ${NPROC} +# --reconfigure +# toolset=clang +# link=static +# variant=release +# threading=multi +# boost.locale.icu=off +# --disable-icu +# "cflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET}" +# "cxxflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET}" +# "mflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET}" +# "mmflags=-fPIC -mmacosx-version-min=${DEP_OSX_TARGET}" +# install +# INSTALL_COMMAND "" # b2 does that already +# ) -ExternalProject_Add(dep_libcurl - EXCLUDE_FROM_ALL 1 - URL "https://curl.haxx.se/download/curl-7.58.0.tar.gz" - URL_HASH SHA256=cc245bf9a1a42a45df491501d97d5593392a03f7b4f07b952793518d97666115 - BUILD_IN_SOURCE 1 - CONFIGURE_COMMAND ./configure - --enable-static - --disable-shared - "--with-ssl=${DESTDIR}/usr/local" - --with-pic - --enable-ipv6 - --enable-versioned-symbols - --enable-threaded-resolver - --with-darwinssl - --without-ssl # disables OpenSSL - --disable-ldap - --disable-ldaps - --disable-manual - --disable-rtsp - --disable-dict - --disable-telnet - --disable-pop3 - --disable-imap - --disable-smb - --disable-smtp - --disable-gopher - --without-gssapi - --without-libpsl - --without-libidn2 - --without-gnutls - --without-polarssl - --without-mbedtls - --without-cyassl - --without-nss - --without-axtls - --without-brotli - --without-libmetalink - --without-libssh - --without-libssh2 - --without-librtmp - --without-nghttp2 - --without-zsh-functions-dir - BUILD_COMMAND make "-j${NPROC}" - INSTALL_COMMAND make install "DESTDIR=${DESTDIR}" -) -add_dependencies(dep_openvdb dep_boost) +# ExternalProject_Add(dep_libcurl +# EXCLUDE_FROM_ALL 1 +# URL "https://curl.haxx.se/download/curl-7.58.0.tar.gz" +# URL_HASH SHA256=cc245bf9a1a42a45df491501d97d5593392a03f7b4f07b952793518d97666115 +# BUILD_IN_SOURCE 1 +# CONFIGURE_COMMAND ./configure +# --enable-static +# --disable-shared +# "--with-ssl=${DESTDIR}/usr/local" +# --with-pic +# --enable-ipv6 +# --enable-versioned-symbols +# --enable-threaded-resolver +# --with-darwinssl +# --without-ssl # disables OpenSSL +# --disable-ldap +# --disable-ldaps +# --disable-manual +# --disable-rtsp +# --disable-dict +# --disable-telnet +# --disable-pop3 +# --disable-imap +# --disable-smb +# --disable-smtp +# --disable-gopher +# --without-gssapi +# --without-libpsl +# --without-libidn2 +# --without-gnutls +# --without-polarssl +# --without-mbedtls +# --without-cyassl +# --without-nss +# --without-axtls +# --without-brotli +# --without-libmetalink +# --without-libssh +# --without-libssh2 +# --without-librtmp +# --without-nghttp2 +# --without-zsh-functions-dir +# BUILD_COMMAND make "-j${NPROC}" +# INSTALL_COMMAND make install "DESTDIR=${DESTDIR}" +# ) +# add_dependencies(dep_openvdb dep_boost) \ No newline at end of file diff --git a/deps/deps-mingw.cmake b/deps/deps-mingw.cmake index cae7fc371..b86554f64 100644 --- a/deps/deps-mingw.cmake +++ b/deps/deps-mingw.cmake @@ -6,57 +6,3 @@ find_package(Git REQUIRED) # TODO make sure to build tbb with -flifetime-dse=1 include("deps-unix-common.cmake") - -ExternalProject_Add(dep_boost - EXCLUDE_FROM_ALL 1 - URL "https://boostorg.jfrog.io/artifactory/main/release/1.75.0/source/boost_1_75_0.tar.gz" - URL_HASH SHA256=aeb26f80e80945e82ee93e5939baebdca47b9dee80a07d3144be1e1a6a66dd6a - BUILD_IN_SOURCE 1 - CONFIGURE_COMMAND bootstrap.bat - BUILD_COMMAND b2.exe - -j "${NPROC}" - --with-system - --with-filesystem - --with-thread - --with-log - --with-locale - --with-regex - --with-date_time - "--prefix=${DESTDIR}/usr/local" - "address-model=${DEPS_BITS}" - "toolset=${DEP_BOOST_TOOLSET}" - link=static - define=BOOST_USE_WINAPI_VERSION=0x0502 - variant=release - threading=multi - boost.locale.icu=off - "${DEP_BOOST_DEBUG}" release install - INSTALL_COMMAND "" # b2 does that already -) - -ExternalProject_Add(dep_libcurl - EXCLUDE_FROM_ALL 1 - URL "https://curl.haxx.se/download/curl-7.58.0.tar.gz" - URL_HASH SHA256=cc245bf9a1a42a45df491501d97d5593392a03f7b4f07b952793518d97666115 - CMAKE_ARGS - -DBUILD_SHARED_LIBS=OFF - -DBUILD_TESTING=OFF - -DCURL_STATICLIB=ON - -DCURL_STATIC_CRT=ON - -DENABLE_THREADED_RESOLVER=ON - -DCURL_DISABLE_FTP=ON - -DCURL_DISABLE_LDAP=ON - -DCURL_DISABLE_LDAPS=ON - -DCURL_DISABLE_TELNET=ON - -DCURL_DISABLE_DICT=ON - -DCURL_DISABLE_FILE=ON - -DCURL_DISABLE_TFTP=ON - -DCURL_DISABLE_RTSP=ON - -DCURL_DISABLE_POP3=ON - -DCURL_DISABLE_IMAP=ON - -DCURL_DISABLE_SMTP=ON - -DCURL_DISABLE_GOPHER=ON - -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local - ${DEP_CMAKE_OPTS} -) - diff --git a/deps/deps-unix-common.cmake b/deps/deps-unix-common.cmake index 46c9f8864..d715e81a1 100644 --- a/deps/deps-unix-common.cmake +++ b/deps/deps-unix-common.cmake @@ -17,113 +17,3 @@ endif () # if (NOT EXPAT_FOUND) # message(WARNING "No EXPAT dev package found in system, building static library. Consider installing the system package.") # endif () - -ExternalProject_Add(dep_tbb - EXCLUDE_FROM_ALL 1 - URL "https://github.com/wjakob/tbb/archive/a0dc9bf76d0120f917b641ed095360448cabc85b.tar.gz" - URL_HASH SHA256=0545cb6033bd1873fcae3ea304def720a380a88292726943ae3b9b207f322efe - CMAKE_ARGS - -DTBB_BUILD_SHARED=OFF - -DTBB_BUILD_TESTS=OFF - -DCMAKE_CXX_FLAGS=${TBB_MINGW_WORKAROUND} - -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local - ${DEP_CMAKE_OPTS} -) - -ExternalProject_Add(dep_gtest - EXCLUDE_FROM_ALL 1 - URL "https://github.com/google/googletest/archive/release-1.8.1.tar.gz" - URL_HASH SHA256=9bf1fe5182a604b4135edc1a425ae356c9ad15e9b23f9f12a02e80184c3a249c - CMAKE_ARGS -DBUILD_GMOCK=OFF ${DEP_CMAKE_OPTS} -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local -) - -ExternalProject_Add(dep_cereal - EXCLUDE_FROM_ALL 1 - URL "https://github.com/USCiLab/cereal/archive/v1.2.2.tar.gz" -# URL_HASH SHA256=c6dd7a5701fff8ad5ebb45a3dc8e757e61d52658de3918e38bab233e7fd3b4ae - CMAKE_ARGS - -DJUST_INSTALL_CEREAL=on - -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local - ${DEP_CMAKE_OPTS} -) - -ExternalProject_Add(dep_nlopt - EXCLUDE_FROM_ALL 1 - URL "https://github.com/stevengj/nlopt/archive/v2.5.0.tar.gz" - URL_HASH SHA256=c6dd7a5701fff8ad5ebb45a3dc8e757e61d52658de3918e38bab233e7fd3b4ae - CMAKE_ARGS - -DBUILD_SHARED_LIBS=OFF - -DNLOPT_PYTHON=OFF - -DNLOPT_OCTAVE=OFF - -DNLOPT_MATLAB=OFF - -DNLOPT_GUILE=OFF - -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local - ${DEP_CMAKE_OPTS} -) - -ExternalProject_Add(dep_qhull - EXCLUDE_FROM_ALL 1 - #URL "https://github.com/qhull/qhull/archive/v7.3.2.tar.gz" - #URL_HASH SHA256=619c8a954880d545194bc03359404ef36a1abd2dde03678089459757fd790cb0 - GIT_REPOSITORY https://github.com/qhull/qhull.git - GIT_TAG 7afedcc73666e46a9f1d74632412ebecf53b1b30 # v7.3.2 plus the mac build patch - CMAKE_ARGS - -DBUILD_SHARED_LIBS=OFF - -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local - ${DEP_CMAKE_OPTS} -) - -ExternalProject_Add(dep_blosc - EXCLUDE_FROM_ALL 1 - GIT_REPOSITORY https://github.com/Blosc/c-blosc.git - GIT_TAG e63775855294b50820ef44d1b157f4de1cc38d3e #v1.17.0 - DEPENDS - CMAKE_ARGS - -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local - -DBUILD_SHARED_LIBS=OFF - -DCMAKE_POSITION_INDEPENDENT_CODE=ON - -DCMAKE_DEBUG_POSTFIX=d - -DBUILD_SHARED=OFF - -DBUILD_STATIC=ON - -DBUILD_TESTS=OFF - -DBUILD_BENCHMARKS=OFF - -DPREFER_EXTERNAL_ZLIB=ON - PATCH_COMMAND ${GIT_EXECUTABLE} reset --hard && git clean -df && - ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/blosc-mods.patch -) - -ExternalProject_Add(dep_openexr - EXCLUDE_FROM_ALL 1 - GIT_REPOSITORY https://github.com/openexr/openexr.git - GIT_TAG eae0e337c9f5117e78114fd05f7a415819df413a #v2.4.0 - CMAKE_ARGS - -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local - -DBUILD_SHARED_LIBS=OFF - -DCMAKE_POSITION_INDEPENDENT_CODE=ON - -DBUILD_TESTING=OFF - -DPYILMBASE_ENABLE:BOOL=OFF - -DOPENEXR_VIEWERS_ENABLE:BOOL=OFF - -DOPENEXR_BUILD_UTILS:BOOL=OFF -) - -ExternalProject_Add(dep_openvdb - EXCLUDE_FROM_ALL 1 - GIT_REPOSITORY https://github.com/AcademySoftwareFoundation/openvdb.git - GIT_TAG aebaf8d95be5e57fd33949281ec357db4a576c2e #v6.2.1 - DEPENDS dep_blosc dep_openexr dep_tbb - CMAKE_ARGS - -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local - -DCMAKE_DEBUG_POSTFIX=d - -DCMAKE_PREFIX_PATH=${DESTDIR}/usr/local - -DBUILD_SHARED_LIBS=OFF - -DCMAKE_POSITION_INDEPENDENT_CODE=ON - -DOPENVDB_BUILD_PYTHON_MODULE=OFF - -DUSE_BLOSC=ON - -DOPENVDB_CORE_SHARED=OFF - -DOPENVDB_CORE_STATIC=ON - -DTBB_STATIC=ON - -DOPENVDB_BUILD_VDB_PRINT=ON - -DDISABLE_DEPENDENCY_VERSION_CHECKS=ON - PATCH_COMMAND PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && - ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/openvdb-mods.patch -) diff --git a/deps/deps-windows.cmake b/deps/deps-windows.cmake index fc9f55f5f..7288cfe6f 100644 --- a/deps/deps-windows.cmake +++ b/deps/deps-windows.cmake @@ -53,154 +53,6 @@ if (${DEP_DEBUG}) endif () endmacro() -ExternalProject_Add(dep_boost - EXCLUDE_FROM_ALL 1 - URL "https://boostorg.jfrog.io/artifactory/main/release/1.75.0/source/boost_1_75_0.tar.gz" - URL_HASH SHA256=aeb26f80e80945e82ee93e5939baebdca47b9dee80a07d3144be1e1a6a66dd6a - BUILD_IN_SOURCE 1 - CONFIGURE_COMMAND bootstrap.bat - BUILD_COMMAND b2.exe - -j "${NPROC}" - --with-system - --with-iostreams - --with-filesystem - --with-thread - --with-log - --with-locale - --with-regex - --with-date_time - "--prefix=${DESTDIR}/usr/local" - "address-model=${DEPS_BITS}" - "toolset=${DEP_BOOST_TOOLSET}" - link=static - variant=release - threading=multi - boost.locale.icu=off - --disable-icu - "${DEP_BOOST_DEBUG}" release install - INSTALL_COMMAND "" # b2 does that already -) - -ExternalProject_Add(dep_tbb - EXCLUDE_FROM_ALL 1 - URL "https://github.com/wjakob/tbb/archive/a0dc9bf76d0120f917b641ed095360448cabc85b.tar.gz" - URL_HASH SHA256=0545cb6033bd1873fcae3ea304def720a380a88292726943ae3b9b207f322efe - CMAKE_GENERATOR "${DEP_MSVC_GEN}" - CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}" - CMAKE_ARGS - -DCMAKE_DEBUG_POSTFIX=_debug - -DTBB_BUILD_SHARED=OFF - -DTBB_BUILD_TESTS=OFF - "-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local" - BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj - INSTALL_COMMAND "" -) - -add_debug_dep(dep_tbb) - -# ExternalProject_Add(dep_gtest -# EXCLUDE_FROM_ALL 1 -# URL "https://github.com/google/googletest/archive/release-1.8.1.tar.gz" -# URL_HASH SHA256=9bf1fe5182a604b4135edc1a425ae356c9ad15e9b23f9f12a02e80184c3a249c -# CMAKE_GENERATOR "${DEP_MSVC_GEN}" -# CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}" -# CMAKE_ARGS -# -DBUILD_GMOCK=OFF -# -Dgtest_force_shared_crt=ON -# -DCMAKE_POSITION_INDEPENDENT_CODE=ON -# "-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local" -# BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj -# INSTALL_COMMAND "" -# ) - -# add_debug_dep(dep_gtest) - -ExternalProject_Add(dep_cereal - EXCLUDE_FROM_ALL 1 - URL "https://github.com/USCiLab/cereal/archive/v1.2.2.tar.gz" -# URL_HASH SHA256=c6dd7a5701fff8ad5ebb45a3dc8e757e61d52658de3918e38bab233e7fd3b4ae - CMAKE_GENERATOR "${DEP_MSVC_GEN}" - CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}" - CMAKE_ARGS - -DJUST_INSTALL_CEREAL=on - "-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local" - BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj - INSTALL_COMMAND "" -) - -ExternalProject_Add(dep_nlopt - EXCLUDE_FROM_ALL 1 - URL "https://github.com/stevengj/nlopt/archive/v2.5.0.tar.gz" - URL_HASH SHA256=c6dd7a5701fff8ad5ebb45a3dc8e757e61d52658de3918e38bab233e7fd3b4ae - CMAKE_GENERATOR "${DEP_MSVC_GEN}" - CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}" - CMAKE_ARGS - -DBUILD_SHARED_LIBS=OFF - -DNLOPT_PYTHON=OFF - -DNLOPT_OCTAVE=OFF - -DNLOPT_MATLAB=OFF - -DNLOPT_GUILE=OFF - -DCMAKE_POSITION_INDEPENDENT_CODE=ON - -DCMAKE_DEBUG_POSTFIX=d - "-DCMAKE_INSTALL_PREFIX:PATH=${DESTDIR}\\usr\\local" - BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj - INSTALL_COMMAND "" -) - -add_debug_dep(dep_nlopt) - -if (${DEPS_BITS} EQUAL 32) - set(DEP_LIBCURL_TARGET "x86") -else () - set(DEP_LIBCURL_TARGET "x64") -endif () - -ExternalProject_Add(dep_libcurl - EXCLUDE_FROM_ALL 1 - URL "https://curl.haxx.se/download/curl-7.58.0.tar.gz" - URL_HASH SHA256=cc245bf9a1a42a45df491501d97d5593392a03f7b4f07b952793518d97666115 - BUILD_IN_SOURCE 1 - CONFIGURE_COMMAND "" - BUILD_COMMAND cd winbuild && nmake /f Makefile.vc mode=static "VC=${DEP_VS_VER}" GEN_PDB=yes DEBUG=no "MACHINE=${DEP_LIBCURL_TARGET}" - INSTALL_COMMAND cd builds\\libcurl-*-release-*-winssl - && "${CMAKE_COMMAND}" -E copy_directory include "${DESTDIR}\\usr\\local\\include" - && "${CMAKE_COMMAND}" -E copy_directory lib "${DESTDIR}\\usr\\local\\lib" -) -if (${DEP_DEBUG}) - ExternalProject_Get_Property(dep_libcurl SOURCE_DIR) - ExternalProject_Add_Step(dep_libcurl build_debug - DEPENDEES build - DEPENDERS install - COMMAND cd winbuild && nmake /f Makefile.vc mode=static "VC=${DEP_VS_VER}" GEN_PDB=yes DEBUG=yes "MACHINE=${DEP_LIBCURL_TARGET}" - WORKING_DIRECTORY "${SOURCE_DIR}" - ) - ExternalProject_Add_Step(dep_libcurl install_debug - DEPENDEES install - COMMAND cd builds\\libcurl-*-debug-*-winssl - && "${CMAKE_COMMAND}" -E copy_directory include "${DESTDIR}\\usr\\local\\include" - && "${CMAKE_COMMAND}" -E copy_directory lib "${DESTDIR}\\usr\\local\\lib" - WORKING_DIRECTORY "${SOURCE_DIR}" - ) -endif () - -ExternalProject_Add(dep_qhull - EXCLUDE_FROM_ALL 1 - #URL "https://github.com/qhull/qhull/archive/v7.3.2.tar.gz" - #URL_HASH SHA256=619c8a954880d545194bc03359404ef36a1abd2dde03678089459757fd790cb0 - GIT_REPOSITORY https://github.com/qhull/qhull.git - GIT_TAG 7afedcc73666e46a9f1d74632412ebecf53b1b30 # v7.3.2 plus the mac build patch - CMAKE_GENERATOR "${DEP_MSVC_GEN}" - CMAKE_ARGS - -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local - -DBUILD_SHARED_LIBS=OFF - -DCMAKE_POSITION_INDEPENDENT_CODE=ON - -DCMAKE_DEBUG_POSTFIX=d - BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj - INSTALL_COMMAND "" -) - -add_debug_dep(dep_qhull) - if (${DEPS_BITS} EQUAL 32) set(DEP_WXWIDGETS_TARGET "") set(DEP_WXWIDGETS_LIBDIR "vc_lib") @@ -210,90 +62,3 @@ else () endif () find_package(Git REQUIRED) - -ExternalProject_Add(dep_blosc - EXCLUDE_FROM_ALL 1 - #URL https://github.com/Blosc/c-blosc/archive/v1.17.0.zip - #URL_HASH SHA256=7463a1df566704f212263312717ab2c36b45d45cba6cd0dccebf91b2cc4b4da9 - GIT_REPOSITORY https://github.com/Blosc/c-blosc.git - GIT_TAG e63775855294b50820ef44d1b157f4de1cc38d3e #v1.17.0 - CMAKE_GENERATOR "${DEP_MSVC_GEN}" - CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}" - CMAKE_ARGS - -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local - -DBUILD_SHARED_LIBS=OFF - -DCMAKE_POSITION_INDEPENDENT_CODE=ON - -DCMAKE_DEBUG_POSTFIX=d - -DBUILD_SHARED=OFF - -DBUILD_STATIC=ON - -DBUILD_TESTS=OFF - -DBUILD_BENCHMARKS=OFF - -DPREFER_EXTERNAL_ZLIB=ON - -DBLOSC_IS_SUBPROJECT:BOOL=ON - -DBLOSC_INSTALL:BOOL=ON - PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && - ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/blosc-mods.patch - BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj - INSTALL_COMMAND "" -) - -add_debug_dep(dep_blosc) - -ExternalProject_Add(dep_openexr - EXCLUDE_FROM_ALL 1 - GIT_REPOSITORY https://github.com/openexr/openexr.git - GIT_TAG eae0e337c9f5117e78114fd05f7a415819df413a #v2.4.0 - CMAKE_GENERATOR "${DEP_MSVC_GEN}" - CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}" - CMAKE_ARGS - -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local - -DBUILD_SHARED_LIBS=OFF - -DCMAKE_POSITION_INDEPENDENT_CODE=ON - -DBUILD_TESTING=OFF - -DPYILMBASE_ENABLE:BOOL=OFF - -DOPENEXR_VIEWERS_ENABLE:BOOL=OFF - -DOPENEXR_BUILD_UTILS:BOOL=OFF - BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj - INSTALL_COMMAND "" -) - -add_debug_dep(dep_openexr) - -ExternalProject_Add(dep_openvdb - EXCLUDE_FROM_ALL 1 - #URL https://github.com/AcademySoftwareFoundation/openvdb/archive/v6.2.1.zip - #URL_HASH SHA256=dc337399dce8e1c9f21f20e97b1ce7e4933cb0a63bb3b8b734d8fcc464aa0c48 - GIT_REPOSITORY https://github.com/AcademySoftwareFoundation/openvdb.git - GIT_TAG aebaf8d95be5e57fd33949281ec357db4a576c2e #v6.2.1 - DEPENDS dep_blosc dep_openexr dep_tbb dep_boost - CMAKE_GENERATOR "${DEP_MSVC_GEN}" - CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}" - CMAKE_ARGS - -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local - -DCMAKE_DEBUG_POSTFIX=d - -DCMAKE_PREFIX_PATH=${DESTDIR}/usr/local - -DBUILD_SHARED_LIBS=OFF - -DCMAKE_POSITION_INDEPENDENT_CODE=ON - -DOPENVDB_BUILD_PYTHON_MODULE=OFF - -DUSE_BLOSC=ON - -DOPENVDB_CORE_SHARED=OFF - -DOPENVDB_CORE_STATIC=ON - -DTBB_STATIC=ON - -DOPENVDB_BUILD_VDB_PRINT=ON - BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj - PATCH_COMMAND ${GIT_EXECUTABLE} checkout -f -- . && git clean -df && - ${GIT_EXECUTABLE} apply --whitespace=fix ${CMAKE_CURRENT_SOURCE_DIR}/openvdb-mods.patch - INSTALL_COMMAND "" -) - -if (${DEP_DEBUG}) - ExternalProject_Get_Property(dep_openvdb BINARY_DIR) - ExternalProject_Add_Step(dep_openvdb build_debug - DEPENDEES build - DEPENDERS install - COMMAND ${CMAKE_COMMAND} ../dep_openvdb -DOPENVDB_BUILD_VDB_PRINT=OFF - COMMAND msbuild /m /P:Configuration=Debug INSTALL.vcxproj - WORKING_DIRECTORY "${BINARY_DIR}" - ) -endif () - diff --git a/deps/openvdb-mods.patch b/deps/openvdb-mods.patch deleted file mode 100644 index d80d0ffde..000000000 --- a/deps/openvdb-mods.patch +++ /dev/null @@ -1,1908 +0,0 @@ -From d359098d9989ac7dbd149611d6ac941529fb4157 Mon Sep 17 00:00:00 2001 -From: tamasmeszaros -Date: Thu, 23 Jan 2020 17:17:36 +0100 -Subject: [PATCH] openvdb-mods - ---- - CMakeLists.txt | 3 - - cmake/CheckAtomic.cmake | 106 ++++++ - cmake/FindBlosc.cmake | 218 ------------ - cmake/FindCppUnit.cmake | 4 +- - cmake/FindIlmBase.cmake | 337 ------------------ - cmake/FindOpenEXR.cmake | 329 ------------------ - cmake/FindOpenVDB.cmake | 19 +- - cmake/FindTBB.cmake | 599 ++++++++++++++++---------------- - openvdb/CMakeLists.txt | 16 +- - openvdb/Grid.cc | 3 + - openvdb/PlatformConfig.h | 9 +- - openvdb/cmd/CMakeLists.txt | 4 +- - openvdb/unittest/CMakeLists.txt | 3 +- - openvdb/unittest/TestFile.cc | 2 +- - 14 files changed, 442 insertions(+), 1210 deletions(-) - create mode 100644 cmake/CheckAtomic.cmake - delete mode 100644 cmake/FindBlosc.cmake - delete mode 100644 cmake/FindIlmBase.cmake - delete mode 100644 cmake/FindOpenEXR.cmake - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 580b353..6d364c1 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -267,12 +267,9 @@ endif() - - if(OPENVDB_INSTALL_CMAKE_MODULES) - set(OPENVDB_CMAKE_MODULES -- cmake/FindBlosc.cmake - cmake/FindCppUnit.cmake - cmake/FindJemalloc.cmake -- cmake/FindIlmBase.cmake - cmake/FindLog4cplus.cmake -- cmake/FindOpenEXR.cmake - cmake/FindOpenVDB.cmake - cmake/FindTBB.cmake - cmake/OpenVDBGLFW3Setup.cmake -diff --git a/cmake/CheckAtomic.cmake b/cmake/CheckAtomic.cmake -new file mode 100644 -index 0000000..c045e30 ---- /dev/null -+++ b/cmake/CheckAtomic.cmake -@@ -0,0 +1,106 @@ -+# atomic builtins are required for threading support. -+ -+INCLUDE(CheckCXXSourceCompiles) -+INCLUDE(CheckLibraryExists) -+ -+# Sometimes linking against libatomic is required for atomic ops, if -+# the platform doesn't support lock-free atomics. -+ -+function(check_working_cxx_atomics varname) -+ set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) -+ set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11") -+ CHECK_CXX_SOURCE_COMPILES(" -+#include -+std::atomic x; -+int main() { -+ return x; -+} -+" ${varname}) -+ set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) -+endfunction(check_working_cxx_atomics) -+ -+function(check_working_cxx_atomics64 varname) -+ set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) -+ set(CMAKE_REQUIRED_FLAGS "-std=c++11 ${CMAKE_REQUIRED_FLAGS}") -+ CHECK_CXX_SOURCE_COMPILES(" -+#include -+#include -+std::atomic x (0); -+int main() { -+ uint64_t i = x.load(std::memory_order_relaxed); -+ return 0; -+} -+" ${varname}) -+ set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) -+endfunction(check_working_cxx_atomics64) -+ -+ -+# This isn't necessary on MSVC, so avoid command-line switch annoyance -+# by only running on GCC-like hosts. -+if (LLVM_COMPILER_IS_GCC_COMPATIBLE) -+ # First check if atomics work without the library. -+ check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB) -+ # If not, check if the library exists, and atomics work with it. -+ if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB) -+ check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC) -+ if( HAVE_LIBATOMIC ) -+ list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") -+ check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB) -+ if (NOT HAVE_CXX_ATOMICS_WITH_LIB) -+ message(FATAL_ERROR "Host compiler must support std::atomic!") -+ endif() -+ else() -+ message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.") -+ endif() -+ endif() -+endif() -+ -+# Check for 64 bit atomic operations. -+if(MSVC) -+ set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True) -+else() -+ check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB) -+endif() -+ -+# If not, check if the library exists, and atomics work with it. -+if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB) -+ check_library_exists(atomic __atomic_load_8 "" HAVE_CXX_LIBATOMICS64) -+ if(HAVE_CXX_LIBATOMICS64) -+ list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") -+ check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB) -+ if (NOT HAVE_CXX_ATOMICS64_WITH_LIB) -+ message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!") -+ endif() -+ else() -+ message(FATAL_ERROR "Host compiler appears to require libatomic for 64-bit operations, but cannot find it.") -+ endif() -+endif() -+ -+## TODO: This define is only used for the legacy atomic operations in -+## llvm's Atomic.h, which should be replaced. Other code simply -+## assumes C++11 works. -+CHECK_CXX_SOURCE_COMPILES(" -+#ifdef _MSC_VER -+#include -+#endif -+int main() { -+#ifdef _MSC_VER -+ volatile LONG val = 1; -+ MemoryBarrier(); -+ InterlockedCompareExchange(&val, 0, 1); -+ InterlockedIncrement(&val); -+ InterlockedDecrement(&val); -+#else -+ volatile unsigned long val = 1; -+ __sync_synchronize(); -+ __sync_val_compare_and_swap(&val, 1, 0); -+ __sync_add_and_fetch(&val, 1); -+ __sync_sub_and_fetch(&val, 1); -+#endif -+ return 0; -+ } -+" LLVM_HAS_ATOMICS) -+ -+if( NOT LLVM_HAS_ATOMICS ) -+ message(STATUS "Warning: LLVM will be built thread-unsafe because atomic builtins are missing") -+endif() -\ No newline at end of file -diff --git a/cmake/FindBlosc.cmake b/cmake/FindBlosc.cmake -deleted file mode 100644 -index 5aacfdd..0000000 ---- a/cmake/FindBlosc.cmake -+++ /dev/null -@@ -1,218 +0,0 @@ --# Copyright (c) DreamWorks Animation LLC --# --# All rights reserved. This software is distributed under the --# Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) --# --# Redistributions of source code must retain the above copyright --# and license notice and the following restrictions and disclaimer. --# --# * Neither the name of DreamWorks Animation nor the names of --# its contributors may be used to endorse or promote products derived --# from this software without specific prior written permission. --# --# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS --# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT --# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR --# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT --# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, --# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT --# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, --# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY --# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT --# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE --# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --# IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE --# LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. --# --#[=======================================================================[.rst: -- --FindBlosc ----------- -- --Find Blosc include dirs and libraries -- --Use this module by invoking find_package with the form:: -- -- find_package(Blosc -- [version] [EXACT] # Minimum or EXACT version e.g. 1.5.0 -- [REQUIRED] # Fail with error if Blosc is not found -- ) -- --IMPORTED Targets --^^^^^^^^^^^^^^^^ -- --``Blosc::blosc`` -- This module defines IMPORTED target Blosc::Blosc, if Blosc has been found. -- --Result Variables --^^^^^^^^^^^^^^^^ -- --This will define the following variables: -- --``Blosc_FOUND`` -- True if the system has the Blosc library. --``Blosc_VERSION`` -- The version of the Blosc library which was found. --``Blosc_INCLUDE_DIRS`` -- Include directories needed to use Blosc. --``Blosc_LIBRARIES`` -- Libraries needed to link to Blosc. --``Blosc_LIBRARY_DIRS`` -- Blosc library directories. -- --Cache Variables --^^^^^^^^^^^^^^^ -- --The following cache variables may also be set: -- --``Blosc_INCLUDE_DIR`` -- The directory containing ``blosc.h``. --``Blosc_LIBRARY`` -- The path to the Blosc library. -- --Hints --^^^^^ -- --Instead of explicitly setting the cache variables, the following variables --may be provided to tell this module where to look. -- --``BLOSC_ROOT`` -- Preferred installation prefix. --``BLOSC_INCLUDEDIR`` -- Preferred include directory e.g. /include --``BLOSC_LIBRARYDIR`` -- Preferred library directory e.g. /lib --``SYSTEM_LIBRARY_PATHS`` -- Paths appended to all include and lib searches. -- --#]=======================================================================] -- --mark_as_advanced( -- Blosc_INCLUDE_DIR -- Blosc_LIBRARY --) -- --# Append BLOSC_ROOT or $ENV{BLOSC_ROOT} if set (prioritize the direct cmake var) --set(_BLOSC_ROOT_SEARCH_DIR "") -- --if(BLOSC_ROOT) -- list(APPEND _BLOSC_ROOT_SEARCH_DIR ${BLOSC_ROOT}) --else() -- set(_ENV_BLOSC_ROOT $ENV{BLOSC_ROOT}) -- if(_ENV_BLOSC_ROOT) -- list(APPEND _BLOSC_ROOT_SEARCH_DIR ${_ENV_BLOSC_ROOT}) -- endif() --endif() -- --# Additionally try and use pkconfig to find blosc -- --find_package(PkgConfig) --pkg_check_modules(PC_Blosc QUIET blosc) -- --# ------------------------------------------------------------------------ --# Search for blosc include DIR --# ------------------------------------------------------------------------ -- --set(_BLOSC_INCLUDE_SEARCH_DIRS "") --list(APPEND _BLOSC_INCLUDE_SEARCH_DIRS -- ${BLOSC_INCLUDEDIR} -- ${_BLOSC_ROOT_SEARCH_DIR} -- ${PC_Blosc_INCLUDE_DIRS} -- ${SYSTEM_LIBRARY_PATHS} --) -- --# Look for a standard blosc header file. --find_path(Blosc_INCLUDE_DIR blosc.h -- NO_DEFAULT_PATH -- PATHS ${_BLOSC_INCLUDE_SEARCH_DIRS} -- PATH_SUFFIXES include --) -- --if(EXISTS "${Blosc_INCLUDE_DIR}/blosc.h") -- file(STRINGS "${Blosc_INCLUDE_DIR}/blosc.h" -- _blosc_version_major_string REGEX "#define BLOSC_VERSION_MAJOR +[0-9]+ " -- ) -- string(REGEX REPLACE "#define BLOSC_VERSION_MAJOR +([0-9]+).*$" "\\1" -- _blosc_version_major_string "${_blosc_version_major_string}" -- ) -- string(STRIP "${_blosc_version_major_string}" Blosc_VERSION_MAJOR) -- -- file(STRINGS "${Blosc_INCLUDE_DIR}/blosc.h" -- _blosc_version_minor_string REGEX "#define BLOSC_VERSION_MINOR +[0-9]+ " -- ) -- string(REGEX REPLACE "#define BLOSC_VERSION_MINOR +([0-9]+).*$" "\\1" -- _blosc_version_minor_string "${_blosc_version_minor_string}" -- ) -- string(STRIP "${_blosc_version_minor_string}" Blosc_VERSION_MINOR) -- -- unset(_blosc_version_major_string) -- unset(_blosc_version_minor_string) -- -- set(Blosc_VERSION ${Blosc_VERSION_MAJOR}.${Blosc_VERSION_MINOR}) --endif() -- --# ------------------------------------------------------------------------ --# Search for blosc lib DIR --# ------------------------------------------------------------------------ -- --set(_BLOSC_LIBRARYDIR_SEARCH_DIRS "") --list(APPEND _BLOSC_LIBRARYDIR_SEARCH_DIRS -- ${BLOSC_LIBRARYDIR} -- ${_BLOSC_ROOT_SEARCH_DIR} -- ${PC_Blosc_LIBRARY_DIRS} -- ${SYSTEM_LIBRARY_PATHS} --) -- --# Static library setup --if(UNIX AND BLOSC_USE_STATIC_LIBS) -- set(_BLOSC_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) -- set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") --endif() -- --set(BLOSC_PATH_SUFFIXES -- lib64 -- lib --) -- --find_library(Blosc_LIBRARY blosc -- NO_DEFAULT_PATH -- PATHS ${_BLOSC_LIBRARYDIR_SEARCH_DIRS} -- PATH_SUFFIXES ${BLOSC_PATH_SUFFIXES} --) -- --if(UNIX AND BLOSC_USE_STATIC_LIBS) -- set(CMAKE_FIND_LIBRARY_SUFFIXES ${_BLOSC_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) -- unset(_BLOSC_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES) --endif() -- --# ------------------------------------------------------------------------ --# Cache and set Blosc_FOUND --# ------------------------------------------------------------------------ -- --include(FindPackageHandleStandardArgs) --find_package_handle_standard_args(Blosc -- FOUND_VAR Blosc_FOUND -- REQUIRED_VARS -- Blosc_LIBRARY -- Blosc_INCLUDE_DIR -- VERSION_VAR Blosc_VERSION --) -- --if(Blosc_FOUND) -- set(Blosc_LIBRARIES ${Blosc_LIBRARY}) -- set(Blosc_INCLUDE_DIRS ${Blosc_INCLUDE_DIR}) -- set(Blosc_DEFINITIONS ${PC_Blosc_CFLAGS_OTHER}) -- -- get_filename_component(Blosc_LIBRARY_DIRS ${Blosc_LIBRARY} DIRECTORY) -- -- if(NOT TARGET Blosc::blosc) -- add_library(Blosc::blosc UNKNOWN IMPORTED) -- set_target_properties(Blosc::blosc PROPERTIES -- IMPORTED_LOCATION "${Blosc_LIBRARIES}" -- INTERFACE_COMPILE_DEFINITIONS "${Blosc_DEFINITIONS}" -- INTERFACE_INCLUDE_DIRECTORIES "${Blosc_INCLUDE_DIRS}" -- ) -- endif() --elseif(Blosc_FIND_REQUIRED) -- message(FATAL_ERROR "Unable to find Blosc") --endif() -diff --git a/cmake/FindCppUnit.cmake b/cmake/FindCppUnit.cmake -index e2beb93..a891624 100644 ---- a/cmake/FindCppUnit.cmake -+++ b/cmake/FindCppUnit.cmake -@@ -125,7 +125,7 @@ list(APPEND _CPPUNIT_INCLUDE_SEARCH_DIRS - - # Look for a standard cppunit header file. - find_path(CppUnit_INCLUDE_DIR cppunit/Portability.h -- NO_DEFAULT_PATH -+ # NO_DEFAULT_PATH - PATHS ${_CPPUNIT_INCLUDE_SEARCH_DIRS} - PATH_SUFFIXES include - ) -@@ -177,7 +177,7 @@ set(CPPUNIT_PATH_SUFFIXES - ) - - find_library(CppUnit_LIBRARY cppunit -- NO_DEFAULT_PATH -+ # NO_DEFAULT_PATH - PATHS ${_CPPUNIT_LIBRARYDIR_SEARCH_DIRS} - PATH_SUFFIXES ${CPPUNIT_PATH_SUFFIXES} - ) -diff --git a/cmake/FindIlmBase.cmake b/cmake/FindIlmBase.cmake -deleted file mode 100644 -index 9dbc252..0000000 ---- a/cmake/FindIlmBase.cmake -+++ /dev/null -@@ -1,337 +0,0 @@ --# Copyright (c) DreamWorks Animation LLC --# --# All rights reserved. This software is distributed under the --# Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) --# --# Redistributions of source code must retain the above copyright --# and license notice and the following restrictions and disclaimer. --# --# * Neither the name of DreamWorks Animation nor the names of --# its contributors may be used to endorse or promote products derived --# from this software without specific prior written permission. --# --# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS --# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT --# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR --# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT --# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, --# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT --# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, --# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY --# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT --# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE --# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --# IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE --# LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. --# --#[=======================================================================[.rst: -- --FindIlmBase ------------- -- --Find IlmBase include dirs and libraries -- --Use this module by invoking find_package with the form:: -- -- find_package(IlmBase -- [version] [EXACT] # Minimum or EXACT version -- [REQUIRED] # Fail with error if IlmBase is not found -- [COMPONENTS ...] # IlmBase libraries by their canonical name -- # e.g. "Half" for "libHalf" -- ) -- --IMPORTED Targets --^^^^^^^^^^^^^^^^ -- --``IlmBase::Half`` -- The Half library target. --``IlmBase::Iex`` -- The Iex library target. --``IlmBase::IexMath`` -- The IexMath library target. --``IlmBase::IlmThread`` -- The IlmThread library target. --``IlmBase::Imath`` -- The Imath library target. -- --Result Variables --^^^^^^^^^^^^^^^^ -- --This will define the following variables: -- --``IlmBase_FOUND`` -- True if the system has the IlmBase library. --``IlmBase_VERSION`` -- The version of the IlmBase library which was found. --``IlmBase_INCLUDE_DIRS`` -- Include directories needed to use IlmBase. --``IlmBase_LIBRARIES`` -- Libraries needed to link to IlmBase. --``IlmBase_LIBRARY_DIRS`` -- IlmBase library directories. --``IlmBase_{COMPONENT}_FOUND`` -- True if the system has the named IlmBase component. -- --Cache Variables --^^^^^^^^^^^^^^^ -- --The following cache variables may also be set: -- --``IlmBase_INCLUDE_DIR`` -- The directory containing ``IlmBase/config-auto.h``. --``IlmBase_{COMPONENT}_LIBRARY`` -- Individual component libraries for IlmBase --``IlmBase_{COMPONENT}_DLL`` -- Individual component dlls for IlmBase on Windows. -- --Hints --^^^^^ -- --Instead of explicitly setting the cache variables, the following variables --may be provided to tell this module where to look. -- --``ILMBASE_ROOT`` -- Preferred installation prefix. --``ILMBASE_INCLUDEDIR`` -- Preferred include directory e.g. /include --``ILMBASE_LIBRARYDIR`` -- Preferred library directory e.g. /lib --``SYSTEM_LIBRARY_PATHS`` -- Paths appended to all include and lib searches. -- --#]=======================================================================] -- --# Support new if() IN_LIST operator --if(POLICY CMP0057) -- cmake_policy(SET CMP0057 NEW) --endif() -- --mark_as_advanced( -- IlmBase_INCLUDE_DIR -- IlmBase_LIBRARY --) -- --set(_ILMBASE_COMPONENT_LIST -- Half -- Iex -- IexMath -- IlmThread -- Imath --) -- --if(IlmBase_FIND_COMPONENTS) -- set(ILMBASE_COMPONENTS_PROVIDED TRUE) -- set(_IGNORED_COMPONENTS "") -- foreach(COMPONENT ${IlmBase_FIND_COMPONENTS}) -- if(NOT ${COMPONENT} IN_LIST _ILMBASE_COMPONENT_LIST) -- list(APPEND _IGNORED_COMPONENTS ${COMPONENT}) -- endif() -- endforeach() -- -- if(_IGNORED_COMPONENTS) -- message(STATUS "Ignoring unknown components of IlmBase:") -- foreach(COMPONENT ${_IGNORED_COMPONENTS}) -- message(STATUS " ${COMPONENT}") -- endforeach() -- list(REMOVE_ITEM IlmBase_FIND_COMPONENTS ${_IGNORED_COMPONENTS}) -- endif() --else() -- set(ILMBASE_COMPONENTS_PROVIDED FALSE) -- set(IlmBase_FIND_COMPONENTS ${_ILMBASE_COMPONENT_LIST}) --endif() -- --# Append ILMBASE_ROOT or $ENV{ILMBASE_ROOT} if set (prioritize the direct cmake var) --set(_ILMBASE_ROOT_SEARCH_DIR "") -- --if(ILMBASE_ROOT) -- list(APPEND _ILMBASE_ROOT_SEARCH_DIR ${ILMBASE_ROOT}) --else() -- set(_ENV_ILMBASE_ROOT $ENV{ILMBASE_ROOT}) -- if(_ENV_ILMBASE_ROOT) -- list(APPEND _ILMBASE_ROOT_SEARCH_DIR ${_ENV_ILMBASE_ROOT}) -- endif() --endif() -- --# Additionally try and use pkconfig to find IlmBase -- --find_package(PkgConfig) --pkg_check_modules(PC_IlmBase QUIET IlmBase) -- --# ------------------------------------------------------------------------ --# Search for IlmBase include DIR --# ------------------------------------------------------------------------ -- --set(_ILMBASE_INCLUDE_SEARCH_DIRS "") --list(APPEND _ILMBASE_INCLUDE_SEARCH_DIRS -- ${ILMBASE_INCLUDEDIR} -- ${_ILMBASE_ROOT_SEARCH_DIR} -- ${PC_IlmBase_INCLUDEDIR} -- ${SYSTEM_LIBRARY_PATHS} --) -- --# Look for a standard IlmBase header file. --find_path(IlmBase_INCLUDE_DIR IlmBaseConfig.h -- NO_DEFAULT_PATH -- PATHS ${_ILMBASE_INCLUDE_SEARCH_DIRS} -- PATH_SUFFIXES include/OpenEXR OpenEXR --) -- --if(EXISTS "${IlmBase_INCLUDE_DIR}/IlmBaseConfig.h") -- # Get the ILMBASE version information from the config header -- file(STRINGS "${IlmBase_INCLUDE_DIR}/IlmBaseConfig.h" -- _ilmbase_version_major_string REGEX "#define ILMBASE_VERSION_MAJOR " -- ) -- string(REGEX REPLACE "#define ILMBASE_VERSION_MAJOR" "" -- _ilmbase_version_major_string "${_ilmbase_version_major_string}" -- ) -- string(STRIP "${_ilmbase_version_major_string}" IlmBase_VERSION_MAJOR) -- -- file(STRINGS "${IlmBase_INCLUDE_DIR}/IlmBaseConfig.h" -- _ilmbase_version_minor_string REGEX "#define ILMBASE_VERSION_MINOR " -- ) -- string(REGEX REPLACE "#define ILMBASE_VERSION_MINOR" "" -- _ilmbase_version_minor_string "${_ilmbase_version_minor_string}" -- ) -- string(STRIP "${_ilmbase_version_minor_string}" IlmBase_VERSION_MINOR) -- -- unset(_ilmbase_version_major_string) -- unset(_ilmbase_version_minor_string) -- -- set(IlmBase_VERSION ${IlmBase_VERSION_MAJOR}.${IlmBase_VERSION_MINOR}) --endif() -- --# ------------------------------------------------------------------------ --# Search for ILMBASE lib DIR --# ------------------------------------------------------------------------ -- --set(_ILMBASE_LIBRARYDIR_SEARCH_DIRS "") -- --# Append to _ILMBASE_LIBRARYDIR_SEARCH_DIRS in priority order -- --list(APPEND _ILMBASE_LIBRARYDIR_SEARCH_DIRS -- ${ILMBASE_LIBRARYDIR} -- ${_ILMBASE_ROOT_SEARCH_DIR} -- ${PC_IlmBase_LIBDIR} -- ${SYSTEM_LIBRARY_PATHS} --) -- --# Build suffix directories -- --set(ILMBASE_PATH_SUFFIXES -- lib64 -- lib --) -- --if(UNIX) -- list(INSERT ILMBASE_PATH_SUFFIXES 0 lib/x86_64-linux-gnu) --endif() -- --set(_ILMBASE_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) -- --# library suffix handling --if(WIN32) -- list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES -- "-${IlmBase_VERSION_MAJOR}_${IlmBase_VERSION_MINOR}.lib" -- ) --else() -- if(ILMBASE_USE_STATIC_LIBS) -- list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES -- "-${IlmBase_VERSION_MAJOR}_${IlmBase_VERSION_MINOR}.a" -- ) -- else() -- if(APPLE) -- list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES -- "-${IlmBase_VERSION_MAJOR}_${IlmBase_VERSION_MINOR}.dylib" -- ) -- else() -- list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES -- "-${IlmBase_VERSION_MAJOR}_${IlmBase_VERSION_MINOR}.so" -- ) -- endif() -- endif() --endif() -- --set(IlmBase_LIB_COMPONENTS "") -- --foreach(COMPONENT ${IlmBase_FIND_COMPONENTS}) -- find_library(IlmBase_${COMPONENT}_LIBRARY ${COMPONENT} -- NO_DEFAULT_PATH -- PATHS ${_ILMBASE_LIBRARYDIR_SEARCH_DIRS} -- PATH_SUFFIXES ${ILMBASE_PATH_SUFFIXES} -- ) -- list(APPEND IlmBase_LIB_COMPONENTS ${IlmBase_${COMPONENT}_LIBRARY}) -- -- if(WIN32 AND NOT ILMBASE_USE_STATIC_LIBS) -- set(_ILMBASE_TMP ${CMAKE_FIND_LIBRARY_SUFFIXES}) -- set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll") -- find_library(IlmBase_${COMPONENT}_DLL ${COMPONENT} -- NO_DEFAULT_PATH -- PATHS ${_ILMBASE_LIBRARYDIR_SEARCH_DIRS} -- PATH_SUFFIXES bin -- ) -- set(CMAKE_FIND_LIBRARY_SUFFIXES ${_ILMBASE_TMP}) -- unset(_ILMBASE_TMP) -- endif() -- -- if(IlmBase_${COMPONENT}_LIBRARY) -- set(IlmBase_${COMPONENT}_FOUND TRUE) -- else() -- set(IlmBase_${COMPONENT}_FOUND FALSE) -- endif() --endforeach() -- --# reset lib suffix -- --set(CMAKE_FIND_LIBRARY_SUFFIXES ${_ILMBASE_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) --unset(_ILMBASE_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES) -- --# ------------------------------------------------------------------------ --# Cache and set ILMBASE_FOUND --# ------------------------------------------------------------------------ -- --include(FindPackageHandleStandardArgs) --find_package_handle_standard_args(IlmBase -- FOUND_VAR IlmBase_FOUND -- REQUIRED_VARS -- IlmBase_INCLUDE_DIR -- IlmBase_LIB_COMPONENTS -- VERSION_VAR IlmBase_VERSION -- HANDLE_COMPONENTS --) -- --if(IlmBase_FOUND) -- set(IlmBase_LIBRARIES ${IlmBase_LIB_COMPONENTS}) -- -- # We have to add both include and include/OpenEXR to the include -- # path in case OpenEXR and IlmBase are installed separately -- -- set(IlmBase_INCLUDE_DIRS) -- list(APPEND IlmBase_INCLUDE_DIRS -- ${IlmBase_INCLUDE_DIR}/../ -- ${IlmBase_INCLUDE_DIR} -- ) -- set(IlmBase_DEFINITIONS ${PC_IlmBase_CFLAGS_OTHER}) -- -- set(IlmBase_LIBRARY_DIRS "") -- foreach(LIB ${IlmBase_LIB_COMPONENTS}) -- get_filename_component(_ILMBASE_LIBDIR ${LIB} DIRECTORY) -- list(APPEND IlmBase_LIBRARY_DIRS ${_ILMBASE_LIBDIR}) -- endforeach() -- list(REMOVE_DUPLICATES IlmBase_LIBRARY_DIRS) -- -- # Configure imported targets -- -- foreach(COMPONENT ${IlmBase_FIND_COMPONENTS}) -- if(NOT TARGET IlmBase::${COMPONENT}) -- add_library(IlmBase::${COMPONENT} UNKNOWN IMPORTED) -- set_target_properties(IlmBase::${COMPONENT} PROPERTIES -- IMPORTED_LOCATION "${IlmBase_${COMPONENT}_LIBRARY}" -- INTERFACE_COMPILE_OPTIONS "${IlmBase_DEFINITIONS}" -- INTERFACE_INCLUDE_DIRECTORIES "${IlmBase_INCLUDE_DIRS}" -- ) -- endif() -- endforeach() -- --elseif(IlmBase_FIND_REQUIRED) -- message(FATAL_ERROR "Unable to find IlmBase") --endif() -diff --git a/cmake/FindOpenEXR.cmake b/cmake/FindOpenEXR.cmake -deleted file mode 100644 -index 339c1a2..0000000 ---- a/cmake/FindOpenEXR.cmake -+++ /dev/null -@@ -1,329 +0,0 @@ --# Copyright (c) DreamWorks Animation LLC --# --# All rights reserved. This software is distributed under the --# Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) --# --# Redistributions of source code must retain the above copyright --# and license notice and the following restrictions and disclaimer. --# --# * Neither the name of DreamWorks Animation nor the names of --# its contributors may be used to endorse or promote products derived --# from this software without specific prior written permission. --# --# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS --# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT --# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR --# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT --# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, --# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT --# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, --# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY --# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT --# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE --# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --# IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE --# LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. --# --#[=======================================================================[.rst: -- --FindOpenEXR ------------- -- --Find OpenEXR include dirs and libraries -- --Use this module by invoking find_package with the form:: -- -- find_package(OpenEXR -- [version] [EXACT] # Minimum or EXACT version -- [REQUIRED] # Fail with error if OpenEXR is not found -- [COMPONENTS ...] # OpenEXR libraries by their canonical name -- # e.g. "IlmImf" for "libIlmImf" -- ) -- --IMPORTED Targets --^^^^^^^^^^^^^^^^ -- --``OpenEXR::IlmImf`` -- The IlmImf library target. --``OpenEXR::IlmImfUtil`` -- The IlmImfUtil library target. -- --Result Variables --^^^^^^^^^^^^^^^^ -- --This will define the following variables: -- --``OpenEXR_FOUND`` -- True if the system has the OpenEXR library. --``OpenEXR_VERSION`` -- The version of the OpenEXR library which was found. --``OpenEXR_INCLUDE_DIRS`` -- Include directories needed to use OpenEXR. --``OpenEXR_LIBRARIES`` -- Libraries needed to link to OpenEXR. --``OpenEXR_LIBRARY_DIRS`` -- OpenEXR library directories. --``OpenEXR_DEFINITIONS`` -- Definitions to use when compiling code that uses OpenEXR. --``OpenEXR_{COMPONENT}_FOUND`` -- True if the system has the named OpenEXR component. -- --Cache Variables --^^^^^^^^^^^^^^^ -- --The following cache variables may also be set: -- --``OpenEXR_INCLUDE_DIR`` -- The directory containing ``OpenEXR/config-auto.h``. --``OpenEXR_{COMPONENT}_LIBRARY`` -- Individual component libraries for OpenEXR --``OpenEXR_{COMPONENT}_DLL`` -- Individual component dlls for OpenEXR on Windows. -- --Hints --^^^^^ -- --Instead of explicitly setting the cache variables, the following variables --may be provided to tell this module where to look. -- --``OPENEXR_ROOT`` -- Preferred installation prefix. --``OPENEXR_INCLUDEDIR`` -- Preferred include directory e.g. /include --``OPENEXR_LIBRARYDIR`` -- Preferred library directory e.g. /lib --``SYSTEM_LIBRARY_PATHS`` -- Paths appended to all include and lib searches. -- --#]=======================================================================] -- --# Support new if() IN_LIST operator --if(POLICY CMP0057) -- cmake_policy(SET CMP0057 NEW) --endif() -- --mark_as_advanced( -- OpenEXR_INCLUDE_DIR -- OpenEXR_LIBRARY --) -- --set(_OPENEXR_COMPONENT_LIST -- IlmImf -- IlmImfUtil --) -- --if(OpenEXR_FIND_COMPONENTS) -- set(OPENEXR_COMPONENTS_PROVIDED TRUE) -- set(_IGNORED_COMPONENTS "") -- foreach(COMPONENT ${OpenEXR_FIND_COMPONENTS}) -- if(NOT ${COMPONENT} IN_LIST _OPENEXR_COMPONENT_LIST) -- list(APPEND _IGNORED_COMPONENTS ${COMPONENT}) -- endif() -- endforeach() -- -- if(_IGNORED_COMPONENTS) -- message(STATUS "Ignoring unknown components of OpenEXR:") -- foreach(COMPONENT ${_IGNORED_COMPONENTS}) -- message(STATUS " ${COMPONENT}") -- endforeach() -- list(REMOVE_ITEM OpenEXR_FIND_COMPONENTS ${_IGNORED_COMPONENTS}) -- endif() --else() -- set(OPENEXR_COMPONENTS_PROVIDED FALSE) -- set(OpenEXR_FIND_COMPONENTS ${_OPENEXR_COMPONENT_LIST}) --endif() -- --# Append OPENEXR_ROOT or $ENV{OPENEXR_ROOT} if set (prioritize the direct cmake var) --set(_OPENEXR_ROOT_SEARCH_DIR "") -- --if(OPENEXR_ROOT) -- list(APPEND _OPENEXR_ROOT_SEARCH_DIR ${OPENEXR_ROOT}) --else() -- set(_ENV_OPENEXR_ROOT $ENV{OPENEXR_ROOT}) -- if(_ENV_OPENEXR_ROOT) -- list(APPEND _OPENEXR_ROOT_SEARCH_DIR ${_ENV_OPENEXR_ROOT}) -- endif() --endif() -- --# Additionally try and use pkconfig to find OpenEXR -- --find_package(PkgConfig) --pkg_check_modules(PC_OpenEXR QUIET OpenEXR) -- --# ------------------------------------------------------------------------ --# Search for OpenEXR include DIR --# ------------------------------------------------------------------------ -- --set(_OPENEXR_INCLUDE_SEARCH_DIRS "") --list(APPEND _OPENEXR_INCLUDE_SEARCH_DIRS -- ${OPENEXR_INCLUDEDIR} -- ${_OPENEXR_ROOT_SEARCH_DIR} -- ${PC_OpenEXR_INCLUDEDIR} -- ${SYSTEM_LIBRARY_PATHS} --) -- --# Look for a standard OpenEXR header file. --find_path(OpenEXR_INCLUDE_DIR OpenEXRConfig.h -- NO_DEFAULT_PATH -- PATHS ${_OPENEXR_INCLUDE_SEARCH_DIRS} -- PATH_SUFFIXES include/OpenEXR OpenEXR --) -- --if(EXISTS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h") -- # Get the EXR version information from the config header -- file(STRINGS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h" -- _openexr_version_major_string REGEX "#define OPENEXR_VERSION_MAJOR " -- ) -- string(REGEX REPLACE "#define OPENEXR_VERSION_MAJOR" "" -- _openexr_version_major_string "${_openexr_version_major_string}" -- ) -- string(STRIP "${_openexr_version_major_string}" OpenEXR_VERSION_MAJOR) -- -- file(STRINGS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h" -- _openexr_version_minor_string REGEX "#define OPENEXR_VERSION_MINOR " -- ) -- string(REGEX REPLACE "#define OPENEXR_VERSION_MINOR" "" -- _openexr_version_minor_string "${_openexr_version_minor_string}" -- ) -- string(STRIP "${_openexr_version_minor_string}" OpenEXR_VERSION_MINOR) -- -- unset(_openexr_version_major_string) -- unset(_openexr_version_minor_string) -- -- set(OpenEXR_VERSION ${OpenEXR_VERSION_MAJOR}.${OpenEXR_VERSION_MINOR}) --endif() -- --# ------------------------------------------------------------------------ --# Search for OPENEXR lib DIR --# ------------------------------------------------------------------------ -- --set(_OPENEXR_LIBRARYDIR_SEARCH_DIRS "") -- --# Append to _OPENEXR_LIBRARYDIR_SEARCH_DIRS in priority order -- --list(APPEND _OPENEXR_LIBRARYDIR_SEARCH_DIRS -- ${OPENEXR_LIBRARYDIR} -- ${_OPENEXR_ROOT_SEARCH_DIR} -- ${PC_OpenEXR_LIBDIR} -- ${SYSTEM_LIBRARY_PATHS} --) -- --# Build suffix directories -- --set(OPENEXR_PATH_SUFFIXES -- lib64 -- lib --) -- --if(UNIX ) -- list(INSERT OPENEXR_PATH_SUFFIXES 0 lib/x86_64-linux-gnu) --endif() -- --set(_OPENEXR_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) -- --# library suffix handling --if(WIN32) -- list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES -- "-${OpenEXR_VERSION_MAJOR}_${OpenEXR_VERSION_MINOR}.lib" -- ) --else() -- if(OPENEXR_USE_STATIC_LIBS) -- list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES -- "-${OpenEXR_VERSION_MAJOR}_${OpenEXR_VERSION_MINOR}.a" -- ) -- else() -- if(APPLE) -- list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES -- "-${OpenEXR_VERSION_MAJOR}_${OpenEXR_VERSION_MINOR}.dylib" -- ) -- else() -- list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES -- "-${OpenEXR_VERSION_MAJOR}_${OpenEXR_VERSION_MINOR}.so" -- ) -- endif() -- endif() --endif() -- --set(OpenEXR_LIB_COMPONENTS "") -- --foreach(COMPONENT ${OpenEXR_FIND_COMPONENTS}) -- find_library(OpenEXR_${COMPONENT}_LIBRARY ${COMPONENT} -- NO_DEFAULT_PATH -- PATHS ${_OPENEXR_LIBRARYDIR_SEARCH_DIRS} -- PATH_SUFFIXES ${OPENEXR_PATH_SUFFIXES} -- ) -- list(APPEND OpenEXR_LIB_COMPONENTS ${OpenEXR_${COMPONENT}_LIBRARY}) -- -- if(WIN32 AND NOT OPENEXR_USE_STATIC_LIBS) -- set(_OPENEXR_TMP ${CMAKE_FIND_LIBRARY_SUFFIXES}) -- set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll") -- find_library(OpenEXR_${COMPONENT}_DLL ${COMPONENT} -- NO_DEFAULT_PATH -- PATHS ${_OPENEXR_LIBRARYDIR_SEARCH_DIRS} -- PATH_SUFFIXES bin -- ) -- set(CMAKE_FIND_LIBRARY_SUFFIXES ${_OPENEXR_TMP}) -- unset(_OPENEXR_TMP) -- endif() -- -- if(OpenEXR_${COMPONENT}_LIBRARY) -- set(OpenEXR_${COMPONENT}_FOUND TRUE) -- else() -- set(OpenEXR_${COMPONENT}_FOUND FALSE) -- endif() --endforeach() -- --# reset lib suffix -- --set(CMAKE_FIND_LIBRARY_SUFFIXES ${_OPENEXR_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) --unset(_OPENEXR_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES) -- --# ------------------------------------------------------------------------ --# Cache and set OPENEXR_FOUND --# ------------------------------------------------------------------------ -- --include(FindPackageHandleStandardArgs) --find_package_handle_standard_args(OpenEXR -- FOUND_VAR OpenEXR_FOUND -- REQUIRED_VARS -- OpenEXR_INCLUDE_DIR -- OpenEXR_LIB_COMPONENTS -- VERSION_VAR OpenEXR_VERSION -- HANDLE_COMPONENTS --) -- --if(OpenEXR_FOUND) -- set(OpenEXR_LIBRARIES ${OpenEXR_LIB_COMPONENTS}) -- -- # We have to add both include and include/OpenEXR to the include -- # path in case OpenEXR and IlmBase are installed separately -- -- set(OpenEXR_INCLUDE_DIRS) -- list(APPEND OpenEXR_INCLUDE_DIRS -- ${OpenEXR_INCLUDE_DIR}/../ -- ${OpenEXR_INCLUDE_DIR} -- ) -- set(OpenEXR_DEFINITIONS ${PC_OpenEXR_CFLAGS_OTHER}) -- -- set(OpenEXR_LIBRARY_DIRS "") -- foreach(LIB ${OpenEXR_LIB_COMPONENTS}) -- get_filename_component(_OPENEXR_LIBDIR ${LIB} DIRECTORY) -- list(APPEND OpenEXR_LIBRARY_DIRS ${_OPENEXR_LIBDIR}) -- endforeach() -- list(REMOVE_DUPLICATES OpenEXR_LIBRARY_DIRS) -- -- # Configure imported target -- -- foreach(COMPONENT ${OpenEXR_FIND_COMPONENTS}) -- if(NOT TARGET OpenEXR::${COMPONENT}) -- add_library(OpenEXR::${COMPONENT} UNKNOWN IMPORTED) -- set_target_properties(OpenEXR::${COMPONENT} PROPERTIES -- IMPORTED_LOCATION "${OpenEXR_${COMPONENT}_LIBRARY}" -- INTERFACE_COMPILE_OPTIONS "${OpenEXR_DEFINITIONS}" -- INTERFACE_INCLUDE_DIRECTORIES "${OpenEXR_INCLUDE_DIRS}" -- ) -- endif() -- endforeach() --elseif(OpenEXR_FIND_REQUIRED) -- message(FATAL_ERROR "Unable to find OpenEXR") --endif() -diff --git a/cmake/FindOpenVDB.cmake b/cmake/FindOpenVDB.cmake -index 63a2eda..d9f6d07 100644 ---- a/cmake/FindOpenVDB.cmake -+++ b/cmake/FindOpenVDB.cmake -@@ -244,7 +244,7 @@ set(OpenVDB_LIB_COMPONENTS "") - - foreach(COMPONENT ${OpenVDB_FIND_COMPONENTS}) - set(LIB_NAME ${COMPONENT}) -- find_library(OpenVDB_${COMPONENT}_LIBRARY ${LIB_NAME} -+ find_library(OpenVDB_${COMPONENT}_LIBRARY ${LIB_NAME} lib${LIB_NAME} - NO_DEFAULT_PATH - PATHS ${_OPENVDB_LIBRARYDIR_SEARCH_DIRS} - PATH_SUFFIXES ${OPENVDB_PATH_SUFFIXES} -@@ -282,16 +282,13 @@ find_package_handle_standard_args(OpenVDB - # ------------------------------------------------------------------------ - - # Set the ABI number the library was built against. Uses vdb_print -+find_program(OPENVDB_PRINT vdb_print -+ PATHS ${_OPENVDB_INSTALL}/bin ${OpenVDB_INCLUDE_DIR} -+ NO_DEFAULT_PATH) - - if(_OPENVDB_INSTALL) - OPENVDB_ABI_VERSION_FROM_PRINT( -- "${_OPENVDB_INSTALL}/bin/vdb_print" -- ABI OpenVDB_ABI -- ) --else() -- # Try and find vdb_print from the include path -- OPENVDB_ABI_VERSION_FROM_PRINT( -- "${OpenVDB_INCLUDE_DIR}/../bin/vdb_print" -+ "${OPENVDB_PRINT}" - ABI OpenVDB_ABI - ) - endif() -@@ -472,6 +469,12 @@ foreach(COMPONENT ${OpenVDB_FIND_COMPONENTS}) - INTERFACE_LINK_LIBRARIES "${_OPENVDB_VISIBLE_DEPENDENCIES}" # visible deps (headers) - INTERFACE_COMPILE_FEATURES cxx_std_11 - ) -+ -+ if (OPENVDB_USE_STATIC_LIBS) -+ set_target_properties(OpenVDB::${COMPONENT} PROPERTIES -+ INTERFACE_COMPILE_DEFINITIONS "OPENVDB_STATICLIB;OPENVDB_OPENEXR_STATICLIB" -+ ) -+ endif() - endif() - endforeach() - -diff --git a/cmake/FindTBB.cmake b/cmake/FindTBB.cmake -index bdf9c81..06093a4 100644 ---- a/cmake/FindTBB.cmake -+++ b/cmake/FindTBB.cmake -@@ -1,333 +1,332 @@ --# Copyright (c) DreamWorks Animation LLC -+# The MIT License (MIT) - # --# All rights reserved. This software is distributed under the --# Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ ) -+# Copyright (c) 2015 Justus Calvin - # --# Redistributions of source code must retain the above copyright --# and license notice and the following restrictions and disclaimer. -+# Permission is hereby granted, free of charge, to any person obtaining a copy -+# of this software and associated documentation files (the "Software"), to deal -+# in the Software without restriction, including without limitation the rights -+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+# copies of the Software, and to permit persons to whom the Software is -+# furnished to do so, subject to the following conditions: - # --# * Neither the name of DreamWorks Animation nor the names of --# its contributors may be used to endorse or promote products derived --# from this software without specific prior written permission. -+# The above copyright notice and this permission notice shall be included in all -+# copies or substantial portions of the Software. - # --# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS --# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT --# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR --# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT --# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL, --# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT --# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, --# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY --# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT --# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE --# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --# IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE --# LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00. -+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -+# SOFTWARE. -+ - # --#[=======================================================================[.rst: -- --FindTBB --------- -- --Find Tbb include dirs and libraries -- --Use this module by invoking find_package with the form:: -- -- find_package(TBB -- [version] [EXACT] # Minimum or EXACT version -- [REQUIRED] # Fail with error if Tbb is not found -- [COMPONENTS ...] # Tbb libraries by their canonical name -- # e.g. "tbb" for "libtbb" -- ) -- --IMPORTED Targets --^^^^^^^^^^^^^^^^ -- --``TBB::tbb`` -- The tbb library target. --``TBB::tbbmalloc`` -- The tbbmalloc library target. --``TBB::tbbmalloc_proxy`` -- The tbbmalloc_proxy library target. -- --Result Variables --^^^^^^^^^^^^^^^^ -- --This will define the following variables: -- --``Tbb_FOUND`` -- True if the system has the Tbb library. --``Tbb_VERSION`` -- The version of the Tbb library which was found. --``Tbb_INCLUDE_DIRS`` -- Include directories needed to use Tbb. --``Tbb_LIBRARIES`` -- Libraries needed to link to Tbb. --``Tbb_LIBRARY_DIRS`` -- Tbb library directories. --``TBB_{COMPONENT}_FOUND`` -- True if the system has the named TBB component. -- --Cache Variables --^^^^^^^^^^^^^^^ -- --The following cache variables may also be set: -- --``Tbb_INCLUDE_DIR`` -- The directory containing ``tbb/tbb_stddef.h``. --``Tbb_{COMPONENT}_LIBRARY`` -- Individual component libraries for Tbb -- --Hints --^^^^^ -- --Instead of explicitly setting the cache variables, the following variables --may be provided to tell this module where to look. -- --``TBB_ROOT`` -- Preferred installation prefix. --``TBB_INCLUDEDIR`` -- Preferred include directory e.g. /include --``TBB_LIBRARYDIR`` -- Preferred library directory e.g. /lib --``SYSTEM_LIBRARY_PATHS`` -- Paths appended to all include and lib searches. -- --#]=======================================================================] -- --# Support new if() IN_LIST operator --if(POLICY CMP0057) -- cmake_policy(SET CMP0057 NEW) --endif() -+# FindTBB -+# ------- -+# -+# Find TBB include directories and libraries. -+# -+# Usage: -+# -+# find_package(TBB [major[.minor]] [EXACT] -+# [QUIET] [REQUIRED] -+# [[COMPONENTS] [components...]] -+# [OPTIONAL_COMPONENTS components...]) -+# -+# where the allowed components are tbbmalloc and tbb_preview. Users may modify -+# the behavior of this module with the following variables: -+# -+# * TBB_ROOT_DIR - The base directory the of TBB installation. -+# * TBB_INCLUDE_DIR - The directory that contains the TBB headers files. -+# * TBB_LIBRARY - The directory that contains the TBB library files. -+# * TBB__LIBRARY - The path of the TBB the corresponding TBB library. -+# These libraries, if specified, override the -+# corresponding library search results, where -+# may be tbb, tbb_debug, tbbmalloc, tbbmalloc_debug, -+# tbb_preview, or tbb_preview_debug. -+# * TBB_USE_DEBUG_BUILD - The debug version of tbb libraries, if present, will -+# be used instead of the release version. -+# * TBB_STATIC - Static linking of libraries with a _static suffix. -+# For example, on Windows a tbb_static.lib will be searched for -+# instead of tbb.lib. -+# -+# Users may modify the behavior of this module with the following environment -+# variables: -+# -+# * TBB_INSTALL_DIR -+# * TBBROOT -+# * LIBRARY_PATH -+# -+# This module will set the following variables: -+# -+# * TBB_FOUND - Set to false, or undefined, if we haven’t found, or -+# don’t want to use TBB. -+# * TBB__FOUND - If False, optional part of TBB sytem is -+# not available. -+# * TBB_VERSION - The full version string -+# * TBB_VERSION_MAJOR - The major version -+# * TBB_VERSION_MINOR - The minor version -+# * TBB_INTERFACE_VERSION - The interface version number defined in -+# tbb/tbb_stddef.h. -+# * TBB__LIBRARY_RELEASE - The path of the TBB release version of -+# , where may be tbb, tbb_debug, -+# tbbmalloc, tbbmalloc_debug, tbb_preview, or -+# tbb_preview_debug. -+# * TBB__LIBRARY_DEGUG - The path of the TBB release version of -+# , where may be tbb, tbb_debug, -+# tbbmalloc, tbbmalloc_debug, tbb_preview, or -+# tbb_preview_debug. -+# -+# The following varibles should be used to build and link with TBB: -+# -+# * TBB_INCLUDE_DIRS - The include directory for TBB. -+# * TBB_LIBRARIES - The libraries to link against to use TBB. -+# * TBB_LIBRARIES_RELEASE - The release libraries to link against to use TBB. -+# * TBB_LIBRARIES_DEBUG - The debug libraries to link against to use TBB. -+# * TBB_DEFINITIONS - Definitions to use when compiling code that uses -+# TBB. -+# * TBB_DEFINITIONS_RELEASE - Definitions to use when compiling release code that -+# uses TBB. -+# * TBB_DEFINITIONS_DEBUG - Definitions to use when compiling debug code that -+# uses TBB. -+# -+# This module will also create the "tbb" target that may be used when building -+# executables and libraries. - --mark_as_advanced( -- Tbb_INCLUDE_DIR -- Tbb_LIBRARY --) -- --set(_TBB_COMPONENT_LIST -- tbb -- tbbmalloc -- tbbmalloc_proxy --) -- --if(TBB_FIND_COMPONENTS) -- set(_TBB_COMPONENTS_PROVIDED TRUE) -- set(_IGNORED_COMPONENTS "") -- foreach(COMPONENT ${TBB_FIND_COMPONENTS}) -- if(NOT ${COMPONENT} IN_LIST _TBB_COMPONENT_LIST) -- list(APPEND _IGNORED_COMPONENTS ${COMPONENT}) -- endif() -- endforeach() -+unset(TBB_FOUND CACHE) -+unset(TBB_INCLUDE_DIRS CACHE) -+unset(TBB_LIBRARIES) -+unset(TBB_LIBRARIES_DEBUG) -+unset(TBB_LIBRARIES_RELEASE) - -- if(_IGNORED_COMPONENTS) -- message(STATUS "Ignoring unknown components of TBB:") -- foreach(COMPONENT ${_IGNORED_COMPONENTS}) -- message(STATUS " ${COMPONENT}") -- endforeach() -- list(REMOVE_ITEM TBB_FIND_COMPONENTS ${_IGNORED_COMPONENTS}) -- endif() --else() -- set(_TBB_COMPONENTS_PROVIDED FALSE) -- set(TBB_FIND_COMPONENTS ${_TBB_COMPONENT_LIST}) --endif() -+include(FindPackageHandleStandardArgs) - --# Append TBB_ROOT or $ENV{TBB_ROOT} if set (prioritize the direct cmake var) --set(_TBB_ROOT_SEARCH_DIR "") -+find_package(Threads QUIET REQUIRED) - --if(TBB_ROOT) -- list(APPEND _TBB_ROOT_SEARCH_DIR ${TBB_ROOT}) --else() -- set(_ENV_TBB_ROOT $ENV{TBB_ROOT}) -- if(_ENV_TBB_ROOT) -- list(APPEND _TBB_ROOT_SEARCH_DIR ${_ENV_TBB_ROOT}) -- endif() --endif() -+if(NOT TBB_FOUND) - --# Additionally try and use pkconfig to find Tbb -- --find_package(PkgConfig) --pkg_check_modules(PC_Tbb QUIET tbb) -- --# ------------------------------------------------------------------------ --# Search for tbb include DIR --# ------------------------------------------------------------------------ -- --set(_TBB_INCLUDE_SEARCH_DIRS "") --list(APPEND _TBB_INCLUDE_SEARCH_DIRS -- ${TBB_INCLUDEDIR} -- ${_TBB_ROOT_SEARCH_DIR} -- ${PC_Tbb_INCLUDE_DIRS} -- ${SYSTEM_LIBRARY_PATHS} --) -- --# Look for a standard tbb header file. --find_path(Tbb_INCLUDE_DIR tbb/tbb_stddef.h -- NO_DEFAULT_PATH -- PATHS ${_TBB_INCLUDE_SEARCH_DIRS} -- PATH_SUFFIXES include --) -- --if(EXISTS "${Tbb_INCLUDE_DIR}/tbb/tbb_stddef.h") -- file(STRINGS "${Tbb_INCLUDE_DIR}/tbb/tbb_stddef.h" -- _tbb_version_major_string REGEX "#define TBB_VERSION_MAJOR " -- ) -- string(REGEX REPLACE "#define TBB_VERSION_MAJOR" "" -- _tbb_version_major_string "${_tbb_version_major_string}" -- ) -- string(STRIP "${_tbb_version_major_string}" Tbb_VERSION_MAJOR) -- -- file(STRINGS "${Tbb_INCLUDE_DIR}/tbb/tbb_stddef.h" -- _tbb_version_minor_string REGEX "#define TBB_VERSION_MINOR " -- ) -- string(REGEX REPLACE "#define TBB_VERSION_MINOR" "" -- _tbb_version_minor_string "${_tbb_version_minor_string}" -- ) -- string(STRIP "${_tbb_version_minor_string}" Tbb_VERSION_MINOR) -- -- unset(_tbb_version_major_string) -- unset(_tbb_version_minor_string) -- -- set(Tbb_VERSION ${Tbb_VERSION_MAJOR}.${Tbb_VERSION_MINOR}) --endif() -+ ################################## -+ # Check the build type -+ ################################## -+ -+ if(NOT DEFINED TBB_USE_DEBUG_BUILD) -+ if(CMAKE_BUILD_TYPE MATCHES "(Debug|DEBUG|debug)") -+ set(TBB_BUILD_TYPE DEBUG) -+ else() -+ set(TBB_BUILD_TYPE RELEASE) -+ endif() -+ elseif(TBB_USE_DEBUG_BUILD) -+ set(TBB_BUILD_TYPE DEBUG) -+ else() -+ set(TBB_BUILD_TYPE RELEASE) -+ endif() - --# ------------------------------------------------------------------------ --# Search for TBB lib DIR --# ------------------------------------------------------------------------ -+ ################################## -+ # Set the TBB search directories -+ ################################## - --set(_TBB_LIBRARYDIR_SEARCH_DIRS "") -+ # Define search paths based on user input and environment variables -+ set(TBB_SEARCH_DIR ${TBB_ROOT_DIR} $ENV{TBB_INSTALL_DIR} $ENV{TBBROOT}) - --# Append to _TBB_LIBRARYDIR_SEARCH_DIRS in priority order -+ # Define the search directories based on the current platform -+ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") -+ set(TBB_DEFAULT_SEARCH_DIR "C:/Program Files/Intel/TBB" -+ "C:/Program Files (x86)/Intel/TBB") - --set(_TBB_LIBRARYDIR_SEARCH_DIRS "") --list(APPEND _TBB_LIBRARYDIR_SEARCH_DIRS -- ${TBB_LIBRARYDIR} -- ${_TBB_ROOT_SEARCH_DIR} -- ${PC_Tbb_LIBRARY_DIRS} -- ${SYSTEM_LIBRARY_PATHS} --) -+ # Set the target architecture -+ if(CMAKE_SIZEOF_VOID_P EQUAL 8) -+ set(TBB_ARCHITECTURE "intel64") -+ else() -+ set(TBB_ARCHITECTURE "ia32") -+ endif() - --set(TBB_PATH_SUFFIXES -- lib64 -- lib --) -+ # Set the TBB search library path search suffix based on the version of VC -+ if(WINDOWS_STORE) -+ set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc11_ui") -+ elseif(MSVC14) -+ set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc14") -+ elseif(MSVC12) -+ set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc12") -+ elseif(MSVC11) -+ set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc11") -+ elseif(MSVC10) -+ set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc10") -+ endif() - --# platform branching -+ # Add the library path search suffix for the VC independent version of TBB -+ list(APPEND TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc_mt") - --if(UNIX) -- list(INSERT TBB_PATH_SUFFIXES 0 lib/x86_64-linux-gnu) --endif() -+ elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") -+ # OS X -+ set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb") - --if(APPLE) -- if(TBB_FOR_CLANG) -- list(INSERT TBB_PATH_SUFFIXES 0 lib/libc++) -- endif() --elseif(WIN32) -- if(MSVC10) -- set(TBB_VC_DIR vc10) -- elseif(MSVC11) -- set(TBB_VC_DIR vc11) -- elseif(MSVC12) -- set(TBB_VC_DIR vc12) -- endif() -- list(INSERT TBB_PATH_SUFFIXES 0 lib/intel64/${TBB_VC_DIR}) --else() -- if(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU) -- if(TBB_MATCH_COMPILER_VERSION) -- string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${CMAKE_CXX_COMPILER_VERSION}) -- list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR) -- list(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR) -- list(INSERT TBB_PATH_SUFFIXES 0 lib/intel64/gcc${GCC_MAJOR}.${GCC_MINOR}) -+ # TODO: Check to see which C++ library is being used by the compiler. -+ if(NOT ${CMAKE_SYSTEM_VERSION} VERSION_LESS 13.0) -+ # The default C++ library on OS X 10.9 and later is libc++ -+ set(TBB_LIB_PATH_SUFFIX "lib/libc++" "lib") - else() -- list(INSERT TBB_PATH_SUFFIXES 0 lib/intel64/gcc4.4) -+ set(TBB_LIB_PATH_SUFFIX "lib") -+ endif() -+ elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") -+ # Linux -+ set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb") -+ -+ # TODO: Check compiler version to see the suffix should be /gcc4.1 or -+ # /gcc4.1. For now, assume that the compiler is more recent than -+ # gcc 4.4.x or later. -+ if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") -+ set(TBB_LIB_PATH_SUFFIX "lib/intel64/gcc4.4") -+ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$") -+ set(TBB_LIB_PATH_SUFFIX "lib/ia32/gcc4.4") - endif() - endif() --endif() -- --if(UNIX AND TBB_USE_STATIC_LIBS) -- set(_TBB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) -- set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") --endif() - --set(Tbb_LIB_COMPONENTS "") -- --foreach(COMPONENT ${TBB_FIND_COMPONENTS}) -- find_library(Tbb_${COMPONENT}_LIBRARY ${COMPONENT} -- NO_DEFAULT_PATH -- PATHS ${_TBB_LIBRARYDIR_SEARCH_DIRS} -- PATH_SUFFIXES ${TBB_PATH_SUFFIXES} -- ) -- -- # On Unix, TBB sometimes uses linker scripts instead of symlinks, so parse the linker script -- # and correct the library name if so -- if(UNIX AND EXISTS ${Tbb_${COMPONENT}_LIBRARY}) -- # Ignore files where the first four bytes equals the ELF magic number -- file(READ ${Tbb_${COMPONENT}_LIBRARY} Tbb_${COMPONENT}_HEX OFFSET 0 LIMIT 4 HEX) -- if(NOT ${Tbb_${COMPONENT}_HEX} STREQUAL "7f454c46") -- # Read the first 1024 bytes of the library and match against an "INPUT (file)" regex -- file(READ ${Tbb_${COMPONENT}_LIBRARY} Tbb_${COMPONENT}_ASCII OFFSET 0 LIMIT 1024) -- if("${Tbb_${COMPONENT}_ASCII}" MATCHES "INPUT \\(([^(]+)\\)") -- # Extract the directory and apply the matched text (in brackets) -- get_filename_component(Tbb_${COMPONENT}_DIR "${Tbb_${COMPONENT}_LIBRARY}" DIRECTORY) -- set(Tbb_${COMPONENT}_LIBRARY "${Tbb_${COMPONENT}_DIR}/${CMAKE_MATCH_1}") -- endif() -- endif() -+ ################################## -+ # Find the TBB include dir -+ ################################## -+ -+ find_path(TBB_INCLUDE_DIRS tbb/tbb.h -+ HINTS ${TBB_INCLUDE_DIR} ${TBB_SEARCH_DIR} -+ PATHS ${TBB_DEFAULT_SEARCH_DIR} -+ PATH_SUFFIXES include) -+ -+ ################################## -+ # Set version strings -+ ################################## -+ -+ if(TBB_INCLUDE_DIRS) -+ file(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _tbb_version_file) -+ string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" -+ TBB_VERSION_MAJOR "${_tbb_version_file}") -+ string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" -+ TBB_VERSION_MINOR "${_tbb_version_file}") -+ string(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" -+ TBB_INTERFACE_VERSION "${_tbb_version_file}") -+ set(TBB_VERSION "${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR}") - endif() - -- list(APPEND Tbb_LIB_COMPONENTS ${Tbb_${COMPONENT}_LIBRARY}) -+ ################################## -+ # Find TBB components -+ ################################## - -- if(Tbb_${COMPONENT}_LIBRARY) -- set(TBB_${COMPONENT}_FOUND TRUE) -+ if(TBB_VERSION VERSION_LESS 4.3) -+ set(TBB_SEARCH_COMPOMPONENTS tbb_preview tbbmalloc tbb) - else() -- set(TBB_${COMPONENT}_FOUND FALSE) -+ set(TBB_SEARCH_COMPOMPONENTS tbb_preview tbbmalloc_proxy tbbmalloc tbb) - endif() --endforeach() - --if(UNIX AND TBB_USE_STATIC_LIBS) -- set(CMAKE_FIND_LIBRARY_SUFFIXES ${_TBB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) -- unset(_TBB_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES) --endif() -+ if(TBB_STATIC) -+ set(TBB_STATIC_SUFFIX "_static") -+ endif() - --# ------------------------------------------------------------------------ --# Cache and set TBB_FOUND --# ------------------------------------------------------------------------ -+ # Find each component -+ foreach(_comp ${TBB_SEARCH_COMPOMPONENTS}) -+ if(";${TBB_FIND_COMPONENTS};tbb;" MATCHES ";${_comp};") -+ -+ unset(TBB_${_comp}_LIBRARY_DEBUG CACHE) -+ unset(TBB_${_comp}_LIBRARY_RELEASE CACHE) -+ -+ # Search for the libraries -+ find_library(TBB_${_comp}_LIBRARY_RELEASE ${_comp}${TBB_STATIC_SUFFIX} -+ HINTS ${TBB_LIBRARY} ${TBB_SEARCH_DIR} -+ PATHS ${TBB_DEFAULT_SEARCH_DIR} ENV LIBRARY_PATH -+ PATH_SUFFIXES ${TBB_LIB_PATH_SUFFIX}) -+ -+ find_library(TBB_${_comp}_LIBRARY_DEBUG ${_comp}${TBB_STATIC_SUFFIX}_debug -+ HINTS ${TBB_LIBRARY} ${TBB_SEARCH_DIR} -+ PATHS ${TBB_DEFAULT_SEARCH_DIR} ENV LIBRARY_PATH -+ PATH_SUFFIXES ${TBB_LIB_PATH_SUFFIX}) -+ -+ if(TBB_${_comp}_LIBRARY_DEBUG) -+ list(APPEND TBB_LIBRARIES_DEBUG "${TBB_${_comp}_LIBRARY_DEBUG}") -+ endif() -+ if(TBB_${_comp}_LIBRARY_RELEASE) -+ list(APPEND TBB_LIBRARIES_RELEASE "${TBB_${_comp}_LIBRARY_RELEASE}") -+ endif() -+ if(TBB_${_comp}_LIBRARY_${TBB_BUILD_TYPE} AND NOT TBB_${_comp}_LIBRARY) -+ set(TBB_${_comp}_LIBRARY "${TBB_${_comp}_LIBRARY_${TBB_BUILD_TYPE}}") -+ endif() -+ -+ if(TBB_${_comp}_LIBRARY AND EXISTS "${TBB_${_comp}_LIBRARY}") -+ set(TBB_${_comp}_FOUND TRUE) -+ else() -+ set(TBB_${_comp}_FOUND FALSE) -+ endif() -+ -+ # Mark internal variables as advanced -+ mark_as_advanced(TBB_${_comp}_LIBRARY_RELEASE) -+ mark_as_advanced(TBB_${_comp}_LIBRARY_DEBUG) -+ mark_as_advanced(TBB_${_comp}_LIBRARY) - --include(FindPackageHandleStandardArgs) --find_package_handle_standard_args(TBB -- FOUND_VAR TBB_FOUND -- REQUIRED_VARS -- Tbb_INCLUDE_DIR -- Tbb_LIB_COMPONENTS -- VERSION_VAR Tbb_VERSION -- HANDLE_COMPONENTS --) -- --if(TBB_FOUND) -- set(Tbb_LIBRARIES -- ${Tbb_LIB_COMPONENTS} -- ) -- set(Tbb_INCLUDE_DIRS ${Tbb_INCLUDE_DIR}) -- set(Tbb_DEFINITIONS ${PC_Tbb_CFLAGS_OTHER}) -- -- set(Tbb_LIBRARY_DIRS "") -- foreach(LIB ${Tbb_LIB_COMPONENTS}) -- get_filename_component(_TBB_LIBDIR ${LIB} DIRECTORY) -- list(APPEND Tbb_LIBRARY_DIRS ${_TBB_LIBDIR}) -- endforeach() -- list(REMOVE_DUPLICATES Tbb_LIBRARY_DIRS) -- -- # Configure imported targets -- -- foreach(COMPONENT ${TBB_FIND_COMPONENTS}) -- if(NOT TARGET TBB::${COMPONENT}) -- add_library(TBB::${COMPONENT} UNKNOWN IMPORTED) -- set_target_properties(TBB::${COMPONENT} PROPERTIES -- IMPORTED_LOCATION "${Tbb_${COMPONENT}_LIBRARY}" -- INTERFACE_COMPILE_OPTIONS "${Tbb_DEFINITIONS}" -- INTERFACE_INCLUDE_DIRECTORIES "${Tbb_INCLUDE_DIR}" -- ) - endif() - endforeach() --elseif(TBB_FIND_REQUIRED) -- message(FATAL_ERROR "Unable to find TBB") -+ -+ ################################## -+ # Set compile flags and libraries -+ ################################## -+ -+ set(TBB_DEFINITIONS_RELEASE "") -+ set(TBB_DEFINITIONS_DEBUG "TBB_USE_DEBUG=1") -+ -+ if(TBB_LIBRARIES_${TBB_BUILD_TYPE}) -+ set(TBB_LIBRARIES "${TBB_LIBRARIES_${TBB_BUILD_TYPE}}") -+ endif() -+ -+ if(NOT MSVC AND NOT TBB_LIBRARIES) -+ set(TBB_LIBRARIES ${TBB_LIBRARIES_RELEASE}) -+ endif() -+ -+ set(TBB_DEFINITIONS "") -+ if (MSVC AND TBB_STATIC) -+ set(TBB_DEFINITIONS __TBB_NO_IMPLICIT_LINKAGE) -+ endif () -+ -+ unset (TBB_STATIC_SUFFIX) -+ -+ find_package_handle_standard_args(TBB -+ REQUIRED_VARS TBB_INCLUDE_DIRS TBB_LIBRARIES -+ FAIL_MESSAGE "TBB library cannot be found. Consider set TBBROOT environment variable." -+ HANDLE_COMPONENTS -+ VERSION_VAR TBB_VERSION) -+ -+ ################################## -+ # Create targets -+ ################################## -+ -+ if(NOT CMAKE_VERSION VERSION_LESS 3.0 AND TBB_FOUND) -+ add_library(TBB::tbb UNKNOWN IMPORTED) -+ set_target_properties(TBB::tbb PROPERTIES -+ INTERFACE_COMPILE_DEFINITIONS "${TBB_DEFINITIONS}" -+ INTERFACE_LINK_LIBRARIES "Threads::Threads;${CMAKE_DL_LIBS}" -+ INTERFACE_INCLUDE_DIRECTORIES ${TBB_INCLUDE_DIRS} -+ IMPORTED_LOCATION ${TBB_LIBRARIES}) -+ if(TBB_LIBRARIES_RELEASE AND TBB_LIBRARIES_DEBUG) -+ set_target_properties(TBB::tbb PROPERTIES -+ INTERFACE_COMPILE_DEFINITIONS "${TBB_DEFINITIONS};$<$,$>:${TBB_DEFINITIONS_DEBUG}>;$<$:${TBB_DEFINITIONS_RELEASE}>" -+ IMPORTED_LOCATION_DEBUG ${TBB_LIBRARIES_DEBUG} -+ IMPORTED_LOCATION_RELWITHDEBINFO ${TBB_LIBRARIES_RELEASE} -+ IMPORTED_LOCATION_RELEASE ${TBB_LIBRARIES_RELEASE} -+ IMPORTED_LOCATION_MINSIZEREL ${TBB_LIBRARIES_RELEASE} -+ ) -+ endif() -+ endif() -+ -+ mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARIES) -+ -+ unset(TBB_ARCHITECTURE) -+ unset(TBB_BUILD_TYPE) -+ unset(TBB_LIB_PATH_SUFFIX) -+ unset(TBB_DEFAULT_SEARCH_DIR) -+ -+ if(TBB_DEBUG) -+ message(STATUS " TBB_FOUND = ${TBB_FOUND}") -+ message(STATUS " TBB_INCLUDE_DIRS = ${TBB_INCLUDE_DIRS}") -+ message(STATUS " TBB_DEFINITIONS = ${TBB_DEFINITIONS}") -+ message(STATUS " TBB_LIBRARIES = ${TBB_LIBRARIES}") -+ message(STATUS " TBB_DEFINITIONS_DEBUG = ${TBB_DEFINITIONS_DEBUG}") -+ message(STATUS " TBB_LIBRARIES_DEBUG = ${TBB_LIBRARIES_DEBUG}") -+ message(STATUS " TBB_DEFINITIONS_RELEASE = ${TBB_DEFINITIONS_RELEASE}") -+ message(STATUS " TBB_LIBRARIES_RELEASE = ${TBB_LIBRARIES_RELEASE}") -+ endif() -+ - endif() -diff --git a/openvdb/CMakeLists.txt b/openvdb/CMakeLists.txt -index 89301bd..6a3c90c 100644 ---- a/openvdb/CMakeLists.txt -+++ b/openvdb/CMakeLists.txt -@@ -78,7 +78,7 @@ else() - endif() - - find_package(TBB ${MINIMUM_TBB_VERSION} REQUIRED COMPONENTS tbb) --if(${Tbb_VERSION} VERSION_LESS FUTURE_MINIMUM_TBB_VERSION) -+if(${TBB_VERSION} VERSION_LESS FUTURE_MINIMUM_TBB_VERSION) - message(DEPRECATION "Support for TBB versions < ${FUTURE_MINIMUM_TBB_VERSION} " - "is deprecated and will be removed.") - endif() -@@ -129,10 +129,13 @@ endif() - # include paths from shared installs (including houdini) may pull in the wrong - # headers - -+include (CheckAtomic) -+ - set(OPENVDB_CORE_DEPENDENT_LIBS - Boost::iostreams - Boost::system - IlmBase::Half -+ ${CMAKE_REQUIRED_LIBRARIES} - ) - - if(USE_EXR) -@@ -185,11 +188,6 @@ if(WIN32) - endif() - endif() - --# @todo Should be target definitions --if(WIN32) -- add_definitions(-D_WIN32 -DNOMINMAX -DOPENVDB_DLL) --endif() -- - ##### Core library configuration - - set(OPENVDB_LIBRARY_SOURCE_FILES -@@ -374,10 +372,16 @@ set(OPENVDB_LIBRARY_UTIL_INCLUDE_FILES - - if(OPENVDB_CORE_SHARED) - add_library(openvdb_shared SHARED ${OPENVDB_LIBRARY_SOURCE_FILES}) -+ if(WIN32) -+ target_compile_definitions(openvdb_shared PUBLIC OPENVDB_DLL) -+ endif() - endif() - - if(OPENVDB_CORE_STATIC) - add_library(openvdb_static STATIC ${OPENVDB_LIBRARY_SOURCE_FILES}) -+ if(WIN32) -+ target_compile_definitions(openvdb_static PUBLIC OPENVDB_STATICLIB) -+ endif() - endif() - - # Alias either the shared or static library to the generic OpenVDB -diff --git a/openvdb/Grid.cc b/openvdb/Grid.cc -index 0015f81..cb6084a 100644 ---- a/openvdb/Grid.cc -+++ b/openvdb/Grid.cc -@@ -35,6 +35,9 @@ - #include - #include - -+// WTF??? Somehow from stdlib.h -+#undef min -+#undef max - - namespace openvdb { - OPENVDB_USE_VERSION_NAMESPACE -diff --git a/openvdb/PlatformConfig.h b/openvdb/PlatformConfig.h -index 20ad9a3..c2dd1ef 100644 ---- a/openvdb/PlatformConfig.h -+++ b/openvdb/PlatformConfig.h -@@ -44,9 +44,12 @@ - - // By default, assume that we're dynamically linking OpenEXR, unless - // OPENVDB_OPENEXR_STATICLIB is defined. -- #if !defined(OPENVDB_OPENEXR_STATICLIB) && !defined(OPENEXR_DLL) -- #define OPENEXR_DLL -- #endif -+ // Meszaros Tamas: Why? OpenEXR and its imported targets have OPENEXR_DLL -+ // in INTERFACE_COMPILE_DEFINITIONS if build with it. -+ // #if !defined(OPENVDB_OPENEXR_STATICLIB) && !defined(OPENEXR_DLL) -+ // #define OPENEXR_DLL -+ // static_assert(false, "This is bad: OPENEXR_DLL"); -+ // #endif - - #endif // _WIN32 - -diff --git a/openvdb/cmd/CMakeLists.txt b/openvdb/cmd/CMakeLists.txt -index 57fbec0..55b3850 100644 ---- a/openvdb/cmd/CMakeLists.txt -+++ b/openvdb/cmd/CMakeLists.txt -@@ -74,8 +74,9 @@ if(WIN32) - endif() - endif() - -+# @todo Should be target definitions - if(WIN32) -- add_definitions(-D_WIN32 -DNOMINMAX -DOPENVDB_DLL) -+ add_definitions(-D_WIN32 -DNOMINMAX) - endif() - - # rpath handling -@@ -88,7 +89,6 @@ if(OPENVDB_ENABLE_RPATH) - ${IlmBase_LIBRARY_DIRS} - ${Log4cplus_LIBRARY_DIRS} - ${Blosc_LIBRARY_DIRS} -- ${Tbb_LIBRARY_DIRS} - ) - if(OPENVDB_BUILD_CORE) - list(APPEND RPATHS ${CMAKE_INSTALL_PREFIX}/lib) -diff --git a/openvdb/unittest/CMakeLists.txt b/openvdb/unittest/CMakeLists.txt -index c9e0c34..7e261c0 100644 ---- a/openvdb/unittest/CMakeLists.txt -+++ b/openvdb/unittest/CMakeLists.txt -@@ -71,8 +71,9 @@ if(WIN32) - link_directories(${Boost_LIBRARY_DIR}) - endif() - -+# @todo Should be target definitions - if(WIN32) -- add_definitions(-D_WIN32 -DNOMINMAX -DOPENVDB_DLL) -+ add_definitions(-D_WIN32 -DNOMINMAX) - endif() - - ##### VDB unit tests -diff --git a/openvdb/unittest/TestFile.cc b/openvdb/unittest/TestFile.cc -index df51830..0ab0c12 100644 ---- a/openvdb/unittest/TestFile.cc -+++ b/openvdb/unittest/TestFile.cc -@@ -2573,7 +2573,7 @@ TestFile::testBlosc() - outdata(new char[decompbufbytes]); - - for (int compcode = 0; compcode <= BLOSC_ZLIB; ++compcode) { -- char* compname = nullptr; -+ const char* compname = nullptr; - if (0 > blosc_compcode_to_compname(compcode, &compname)) continue; - /// @todo This changes the compressor setting globally. - if (blosc_set_compressor(compname) < 0) continue; --- -2.17.1 - diff --git a/deps/qhull-mods.patch b/deps/qhull-mods.patch deleted file mode 100644 index 70f7be6a7..000000000 --- a/deps/qhull-mods.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 7f55a56b3d112f4dffbf21b1722f400c64bf03b1 Mon Sep 17 00:00:00 2001 -From: tamasmeszaros -Date: Mon, 21 Oct 2019 16:52:04 +0200 -Subject: [PATCH] Fix the build on macOS - ---- - CMakeLists.txt | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 07d3da2..14df8e9 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -626,18 +626,18 @@ install(TARGETS ${qhull_TARGETS_INSTALL} EXPORT QhullTargets - include(CMakePackageConfigHelpers) - - write_basic_package_version_file( -- "${CMAKE_CURRENT_BINARY_DIR}/Qhull/QhullConfigVersion.cmake" -+ "${CMAKE_CURRENT_BINARY_DIR}/QhullExport/QhullConfigVersion.cmake" - VERSION ${qhull_VERSION} - COMPATIBILITY AnyNewerVersion - ) - - export(EXPORT QhullTargets -- FILE "${CMAKE_CURRENT_BINARY_DIR}/Qhull/QhullTargets.cmake" -+ FILE "${CMAKE_CURRENT_BINARY_DIR}/QhullExport/QhullTargets.cmake" - NAMESPACE Qhull:: - ) - - configure_file(${PROJECT_SOURCE_DIR}/build/config.cmake.in -- "${CMAKE_CURRENT_BINARY_DIR}/Qhull/QhullConfig.cmake" -+ "${CMAKE_CURRENT_BINARY_DIR}/QhullExport/QhullConfig.cmake" - @ONLY - ) - -@@ -652,8 +652,8 @@ install(EXPORT QhullTargets - ) - install( - FILES -- "${CMAKE_CURRENT_BINARY_DIR}/Qhull/QhullConfig.cmake" -- "${CMAKE_CURRENT_BINARY_DIR}/Qhull/QhullConfigVersion.cmake" -+ "${CMAKE_CURRENT_BINARY_DIR}/QhullExport/QhullConfig.cmake" -+ "${CMAKE_CURRENT_BINARY_DIR}/QhullExport/QhullConfigVersion.cmake" - DESTINATION - ${ConfigPackageLocation} - COMPONENT --- -2.17.1 - diff --git a/deps/wxWidgets/wxWidgets.cmake b/deps/wxWidgets/wxWidgets.cmake index 0c8eaca97..a7f5b12e7 100644 --- a/deps/wxWidgets/wxWidgets.cmake +++ b/deps/wxWidgets/wxWidgets.cmake @@ -1,6 +1,5 @@ set(_wx_git_tag v3.1.4-patched) -# set(_patch_command "") set(_wx_toolkit "") if(CMAKE_SYSTEM_NAME STREQUAL "Linux") set(_gtk_ver 2) @@ -11,10 +10,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") endif() prusaslicer_add_cmake_project(wxWidgets - GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets" - GIT_TAG ${_wx_git_tag} - # PATCH_COMMAND "${_patch_command}" - DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} + # GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets" + # GIT_TAG tm_cross_compile #${_wx_git_tag} + URL https://github.com/prusa3d/wxWidgets/archive/refs/heads/v3.1.4-patched.zip + URL_HASH SHA256=a1e145a083d173cf320c0bd8522c7ee5829052b49b68fe5268ac84f0c576b940 + DEPENDS ${PNG_PKG} ${ZLIB_PKG} ${EXPAT_PKG} dep_TIFF dep_JPEG CMAKE_ARGS -DwxBUILD_PRECOMP=ON ${_wx_toolkit} @@ -28,9 +28,11 @@ prusaslicer_add_cmake_project(wxWidgets -DwxUSE_ZLIB=sys -DwxUSE_REGEX=builtin -DwxUSE_LIBXPM=builtin - -DwxUSE_LIBJPEG=builtin - -DwxUSE_LIBTIFF=builtin + -DwxUSE_LIBJPEG=sys + -DwxUSE_LIBTIFF=sys -DwxUSE_EXPAT=sys + -DwxUSE_LIBSDL=OFF + -DwxUSE_XTEST=OFF ) if (MSVC) diff --git a/deps/wxwidgets-pngprefix.h b/deps/wxwidgets-pngprefix.h deleted file mode 100644 index 67c70af80..000000000 --- a/deps/wxwidgets-pngprefix.h +++ /dev/null @@ -1,168 +0,0 @@ -// Patched in PrusaSlicer: These two were missing: -#define png_write_eXIf wx_png_write_eXIf -#define png_handle_eXIf wx_png_handle_eXIf - -#define png_sRGB_table wx_png_sRGB_table -#define png_sRGB_base wx_png_sRGB_base -#define png_sRGB_delta wx_png_sRGB_delta -#define png_zstream_error wx_png_zstream_error -#define png_free_buffer_list wx_png_free_buffer_list -#define png_fixed wx_png_fixed -#define png_user_version_check wx_png_user_version_check -#define png_malloc_base wx_png_malloc_base -#define png_malloc_array wx_png_malloc_array -#define png_realloc_array wx_png_realloc_array -#define png_create_png_struct wx_png_create_png_struct -#define png_destroy_png_struct wx_png_destroy_png_struct -#define png_free_jmpbuf wx_png_free_jmpbuf -#define png_zalloc wx_png_zalloc -#define png_zfree wx_png_zfree -#define png_default_read_data wx_png_default_read_data -#define png_push_fill_buffer wx_png_push_fill_buffer -#define png_default_write_data wx_png_default_write_data -#define png_default_flush wx_png_default_flush -#define png_reset_crc wx_png_reset_crc -#define png_write_data wx_png_write_data -#define png_read_sig wx_png_read_sig -#define png_read_chunk_header wx_png_read_chunk_header -#define png_read_data wx_png_read_data -#define png_crc_read wx_png_crc_read -#define png_crc_finish wx_png_crc_finish -#define png_crc_error wx_png_crc_error -#define png_calculate_crc wx_png_calculate_crc -#define png_flush wx_png_flush -#define png_write_IHDR wx_png_write_IHDR -#define png_write_PLTE wx_png_write_PLTE -#define png_compress_IDAT wx_png_compress_IDAT -#define png_write_IEND wx_png_write_IEND -#define png_write_gAMA_fixed wx_png_write_gAMA_fixed -#define png_write_sBIT wx_png_write_sBIT -#define png_write_cHRM_fixed wx_png_write_cHRM_fixed -#define png_write_sRGB wx_png_write_sRGB -#define png_write_iCCP wx_png_write_iCCP -#define png_write_sPLT wx_png_write_sPLT -#define png_write_tRNS wx_png_write_tRNS -#define png_write_bKGD wx_png_write_bKGD -#define png_write_hIST wx_png_write_hIST -#define png_write_tEXt wx_png_write_tEXt -#define png_write_zTXt wx_png_write_zTXt -#define png_write_iTXt wx_png_write_iTXt -#define png_set_text_2 wx_png_set_text_2 -#define png_write_oFFs wx_png_write_oFFs -#define png_write_pCAL wx_png_write_pCAL -#define png_write_pHYs wx_png_write_pHYs -#define png_write_tIME wx_png_write_tIME -#define png_write_sCAL_s wx_png_write_sCAL_s -#define png_write_finish_row wx_png_write_finish_row -#define png_write_start_row wx_png_write_start_row -#define png_combine_row wx_png_combine_row -#define png_do_read_interlace wx_png_do_read_interlace -#define png_do_write_interlace wx_png_do_write_interlace -#define png_read_filter_row wx_png_read_filter_row -#define png_write_find_filter wx_png_write_find_filter -#define png_read_IDAT_data wx_png_read_IDAT_data -#define png_read_finish_IDAT wx_png_read_finish_IDAT -#define png_read_finish_row wx_png_read_finish_row -#define png_read_start_row wx_png_read_start_row -#define png_zlib_inflate wx_png_zlib_inflate -#define png_read_transform_info wx_png_read_transform_info -#define png_do_strip_channel wx_png_do_strip_channel -#define png_do_swap wx_png_do_swap -#define png_do_packswap wx_png_do_packswap -#define png_do_invert wx_png_do_invert -#define png_do_bgr wx_png_do_bgr -#define png_handle_IHDR wx_png_handle_IHDR -#define png_handle_PLTE wx_png_handle_PLTE -#define png_handle_IEND wx_png_handle_IEND -#define png_handle_bKGD wx_png_handle_bKGD -#define png_handle_cHRM wx_png_handle_cHRM -#define png_handle_gAMA wx_png_handle_gAMA -#define png_handle_hIST wx_png_handle_hIST -#define png_handle_iCCP wx_png_handle_iCCP -#define png_handle_iTXt wx_png_handle_iTXt -#define png_handle_oFFs wx_png_handle_oFFs -#define png_handle_pCAL wx_png_handle_pCAL -#define png_handle_pHYs wx_png_handle_pHYs -#define png_handle_sBIT wx_png_handle_sBIT -#define png_handle_sCAL wx_png_handle_sCAL -#define png_handle_sPLT wx_png_handle_sPLT -#define png_handle_sRGB wx_png_handle_sRGB -#define png_handle_tEXt wx_png_handle_tEXt -#define png_handle_tIME wx_png_handle_tIME -#define png_handle_tRNS wx_png_handle_tRNS -#define png_handle_zTXt wx_png_handle_zTXt -#define png_check_chunk_name wx_png_check_chunk_name -#define png_check_chunk_length wx_png_check_chunk_length -#define png_handle_unknown wx_png_handle_unknown -#define png_chunk_unknown_handling wx_png_chunk_unknown_handling -#define png_do_read_transformations wx_png_do_read_transformations -#define png_do_write_transformations wx_png_do_write_transformations -#define png_init_read_transformations wx_png_init_read_transformations -#define png_push_read_chunk wx_png_push_read_chunk -#define png_push_read_sig wx_png_push_read_sig -#define png_push_check_crc wx_png_push_check_crc -#define png_push_save_buffer wx_png_push_save_buffer -#define png_push_restore_buffer wx_png_push_restore_buffer -#define png_push_read_IDAT wx_png_push_read_IDAT -#define png_process_IDAT_data wx_png_process_IDAT_data -#define png_push_process_row wx_png_push_process_row -#define png_push_handle_unknown wx_png_push_handle_unknown -#define png_push_have_info wx_png_push_have_info -#define png_push_have_end wx_png_push_have_end -#define png_push_have_row wx_png_push_have_row -#define png_push_read_end wx_png_push_read_end -#define png_process_some_data wx_png_process_some_data -#define png_read_push_finish_row wx_png_read_push_finish_row -#define png_push_handle_tEXt wx_png_push_handle_tEXt -#define png_push_read_tEXt wx_png_push_read_tEXt -#define png_push_handle_zTXt wx_png_push_handle_zTXt -#define png_push_read_zTXt wx_png_push_read_zTXt -#define png_push_handle_iTXt wx_png_push_handle_iTXt -#define png_push_read_iTXt wx_png_push_read_iTXt -#define png_colorspace_set_gamma wx_png_colorspace_set_gamma -#define png_colorspace_sync_info wx_png_colorspace_sync_info -#define png_colorspace_sync wx_png_colorspace_sync -#define png_colorspace_set_chromaticities wx_png_colorspace_set_chromaticities -#define png_colorspace_set_endpoints wx_png_colorspace_set_endpoints -#define png_colorspace_set_sRGB wx_png_colorspace_set_sRGB -#define png_colorspace_set_ICC wx_png_colorspace_set_ICC -#define png_icc_check_length wx_png_icc_check_length -#define png_icc_check_header wx_png_icc_check_header -#define png_icc_check_tag_table wx_png_icc_check_tag_table -#define png_icc_set_sRGB wx_png_icc_set_sRGB -#define png_colorspace_set_rgb_coefficients wx_png_colorspace_set_rgb_coefficients -#define png_check_IHDR wx_png_check_IHDR -#define png_do_check_palette_indexes wx_png_do_check_palette_indexes -#define png_fixed_error wx_png_fixed_error -#define png_safecat wx_png_safecat -#define png_format_number wx_png_format_number -#define png_warning_parameter wx_png_warning_parameter -#define png_warning_parameter_unsigned wx_png_warning_parameter_unsigned -#define png_warning_parameter_signed wx_png_warning_parameter_signed -#define png_formatted_warning wx_png_formatted_warning -#define png_app_warning wx_png_app_warning -#define png_app_error wx_png_app_error -#define png_chunk_report wx_png_chunk_report -#define png_ascii_from_fp wx_png_ascii_from_fp -#define png_ascii_from_fixed wx_png_ascii_from_fixed -#define png_check_fp_number wx_png_check_fp_number -#define png_check_fp_string wx_png_check_fp_string -#define png_muldiv wx_png_muldiv -#define png_muldiv_warn wx_png_muldiv_warn -#define png_reciprocal wx_png_reciprocal -#define png_reciprocal2 wx_png_reciprocal2 -#define png_gamma_significant wx_png_gamma_significant -#define png_gamma_correct wx_png_gamma_correct -#define png_gamma_16bit_correct wx_png_gamma_16bit_correct -#define png_gamma_8bit_correct wx_png_gamma_8bit_correct -#define png_destroy_gamma_table wx_png_destroy_gamma_table -#define png_build_gamma_table wx_png_build_gamma_table -#define png_safe_error wx_png_safe_error -#define png_safe_warning wx_png_safe_warning -#define png_safe_execute wx_png_safe_execute -#define png_image_error wx_png_image_error -#define png_check_keyword wx_png_check_keyword - - - - diff --git a/resources/data/hints.ini b/resources/data/hints.ini new file mode 100644 index 000000000..2ebf9091f --- /dev/null +++ b/resources/data/hints.ini @@ -0,0 +1,168 @@ + +[hint:Perspective camera] +text = Perspective camera\nDid you know that you can use the K key to quickly switch between an orthographic and perspective camera? + +[hint:Camera Views] +text = Camera Views\nDid you know that you can use the number keys 0-6 to quickly switch between predefined camera angles? + +[hint:Place on face] +text = Place on face\nDid you know that you can quickly orient a model so that one of its faces sits on the print bed? Select thePlace on facefunction or press the F key. +hypertext_type = gizmo +hypertext_gizmo_item = place + +[hint:Set number of instances] +text = Set number of instances\nDid you know that you can right-click a model and set an exact number of instances instead of copy-pasting it several times? + +[hint:Combine infill] +text = Combine infill\nDid you know that you can print the infill with a higher layer height compared to perimeters to save print time using the settingCombine infill every. +hypertext_type = settings +hypertext_settings_opt = infill_every_layers +hypertext_settings_type = 1 +hypertext_settings_category = Infill +disabled_modes = SLA; simple + +[hint:Hiding sidebar] +text = Hiding sidebar\nDid you know that you can hide the right sidebar using the shortcut Shift+Tab? You can also enable the icon for this from thePreferences. +hypertext_type = preferences +hypertext_preferences_page = 2 + +[hint:Variable layer height] +text = Variable layer height\nDid you know that you can print different regions of your model with a different layer height and smooth the transitions between them? Try theVariable layer height tool.(Not available for SLA printers.) +hypertext_type = plater +hypertext_plater_item = layersediting +disabled_modes = SLA + +[hint:Undo/redo history] +text = Undo/redo history\nDid you know that you can right-click theundo/redo arrowsto see the history of changes and to undo or redo several actions at once? +hypertext_type = plater +hypertext_plater_item = undo + +[hint:Auto-arrange settings] +text = Auto-arrange settings\nDid you know that you can right-click theauto-arrange iconto adjust the size of the gap between objects and to allow automatic rotations? +hypertext_type = plater +hypertext_plater_item = arrange + +[hint:Reload from disk] +text = Reload from disk\nDid you know that if you created a newer version of your model, you can simply reload it in PrusaSlicer? Right-click the model in the 3D view and choose Reload from disk. Read more in thedocumentation. +hypertext_type = link +hypertext_link = https://help.prusa3d.com/en/article/reload-from-disk_120427 + +[hint:Different layer height for each model] +text = Different layer height for each model\nDid you know that you can print each model on the plater with a different layer height? Right-click the model in the 3D view, choose Layers and Perimeters and adjust the values in the right panel. Read more in thedocumentation. +hypertext_type = link +hypertext_link = https://help.prusa3d.com/en/article/per-model-settings_1674 + +[hint:Solid infill threshold area] +text = Solid infill threshold area\nDid you know that you can make parts of your model with a small cross-section be filled with solid infill automatically? Set theSolid infill threshold area.(Expert mode only.) +hypertext_type = settings +hypertext_settings_opt = solid_infill_below_area +hypertext_settings_type = 1 +hypertext_settings_category = Infill +disabled_modes = SLA; simple; advanced + +[hint:Search functionality] +text = Search functionality\n Did you know that you use theSearchtool to quickly find a specific PrusaSlicer setting? Or use the familiar shortcut Ctrl+F. +hypertext_type = plater +hypertext_plater_item = search + +[hint:Box selection] +text = Box selection\nDid you know that you can do a box selection with Shift+Mouse drag? You can also box-deselect objects with Alt+Mouse drag. + +[hint:Zoom on selected objects or on all objects if none selected] +text =Zoom on selected objects or on all objects if none selected\nDid you know that you can zoom in on selected objects by pressing the Z key? If none are selected, the camera will zoom on all objects in the scene. + +[hint:Shapes gallery] +text = Shapes gallery\nDid you know that PrusaSlicer has a Shapes Gallery? You can use the included models as modifiers, negative volumes or as printable objects. Right-click the platter and selectAdd Shape - Gallery. +hypertext_type = gallery +disable_modes = simple + +[hint:Printable toggle] +text = Printable toggle\nDid you know that you can disable the G-code generation for the selected model without having to move or delete it? Toggle the Printable property of a model from the Right-click context menu. + +[hint:Mirror] +text = Mirror\nDid you know that you can mirror the selected model to create a reversed version of it? Right-click the model, select Mirror and pick the mirror axis. + +[hint:PageUp / PageDown quick rotation by 45 degrees] +text = PageUp / PageDown quick rotation by 45 degrees\nDid you know that you can quickly rotate selected models by 45 degrees around the Z-axis clockwise or counter-clockwise by pressing Page Up or Page Down respectively? + +[hint:Load config from G-code] +text = Load config from G-code\nDid you know that you can use File-Import Config to load print, filament and printer profiles from an existing G-code file? Similarly, you can use File-Import SL1 archive, which also lets you reconstruct 3D models from the voxel data. + +[hint:Ironing] +text = Ironing\nDid you know that you can smooth top surfaces of prints using Ironing? The nozzle will run a special second infill phase at the same layer to fill in holes and flatten any lifted plastic. Read more in thedocumentation. (Requires Advanced or Expert mode.) +hypertext_type = link +hypertext_link = https://help.prusa3d.com/en/article/ironing_177488 +disabled_modes = SLA; simple + +[hint:Fuzzy skin] +text = Fuzzy skin\nDid you know that you can create rough fibre-like texture on the sides of your models using theFuzzy skinfeature? You can also use modifiers to apply fuzzy-skin only to a portion of your model. +hypertext_type = settings +hypertext_settings_opt = fuzzy_skin +hypertext_settings_type = 1 +hypertext_settings_category = Layers and perimeters +disabled_modes = SLA + +[hint:Negative volume] +text = Negative volume\nDid you know that you can subtract one mesh from another using the Negative volume modifier? That way you can, for example, create easily resizable holes directly in PrusaSlicer. Read more in thedocumentation.(Requires Advanced or Expert mode.) +hypertext_type = link +hypertext_link = https://help.prusa3d.com/en/article/negative-volume_238503 +disabled_modes = SLA; simple + +[hint:Paint-on supports] +text = Paint-on supports\nDid you know that you can paint directly on the object and select areas, where supports should be enforced or blocked? Try thePaint-on supportsfeature. (Requires Advanced or Expert mode.) +hypertext_type = gizmo +hypertext_gizmo_item = fdm_supports +disabled_modes = SLA; simple + +[hint:Paint-on seam] +text = Paint-on seam\nDid you know that you can paint directly on the object and select where to place the start/endpoint of each perimeter loop? Try theSeam paintingfeature. (Requires Advanced or Expert mode.) +hypertext_type = gizmo +hypertext_gizmo_item = seam +disabled_modes = SLA; simple + +[hint:Insert Pause] +text = Insert Pause\nDid you know that you can schedule the print to pause at a specific layer? Right-click the layer slider in the Preview and select Add pause print (M601). This can be used to insert magnets, weights or nuts into your prints. Read more in thedocumentation. +hypertext_type = link +hypertext_link = https://help.prusa3d.com/en/article/insert-pause-or-custom-g-code-at-layer_120490#insert-pause-at-layer + +[hint:Insert Custom G-code] +text = Insert Custom G-code\nDid you know that you can insert a custom G-code at a specific layer? Right-click the layer in the Preview and select Add custom G-code. With this function you can, for example, create a temperature tower. Read more in thedocumentation. +hypertext_type = link +hypertext_link = https://help.prusa3d.com/en/article/insert-pause-or-custom-g-code-at-layer_120490#insert-custom-g-code-at-layer + +[hint:Configuration snapshots] +text = Configuration snapshots\nDid you know that roll back to a complete backup of all system and user profiles? You can view and move back and forth between snapshots using the Configuration - Configuration snapshots menu. Read more in thedocumentation. +hypertext_type = link +hypertext_link = https://help.prusa3d.com/en/article/configuration-snapshots_1776 + +[hint:Minimum wall thickness] +text = Minimum wall thickness\nDid you know that instead of the number of top and bottom layers, you can define theMinimum shell thicknessin millimeters? This feature is especially useful when using the variable layer height function. +hypertext_type = settings +hypertext_settings_opt = top_solid_min_thickness +hypertext_settings_type = 1 +hypertext_settings_category = Layers and perimeters +disabled_modes = SLA + +[hint:Settings in non-modal window] +text = Settings in non-modal window\nDid you know that you can open the Settings in a new non-modal window? This means you can have settings open on one screen and the G-code Preview on the other. Go to thePreferencesand select Settings in non-modal window. +hypertext_type = preferences +hypertext_preferences_page = 2 + +[hint:Adaptive infills] +text = Adaptive infills\nDid you know that you can use the Adaptive cubic and Support cubic infills to decrease the print time and lower the filament consumption? Read more in thedocumentation. +hypertext_type = link +hypertext_link = https://help.prusa3d.com/en/article/infill-patterns_177130 + +[hint:Fullscreen mode] +text = Fullscreen mode\nDid you know that you can switch PrusaSlicer to fullscreen mode? Use the F11 hotkey. + +[hint:Simplify mesh] +text = Simplify mesh\nDid you know that you can reduce the number of triangles in a mesh using the Simplify mesh feature? Right-click the model and select Simplify model. Read more in thedocumentation. +hypertext_type = link +hypertext_link = https://help.prusa3d.com/en/article/simplify-mesh_238941 + +#[hint:] +#text = +#hypertext = +#follow_text = + diff --git a/resources/icons/notification_preferences.svg b/resources/icons/notification_preferences.svg new file mode 100644 index 000000000..979101e58 --- /dev/null +++ b/resources/icons/notification_preferences.svg @@ -0,0 +1,67 @@ + +image/svg+xml + + + + + + + + diff --git a/resources/icons/notification_preferences_hover.svg b/resources/icons/notification_preferences_hover.svg new file mode 100644 index 000000000..09f229ba9 --- /dev/null +++ b/resources/icons/notification_preferences_hover.svg @@ -0,0 +1,70 @@ + +image/svg+xml + + + + + + + + diff --git a/resources/icons/notification_right.svg b/resources/icons/notification_right.svg new file mode 100644 index 000000000..58db9cc3c --- /dev/null +++ b/resources/icons/notification_right.svg @@ -0,0 +1,68 @@ + +image/svg+xml + + + + + + + diff --git a/resources/icons/notification_right_hover.svg b/resources/icons/notification_right_hover.svg new file mode 100644 index 000000000..ede2eb677 --- /dev/null +++ b/resources/icons/notification_right_hover.svg @@ -0,0 +1,68 @@ + +image/svg+xml + + + + + + + diff --git a/resources/icons/toolbar_arrow.png b/resources/icons/toolbar_arrow.png new file mode 100644 index 000000000..65905a727 Binary files /dev/null and b/resources/icons/toolbar_arrow.png differ diff --git a/resources/icons/toolbar_arrow.svg b/resources/icons/toolbar_arrow.svg new file mode 100644 index 000000000..a1476bcd9 --- /dev/null +++ b/resources/icons/toolbar_arrow.svg @@ -0,0 +1,79 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx index a09ebd5b3..d4d05f625 100644 --- a/resources/profiles/PrusaResearch.idx +++ b/resources/profiles/PrusaResearch.idx @@ -1,4 +1,5 @@ min_slic3r_version = 2.4.0-alpha0 +1.4.0-alpha5 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S). 1.4.0-alpha4 Decreased Area Fill (SL1S). 1.4.0-alpha3 Updated SL1S tilt times. 1.4.0-alpha2 Updated Prusa MINI machine limits. @@ -8,8 +9,10 @@ min_slic3r_version = 2.4.0-alpha0 1.3.0-alpha1 Added Prusament PCCF. Increased travel acceleration for Prusa MINI. Updated start g-code for Prusa MINI. Added multiple add:north and Extrudr filament profiles. Updated Z travel speed values. 1.3.0-alpha0 Disabled thick bridges, updated support settings. min_slic3r_version = 2.3.2-alpha0 +1.3.1 Added multiple add:north and Extrudr filament profiles. Updated support head settings (SL1S). 1.3.0 Added SL1S profiles. min_slic3r_version = 2.3.0-rc1 +1.2.8 Added multiple add:north and Extrudr filament profiles. 1.2.7 Updated "Prusament PC Blend Carbon Fiber" profile for Prusa MINI. 1.2.6 Added filament profile for "Prusament PC Blend Carbon Fiber". 1.2.5 Updated firmware version. Added filament profiles. Various improvements. diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 74fead88d..0f3fa6364 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -5,7 +5,7 @@ name = Prusa Research # Configuration version of this file. Config file will only be installed, if the config_version differs. # This means, the server may force the PrusaSlicer configuration to be downgraded. -config_version = 1.4.0-alpha4 +config_version = 1.4.0-alpha5 # Where to get the updates from? config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/ changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1% @@ -2025,7 +2025,7 @@ first_layer_temperature = 220 temperature = 220 filament_max_volumetric_speed = 10 compatible_printers_condition = ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) -filament_spool_weight = 0 +filament_spool_weight = 230 [filament:Extrudr PETG] inherits = *PET* @@ -2040,7 +2040,7 @@ temperature = 220 slowdown_below_layer_time = 20 filament_retract_length = nil filament_retract_lift = nil -filament_spool_weight = 0 +filament_spool_weight = 262 full_fan_speed_layer = 0 compatible_printers_condition = printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) @@ -2056,6 +2056,7 @@ filament_notes = "https://www.extrudr.com/en/products/catalogue/?material=198" first_layer_temperature = 235 temperature = 235 compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) +filament_spool_weight = 230 [filament:Extrudr XPETG CF @MINI] inherits = Extrudr XPETG CF; *PETMINI* @@ -2086,7 +2087,7 @@ max_fan_speed = 45 min_fan_speed = 25 slowdown_below_layer_time = 20 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.07{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K43{endif} ; Filament gcode LA 1.0" -filament_spool_weight = 0 +filament_spool_weight = 230 [filament:Extrudr Flax] inherits = *PLA* @@ -2100,19 +2101,19 @@ max_fan_speed = 80 min_fan_speed = 30 full_fan_speed_layer = 0 slowdown_below_layer_time = 20 -filament_max_volumetric_speed = 10 -filament_spool_weight = 0 +filament_max_volumetric_speed = 11 +filament_spool_weight = 262 [filament:Extrudr GreenTEC] inherits = *PLA* filament_vendor = Extrudr -filament_cost = 23.63 -filament_density = 1.35 +filament_cost = 56 +filament_density = 1.3 filament_notes = "https://www.extrudr.com/en/products/catalogue/?material=106" first_layer_temperature = 208 temperature = 208 slowdown_below_layer_time = 20 -filament_spool_weight = 0 +filament_spool_weight = 230 [filament:Extrudr GreenTEC Pro] inherits = *PLA* @@ -2125,7 +2126,7 @@ max_fan_speed = 80 min_fan_speed = 30 full_fan_speed_layer = 0 slowdown_below_layer_time = 20 -filament_spool_weight = 0 +filament_spool_weight = 230 [filament:Extrudr GreenTEC Pro Carbon] inherits = *PLA* @@ -2139,7 +2140,7 @@ min_fan_speed = 30 temperature = 225 full_fan_speed_layer = 0 slowdown_below_layer_time = 20 -filament_spool_weight = 0 +filament_spool_weight = 230 compatible_printers_condition = nozzle_diameter[0]>=0.4 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) [filament:Extrudr PLA NX1] @@ -2156,7 +2157,7 @@ full_fan_speed_layer = 0 max_fan_speed = 90 min_fan_speed = 30 slowdown_below_layer_time = 20 -filament_spool_weight = 0 +filament_spool_weight = 262 [filament:Extrudr PLA NX2] inherits = Extrudr PLA NX1 @@ -2176,7 +2177,7 @@ filament_max_volumetric_speed = 3 filament_notes = "https://www.extrudr.com/en/products/catalogue/?material=115" filament_retract_length = 0.4 filament_wipe = nil -filament_spool_weight = 0 +filament_spool_weight = 230 slowdown_below_layer_time = 20 [filament:Extrudr Flex Medium] @@ -2191,7 +2192,7 @@ filament_max_volumetric_speed = 2 filament_notes = "https://www.extrudr.com/en/products/catalogue/?material=115" filament_retract_length = 0.4 filament_wipe = nil -filament_spool_weight = 0 +filament_spool_weight = 230 slowdown_below_layer_time = 20 [filament:Extrudr Flex SemiSoft] @@ -2206,7 +2207,7 @@ filament_max_volumetric_speed = 1.2 filament_notes = "https://www.extrudr.com/en/products/catalogue/?material=115" filament_retract_length = 0.4 filament_wipe = nil -filament_spool_weight = 0 +filament_spool_weight = 230 slowdown_below_layer_time = 20 [filament:addnorth Adamant S1] @@ -2221,6 +2222,7 @@ bed_temperature = 50 first_layer_temperature = 245 first_layer_bed_temperature = 50 slowdown_below_layer_time = 20 +min_print_speed = 20 fan_below_layer_time = 15 fan_always_on = 1 cooling = 1 @@ -2233,6 +2235,7 @@ filament_retract_length = 0.6 filament_retract_lift = 0.5 filament_spool_weight = 0 filament_retract_restart_extra = 0.1 +filament_wipe = nil [filament:addnorth Adura X] inherits = *PET* @@ -2257,14 +2260,23 @@ full_fan_speed_layer = 0 filament_retract_length = 1.4 filament_retract_lift = 0.4 filament_max_volumetric_speed = 4 -start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.01{elsif nozzle_diameter[0]==0.6}0.04{else}0.05{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K18{elsif nozzle_diameter[0]==0.8};{else}M900 K30{endif} ; Filament gcode LA 1.0" +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.6}0.12{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/ and nozzle_diameter[0]==0.8}0.06{elsif printer_notes=~/.*PRINTER_MODEL_MINI.*/}0.2{elsif nozzle_diameter[0]==0.8}0.02{elsif nozzle_diameter[0]==0.6}0.04{else}0.08{endif} ; Filament gcode LA 1.5\n{if printer_notes=~/.*PRINTER_MODEL_MINI.*/};{elsif printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}M900 K200{elsif nozzle_diameter[0]==0.6}M900 K24{elsif nozzle_diameter[0]==0.8};{else}M900 K45{endif} ; Filament gcode LA 1.0" filament_spool_weight = 0 +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model!="MINI" and printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) -## [filament:addnorth Adura X @MINI] -## inherits = addnorth Adura X -## filament_retract_length = nil -## filament_retract_lift = nil -## compatible_printers_condition = printer_model=="MINI" +[filament:addnorth Adura X @MINI] +inherits = addnorth Adura X +filament_retract_length = nil +filament_retract_lift = nil +filament_retract_speed = 40 +filament_deretract_speed = 25 +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI" + +[filament:addnorth Adura X @MMU1] +inherits = addnorth Adura X +filament_retract_length = nil +filament_retract_lift = nil +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MK2SMM" [filament:addnorth E-PLA] inherits = *PLA* @@ -2304,13 +2316,21 @@ filament_retract_lift = 0 filament_max_volumetric_speed = 2 filament_spool_weight = 0 -## [filament:addnorth ESD-PETG @MINI] -## inherits = addnorth ESD-PETG -## filament_retract_length = nil -## filament_max_volumetric_speed = 2 -## compatible_printers_condition = printer_model=="MINI" +[filament:addnorth ESD-PETG @MINI] +inherits = addnorth ESD-PETG +filament_retract_length = nil +filament_retract_speed = 40 +filament_deretract_speed = 25 +filament_max_volumetric_speed = 2 +compatible_printers_condition = printer_model=="MINI" -[filament:addnorth OBC] +[filament:addnorth ESD-PETG @MMU1] +inherits = addnorth ESD-PETG +filament_retract_length = nil +filament_max_volumetric_speed = 2 +compatible_printers_condition = printer_model=="MK2SMM" + +[filament:addnorth OBC Polyethylene] inherits = *FLEX* filament_vendor = addnorth disable_fan_first_layers = 3 @@ -2363,9 +2383,18 @@ filament_spool_weight = 0 inherits = addnorth PETG filament_retract_length = nil filament_retract_lift = nil +filament_retract_speed = 40 +filament_deretract_speed = 25 filament_max_volumetric_speed = 7 compatible_printers_condition = printer_model=="MINI" +[filament:addnorth PETG @MMU1] +inherits = addnorth PETG +filament_retract_length = nil +filament_retract_lift = nil +filament_max_volumetric_speed = 7 +compatible_printers_condition = printer_model=="MK2SMM" + [filament:addnorth Rigid X] inherits = *PET* filament_vendor = addnorth @@ -2389,14 +2418,21 @@ filament_retract_length = 1.4 filament_max_volumetric_speed = 5 filament_spool_weight = 0 filament_notes = "Please use a nozzle that is resistant to abrasive filaments, like hardened steel." +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model!="MINI" and printer_model!="MK2SMM" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) -## [filament:addnorth Rigid X @MINI] -## inherits = addnorth Rigid X -## filament_retract_length = nil -## filament_retract_lift = nil -## filament_max_volumetric_speed = 5 -## filament_notes = "Please use a nozzle that is resistant to abrasive filaments, like hardened steel." -## compatible_printers_condition = printer_model=="MINI" +[filament:addnorth Rigid X @MINI] +inherits = addnorth Rigid X +filament_retract_length = nil +filament_retract_lift = nil +filament_retract_speed = 40 +filament_deretract_speed = 25 +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MINI" + +[filament:addnorth Rigid X @MMU1] +inherits = addnorth Rigid X +filament_retract_length = nil +filament_retract_lift = nil +compatible_printers_condition = nozzle_diameter[0]>=0.4 and printer_model=="MK2SMM" [filament:addnorth Textura] inherits = *PLA* @@ -2418,10 +2454,15 @@ filament_spool_weight = 0 filament_retract_length = 1 compatible_printers_condition = printer_model!="MK2SMM" and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material) -## [filament:addnorth Textura @MINI] -## inherits = addnorth Textura -## filament_retract_length = nil -## compatible_printers_condition = printer_model=="MINI" +[filament:addnorth Textura @MINI] +inherits = addnorth Textura +filament_retract_length = nil +compatible_printers_condition = printer_model=="MINI" + +[filament:addnorth Textura @MMU1] +inherits = addnorth Textura +filament_retract_length = nil +compatible_printers_condition = printer_model=="MK2SMM" [filament:Filament PM PETG] inherits = *PET* @@ -2481,16 +2522,43 @@ filament_cost = 33.99 filament_density = 1.20 filament_spool_weight = 230 filament_max_volumetric_speed = 1.2 -filament_retract_length = 0 +filament_retract_length = 0.4 filament_retract_speed = nil -filament_retract_lift = nil +filament_deretract_speed = 20 fan_always_on = 1 cooling = 0 -max_fan_speed = 50 -min_fan_speed = 50 +max_fan_speed = 60 +min_fan_speed = 60 disable_fan_first_layers = 4 full_fan_speed_layer = 6 +[filament:AmazonBasics TPU] +inherits = *FLEX* +filament_vendor = AmazonBasics +fan_always_on = 1 +filament_max_volumetric_speed = 1.8 +extrusion_multiplier = 1.14 +first_layer_temperature = 235 +first_layer_bed_temperature = 50 +temperature = 235 +bed_temperature = 50 +bridge_fan_speed = 100 +max_fan_speed = 80 +min_fan_speed = 80 +filament_retract_before_travel = 3 +filament_cost = 19.99 +filament_density = 1.21 +filament_retract_length = 2 +filament_retract_speed = 45 +filament_deretract_speed = 20 +filament_retract_lift = 0 +filament_wipe = 0 +disable_fan_first_layers = 4 +full_fan_speed_layer = 6 +min_print_speed = 15 +slowdown_below_layer_time = 10 +cooling = 1 + [filament:SainSmart TPU] inherits = *FLEX* filament_vendor = SainSmart @@ -3068,12 +3136,19 @@ filament_cost = 35.48 filament_density = 1.24 filament_spool_weight = 230 -[filament:SemiFlex or Flexfill 98A] +[filament:SemiFlex] inherits = *FLEX* +renamed_from = "SemiFlex or Flexfill 98A" filament_vendor = Generic filament_cost = 82.26 filament_density = 1.22 +extrusion_multiplier = 1.12 filament_max_volumetric_speed = 1.35 +fan_always_on = 1 +cooling = 0 +max_fan_speed = 30 +min_fan_speed = 30 +filament_retract_length = nil [filament:Fillamentum Flexfill 98A] inherits = *FLEX* @@ -3081,13 +3156,16 @@ filament_vendor = Fillamentum filament_cost = 82.26 filament_density = 1.23 filament_spool_weight = 230 +extrusion_multiplier = 1.12 filament_max_volumetric_speed = 1.35 fan_always_on = 1 cooling = 0 -max_fan_speed = 50 -min_fan_speed = 50 +max_fan_speed = 60 +min_fan_speed = 60 disable_fan_first_layers = 4 full_fan_speed_layer = 6 +filament_retract_length = 1.2 +filament_deretract_speed = 20 [filament:Taulman Bridge] inherits = *common* @@ -3410,16 +3488,22 @@ fan_always_on = 1 max_fan_speed = 15 min_fan_speed = 15 -[filament:SemiFlex or Flexfill 98A @MMU1] +[filament:SemiFlex @MMU1] inherits = *FLEX* +renamed_from = "SemiFlex or Flexfill 98A @MMU1" filament_vendor = Generic filament_cost = 82.26 filament_density = 1.22 +extrusion_multiplier = 1.12 filament_max_volumetric_speed = 1.35 filament_retract_length = nil filament_retract_speed = nil filament_retract_lift = nil compatible_printers_condition = printer_model=="MK2SMM" +fan_always_on = 1 +cooling = 0 +max_fan_speed = 30 +min_fan_speed = 30 [filament:Generic FLEX @MMU1] inherits = *FLEX* @@ -3550,16 +3634,18 @@ bed_temperature = 100 compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.8 [filament:Fillamentum Flexfill 98A @MINI] -inherits = SemiFlex or Flexfill 98A; *FLEXMINI* +inherits = SemiFlex; *FLEXMINI* filament_vendor = Fillamentum first_layer_temperature = 240 temperature = 240 filament_max_volumetric_speed = 1.35 filament_cost = 82.26 filament_spool_weight = 230 +max_fan_speed = 60 +min_fan_speed = 60 [filament:Generic FLEX @MINI] -inherits = SemiFlex or Flexfill 98A; *FLEXMINI* +inherits = SemiFlex; *FLEXMINI* filament_vendor = Generic fan_always_on = 0 bridge_fan_speed = 80 @@ -3639,8 +3725,8 @@ filament_cost = 33.95 bridge_fan_speed = 70 fan_always_on = 1 cooling = 0 -max_fan_speed = 50 -min_fan_speed = 50 +max_fan_speed = 60 +min_fan_speed = 60 filament_max_volumetric_speed = 1.2 compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model=="MINI" disable_fan_first_layers = 4 @@ -4080,6 +4166,8 @@ layer_height = 0.05 [sla_print:0.1 Fast @SL1S] inherits = *SL1S* layer_height = 0.1 +support_head_front_diameter = 0.6 +support_head_penetration = 0.6 ########### Materials diff --git a/resources/shaders/picking.fs b/resources/shaders/picking.fs deleted file mode 100644 index 0c9683e0d..000000000 --- a/resources/shaders/picking.fs +++ /dev/null @@ -1,14 +0,0 @@ -#version 110 - -uniform vec4 uniform_color; -uniform bool viewed_from_top; - -varying float world_pos_z; - -void main() -{ - if (viewed_from_top && world_pos_z < 0.0) - discard; - - gl_FragColor = uniform_color; -} diff --git a/resources/shaders/picking.vs b/resources/shaders/picking.vs deleted file mode 100644 index 0dc084dc1..000000000 --- a/resources/shaders/picking.vs +++ /dev/null @@ -1,11 +0,0 @@ -#version 110 - -uniform mat4 world_matrix; - -varying float world_pos_z; - -void main() -{ - world_pos_z = (world_matrix * gl_Vertex).z; - gl_Position = ftransform(); -} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f375e9c98..bbade8a97 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,26 +57,23 @@ if (SLIC3R_GUI) include(${wxWidgets_USE_FILE}) + find_package(JPEG QUIET) + find_package(TIFF QUIET) + string(REGEX MATCH "wxpng" WX_PNG_BUILTIN ${wxWidgets_LIBRARIES}) - if (NOT WX_PNG_BUILTIN) - find_package(JPEG QUIET) - if (PNG_FOUND) - list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX png) - list(APPEND wxWidgets_LIBRARIES ${PNG_LIBRARIES}) - endif () + if (PNG_FOUND AND NOT WX_PNG_BUILTIN) + list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX png) + list(APPEND wxWidgets_LIBRARIES ${PNG_LIBRARIES}) endif () string(REGEX MATCH "wxtiff" WX_TIFF_BUILTIN ${wxWidgets_LIBRARIES}) - if (NOT WX_TIFF_BUILTIN) - find_package(TIFF QUIET) - if (TIFF_FOUND) - list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX tiff) - list(APPEND wxWidgets_LIBRARIES ${TIFF_LIBRARIES}) - endif () + if (TIFF_FOUND AND NOT WX_TIFF_BUILTIN) + list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX tiff) + list(APPEND wxWidgets_LIBRARIES ${TIFF_LIBRARIES}) endif () string(REGEX MATCH "wxjpeg" WX_JPEG_BUILTIN ${wxWidgets_LIBRARIES}) - if (TIFF_FOUND AND NOT WX_JPEG_BUILTIN) + if (JPEG_FOUND AND NOT WX_JPEG_BUILTIN) list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX jpeg) list(APPEND wxWidgets_LIBRARIES ${JPEG_LIBRARIES}) endif () @@ -86,6 +83,7 @@ if (SLIC3R_GUI) list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX expat) list(APPEND wxWidgets_LIBRARIES ${EXPAT_LIBRARIES}) endif () + # This is an issue in the new wxWidgets cmake build, doesn't deal with librt find_library(LIBRT rt) if(LIBRT) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 04df43496..b3e6841c9 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -49,7 +49,7 @@ #include "libslic3r/Format/SL1.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/Thread.hpp" -#include "libslic3r/LibraryCheck.hpp" +#include "libslic3r/BlacklistedLibraryCheck.hpp" #include "PrusaSlicer.hpp" @@ -622,13 +622,18 @@ bool CLI::setup(int argc, char **argv) detect_platform(); #ifdef WIN32 - // Notify user if blacklisted library is already loaded (Nahimic) - // If there are cases of no reports with blacklisted lib - this check should be performed later. - // Some libraries are loaded when we load libraries during startup. - if (LibraryCheck::get_instance().perform_check()) { - std::wstring text = L"Following libraries has been detected inside of the PrusaSlicer process." - L" We suggest stopping or uninstalling these services if you experience crashes or unexpected behaviour while using PrusaSlicer.\n\n"; - text += LibraryCheck::get_instance().get_blacklisted_string(); + // Notify user that a blacklisted DLL was injected into PrusaSlicer process (for example Nahimic, see GH #5573). + // We hope that if a DLL is being injected into a PrusaSlicer process, it happens at the very start of the application, + // thus we shall detect them now. + if (BlacklistedLibraryCheck::get_instance().perform_check()) { + std::wstring text = L"Following DLLs have been injected into the PrusaSlicer process:\n\n"; + text += BlacklistedLibraryCheck::get_instance().get_blacklisted_string(); + text += L"\n\n" + L"PrusaSlicer is known to not run correctly with these DLLs injected. " + L"We suggest stopping or uninstalling these services if you experience " + L"crashes or unexpected behaviour while using PrusaSlicer.\n" + L"For example, ASUS Sonic Studio injects a Nahimic driver, which makes PrusaSlicer " + L"to crash on a secondary monitor, see PrusaSlicer github issue #5573"; MessageBoxW(NULL, text.c_str(), L"Warning"/*L"Incopatible library found"*/, MB_OK); } #endif diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index 5dd6ec608..dfb314d3c 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -131,8 +131,6 @@ namespace ImGui const char MaterialIconMarker = 0x8; const char CloseNotifButton = 0xB; const char CloseNotifHoverButton = 0xC; -// const char TimerDotMarker = 0xE; -// const char TimerDotEmptyMarker = 0xF; const char MinimalizeButton = 0xE; const char MinimalizeHoverButton = 0xF; const char WarningMarker = 0x10; @@ -141,6 +139,19 @@ namespace ImGui const char EjectHoverButton = 0x13; const char CancelButton = 0x14; const char CancelHoverButton = 0x15; + const char VarLayerHeightMarker = 0x16; + + const char RightArrowButton = 0x18; + const char RightArrowHoverButton = 0x19; + const char PreferencesButton = 0x1A; + const char PreferencesHoverButton = 0x1B; + const char SinkingObjectMarker = 0x1C; + const char CustomSupportsMarker = 0x1D; + const char CustomSeamMarker = 0x1E; + const char MmuSegmentationMarker = 0x1F; + + + // void MyFunction(const char* name, const MyMatrix44& v); } diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index cee9eafdc..4166658f5 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -155,11 +155,6 @@ void AppConfig::set_defaults() if (get("seq_top_layer_only").empty()) set("seq_top_layer_only", "1"); -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER - if (get("seq_top_gcode_indices").empty()) - set("seq_top_gcode_indices", "1"); -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER - if (get("use_perspective_camera").empty()) set("use_perspective_camera", "1"); @@ -172,6 +167,12 @@ void AppConfig::set_defaults() if (get("show_splash_screen").empty()) set("show_splash_screen", "1"); + if (get("last_hint").empty()) + set("last_hint", "0"); + + if (get("show_hints").empty()) + set("show_hints", "1"); + #ifdef _WIN32 if (get("use_legacy_3DConnexion").empty()) set("use_legacy_3DConnexion", "0"); @@ -544,6 +545,8 @@ void AppConfig::update_config_dir(const std::string &dir) void AppConfig::update_skein_dir(const std::string &dir) { + if (is_shapes_dir(dir)) + return; // do not save "shapes gallery" directory this->set("recent", "skein_directory", dir); } /* @@ -576,7 +579,7 @@ std::string AppConfig::get_last_output_dir(const std::string& alt, const bool re if (it2 != it->second.end() && it3 != it->second.end() && !it2->second.empty() && it3->second == "1") return it2->second; } - return alt; + return is_shapes_dir(alt) ? get_last_dir() : alt; } void AppConfig::update_last_output_dir(const std::string& dir, const bool removable) diff --git a/src/libslic3r/LibraryCheck.cpp b/src/libslic3r/BlacklistedLibraryCheck.cpp similarity index 55% rename from src/libslic3r/LibraryCheck.cpp rename to src/libslic3r/BlacklistedLibraryCheck.cpp index 1c7cbe54a..3d2ee3482 100644 --- a/src/libslic3r/LibraryCheck.cpp +++ b/src/libslic3r/BlacklistedLibraryCheck.cpp @@ -1,4 +1,4 @@ -#include "LibraryCheck.hpp" +#include "BlacklistedLibraryCheck.hpp" #include #include @@ -12,61 +12,46 @@ namespace Slic3r { #ifdef WIN32 //only dll name with .dll suffix - currently case sensitive -const std::vector LibraryCheck::blacklist({ L"NahimicOSD.dll" }); +const std::vector BlacklistedLibraryCheck::blacklist({ L"NahimicOSD.dll" }); -bool LibraryCheck::get_blacklisted(std::vector& names) +bool BlacklistedLibraryCheck::get_blacklisted(std::vector& names) { if (m_found.empty()) return false; for (const auto& lib : m_found) names.emplace_back(lib); return true; - } -std::wstring LibraryCheck::get_blacklisted_string() +std::wstring BlacklistedLibraryCheck::get_blacklisted_string() { std::wstring ret; - if (m_found.empty()) - return ret; - //ret = L"These libraries has been detected inside of the PrusaSlicer process.\n" - // L"We suggest stopping or uninstalling these services if you experience crashes while using PrusaSlicer.\n\n"; for (const auto& lib : m_found) - { - ret += lib; - ret += L"\n"; - } + ret += lib + L"\n"; return ret; } -bool LibraryCheck::perform_check() -{ - - DWORD processID = GetCurrentProcessId(); - HMODULE hMods[1024]; - HANDLE hProcess; - DWORD cbNeeded; - unsigned int i; - +bool BlacklistedLibraryCheck::perform_check() +{ // Get a handle to the process. - hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | - PROCESS_VM_READ, - FALSE, processID); + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId()); if (NULL == hProcess) return false; + // Get a list of all the modules in this process. + HMODULE hMods[1024]; + DWORD cbNeeded; if (EnumProcessModulesEx(hProcess, hMods, sizeof(hMods), &cbNeeded, LIST_MODULES_ALL)) { //printf("Total Dlls: %d\n", cbNeeded / sizeof(HMODULE)); - for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) + for (unsigned int i = 0; i < cbNeeded / sizeof(HMODULE); ++ i) { - TCHAR szModName[MAX_PATH]; + wchar_t szModName[MAX_PATH]; // Get the full path to the module's file. - if (GetModuleFileNameEx(hProcess, hMods[i], szModName, - sizeof(szModName) / sizeof(TCHAR))) + if (GetModuleFileNameExW(hProcess, hMods[i], szModName, MAX_PATH)) { // Add to list if blacklisted - if(LibraryCheck::is_blacklisted(szModName)) { + if (BlacklistedLibraryCheck::is_blacklisted(szModName)) { //wprintf(L"Contains library: %s\n", szModName); if (std::find(m_found.begin(), m_found.end(), szModName) == m_found.end()) m_found.emplace_back(szModName); @@ -79,23 +64,22 @@ bool LibraryCheck::perform_check() CloseHandle(hProcess); //printf("\n"); return !m_found.empty(); - } -bool LibraryCheck::is_blacklisted(std::wstring dllpath) +bool BlacklistedLibraryCheck::is_blacklisted(const std::wstring &dllpath) { std::wstring dllname = boost::filesystem::path(dllpath).filename().wstring(); //std::transform(dllname.begin(), dllname.end(), dllname.begin(), std::tolower); - if (std::find(LibraryCheck::blacklist.begin(), LibraryCheck::blacklist.end(), dllname) != LibraryCheck::blacklist.end()) { + if (std::find(BlacklistedLibraryCheck::blacklist.begin(), BlacklistedLibraryCheck::blacklist.end(), dllname) != BlacklistedLibraryCheck::blacklist.end()) { //std::wprintf(L"%s is blacklisted\n", dllname.c_str()); return true; } //std::wprintf(L"%s is NOT blacklisted\n", dllname.c_str()); return false; } -bool LibraryCheck::is_blacklisted(std::string dllpath) +bool BlacklistedLibraryCheck::is_blacklisted(const std::string &dllpath) { - return LibraryCheck::is_blacklisted(boost::nowide::widen(dllpath)); + return BlacklistedLibraryCheck::is_blacklisted(boost::nowide::widen(dllpath)); } #endif //WIN32 diff --git a/src/libslic3r/LibraryCheck.hpp b/src/libslic3r/BlacklistedLibraryCheck.hpp similarity index 50% rename from src/libslic3r/LibraryCheck.hpp rename to src/libslic3r/BlacklistedLibraryCheck.hpp index 663bf019e..f0cdee6de 100644 --- a/src/libslic3r/LibraryCheck.hpp +++ b/src/libslic3r/BlacklistedLibraryCheck.hpp @@ -1,5 +1,5 @@ -#ifndef slic3r_LibraryCheck_hpp_ -#define slic3r_LibraryCheck_hpp_ +#ifndef slic3r_BlacklistedLibraryCheck_hpp_ +#define slic3r_BlacklistedLibraryCheck_hpp_ #ifdef WIN32 #include @@ -10,30 +10,31 @@ namespace Slic3r { #ifdef WIN32 -class LibraryCheck +class BlacklistedLibraryCheck { public: - static LibraryCheck& get_instance() + static BlacklistedLibraryCheck& get_instance() { - static LibraryCheck instance; + static BlacklistedLibraryCheck instance; return instance; } private: - LibraryCheck() {} + BlacklistedLibraryCheck() = default; std::vector m_found; public: - LibraryCheck(LibraryCheck const&) = delete; - void operator=(LibraryCheck const&) = delete; + BlacklistedLibraryCheck(BlacklistedLibraryCheck const&) = delete; + void operator=(BlacklistedLibraryCheck const&) = delete; // returns all found blacklisted dlls bool get_blacklisted(std::vector& names); std::wstring get_blacklisted_string(); // returns true if enumerating found blacklisted dll bool perform_check(); - static bool is_blacklisted(std::string dllpath); - static bool is_blacklisted(std::wstring dllpath); + // UTF-8 encoded path + static bool is_blacklisted(const std::string &dllpath); + static bool is_blacklisted(const std::wstring &dllpath); private: static const std::vector blacklist; }; @@ -42,4 +43,4 @@ private: } // namespace Slic3r -#endif //slic3r_LibraryCheck_hpp_ \ No newline at end of file +#endif //slic3r_BlacklistedLibraryCheck_hpp_ diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 4d4dece27..f9bef903b 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -1,5 +1,5 @@ -project(libslic3r) cmake_minimum_required(VERSION 3.13) +project(libslic3r) include(PrecompiledHeader) @@ -125,8 +125,8 @@ add_library(libslic3r STATIC "${CMAKE_CURRENT_BINARY_DIR}/libslic3r_version.h" Line.cpp Line.hpp - LibraryCheck.cpp - LibraryCheck.hpp + BlacklistedLibraryCheck.cpp + BlacklistedLibraryCheck.hpp LocalesUtils.cpp LocalesUtils.hpp Model.cpp diff --git a/src/libslic3r/EdgeGrid.hpp b/src/libslic3r/EdgeGrid.hpp index 651a6d763..3c9929149 100644 --- a/src/libslic3r/EdgeGrid.hpp +++ b/src/libslic3r/EdgeGrid.hpp @@ -20,10 +20,13 @@ public: Contour(const Slic3r::Point *data, size_t size, bool open) : Contour(data, data + size, open) {} Contour(const std::vector &pts, bool open) : Contour(pts.data(), pts.size(), open) {} - const Slic3r::Point *begin() const { return m_begin; } - const Slic3r::Point *end() const { return m_end; } - bool open() const { return m_open; } - bool closed() const { return ! m_open; } + const Slic3r::Point *begin() const { return m_begin; } + const Slic3r::Point *end() const { return m_end; } + bool open() const { return m_open; } + bool closed() const { return !m_open; } + + const Slic3r::Point &front() const { return *m_begin; } + const Slic3r::Point &back() const { return *(m_end - 1); } // Start point of a segment idx. const Slic3r::Point& segment_start(size_t idx) const { @@ -61,6 +64,23 @@ public: size_t num_segments() const { return this->size() - (m_open ? 1 : 0); } + Line get_segment(size_t idx) const + { + assert(idx < this->num_segments()); + return Line(this->segment_start(idx), this->segment_end(idx)); + } + + Lines get_segments() const + { + Lines lines; + lines.reserve(this->num_segments()); + if (this->num_segments() > 2) { + for (auto it = this->begin(); it != this->end() - 1; ++it) lines.push_back(Line(*it, *(it + 1))); + if (!m_open) lines.push_back(Line(this->back(), this->front())); + } + return lines; + } + private: size_t size() const { return m_end - m_begin; } diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 58592e0d7..613b7444a 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -666,7 +666,6 @@ namespace Slic3r { close_zip_reader(&archive); -#if ENABLE_RELOAD_FROM_DISK_FOR_3MF if (m_version == 0) { // if the 3mf was not produced by PrusaSlicer and there is more than one instance, // split the object in as many objects as instances @@ -711,7 +710,6 @@ namespace Slic3r { ++i; } } -#endif // ENABLE_RELOAD_FROM_DISK_FOR_3MF for (const IdToModelObjectMap::value_type& object : m_objects) { if (object.second >= int(m_model->objects.size())) { @@ -779,7 +777,6 @@ namespace Slic3r { return false; } -#if ENABLE_RELOAD_FROM_DISK_FOR_3MF int object_idx = 0; for (ModelObject* o : model.objects) { int volume_idx = 0; @@ -795,7 +792,6 @@ namespace Slic3r { } ++object_idx; } -#endif // ENABLE_RELOAD_FROM_DISK_FOR_3MF // // fixes the min z of the model if negative // model.adjust_min_z(); @@ -1877,7 +1873,6 @@ namespace Slic3r { stl_get_size(&stl); triangle_mesh.repair(); -#if ENABLE_RELOAD_FROM_DISK_FOR_3MF if (m_version == 0) { // if the 3mf was not produced by PrusaSlicer and there is only one instance, // bake the transformation into the geometry to allow the reload from disk command @@ -1887,7 +1882,6 @@ namespace Slic3r { object.instances.front()->set_transformation(Slic3r::Geometry::Transformation()); } } -#endif // ENABLE_RELOAD_FROM_DISK_FOR_3MF ModelVolume* volume = object.add_volume(std::move(triangle_mesh)); // stores the volume matrix taken from the metadata, if present diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 24bd4939f..9e74d217d 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -172,11 +172,7 @@ namespace Slic3r { // subdivide the retraction in segments if (!wipe_path.empty()) { // add tag for processor -#if ENABLE_VALIDATE_CUSTOM_GCODE gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Start) + "\n"; -#else - gcode += ";" + GCodeProcessor::Wipe_Start_Tag + "\n"; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE for (const Line& line : wipe_path.lines()) { double segment_length = line.length(); /* Reduce retraction length a bit to avoid effective retraction speed to be greater than the configured one @@ -192,11 +188,7 @@ namespace Slic3r { ); } // add tag for processor -#if ENABLE_VALIDATE_CUSTOM_GCODE gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_End) + "\n"; -#else - gcode += ";" + GCodeProcessor::Wipe_End_Tag + "\n"; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE gcodegen.set_last_pos(wipe_path.points.back()); } @@ -655,7 +647,6 @@ namespace DoExport { print_statistics.filament_stats = result.print_statistics.volumes_per_extruder; } -#if ENABLE_VALIDATE_CUSTOM_GCODE // if any reserved keyword is found, returns a std::vector containing the first MAX_COUNT keywords found // into pairs containing: // first: source @@ -714,7 +705,6 @@ namespace DoExport { return ret; } -#endif // ENABLE_VALIDATE_CUSTOM_GCODE } // namespace DoExport void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* result, ThumbnailsGeneratorCallback thumbnail_cb) @@ -729,7 +719,6 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re print->set_started(psGCodeExport); -#if ENABLE_VALIDATE_CUSTOM_GCODE // check if any custom gcode contains keywords used by the gcode processor to // produce time estimation and gcode toolpaths std::vector> validation_res = DoExport::validate_custom_gcode(*print); @@ -743,7 +732,6 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re reports + _(L("This may cause problems in g-code visualization and printing time estimation."))); } -#endif // ENABLE_VALIDATE_CUSTOM_GCODE BOOST_LOG_TRIVIAL(info) << "Exporting G-code..." << log_memory_info(); @@ -794,16 +782,11 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re m_processor.process_file(path_tmp, true, [print]() { print->throw_if_canceled(); }); // DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics); DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->m_print_statistics); -#if ENABLE_GCODE_WINDOW if (result != nullptr) { *result = std::move(m_processor.extract_result()); // set the filename to the correct value result->filename = path; } -#else - if (result != nullptr) - *result = std::move(m_processor.extract_result()); -#endif // ENABLE_GCODE_WINDOW BOOST_LOG_TRIVIAL(debug) << "Finished processing gcode, " << log_memory_info(); if (rename_file(path_tmp, path)) @@ -1168,11 +1151,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu // adds tags for time estimators if (print.config().remaining_times.value) -#if ENABLE_VALIDATE_CUSTOM_GCODE _write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::First_Line_M73_Placeholder).c_str()); -#else - _writeln(file, GCodeProcessor::First_Line_M73_Placeholder_Tag); -#endif // ENABLE_VALIDATE_CUSTOM_GCODE // Prepare the helper object for replacing placeholders in custom G-code and output filename. m_placeholder_parser = print.placeholder_parser(); @@ -1279,11 +1258,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false); // adds tag for processor -#if ENABLE_VALIDATE_CUSTOM_GCODE _write_format(file, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str()); -#else - _write_format(file, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erCustom).c_str()); -#endif // ENABLE_VALIDATE_CUSTOM_GCODE // Write the custom start G-code _writeln(file, start_gcode); @@ -1444,11 +1419,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu _write(file, m_writer.set_fan(false)); // adds tag for processor -#if ENABLE_VALIDATE_CUSTOM_GCODE _write_format(file, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(erCustom).c_str()); -#else - _write_format(file, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(erCustom).c_str()); -#endif // ENABLE_VALIDATE_CUSTOM_GCODE // Process filament-specific gcode in extruder order. { @@ -1475,11 +1446,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu // adds tags for time estimators if (print.config().remaining_times.value) -#if ENABLE_VALIDATE_CUSTOM_GCODE _write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Last_Line_M73_Placeholder).c_str()); -#else - _writeln(file, GCodeProcessor::Last_Line_M73_Placeholder_Tag); -#endif // ENABLE_VALIDATE_CUSTOM_GCODE print.throw_if_canceled(); @@ -1495,11 +1462,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu _write_format(file, "; total filament cost = %.2lf\n", print.m_print_statistics.total_cost); if (print.m_print_statistics.total_toolchanges > 0) _write_format(file, "; total toolchanges = %i\n", print.m_print_statistics.total_toolchanges); -#if ENABLE_VALIDATE_CUSTOM_GCODE _write_format(file, ";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder).c_str()); -#else - _writeln(file, GCodeProcessor::Estimated_Printing_Time_Placeholder_Tag); -#endif // ENABLE_VALIDATE_CUSTOM_GCODE // Append full config. _write(file, "\n"); @@ -1799,11 +1762,11 @@ namespace ProcessLayer assert(m600_extruder_before_layer >= 0); // Color Change or Tool Change as Color Change. // add tag for processor -#if ENABLE_VALIDATE_CUSTOM_GCODE - gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Color_Change) + ",T" + std::to_string(m600_extruder_before_layer) + "\n"; +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Color_Change) + ",T" + std::to_string(m600_extruder_before_layer) + "," + custom_gcode->color + "\n"; #else - gcode += ";" + GCodeProcessor::Color_Change_Tag + ",T" + std::to_string(m600_extruder_before_layer) + "\n"; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE + gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Color_Change) + ",T" + std::to_string(m600_extruder_before_layer) + "\n"; +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER if (!single_extruder_printer && m600_extruder_before_layer >= 0 && first_extruder_id != (unsigned)m600_extruder_before_layer // && !MMU1 @@ -1828,11 +1791,7 @@ namespace ProcessLayer if (gcode_type == CustomGCode::PausePrint) // Pause print { // add tag for processor -#if ENABLE_VALIDATE_CUSTOM_GCODE gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Pause_Print) + "\n"; -#else - gcode += ";" + GCodeProcessor::Pause_Print_Tag + "\n"; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE //! FIXME_in_fw show message during print pause if (!pause_print_msg.empty()) gcode += "M117 " + pause_print_msg + "\n"; @@ -1840,11 +1799,7 @@ namespace ProcessLayer } else { // add tag for processor -#if ENABLE_VALIDATE_CUSTOM_GCODE gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Custom_Code) + "\n"; -#else - gcode += ";" + GCodeProcessor::Custom_Code_Tag + "\n"; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE if (gcode_type == CustomGCode::Template) // Template Custom Gcode gcode += gcodegen.placeholder_parser_process("template_custom_gcode", config.template_custom_gcode, current_extruder_id); else // custom Gcode @@ -1991,22 +1946,14 @@ void GCode::process_layer( assert(is_decimal_separator_point()); // for the sprintfs // add tag for processor -#if ENABLE_VALIDATE_CUSTOM_GCODE gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change) + "\n"; -#else - gcode += ";" + GCodeProcessor::Layer_Change_Tag + "\n"; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE // export layer z char buf[64]; sprintf(buf, ";Z:%g\n", print_z); gcode += buf; // export layer height float height = first_layer ? static_cast(print_z) : static_cast(print_z) - m_last_layer_z; -#if ENABLE_VALIDATE_CUSTOM_GCODE sprintf(buf, ";%s%g\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height).c_str(), height); -#else - sprintf(buf, ";%s%g\n", GCodeProcessor::Height_Tag.c_str(), height); -#endif // ENABLE_VALIDATE_CUSTOM_GCODE gcode += buf; // update caches m_last_layer_z = static_cast(print_z); @@ -2835,21 +2782,13 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, if (path.role() != m_last_processor_extrusion_role) { m_last_processor_extrusion_role = path.role(); -#if ENABLE_VALIDATE_CUSTOM_GCODE sprintf(buf, ";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), ExtrusionEntity::role_to_string(m_last_processor_extrusion_role).c_str()); -#else - sprintf(buf, ";%s%s\n", GCodeProcessor::Extrusion_Role_Tag.c_str(), ExtrusionEntity::role_to_string(m_last_processor_extrusion_role).c_str()); -#endif // ENABLE_VALIDATE_CUSTOM_GCODE gcode += buf; } if (last_was_wipe_tower || m_last_width != path.width) { m_last_width = path.width; -#if ENABLE_VALIDATE_CUSTOM_GCODE sprintf(buf, ";%s%g\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width).c_str(), m_last_width); -#else - sprintf(buf, ";%s%g\n", GCodeProcessor::Width_Tag.c_str(), m_last_width); -#endif // ENABLE_VALIDATE_CUSTOM_GCODE gcode += buf; } @@ -2863,11 +2802,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, if (last_was_wipe_tower || std::abs(m_last_height - path.height) > EPSILON) { m_last_height = path.height; -#if ENABLE_VALIDATE_CUSTOM_GCODE sprintf(buf, ";%s%g\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height).c_str(), m_last_height); -#else - sprintf(buf, ";%s%g\n", GCodeProcessor::Height_Tag.c_str(), m_last_height); -#endif // ENABLE_VALIDATE_CUSTOM_GCODE gcode += buf; } diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index b24404725..1141ca2a7 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -5,15 +5,11 @@ #include "GCodeProcessor.hpp" #include -#if ENABLE_VALIDATE_CUSTOM_GCODE #include -#endif // ENABLE_VALIDATE_CUSTOM_GCODE #include #include #include -#if ENABLE_GCODE_WINDOW #include -#endif // ENABLE_GCODE_WINDOW #include #include @@ -37,7 +33,6 @@ static const Slic3r::Vec3f DEFAULT_EXTRUDER_OFFSET = Slic3r::Vec3f::Zero(); namespace Slic3r { -#if ENABLE_VALIDATE_CUSTOM_GCODE const std::vector GCodeProcessor::Reserved_Tags = { "TYPE:", "WIPE_START", @@ -52,21 +47,6 @@ const std::vector GCodeProcessor::Reserved_Tags = { "_GP_LAST_LINE_M73_PLACEHOLDER", "_GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER" }; -#else -const std::string GCodeProcessor::Extrusion_Role_Tag = "TYPE:"; -const std::string GCodeProcessor::Wipe_Start_Tag = "WIPE_START"; -const std::string GCodeProcessor::Wipe_End_Tag = "WIPE_END"; -const std::string GCodeProcessor::Height_Tag = "HEIGHT:"; -const std::string GCodeProcessor::Width_Tag = "WIDTH:"; -const std::string GCodeProcessor::Layer_Change_Tag = "LAYER_CHANGE"; -const std::string GCodeProcessor::Color_Change_Tag = "COLOR_CHANGE"; -const std::string GCodeProcessor::Pause_Print_Tag = "PAUSE_PRINT"; -const std::string GCodeProcessor::Custom_Code_Tag = "CUSTOM_GCODE"; - -const std::string GCodeProcessor::First_Line_M73_Placeholder_Tag = "; _GP_FIRST_LINE_M73_PLACEHOLDER"; -const std::string GCodeProcessor::Last_Line_M73_Placeholder_Tag = "; _GP_LAST_LINE_M73_PLACEHOLDER"; -const std::string GCodeProcessor::Estimated_Printing_Time_Placeholder_Tag = "; _GP_ESTIMATED_PRINTING_TIME_PLACEHOLDER"; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE const float GCodeProcessor::Wipe_Width = 0.05f; const float GCodeProcessor::Wipe_Height = 0.05f; @@ -202,9 +182,7 @@ void GCodeProcessor::TimeMachine::reset() max_travel_acceleration = 0.0f; extrude_factor_override_percentage = 1.0f; time = 0.0f; -#if ENABLE_EXTENDED_M73_LINES stop_times = std::vector(); -#endif // ENABLE_EXTENDED_M73_LINES curr.reset(); prev.reset(); gcode_time.reset(); @@ -332,13 +310,11 @@ void GCodeProcessor::TimeMachine::calculate_time(size_t keep_last_n_blocks) layers_time[block.layer_id - 1] += block_time; } g1_times_cache.push_back({ block.g1_line_id, time }); -#if ENABLE_EXTENDED_M73_LINES // update times for remaining time to printer stop placeholders auto it_stop_time = std::lower_bound(stop_times.begin(), stop_times.end(), block.g1_line_id, [](const StopTime& t, unsigned int value) { return t.g1_line_id < value; }); if (it_stop_time != stop_times.end() && it_stop_time->g1_line_id == block.g1_line_id) it_stop_time->elapsed_time = time; -#endif // ENABLE_EXTENDED_M73_LINES } if (keep_last_n_blocks) @@ -361,11 +337,7 @@ void GCodeProcessor::TimeProcessor::reset() machines[static_cast(PrintEstimatedStatistics::ETimeMode::Normal)].enabled = true; } -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER void GCodeProcessor::TimeProcessor::post_process(const std::string& filename, std::vector& moves) -#else -void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER { boost::nowide::ifstream in(filename); if (!in.good()) @@ -381,16 +353,12 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) return int(::roundf(time_in_seconds / 60.0f)); }; -#if ENABLE_EXTENDED_M73_LINES auto time_in_last_minute = [](float time_in_seconds) { assert(time_in_seconds <= 60.0f); return time_in_seconds / 60.0f; }; auto format_line_M73_main = [](const std::string& mask, int percent, int time) { -#else - auto format_line_M73 = [](const std::string& mask, int percent, int time) { -#endif // ENABLE_EXTENDED_M73_LINES char line_M73[64]; sprintf(line_M73, mask.c_str(), std::to_string(percent).c_str(), @@ -398,7 +366,6 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) return std::string(line_M73); }; -#if ENABLE_EXTENDED_M73_LINES auto format_line_M73_stop_int = [](const std::string& mask, int time) { char line_M73[64]; sprintf(line_M73, mask.c_str(), std::to_string(time).c_str()); @@ -414,13 +381,11 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) sprintf(line_M73, mask.c_str(), format_time_float(time).c_str()); return std::string(line_M73); }; -#endif // ENABLE_EXTENDED_M73_LINES GCodeReader parser; std::string gcode_line; size_t g1_lines_counter = 0; // keeps track of last exported pair -#if ENABLE_EXTENDED_M73_LINES std::array, static_cast(PrintEstimatedStatistics::ETimeMode::Count)> last_exported_main; for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { last_exported_main[i] = { 0, time_in_minutes(machines[i].time) }; @@ -431,27 +396,18 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { last_exported_stop[i] = time_in_minutes(machines[i].time); } -#else - std::array, static_cast(PrintEstimatedStatistics::ETimeMode::Count)> last_exported; - for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { - last_exported[i] = { 0, time_in_minutes(machines[i].time) }; - } -#endif // ENABLE_EXTENDED_M73_LINES // buffer line to export only when greater than 64K to reduce writing calls std::string export_line; // replace placeholder lines with the proper final value auto process_placeholders = [&](const std::string& gcode_line) { -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER unsigned int extra_lines_count = 0; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER // remove trailing '\n' std::string line = gcode_line.substr(0, gcode_line.length() - 1); std::string ret; -#if ENABLE_VALIDATE_CUSTOM_GCODE if (line.length() > 1) { line = line.substr(1); if (export_remaining_time_enabled && @@ -459,49 +415,23 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { const TimeMachine& machine = machines[i]; if (machine.enabled) { -#if ENABLE_EXTENDED_M73_LINES // export pair ret += format_line_M73_main(machine.line_m73_main_mask.c_str(), (line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? 0 : 100, (line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0); -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER ++extra_lines_count; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER // export remaining time to next printer stop if (line == reserved_tag(ETags::First_Line_M73_Placeholder) && !machine.stop_times.empty()) { int to_export_stop = time_in_minutes(machine.stop_times.front().elapsed_time); ret += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop); last_exported_stop[i] = to_export_stop; -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER ++extra_lines_count; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER } -#else - ret += format_line_M73(machine.line_m73_mask.c_str(), - (line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? 0 : 100, - (line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0); -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER - ++extra_lines_count; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER -#endif // ENABLE_EXTENDED_M73_LINES } } } else if (line == reserved_tag(ETags::Estimated_Printing_Time_Placeholder)) { -#else - if (export_remaining_time_enabled && (line == First_Line_M73_Placeholder_Tag || line == Last_Line_M73_Placeholder_Tag)) { - for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { - const TimeMachine& machine = machines[i]; - if (machine.enabled) { - ret += format_line_M73(machine.line_m73_mask.c_str(), - (line == First_Line_M73_Placeholder_Tag) ? 0 : 100, - (line == First_Line_M73_Placeholder_Tag) ? time_in_minutes(machines[i].time) : 0); - } - } - } - else if (line == Estimated_Printing_Time_Placeholder_Tag) { -#endif // ENABLE_VALIDATE_CUSTOM_GCODE for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { const TimeMachine& machine = machines[i]; PrintEstimatedStatistics::ETimeMode mode = static_cast(i); @@ -514,15 +444,9 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) } } } -#if ENABLE_VALIDATE_CUSTOM_GCODE } -#endif // ENABLE_VALIDATE_CUSTOM_GCODE -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER return std::tuple(!ret.empty(), ret.empty() ? gcode_line : ret, (extra_lines_count == 0) ? extra_lines_count : extra_lines_count - 1); -#else - return std::make_pair(!ret.empty(), ret.empty() ? gcode_line : ret); -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER }; // check for temporary lines @@ -546,9 +470,7 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) // add lines M73 to exported gcode auto process_line_G1 = [&]() { -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER unsigned int exported_lines_count = 0; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER if (export_remaining_time_enabled) { for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { const TimeMachine& machine = machines[i]; @@ -559,30 +481,14 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) while (it != machine.g1_times_cache.end() && it->id < g1_lines_counter) ++it; if (it != machine.g1_times_cache.end() && it->id == g1_lines_counter) { -#if ENABLE_EXTENDED_M73_LINES std::pair to_export_main = { int(100.0f * it->elapsed_time / machine.time), time_in_minutes(machine.time - it->elapsed_time) }; if (last_exported_main[i] != to_export_main) { export_line += format_line_M73_main(machine.line_m73_main_mask.c_str(), to_export_main.first, to_export_main.second); last_exported_main[i] = to_export_main; -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER ++exported_lines_count; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER -#else - float elapsed_time = it->elapsed_time; - std::pair to_export = { int(100.0f * elapsed_time / machine.time), - time_in_minutes(machine.time - elapsed_time) }; - if (last_exported[i] != to_export) { - export_line += format_line_M73(machine.line_m73_mask.c_str(), - to_export.first, to_export.second); - last_exported[i] = to_export; -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER - ++exported_lines_count; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER -#endif // ENABLE_EXTENDED_M73_LINES } -#if ENABLE_EXTENDED_M73_LINES // export remaining time to next printer stop auto it_stop = std::upper_bound(machine.stop_times.begin(), machine.stop_times.end(), it->elapsed_time, [](float value, const TimeMachine::StopTime& t) { return value < t.elapsed_time; }); @@ -593,9 +499,7 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) if (last_exported_stop[i] != to_export_stop) { export_line += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop); last_exported_stop[i] = to_export_stop; -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER ++exported_lines_count; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER } } else { @@ -620,21 +524,16 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) export_line += format_line_M73_stop_float(machine.line_m73_stop_mask.c_str(), time_in_last_minute(it_stop->elapsed_time - it->elapsed_time)); last_exported_stop[i] = to_export_stop; -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER ++exported_lines_count; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER } } } } -#endif // ENABLE_EXTENDED_M73_LINES } } } } -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER return exported_lines_count; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER }; // helper function to write to disk @@ -649,10 +548,8 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) export_line.clear(); }; -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER unsigned int line_id = 0; std::vector> offsets; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER while (std::getline(in, gcode_line)) { if (!in.good()) { @@ -660,19 +557,13 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) throw Slic3r::RuntimeError(std::string("Time estimator post process export failed.\nError while reading from file.\n")); } -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER ++line_id; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER gcode_line += "\n"; // replace placeholder lines -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER auto [processed, result, lines_added_count] = process_placeholders(gcode_line); if (processed && lines_added_count > 0) offsets.push_back({ line_id, lines_added_count }); -#else - auto [processed, result] = process_placeholders(gcode_line); -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER gcode_line = result; if (!processed) { // remove temporary lines @@ -683,15 +574,10 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) parser.parse_line(gcode_line, [&](GCodeReader& reader, const GCodeReader::GCodeLine& line) { if (line.cmd_is("G1")) { -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER unsigned int extra_lines_count = process_line_G1(); ++g1_lines_counter; if (extra_lines_count > 0) offsets.push_back({ line_id, extra_lines_count }); -#else - process_line_G1(); - ++g1_lines_counter; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER } }); } @@ -707,7 +593,6 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) fclose(out); in.close(); -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER // updates moves' gcode ids which have been modified by the insertion of the M73 lines unsigned int curr_offset_id = 0; unsigned int total_offset = 0; @@ -718,7 +603,6 @@ void GCodeProcessor::TimeProcessor::post_process(const std::string& filename) } move.gcode_id += total_offset; } -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER if (rename_file(out_path, filename)) throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + filename + '\n' + @@ -800,6 +684,9 @@ void GCodeProcessor::Result::reset() { extruder_colors = std::vector(); filament_diameters = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER); filament_densities = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY); +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + custom_gcode_per_print_z = std::vector(); +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER time = 0; } #else @@ -811,6 +698,9 @@ void GCodeProcessor::Result::reset() { extruder_colors = std::vector(); filament_diameters = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER); filament_densities = std::vector(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY); +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + custom_gcode_per_print_z = std::vector(); +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER } #endif // ENABLE_GCODE_VIEWER_STATISTICS @@ -827,7 +717,6 @@ const std::vector> GCodeProces unsigned int GCodeProcessor::s_result_id = 0; -#if ENABLE_VALIDATE_CUSTOM_GCODE bool GCodeProcessor::contains_reserved_tag(const std::string& gcode, std::string& found_tag) { bool ret = false; @@ -879,20 +768,14 @@ bool GCodeProcessor::contains_reserved_tags(const std::string& gcode, unsigned i return ret; } -#endif // ENABLE_VALIDATE_CUSTOM_GCODE GCodeProcessor::GCodeProcessor() { reset(); -#if ENABLE_EXTENDED_M73_LINES m_time_processor.machines[static_cast(PrintEstimatedStatistics::ETimeMode::Normal)].line_m73_main_mask = "M73 P%s R%s\n"; m_time_processor.machines[static_cast(PrintEstimatedStatistics::ETimeMode::Normal)].line_m73_stop_mask = "M73 C%s\n"; m_time_processor.machines[static_cast(PrintEstimatedStatistics::ETimeMode::Stealth)].line_m73_main_mask = "M73 Q%s S%s\n"; m_time_processor.machines[static_cast(PrintEstimatedStatistics::ETimeMode::Stealth)].line_m73_stop_mask = "M73 D%s\n"; -#else - m_time_processor.machines[static_cast(PrintEstimatedStatistics::ETimeMode::Normal)].line_m73_mask = "M73 P%s R%s\n"; - m_time_processor.machines[static_cast(PrintEstimatedStatistics::ETimeMode::Stealth)].line_m73_mask = "M73 Q%s S%s\n"; -#endif // ENABLE_EXTENDED_M73_LINES } void GCodeProcessor::apply_config(const PrintConfig& config) @@ -959,11 +842,9 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_time_processor.export_remaining_time_enabled = config.remaining_times.value; m_use_volumetric_e = config.use_volumetric_e; -#if ENABLE_START_GCODE_VISUALIZATION const ConfigOptionFloatOrPercent* first_layer_height = config.option("first_layer_height"); if (first_layer_height != nullptr) m_first_layer_height = std::abs(first_layer_height->value); -#endif // ENABLE_START_GCODE_VISUALIZATION } void GCodeProcessor::apply_config(const DynamicPrintConfig& config) @@ -1188,11 +1069,9 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) if (use_volumetric_e != nullptr) m_use_volumetric_e = use_volumetric_e->value; -#if ENABLE_START_GCODE_VISUALIZATION const ConfigOptionFloatOrPercent* first_layer_height = config.option("first_layer_height"); if (first_layer_height != nullptr) m_first_layer_height = std::abs(first_layer_height->value); -#endif // ENABLE_START_GCODE_VISUALIZATION } void GCodeProcessor::enable_stealth_time_estimator(bool enabled) @@ -1214,12 +1093,8 @@ void GCodeProcessor::reset() m_cached_position.reset(); m_wiping = false; -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER m_line_id = 0; -#if ENABLE_SEAMS_VISUALIZATION m_last_line_id = 0; -#endif // ENABLE_SEAMS_VISUALIZATION -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER m_feedrate = 0.0f; m_width = 0.0f; m_height = 0.0f; @@ -1240,10 +1115,8 @@ void GCodeProcessor::reset() } m_extruded_last_z = 0.0f; -#if ENABLE_START_GCODE_VISUALIZATION m_first_layer_height = 0.0f; m_processing_start_custom_gcode = false; -#endif // ENABLE_START_GCODE_VISUALIZATION m_g1_line_id = 0; m_layer_id = 0; m_cp_color.reset(); @@ -1258,6 +1131,9 @@ void GCodeProcessor::reset() m_result.id = ++s_result_id; m_use_volumetric_e = false; +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + m_last_default_color_id = 0; +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER #if ENABLE_GCODE_VIEWER_DATA_CHECKING m_mm3_per_mm_compare.reset(); @@ -1284,11 +1160,7 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr if (cmd.length() == 0) { const std::string_view comment = line.comment(); if (comment.length() > 1 && detect_producer(comment)) -#if ENABLE_VALIDATE_CUSTOM_GCODE m_parser.quit_parsing(); -#else - m_parser.quit_parsing_file(); -#endif // ENABLE_VALIDATE_CUSTOM_GCODE } }); @@ -1308,9 +1180,7 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr } // process gcode -#if ENABLE_GCODE_WINDOW m_result.filename = filename; -#endif // ENABLE_GCODE_WINDOW m_result.id = ++s_result_id; // 1st move must be a dummy move m_result.moves.emplace_back(MoveVertex()); @@ -1349,11 +1219,7 @@ void GCodeProcessor::process_file(const std::string& filename, bool apply_postpr // post-process to add M73 lines into the gcode if (apply_postprocess) -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER m_time_processor.post_process(filename, m_result.moves); -#else - m_time_processor.post_process(filename); -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER #if ENABLE_GCODE_VIEWER_DATA_CHECKING std::cout << "\n"; @@ -1500,9 +1366,7 @@ void GCodeProcessor::process_gcode_line(const GCodeReader::GCodeLine& line) { /* std::cout << line.raw() << std::endl; */ -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER ++m_line_id; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER // update start position m_start_position = m_end_position; @@ -1627,17 +1491,12 @@ void GCodeProcessor::process_tags(const std::string_view comment) if (m_producers_enabled && process_producers_tags(comment)) return; -#if ENABLE_VALIDATE_CUSTOM_GCODE // extrusion role tag if (boost::starts_with(comment, reserved_tag(ETags::Role))) { set_extrusion_role(ExtrusionEntity::string_to_role(comment.substr(reserved_tag(ETags::Role).length()))); -#if ENABLE_SEAMS_VISUALIZATION if (m_extrusion_role == erExternalPerimeter) m_seams_detector.activate(true); -#endif // ENABLE_SEAMS_VISUALIZATION -#if ENABLE_START_GCODE_VISUALIZATION m_processing_start_custom_gcode = (m_extrusion_role == erCustom && m_g1_line_id == 0); -#endif // ENABLE_START_GCODE_VISUALIZATION return; } @@ -1652,28 +1511,8 @@ void GCodeProcessor::process_tags(const std::string_view comment) m_wiping = false; return; } -#else - // extrusion role tag - if (boost::starts_with(comment, Extrusion_Role_Tag)) { - set_extrusion_role(ExtrusionEntity::string_to_role(comment.substr(Extrusion_Role_Tag.length()))); - return; - } - - // wipe start tag - if (boost::starts_with(comment, Wipe_Start_Tag)) { - m_wiping = true; - return; - } - - // wipe end tag - if (boost::starts_with(comment, Wipe_End_Tag)) { - m_wiping = false; - return; - } -#endif // ENABLE_VALIDATE_CUSTOM_GCODE if (!m_producers_enabled || m_producer == EProducer::PrusaSlicer) { -#if ENABLE_VALIDATE_CUSTOM_GCODE // height tag if (boost::starts_with(comment, reserved_tag(ETags::Height))) { if (!parse_number(comment.substr(reserved_tag(ETags::Height).size()), m_forced_height)) @@ -1686,26 +1525,61 @@ void GCodeProcessor::process_tags(const std::string_view comment) BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ")."; return; } -#else - // height tag - if (boost::starts_with(comment, Height_Tag)) { - if (!parse_number(comment.substr(Height_Tag.size()), m_forced_height)) - BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ")."; - return; - } - // width tag - if (boost::starts_with(comment, Width_Tag)) { - if (!parse_number(comment.substr(Width_Tag.size()), m_forced_width)) - BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ")."; - return; - } -#endif // ENABLE_VALIDATE_CUSTOM_GCODE } -#if ENABLE_VALIDATE_CUSTOM_GCODE // color change tag if (boost::starts_with(comment, reserved_tag(ETags::Color_Change))) { unsigned char extruder_id = 0; +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + static std::vector Default_Colors = { + "#0B2C7A", // { 0.043f, 0.173f, 0.478f }, // bluish + "#1C8891", // { 0.110f, 0.533f, 0.569f }, + "#AAF200", // { 0.667f, 0.949f, 0.000f }, + "#F5CE0A", // { 0.961f, 0.808f, 0.039f }, + "#D16830", // { 0.820f, 0.408f, 0.188f }, + "#942616", // { 0.581f, 0.149f, 0.087f } // reddish + }; + + std::string color = Default_Colors[0]; + auto is_valid_color = [](const std::string& color) { + auto is_hex_digit = [](char c) { + return ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'F') || + (c >= 'a' && c <= 'f')); + }; + + if (color[0] != '#' || color.length() != 7) + return false; + for (int i = 1; i <= 6; ++i) { + if (!is_hex_digit(color[i])) + return false; + } + return true; + }; + + std::vector tokens; + boost::split(tokens, comment, boost::is_any_of(","), boost::token_compress_on); + if (tokens.size() > 1) { + if (tokens[1][0] == 'T') { + int eid; + if (!parse_number(tokens[1].substr(1), eid) || eid < 0 || eid > 255) { + BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Color_Change (" << comment << ")."; + return; + } + extruder_id = static_cast(eid); + } + } + if (tokens.size() > 2) { + if (is_valid_color(tokens[2])) + color = tokens[2]; + } + else { + color = Default_Colors[m_last_default_color_id]; + ++m_last_default_color_id; + if (m_last_default_color_id == Default_Colors.size()) + m_last_default_color_id = 0; + } +#else if (boost::starts_with(comment.substr(reserved_tag(ETags::Color_Change).size()), ",T")) { int eid; if (!parse_number(comment.substr(reserved_tag(ETags::Color_Change).size() + 2), eid) || eid < 0 || eid > 255) { @@ -1714,6 +1588,7 @@ void GCodeProcessor::process_tags(const std::string_view comment) } extruder_id = static_cast(eid); } +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER if (extruder_id < m_extruder_colors.size()) m_extruder_colors[extruder_id] = static_cast(m_extruder_offsets.size()) + m_cp_color.counter; // color_change position in list of color for preview @@ -1724,10 +1599,18 @@ void GCodeProcessor::process_tags(const std::string_view comment) if (m_extruder_id == extruder_id) { m_cp_color.current = m_extruder_colors[extruder_id]; store_move_vertex(EMoveType::Color_change); +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + CustomGCode::Item item = { static_cast(m_end_position[2]), CustomGCode::ColorChange, extruder_id + 1, color, "" }; + m_result.custom_gcode_per_print_z.emplace_back(item); + process_custom_gcode_time(CustomGCode::ColorChange); + process_filaments(CustomGCode::ColorChange); +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER } +#if !ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER process_custom_gcode_time(CustomGCode::ColorChange); process_filaments(CustomGCode::ColorChange); +#endif // !ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER return; } @@ -1735,6 +1618,10 @@ void GCodeProcessor::process_tags(const std::string_view comment) // pause print tag if (comment == reserved_tag(ETags::Pause_Print)) { store_move_vertex(EMoveType::Pause_Print); +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + CustomGCode::Item item = { static_cast(m_end_position[2]), CustomGCode::PausePrint, m_extruder_id + 1, "", "" }; + m_result.custom_gcode_per_print_z.emplace_back(item); +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER process_custom_gcode_time(CustomGCode::PausePrint); return; } @@ -1742,6 +1629,10 @@ void GCodeProcessor::process_tags(const std::string_view comment) // custom code tag if (comment == reserved_tag(ETags::Custom_Code)) { store_move_vertex(EMoveType::Custom_GCode); +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + CustomGCode::Item item = { static_cast(m_end_position[2]), CustomGCode::Custom, m_extruder_id + 1, "", "" }; + m_result.custom_gcode_per_print_z.emplace_back(item); +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER return; } @@ -1750,53 +1641,6 @@ void GCodeProcessor::process_tags(const std::string_view comment) ++m_layer_id; return; } -#else - // color change tag - if (boost::starts_with(comment, Color_Change_Tag)) { - unsigned char extruder_id = 0; - if (boost::starts_with(comment.substr(Color_Change_Tag.size()), ",T")) { - int eid; - if (! parse_number(comment.substr(Color_Change_Tag.size() + 2), eid) || eid < 0 || eid > 255) { - BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Color_Change (" << comment << ")."; - return; - } - extruder_id = static_cast(eid); - } - - m_extruder_colors[extruder_id] = static_cast(m_extruder_offsets.size()) + m_cp_color.counter; // color_change position in list of color for preview - ++m_cp_color.counter; - if (m_cp_color.counter == UCHAR_MAX) - m_cp_color.counter = 0; - - if (m_extruder_id == extruder_id) { - m_cp_color.current = m_extruder_colors[extruder_id]; - store_move_vertex(EMoveType::Color_change); - } - - process_custom_gcode_time(CustomGCode::ColorChange); - - return; - } - - // pause print tag - if (comment == Pause_Print_Tag) { - store_move_vertex(EMoveType::Pause_Print); - process_custom_gcode_time(CustomGCode::PausePrint); - return; - } - - // custom code tag - if (comment == Custom_Code_Tag) { - store_move_vertex(EMoveType::Custom_GCode); - return; - } - - // layer change tag - if (comment == Layer_Change_Tag) { - ++m_layer_id; - return; - } -#endif // ENABLE_VALIDATE_CUSTOM_GCODE #if ENABLE_GCODE_VIEWER_DATA_CHECKING // mm3_per_mm print tag @@ -1857,10 +1701,9 @@ bool GCodeProcessor::process_cura_tags(const std::string_view comment) BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown extrusion role: " << type; } -#if ENABLE_SEAMS_VISUALIZATION if (m_extrusion_role == erExternalPerimeter) m_seams_detector.activate(true); -#endif // ENABLE_SEAMS_VISUALIZATION + return true; } @@ -1925,9 +1768,7 @@ bool GCodeProcessor::process_simplify3d_tags(const std::string_view comment) pos = cmt.find(" outer perimeter"); if (pos == 0) { set_extrusion_role(erExternalPerimeter); -#if ENABLE_SEAMS_VISUALIZATION m_seams_detector.activate(true); -#endif // ENABLE_SEAMS_VISUALIZATION return true; } @@ -2082,10 +1923,8 @@ bool GCodeProcessor::process_craftware_tags(const std::string_view comment) BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown extrusion role: " << type; } -#if ENABLE_SEAMS_VISUALIZATION if (m_extrusion_role == erExternalPerimeter) m_seams_detector.activate(true); -#endif // ENABLE_SEAMS_VISUALIZATION return true; } @@ -2126,10 +1965,9 @@ bool GCodeProcessor::process_ideamaker_tags(const std::string_view comment) BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown extrusion role: " << type; } -#if ENABLE_SEAMS_VISUALIZATION if (m_extrusion_role == erExternalPerimeter) m_seams_detector.activate(true); -#endif // ENABLE_SEAMS_VISUALIZATION + return true; } @@ -2198,9 +2036,7 @@ bool GCodeProcessor::process_kissslicer_tags(const std::string_view comment) pos = comment.find(" 'Perimeter Path'"); if (pos == 0) { set_extrusion_role(erExternalPerimeter); -#if ENABLE_SEAMS_VISUALIZATION m_seams_detector.activate(true); -#endif // ENABLE_SEAMS_VISUALIZATION return true; } @@ -2407,11 +2243,7 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING } -#if ENABLE_START_GCODE_VISUALIZATION if (type == EMoveType::Extrude && (m_width == 0.0f || m_height == 0.0f)) -#else - if (type == EMoveType::Extrude && (m_extrusion_role == erCustom || m_width == 0.0f || m_height == 0.0f)) -#endif // ENABLE_START_GCODE_VISUALIZATION type = EMoveType::Travel; // time estimate section @@ -2578,7 +2410,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) machine.calculate_time(TimeProcessor::Planner::queue_size); } -#if ENABLE_SEAMS_VISUALIZATION if (m_seams_detector.is_active()) { // check for seam starting vertex if (type == EMoveType::Extrude && m_extrusion_role == erExternalPerimeter && !m_seams_detector.has_first_vertex()) @@ -2602,7 +2433,6 @@ void GCodeProcessor::process_G1(const GCodeReader::GCodeLine& line) m_seams_detector.activate(false); } } -#endif // ENABLE_SEAMS_VISUALIZATION // store move store_move_vertex(type); @@ -3057,29 +2887,17 @@ void GCodeProcessor::process_T(const std::string_view command) void GCodeProcessor::store_move_vertex(EMoveType type) { -#if ENABLE_SEAMS_VISUALIZATION m_last_line_id = (type == EMoveType::Color_change || type == EMoveType::Pause_Print || type == EMoveType::Custom_GCode) ? m_line_id + 1 : ((type == EMoveType::Seam) ? m_last_line_id : m_line_id); -#endif // ENABLE_SEAMS_VISUALIZATION MoveVertex vertex = { -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER -#if ENABLE_SEAMS_VISUALIZATION m_last_line_id, -#else - (type == EMoveType::Color_change || type == EMoveType::Pause_Print || type == EMoveType::Custom_GCode) ? m_line_id + 1 : m_line_id, -#endif // ENABLE_SEAMS_VISUALIZATION -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER type, m_extrusion_role, m_extruder_id, m_cp_color.current, -#if ENABLE_START_GCODE_VISUALIZATION Vec3f(m_end_position[X], m_end_position[Y], m_processing_start_custom_gcode ? m_first_layer_height : m_end_position[Z]) + m_extruder_offsets[m_extruder_id], -#else - Vec3f(m_end_position[X], m_end_position[Y], m_end_position[Z]) + m_extruder_offsets[m_extruder_id], -#endif // ENABLE_START_GCODE_VISUALIZATION m_end_position[E] - m_start_position[E], m_feedrate, m_width, @@ -3091,7 +2909,6 @@ void GCodeProcessor::store_move_vertex(EMoveType type) }; m_result.moves.emplace_back(vertex); -#if ENABLE_EXTENDED_M73_LINES // stores stop time placeholders for later use if (type == EMoveType::Color_change || type == EMoveType::Pause_Print) { for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode::Count); ++i) { @@ -3102,7 +2919,6 @@ void GCodeProcessor::store_move_vertex(EMoveType type) machine.stop_times.push_back({ m_g1_line_id, 0.0f }); } } -#endif // ENABLE_EXTENDED_M73_LINES } void GCodeProcessor::set_extrusion_role(ExtrusionRole role) diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index e6073042a..d83c39d09 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -12,9 +12,7 @@ #include #include #include -#if ENABLE_SEAMS_VISUALIZATION #include -#endif // ENABLE_SEAMS_VISUALIZATION namespace Slic3r { @@ -23,9 +21,7 @@ namespace Slic3r { Noop, Retract, Unretract, -#if ENABLE_SEAMS_VISUALIZATION Seam, -#endif // ENABLE_SEAMS_VISUALIZATION Tool_change, Color_change, Pause_Print, @@ -82,11 +78,9 @@ namespace Slic3r { class GCodeProcessor { -#if ENABLE_VALIDATE_CUSTOM_GCODE static const std::vector Reserved_Tags; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE + public: -#if ENABLE_VALIDATE_CUSTOM_GCODE enum class ETags : unsigned char { Role, @@ -109,20 +103,6 @@ namespace Slic3r { // checks the given gcode for reserved tags and returns true when finding any // (the first max_count found tags are returned into found_tag) static bool contains_reserved_tags(const std::string& gcode, unsigned int max_count, std::vector& found_tag); -#else - static const std::string Extrusion_Role_Tag; - static const std::string Wipe_Start_Tag; - static const std::string Wipe_End_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; - static const std::string Width_Tag; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE static const float Wipe_Width; static const float Wipe_Height; @@ -210,7 +190,6 @@ namespace Slic3r { float time() const; }; -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER struct MoveVertex { unsigned int gcode_id{ 0 }; @@ -230,7 +209,6 @@ namespace Slic3r { float volumetric_rate() const { return feedrate * mm3_per_mm; } }; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER private: struct TimeMachine @@ -269,7 +247,6 @@ namespace Slic3r { float max_travel_acceleration; // mm/s^2 float extrude_factor_override_percentage; float time; // s -#if ENABLE_EXTENDED_M73_LINES struct StopTime { unsigned int g1_line_id; @@ -278,9 +255,6 @@ namespace Slic3r { std::vector stop_times; std::string line_m73_main_mask; std::string line_m73_stop_mask; -#else - std::string line_m73_mask; -#endif // ENABLE_EXTENDED_M73_LINES State curr; State prev; CustomGCodeTime gcode_time; @@ -326,12 +300,8 @@ namespace Slic3r { void reset(); // post process the file with the given filename to add remaining time lines M73 -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER // and updates moves' gcode ids accordingly void post_process(const std::string& filename, std::vector& moves); -#else - void post_process(const std::string& filename); -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER }; struct UsedFilaments // filaments per ColorChange @@ -358,27 +328,6 @@ namespace Slic3r { }; public: -#if !ENABLE_GCODE_LINES_ID_IN_H_SLIDER - 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 temperature{ 0.0f }; // Celsius degrees - float time{ 0.0f }; // s - - float volumetric_rate() const { return feedrate * mm3_per_mm; } - }; -#endif // !ENABLE_GCODE_LINES_ID_IN_H_SLIDER - struct Result { struct SettingsIds @@ -393,9 +342,7 @@ namespace Slic3r { printer = ""; } }; -#if ENABLE_GCODE_WINDOW std::string filename; -#endif // ENABLE_GCODE_WINDOW unsigned int id; std::vector moves; Pointfs bed_shape; @@ -405,6 +352,9 @@ namespace Slic3r { std::vector filament_diameters; std::vector filament_densities; PrintEstimatedStatistics print_statistics; +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + std::vector custom_gcode_per_print_z; +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER #if ENABLE_GCODE_VIEWER_STATISTICS int64_t time{ 0 }; @@ -412,7 +362,6 @@ namespace Slic3r { void reset(); }; -#if ENABLE_SEAMS_VISUALIZATION class SeamsDetector { bool m_active{ false }; @@ -433,7 +382,6 @@ namespace Slic3r { bool is_active() const { return m_active; } bool has_first_vertex() const { return m_first_vertex.has_value(); } }; -#endif // ENABLE_SEAMS_VISUALIZATION #if ENABLE_GCODE_VIEWER_DATA_CHECKING struct DataChecker @@ -518,12 +466,8 @@ namespace Slic3r { CachedPosition m_cached_position; bool m_wiping; -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER unsigned int m_line_id; -#if ENABLE_SEAMS_VISUALIZATION unsigned int m_last_line_id; -#endif // ENABLE_SEAMS_VISUALIZATION -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER float m_feedrate; // mm/s float m_width; // mm float m_height; // mm @@ -536,17 +480,16 @@ namespace Slic3r { ExtruderColors m_extruder_colors; ExtruderTemps m_extruder_temps; float m_extruded_last_z; -#if ENABLE_START_GCODE_VISUALIZATION float m_first_layer_height; // mm bool m_processing_start_custom_gcode; -#endif // ENABLE_START_GCODE_VISUALIZATION unsigned int m_g1_line_id; unsigned int m_layer_id; CpColor m_cp_color; bool m_use_volumetric_e; -#if ENABLE_SEAMS_VISUALIZATION SeamsDetector m_seams_detector; -#endif // ENABLE_SEAMS_VISUALIZATION +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + size_t m_last_default_color_id; +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER enum class EProducer { diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 5e1937ad8..577ce9e34 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -34,13 +34,8 @@ public: { // adds tag for analyzer: std::ostringstream str; -#if ENABLE_VALIDATE_CUSTOM_GCODE str << ";" << GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) << m_layer_height << "\n"; // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming str << ";" << GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role) << ExtrusionEntity::role_to_string(erWipeTower) << "\n"; -#else - str << ";" << GCodeProcessor::Height_Tag << m_layer_height << "\n"; // don't rely on GCodeAnalyzer knowing the layer height - it knows nothing at priming - str << ";" << GCodeProcessor::Extrusion_Role_Tag << ExtrusionEntity::role_to_string(erWipeTower) << "\n"; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE m_gcode += str.str(); change_analyzer_line_width(line_width); } @@ -48,11 +43,7 @@ public: WipeTowerWriter& change_analyzer_line_width(float line_width) { // adds tag for analyzer: std::stringstream str; -#if ENABLE_VALIDATE_CUSTOM_GCODE str << ";" << GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Width) << line_width << "\n"; -#else - str << ";" << GCodeProcessor::Width_Tag << line_width << "\n"; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE m_gcode += str.str(); return *this; } diff --git a/src/libslic3r/GCodeReader.cpp b/src/libslic3r/GCodeReader.cpp index efc9ace6d..3c76e05c7 100644 --- a/src/libslic3r/GCodeReader.cpp +++ b/src/libslic3r/GCodeReader.cpp @@ -120,13 +120,8 @@ void GCodeReader::parse_file(const std::string &file, callback_t callback) { boost::nowide::ifstream f(file); std::string line; -#if ENABLE_VALIDATE_CUSTOM_GCODE m_parsing = true; while (m_parsing && std::getline(f, line)) -#else - m_parsing_file = true; - while (m_parsing_file && std::getline(f, line)) -#endif // ENABLE_VALIDATE_CUSTOM_GCODE this->parse_line(line, callback); } diff --git a/src/libslic3r/GCodeReader.hpp b/src/libslic3r/GCodeReader.hpp index 54e193799..ad9b7195a 100644 --- a/src/libslic3r/GCodeReader.hpp +++ b/src/libslic3r/GCodeReader.hpp @@ -84,12 +84,8 @@ public: { const char *ptr = buffer.c_str(); GCodeLine gline; -#if ENABLE_VALIDATE_CUSTOM_GCODE m_parsing = true; while (m_parsing && *ptr != 0) { -#else - while (*ptr != 0) { -#endif // ENABLE_VALIDATE_CUSTOM_GCODE gline.reset(); ptr = this->parse_line(ptr, gline, callback); } @@ -113,11 +109,7 @@ public: { GCodeLine gline; this->parse_line(line.c_str(), gline, callback); } void parse_file(const std::string &file, callback_t callback); -#if ENABLE_VALIDATE_CUSTOM_GCODE void quit_parsing() { m_parsing = false; } -#else - void quit_parsing_file() { m_parsing_file = false; } -#endif // ENABLE_VALIDATE_CUSTOM_GCODE float& x() { return m_position[X]; } float x() const { return m_position[X]; } @@ -156,11 +148,7 @@ private: char m_extrusion_axis; float m_position[NUM_AXES]; bool m_verbose; -#if ENABLE_VALIDATE_CUSTOM_GCODE bool m_parsing{ false }; -#else - bool m_parsing_file{ false }; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE }; } /* namespace Slic3r */ diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 3f2327686..39228516c 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -4,6 +4,7 @@ #include "Fill/Fill.hpp" #include "ShortestPath.hpp" #include "SVG.hpp" +#include "BoundingBox.hpp" #include @@ -258,4 +259,26 @@ void Layer::export_region_fill_surfaces_to_svg_debug(const char *name) const this->export_region_fill_surfaces_to_svg(debug_out_path("Layer-fill_surfaces-%s-%d.svg", name, idx ++).c_str()); } +BoundingBox get_extents(const LayerRegion &layer_region) +{ + BoundingBox bbox; + if (!layer_region.slices.surfaces.empty()) { + bbox = get_extents(layer_region.slices.surfaces.front()); + for (auto it = layer_region.slices.surfaces.cbegin() + 1; it != layer_region.slices.surfaces.cend(); ++it) + bbox.merge(get_extents(*it)); + } + return bbox; +} + +BoundingBox get_extents(const LayerRegionPtrs &layer_regions) +{ + BoundingBox bbox; + if (!layer_regions.empty()) { + bbox = get_extents(*layer_regions.front()); + for (auto it = layer_regions.begin() + 1; it != layer_regions.end(); ++it) + bbox.merge(get_extents(**it)); + } + return bbox; +} + } diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index 6cabdeb40..e6bf4b4fc 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -211,6 +211,9 @@ inline std::vector zs_from_layers(const LayerContainer &layers) return zs; } +extern BoundingBox get_extents(const LayerRegion &layer_region); +extern BoundingBox get_extents(const LayerRegionPtrs &layer_regions); + } #endif diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 306f80394..0b9614fa2 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -918,7 +918,6 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_ // Calculate 2D convex hull of of a projection of the transformed printable volumes into the XY plane. // This method is cheap in that it does not make any unnecessary copy of the volume meshes. // This method is used by the auto arrange function. -#if ENABLE_ALLOW_NEGATIVE_Z Polygon ModelObject::convex_hull_2d(const Transform3d& trafo_instance) const { Points pts; @@ -928,33 +927,6 @@ Polygon ModelObject::convex_hull_2d(const Transform3d& trafo_instance) const } return Geometry::convex_hull(std::move(pts)); } -#else -Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance) const -{ - Points pts; - for (const ModelVolume *v : this->volumes) - if (v->is_model_part()) { - Transform3d trafo = trafo_instance * v->get_matrix(); - const indexed_triangle_set &its = v->mesh().its; - if (its.vertices.empty()) { - // Using the STL faces. - const stl_file& stl = v->mesh().stl; - for (const stl_facet &facet : stl.facet_start) - for (size_t j = 0; j < 3; ++ j) { - Vec3d p = trafo * facet.vertex[j].cast(); - pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y()))); - } - } else { - // Using the shared vertices should be a bit quicker than using the STL faces. - for (size_t i = 0; i < its.vertices.size(); ++ i) { - Vec3d p = trafo * its.vertices[i].cast(); - pts.emplace_back(coord_t(scale_(p.x())), coord_t(scale_(p.y()))); - } - } - } - return Geometry::convex_hull(std::move(pts)); -} -#endif // ENABLE_ALLOW_NEGATIVE_Z void ModelObject::center_around_origin(bool include_modifiers) { @@ -969,19 +941,12 @@ void ModelObject::center_around_origin(bool include_modifiers) this->origin_translation += shift; } -#if ENABLE_ALLOW_NEGATIVE_Z void ModelObject::ensure_on_bed(bool allow_negative_z) { const double min_z = get_min_z(); if (!allow_negative_z || min_z > SINKING_Z_THRESHOLD) translate_instances({ 0.0, 0.0, -min_z }); } -#else -void ModelObject::ensure_on_bed() -{ - translate_instances({ 0.0, 0.0, -get_min_z() }); -} -#endif // ENABLE_ALLOW_NEGATIVE_Z void ModelObject::translate_instances(const Vec3d& vector) { @@ -1734,6 +1699,10 @@ size_t ModelVolume::split(unsigned int max_extruders) for (TriangleMesh *mesh : meshptrs) { mesh->repair(); + if (mesh->empty()) + // Repair may have removed unconnected triangles, thus emptying the mesh. + continue; + if (idx == 0) { this->set_mesh(std::move(*mesh)); @@ -1927,20 +1896,10 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const Vec3d rotation = get_rotation(); rotation.z() = 0.; Transform3d trafo_instance = -#if ENABLE_ALLOW_NEGATIVE_Z - Geometry::assemble_transform(get_offset().z() * Vec3d::UnitZ(), rotation, - get_scaling_factor(), get_mirror()); -#else - Geometry::assemble_transform(Vec3d::Zero(), rotation, - get_scaling_factor(), get_mirror()); -#endif // ENABLE_ALLOW_NEGATIVE_Z + Geometry::assemble_transform(get_offset().z() * Vec3d::UnitZ(), rotation, get_scaling_factor(), get_mirror()); Polygon p = get_object()->convex_hull_2d(trafo_instance); -#if !ENABLE_ALLOW_NEGATIVE_Z - assert(!p.points.empty()); -#endif // !ENABLE_ALLOW_NEGATIVE_Z - // if (!p.points.empty()) { // Polygons pp{p}; // pp = p.simplify(scaled(SIMPLIFY_TOLERANCE_MM)); @@ -1958,14 +1917,16 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, EnforcerBlockerType type) const { TriangleSelector selector(mv.mesh()); - selector.deserialize(m_data); + // Reset of TriangleSelector is done inside TriangleSelector's constructor, so we don't need it to perform it again in deserialize(). + selector.deserialize(m_data, false); return selector.get_facets(type); } indexed_triangle_set FacetsAnnotation::get_facets_strict(const ModelVolume& mv, EnforcerBlockerType type) const { TriangleSelector selector(mv.mesh()); - selector.deserialize(m_data); + // Reset of TriangleSelector is done inside TriangleSelector's constructor, so we don't need it to perform it again in deserialize(). + selector.deserialize(m_data, false); return selector.get_facets_strict(type); } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 5e7e4c03d..fda500810 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -322,12 +322,8 @@ public: Polygon convex_hull_2d(const Transform3d &trafo_instance) const; void center_around_origin(bool include_modifiers = true); - -#if ENABLE_ALLOW_NEGATIVE_Z void ensure_on_bed(bool allow_negative_z = false); -#else - void ensure_on_bed(); -#endif // ENABLE_ALLOW_NEGATIVE_Z + void translate_instances(const Vec3d& vector); void translate_instance(size_t instance_idx, const Vec3d& vector); void translate(const Vec3d &vector) { this->translate(vector(0), vector(1), vector(2)); } @@ -1176,9 +1172,7 @@ void check_model_ids_validity(const Model &model); void check_model_ids_equal(const Model &model1, const Model &model2); #endif /* NDEBUG */ -#if ENABLE_ALLOW_NEGATIVE_Z static const float SINKING_Z_THRESHOLD = -0.001f; -#endif // ENABLE_ALLOW_NEGATIVE_Z } // namespace Slic3r diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 9dde9e9a9..65284ffac 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -12,6 +12,8 @@ #include #include +#include +#include namespace Slic3r { struct ColoredLine { @@ -38,6 +40,10 @@ struct segment_traits { }; } +//#define MMU_SEGMENTATION_DEBUG_GRAPH +//#define MMU_SEGMENTATION_DEBUG_REGIONS +//#define MMU_SEGMENTATION_DEBUG_INPUT + namespace Slic3r { // Assumes that is at most same projected_l length or below than projection_l @@ -74,7 +80,7 @@ struct PaintedLine struct PaintedLineVisitor { - PaintedLineVisitor(const EdgeGrid::Grid &grid, std::vector &painted_lines, size_t reserve) : grid(grid), painted_lines(painted_lines) + PaintedLineVisitor(const EdgeGrid::Grid &grid, std::vector &painted_lines, std::mutex &painted_lines_mutex, size_t reserve) : grid(grid), painted_lines(painted_lines), painted_lines_mutex(painted_lines_mutex) { painted_lines_set.reserve(reserve); } @@ -115,8 +121,11 @@ struct PaintedLineVisitor if ((line_to_test_projected.a - grid_line.a).cast().squaredNorm() > (line_to_test_projected.b - grid_line.a).cast().squaredNorm()) line_to_test_projected.reverse(); - painted_lines.push_back({it_contour_and_segment->first, it_contour_and_segment->second, line_to_test_projected, this->color}); painted_lines_set.insert(*it_contour_and_segment); + { + boost::lock_guard lock(painted_lines_mutex); + painted_lines.push_back({it_contour_and_segment->first, it_contour_and_segment->second, line_to_test_projected, this->color}); + } } } } @@ -127,6 +136,7 @@ struct PaintedLineVisitor const EdgeGrid::Grid &grid; std::vector &painted_lines; + std::mutex &painted_lines_mutex; Line line_to_test; std::unordered_set, boost::hash>> painted_lines_set; int color = -1; @@ -136,14 +146,14 @@ struct PaintedLineVisitor static inline const double append_threshold2 = Slic3r::sqr(append_threshold); }; -static std::vector to_colored_lines(const Polygon &polygon, int color) +static std::vector to_colored_lines(const EdgeGrid::Contour &contour, int color) { std::vector lines; - if (polygon.points.size() > 2) { - lines.reserve(polygon.points.size()); - for (auto it = polygon.points.begin(); it != polygon.points.end() - 1; ++it) + if (contour.num_segments() > 2) { + lines.reserve(contour.num_segments()); + for (auto it = contour.begin(); it != contour.end() - 1; ++it) lines.push_back({Line(*it, *(it + 1)), color}); - lines.push_back({Line(polygon.points.back(), polygon.points.front()), color}); + lines.push_back({Line(contour.back(), contour.front()), color}); } return lines; } @@ -238,7 +248,9 @@ static std::vector colorize_line(const Line & line_to_ std::vector &painted_lines) { std::vector internal_painted; - for (size_t line_idx = start_idx; line_idx <= end_idx; ++line_idx) { internal_painted.emplace_back(painted_lines[line_idx]); } + for (size_t line_idx = start_idx; line_idx <= end_idx; ++line_idx) + internal_painted.emplace_back(painted_lines[line_idx]); + const int filter_eps_value = scale_(0.1f); std::vector filtered_lines; filtered_lines.emplace_back(internal_painted.front()); @@ -324,18 +336,18 @@ static std::vector colorize_line(const Line & line_to_ if (line_1.line.length() <= scale_(0.2)) line_1.color = line_0.color; } - std::vector colored_lines_simpl; - colored_lines_simpl.emplace_back(final_lines.front()); + std::vector colored_lines_simple; + colored_lines_simple.emplace_back(final_lines.front()); for (size_t line_idx = 1; line_idx < final_lines.size(); ++line_idx) { const ColoredLine &line_0 = final_lines[line_idx]; - if (colored_lines_simpl.back().color == line_0.color) - colored_lines_simpl.back().line.b = line_0.line.b; + if (colored_lines_simple.back().color == line_0.color) + colored_lines_simple.back().line.b = line_0.line.b; else - colored_lines_simpl.emplace_back(line_0); + colored_lines_simple.emplace_back(line_0); } - final_lines = colored_lines_simpl; + final_lines = colored_lines_simple; if (final_lines.size() > 1) { if (final_lines.front().color != final_lines[1].color && final_lines.front().line.length() <= scale_(0.2)) { @@ -354,13 +366,12 @@ static std::vector colorize_line(const Line & line_to_ return final_lines; } -static std::vector colorize_polygon(const Polygon &poly, const size_t start_idx, const size_t end_idx, std::vector &painted_lines) +static std::vector colorize_polygon(const EdgeGrid::Contour &contour, const size_t start_idx, const size_t end_idx, std::vector &painted_lines) { std::vector new_lines; - Lines lines = poly.lines(); - + new_lines.reserve(end_idx - start_idx + 1); for (size_t idx = 0; idx < painted_lines[start_idx].line_idx; ++idx) - new_lines.emplace_back(ColoredLine{lines[idx], 0}); + new_lines.emplace_back(ColoredLine{contour.get_segment(idx), 0}); for (size_t first_idx = start_idx; first_idx <= end_idx; ++first_idx) { size_t second_idx = first_idx; @@ -368,18 +379,18 @@ static std::vector colorize_polygon(const Polygon &poly, const size --second_idx; assert(painted_lines[first_idx].line_idx == painted_lines[second_idx].line_idx); - std::vector lines_c_line = colorize_line(lines[painted_lines[first_idx].line_idx], first_idx, second_idx, painted_lines); + std::vector lines_c_line = colorize_line(contour.get_segment(painted_lines[first_idx].line_idx), first_idx, second_idx, painted_lines); new_lines.insert(new_lines.end(), lines_c_line.begin(), lines_c_line.end()); if (second_idx + 1 <= end_idx) for (size_t idx = painted_lines[second_idx].line_idx + 1; idx < painted_lines[second_idx + 1].line_idx; ++idx) - new_lines.emplace_back(ColoredLine{lines[idx], 0}); + new_lines.emplace_back(ColoredLine{contour.get_segment(idx), 0}); first_idx = second_idx; } - for (size_t idx = painted_lines[end_idx].line_idx + 1; idx < poly.size(); ++idx) - new_lines.emplace_back(ColoredLine{lines[idx], 0}); + for (size_t idx = painted_lines[end_idx].line_idx + 1; idx < contour.num_segments(); ++idx) + new_lines.emplace_back(ColoredLine{contour.get_segment(idx), 0}); for (size_t line_idx = 2; line_idx < new_lines.size(); ++line_idx) { const ColoredLine &line_0 = new_lines[line_idx - 2]; @@ -456,15 +467,16 @@ static std::vector colorize_polygon(const Polygon &poly, const size return new_lines; } -static std::vector> colorize_polygons(const Polygons &polygons, std::vector &painted_lines) +static std::vector> colorize_polygons(const std::vector &contours, std::vector &painted_lines) { const size_t start_idx = 0; const size_t end_idx = painted_lines.size() - 1; std::vector> new_polygons; + new_polygons.reserve(contours.size()); for (size_t idx = 0; idx < painted_lines[start_idx].contour_idx; ++idx) - new_polygons.emplace_back(to_colored_lines(polygons[idx], 0)); + new_polygons.emplace_back(to_colored_lines(contours[idx], 0)); for (size_t first_idx = start_idx; first_idx <= end_idx; ++first_idx) { size_t second_idx = first_idx; @@ -473,18 +485,17 @@ static std::vector> colorize_polygons(const Polygons &p --second_idx; assert(painted_lines[first_idx].contour_idx == painted_lines[second_idx].contour_idx); - std::vector polygon_c = colorize_polygon(polygons[painted_lines[first_idx].contour_idx], first_idx, second_idx, painted_lines); - new_polygons.emplace_back(polygon_c); + new_polygons.emplace_back(colorize_polygon(contours[painted_lines[first_idx].contour_idx], first_idx, second_idx, painted_lines)); if (second_idx + 1 <= end_idx) for (size_t idx = painted_lines[second_idx].contour_idx + 1; idx < painted_lines[second_idx + 1].contour_idx; ++idx) - new_polygons.emplace_back(to_colored_lines(polygons[idx], 0)); + new_polygons.emplace_back(to_colored_lines(contours[idx], 0)); first_idx = second_idx; } - for (size_t idx = painted_lines[end_idx].contour_idx + 1; idx < polygons.size(); ++idx) - new_polygons.emplace_back(to_colored_lines(polygons[idx], 0)); + for (size_t idx = painted_lines[end_idx].contour_idx + 1; idx < contours.size(); ++idx) + new_polygons.emplace_back(to_colored_lines(contours[idx], 0)); return new_polygons; } @@ -507,7 +518,6 @@ struct MMU_Graph size_t to_idx; int color; ARC_TYPE type; - bool used{false}; bool operator==(const Arc &rhs) const { return (from_idx == rhs.from_idx) && (to_idx == rhs.to_idx) && (color == rhs.color) && (type == rhs.type); } bool operator!=(const Arc &rhs) const { return !operator==(rhs); } @@ -515,15 +525,16 @@ struct MMU_Graph struct Node { - Point point; - std::list neighbours; + Point point; + std::list arc_idxs; - void remove_edge(const size_t to_idx) + void remove_edge(const size_t to_idx, MMU_Graph &graph) { - for (auto arc_it = this->neighbours.begin(); arc_it != this->neighbours.end(); ++arc_it) { - if (arc_it->to_idx == to_idx) { - assert(arc_it->type != ARC_TYPE::BORDER); - this->neighbours.erase(arc_it); + for (auto arc_it = this->arc_idxs.begin(); arc_it != this->arc_idxs.end(); ++arc_it) { + MMU_Graph::Arc &arc = graph.arcs[*arc_it]; + if (arc.to_idx == to_idx) { + assert(arc.type != ARC_TYPE::BORDER); + this->arc_idxs.erase(arc_it); break; } } @@ -539,8 +550,8 @@ struct MMU_Graph void remove_edge(const size_t from_idx, const size_t to_idx) { - nodes[from_idx].remove_edge(to_idx); - nodes[to_idx].remove_edge(from_idx); + nodes[from_idx].remove_edge(to_idx, *this); + nodes[to_idx].remove_edge(from_idx, *this); } [[nodiscard]] size_t get_global_index(const size_t poly_idx, const size_t point_idx) const { return polygon_idx_offset[poly_idx] + point_idx; } @@ -548,42 +559,55 @@ struct MMU_Graph void append_edge(const size_t &from_idx, const size_t &to_idx, int color = -1, ARC_TYPE type = ARC_TYPE::NON_BORDER) { // Don't append duplicate edges between the same nodes. - for (const MMU_Graph::Arc &arc : this->nodes[from_idx].neighbours) - if (arc.to_idx == to_idx) + for (const size_t &arc_idx : this->nodes[from_idx].arc_idxs) + if (arcs[arc_idx].to_idx == to_idx) return; - for (const MMU_Graph::Arc &arc : this->nodes[to_idx].neighbours) - if (arc.to_idx == to_idx) + for (const size_t &arc_idx : this->nodes[to_idx].arc_idxs) + if (arcs[arc_idx].to_idx == to_idx) return; - this->nodes[from_idx].neighbours.push_back({from_idx, to_idx, color, type}); - this->nodes[to_idx].neighbours.push_back({to_idx, from_idx, color, type}); + this->nodes[from_idx].arc_idxs.push_back(this->arcs.size()); this->arcs.push_back({from_idx, to_idx, color, type}); - this->arcs.push_back({to_idx, from_idx, color, type}); + + // Always insert only one directed arc for the input polygons. + // Two directed arcs in both directions are inserted if arcs aren't between points of the input polygons. + if (type == ARC_TYPE::NON_BORDER) { + this->nodes[to_idx].arc_idxs.push_back(this->arcs.size()); + this->arcs.push_back({to_idx, from_idx, color, type}); + } } - // Ignoring arcs in the opposite direction - MMU_Graph::Arc get_arc(size_t idx) { return this->arcs[idx * 2]; } + // It assumes that between points of the input polygons is always only one directed arc, + // with the same direction as lines of the input polygon. + [[nodiscard]] MMU_Graph::Arc get_border_arc(size_t idx) const { + assert(idx < this->all_border_points); + return this->arcs[idx]; + } [[nodiscard]] size_t nodes_count() const { return this->nodes.size(); } void remove_nodes_with_one_arc() { std::queue update_queue; - for (const MMU_Graph::Node &node : this->nodes) - if (node.neighbours.size() == 1) update_queue.emplace(&node - &this->nodes.front()); + for (const MMU_Graph::Node &node : this->nodes) { + size_t node_idx = &node - &this->nodes.front(); + // Skip nodes that represent points of input polygons. + if (node.arc_idxs.size() == 1 && node_idx >= this->all_border_points) + update_queue.emplace(&node - &this->nodes.front()); + } while (!update_queue.empty()) { size_t node_from_idx = update_queue.front(); MMU_Graph::Node &node_from = this->nodes[update_queue.front()]; update_queue.pop(); - if (node_from.neighbours.empty()) + if (node_from.arc_idxs.empty()) continue; - assert(node_from.neighbours.size() == 1); - size_t node_to_idx = node_from.neighbours.front().to_idx; + assert(node_from.arc_idxs.size() == 1); + size_t node_to_idx = arcs[node_from.arc_idxs.front()].to_idx; MMU_Graph::Node &node_to = this->nodes[node_to_idx]; this->remove_edge(node_from_idx, node_to_idx); - if (node_to.neighbours.size() == 1) + if (node_to.arc_idxs.size() == 1 && node_to_idx >= this->all_border_points) update_queue.emplace(node_to_idx); } } @@ -660,17 +684,17 @@ struct MMU_Graph vertex.color(-1); Point vertex_point = mk_point(vertex); - const Point &first_point = this->nodes[this->get_arc(vertex.incident_edge()->cell()->source_index()).from_idx].point; - const Point &second_point = this->nodes[this->get_arc(vertex.incident_edge()->twin()->cell()->source_index()).from_idx].point; + const Point &first_point = this->nodes[this->get_border_arc(vertex.incident_edge()->cell()->source_index()).from_idx].point; + const Point &second_point = this->nodes[this->get_border_arc(vertex.incident_edge()->twin()->cell()->source_index()).from_idx].point; if (vertex_equal_to_point(&vertex, first_point)) { assert(vertex.color() != vertex.incident_edge()->cell()->source_index()); assert(vertex.color() != vertex.incident_edge()->twin()->cell()->source_index()); - vertex.color(this->get_arc(vertex.incident_edge()->cell()->source_index()).from_idx); + vertex.color(this->get_border_arc(vertex.incident_edge()->cell()->source_index()).from_idx); } else if (vertex_equal_to_point(&vertex, second_point)) { assert(vertex.color() != vertex.incident_edge()->cell()->source_index()); assert(vertex.color() != vertex.incident_edge()->twin()->cell()->source_index()); - vertex.color(this->get_arc(vertex.incident_edge()->twin()->cell()->source_index()).from_idx); + vertex.color(this->get_border_arc(vertex.incident_edge()->twin()->cell()->source_index()).from_idx); } else if (bbox.contains(vertex_point)) { if (auto [contour_pt, c_dist_sqr] = closest_contour_point.find(vertex_point); contour_pt != nullptr && c_dist_sqr < 3 * SCALED_EPSILON) { vertex.color(this->get_global_index(contour_pt->m_contour_idx, contour_pt->m_point_idx)); @@ -684,6 +708,35 @@ struct MMU_Graph } } } + + void garbage_collect() + { + std::vector nodes_map(this->nodes.size(), -1); + int nodes_count = 0; + size_t arcs_count = 0; + for (const MMU_Graph::Node &node : this->nodes) + if (size_t node_idx = &node - &this->nodes.front(); !node.arc_idxs.empty()) { + nodes_map[node_idx] = nodes_count++; + arcs_count += node.arc_idxs.size(); + } + + std::vector new_nodes; + std::vector new_arcs; + new_nodes.reserve(nodes_count); + new_arcs.reserve(arcs_count); + for (const MMU_Graph::Node &node : this->nodes) + if (size_t node_idx = &node - &this->nodes.front(); nodes_map[node_idx] >= 0) { + new_nodes.push_back({node.point}); + for (const size_t &arc_idx : node.arc_idxs) { + const Arc &arc = this->arcs[arc_idx]; + new_nodes.back().arc_idxs.emplace_back(new_arcs.size()); + new_arcs.push_back({size_t(nodes_map[arc.from_idx]), size_t(nodes_map[arc.to_idx]), arc.color, arc.type}); + } + } + + this->nodes = std::move(new_nodes); + this->arcs = std::move(new_arcs); + } }; static inline void mark_processed(const voronoi_diagram::const_edge_iterator &edge_iterator) @@ -825,7 +878,7 @@ static MMU_Graph build_graph(size_t layer_idx, const std::vectorcell()->source_index()); + const MMU_Graph::Arc &graph_arc = graph.get_border_arc(edge_it->cell()->source_index()); const size_t from_idx = (edge_it->vertex1() != nullptr) ? edge_it->vertex1()->color() : edge_it->vertex0()->color(); size_t to_idx = ((contour_line.line.a - contour_intersection).cast().squaredNorm() < (contour_line.line.b - contour_intersection).cast().squaredNorm()) ? @@ -859,12 +912,12 @@ static MMU_Graph build_graph(size_t layer_idx, const std::vectorvertex1()->color() < graph.nodes_count() && !graph.is_vertex_on_contour(edge_it->vertex1())) { Line contour_line_twin = lines_colored[edge_it->twin()->cell()->source_index()].line; if (line_intersection_with_epsilon(contour_line_twin, edge_line, &intersection)) { - const MMU_Graph::Arc &graph_arc = graph.get_arc(edge_it->twin()->cell()->source_index()); + const MMU_Graph::Arc &graph_arc = graph.get_border_arc(edge_it->twin()->cell()->source_index()); const size_t to_idx_l = is_point_closer_to_beginning_of_line(contour_line_twin, intersection) ? graph_arc.from_idx : graph_arc.to_idx; graph.append_edge(edge_it->vertex1()->color(), to_idx_l); } else if (line_intersection_with_epsilon(contour_line, edge_line, &intersection)) { - const MMU_Graph::Arc &graph_arc = graph.get_arc(edge_it->cell()->source_index()); + const MMU_Graph::Arc &graph_arc = graph.get_border_arc(edge_it->cell()->source_index()); const size_t to_idx_l = is_point_closer_to_beginning_of_line(contour_line, intersection) ? graph_arc.from_idx : graph_arc.to_idx; graph.append_edge(edge_it->vertex1()->color(), to_idx_l); } @@ -912,27 +965,25 @@ static MMU_Graph build_graph(size_t layer_idx, const std::vectorvertex0()->color(), graph.get_arc(edge_it->cell()->source_index()).from_idx); - } - if (points_inside(contour_line_prev.line, contour_line, second_part.b)) { - graph.append_edge(edge_it->vertex1()->color(), graph.get_arc(edge_it->cell()->source_index()).from_idx); - } + if (points_inside(contour_line_prev.line, contour_line, first_part.b)) + graph.append_edge(edge_it->vertex0()->color(), graph.get_border_arc(edge_it->cell()->source_index()).from_idx); + + if (points_inside(contour_line_prev.line, contour_line, second_part.b)) + graph.append_edge(edge_it->vertex1()->color(), graph.get_border_arc(edge_it->cell()->source_index()).from_idx); } } else { - const size_t int_point_idx = graph.get_arc(edge_it->cell()->source_index()).to_idx; + const size_t int_point_idx = graph.get_border_arc(edge_it->cell()->source_index()).to_idx; const Point int_point = graph.nodes[int_point_idx].point; const Line first_part(int_point, real_v0); const Line second_part(int_point, real_v1); if (!has_same_color(contour_line_next, colored_line)) { - if (points_inside(contour_line, contour_line_next.line, first_part.b)) { + if (points_inside(contour_line, contour_line_next.line, first_part.b)) graph.append_edge(edge_it->vertex0()->color(), int_point_idx); - } - if (points_inside(contour_line, contour_line_next.line, second_part.b)) { + + if (points_inside(contour_line, contour_line_next.line, second_part.b)) graph.append_edge(edge_it->vertex1()->color(), int_point_idx); - } } } } @@ -974,13 +1025,15 @@ static inline Polygon to_polygon(const Lines &lines) // It iterates through all nodes on the border between two different colors, and from this point, // start selection always left most edges for every node to construct CCW polygons. // Assumes that graph is planar (without self-intersection edges) -static std::vector> extract_colored_segments(MMU_Graph &graph) +static std::vector> extract_colored_segments(const MMU_Graph &graph) { + std::vector used_arcs(graph.arcs.size(), false); // When there is no next arc, then is returned original_arc or edge with is marked as used - auto get_next = [&graph](const Line &process_line, MMU_Graph::Arc &original_arc) -> MMU_Graph::Arc & { - std::vector> sorted_arcs; - for (MMU_Graph::Arc &arc : graph.nodes[original_arc.to_idx].neighbours) { - if (graph.nodes[arc.to_idx].point == process_line.a || arc.used) + auto get_next = [&graph, &used_arcs](const Line &process_line, const MMU_Graph::Arc &original_arc) -> const MMU_Graph::Arc & { + std::vector> sorted_arcs; + for (const size_t &arc_idx : graph.nodes[original_arc.to_idx].arc_idxs) { + const MMU_Graph::Arc &arc = graph.arcs[arc_idx]; + if (graph.nodes[arc.to_idx].point == process_line.a || used_arcs[arc_idx]) continue; assert(original_arc.to_idx == arc.from_idx); @@ -995,11 +1048,11 @@ static std::vector> extract_colored_segments(MMU_Grap } std::sort(sorted_arcs.begin(), sorted_arcs.end(), - [](std::pair &l, std::pair &r) -> bool { return l.second < r.second; }); + [](std::pair &l, std::pair &r) -> bool { return l.second < r.second; }); // Try to return left most edge witch is unused for (auto &sorted_arc : sorted_arcs) - if (!sorted_arc.first->used) + if (size_t arc_idx = sorted_arc.first - &graph.arcs.front(); !used_arcs[arc_idx]) return *sorted_arc.first; if (sorted_arcs.empty()) @@ -1008,35 +1061,39 @@ static std::vector> extract_colored_segments(MMU_Grap return *(sorted_arcs.front().first); }; + auto all_arc_used = [&used_arcs](const MMU_Graph::Node &node) -> bool { + return std::all_of(node.arc_idxs.cbegin(), node.arc_idxs.cend(), [&used_arcs](const size_t &arc_idx) -> bool { return used_arcs[arc_idx]; }); + }; + std::vector> polygons_segments; - for (MMU_Graph::Node &node : graph.nodes) - for (MMU_Graph::Arc &arc : node.neighbours) - arc.used = false; - for (size_t node_idx = 0; node_idx < graph.all_border_points; ++node_idx) { - MMU_Graph::Node &node = graph.nodes[node_idx]; + const MMU_Graph::Node &node = graph.nodes[node_idx]; + + for (const size_t &arc_idx : node.arc_idxs) { + const MMU_Graph::Arc &arc = graph.arcs[arc_idx]; + if (arc.type == MMU_Graph::ARC_TYPE::NON_BORDER || used_arcs[arc_idx])continue; - for (MMU_Graph::Arc &arc : node.neighbours) { - if (arc.type == MMU_Graph::ARC_TYPE::NON_BORDER || arc.used) continue; Line process_line(node.point, graph.nodes[arc.to_idx].point); - arc.used = true; + used_arcs[arc_idx] = true; Lines face_lines; face_lines.emplace_back(process_line); Point start_p = process_line.a; - Line p_vec = process_line; - MMU_Graph::Arc *p_arc = &arc; + Line p_vec = process_line; + const MMU_Graph::Arc *p_arc = &arc; do { - MMU_Graph::Arc &next = get_next(p_vec, *p_arc); - face_lines.emplace_back(Line(graph.nodes[next.from_idx].point, graph.nodes[next.to_idx].point)); - if (next.used) break; + const MMU_Graph::Arc &next = get_next(p_vec, *p_arc); + size_t next_arc_idx = &next - &graph.arcs.front(); + face_lines.emplace_back(graph.nodes[next.from_idx].point, graph.nodes[next.to_idx].point); + if (used_arcs[next_arc_idx]) + break; - next.used = true; - p_vec = Line(graph.nodes[next.from_idx].point, graph.nodes[next.to_idx].point); - p_arc = &next; - } while (graph.nodes[p_arc->to_idx].point != start_p); + used_arcs[next_arc_idx] = true; + p_vec = Line(graph.nodes[next.from_idx].point, graph.nodes[next.to_idx].point); + p_arc = &next; + } while (graph.nodes[p_arc->to_idx].point != start_p || !all_arc_used(graph.nodes[p_arc->to_idx])); Polygon poly = to_polygon(face_lines); if (poly.is_counter_clockwise() && poly.is_valid()) @@ -1049,20 +1106,19 @@ static std::vector> extract_colored_segments(MMU_Grap // Used in remove_multiple_edges_in_vertices() // Returns length of edge with is connected to contour. To this length is include other edges with follows it if they are almost straight (with the // tolerance of 15) And also if node between two subsequent edges is connected only to these two edges. -static inline double compute_edge_length(MMU_Graph &graph, size_t start_idx, MMU_Graph::Arc &start_edge) +static inline double compute_edge_length(const MMU_Graph &graph, const size_t start_idx, const size_t &start_arc_idx) { - for (MMU_Graph::Node &node : graph.nodes) - for (MMU_Graph::Arc &arc : node.neighbours) - arc.used = false; + assert(start_arc_idx < graph.arcs.size()); + std::vector used_arcs(graph.arcs.size(), false); - start_edge.used = true; - MMU_Graph::Arc *arc = &start_edge; - size_t idx = start_idx; - double line_total_length = Line(graph.nodes[idx].point, graph.nodes[arc->to_idx].point).length(); - while (graph.nodes[arc->to_idx].neighbours.size() == 2) { + used_arcs[start_arc_idx] = true; + const MMU_Graph::Arc *arc = &graph.arcs[start_arc_idx]; + size_t idx = start_idx; + double line_total_length = (graph.nodes[arc->to_idx].point - graph.nodes[idx].point).cast().norm();; + while (graph.nodes[arc->to_idx].arc_idxs.size() == 2) { bool found = false; - for (MMU_Graph::Arc &arc_n : graph.nodes[arc->to_idx].neighbours) { - if (arc_n.type == MMU_Graph::ARC_TYPE::NON_BORDER && !arc_n.used && arc_n.to_idx != idx) { + for (const size_t &arc_idx : graph.nodes[arc->to_idx].arc_idxs) { + if (const MMU_Graph::Arc &arc_n = graph.arcs[arc_idx]; arc_n.type == MMU_Graph::ARC_TYPE::NON_BORDER && !used_arcs[arc_idx] && arc_n.to_idx != idx) { Line first_line(graph.nodes[idx].point, graph.nodes[arc->to_idx].point); Line second_line(graph.nodes[arc->to_idx].point, graph.nodes[arc_n.to_idx].point); @@ -1080,8 +1136,8 @@ static inline double compute_edge_length(MMU_Graph &graph, size_t start_idx, MMU idx = arc->to_idx; arc = &arc_n; - line_total_length += Line(graph.nodes[idx].point, graph.nodes[arc->to_idx].point).length(); - arc_n.used = true; + line_total_length += (graph.nodes[arc->to_idx].point - graph.nodes[idx].point).cast().norm(); + used_arcs[arc_idx] = true; found = true; break; } @@ -1104,11 +1160,12 @@ static void remove_multiple_edges_in_vertices(MMU_Graph &graph, const std::vecto size_t second_idx = graph.get_global_index(poly_idx, (colored_segment.second + 1) % graph.polygon_sizes[poly_idx]); Line seg_line(graph.nodes[first_idx].point, graph.nodes[second_idx].point); - if (graph.nodes[first_idx].neighbours.size() >= 3) { + if (graph.nodes[first_idx].arc_idxs.size() >= 3) { std::vector> arc_to_check; - for (MMU_Graph::Arc &n_arc : graph.nodes[first_idx].neighbours) { + for (const size_t &arc_idx : graph.nodes[first_idx].arc_idxs) { + MMU_Graph::Arc &n_arc = graph.arcs[arc_idx]; if (n_arc.type == MMU_Graph::ARC_TYPE::NON_BORDER) { - double total_len = compute_edge_length(graph, first_idx, n_arc); + double total_len = compute_edge_length(graph, first_idx, arc_idx); arc_to_check.emplace_back(&n_arc, total_len); } } @@ -1478,18 +1535,18 @@ static inline std::vector> mmu_segmentation_top_and_bott LayerColorStat out; const Layer &layer = *layers[layer_idx]; for (const LayerRegion *region : layer.regions()) - if (const PrintRegionConfig &config = region->region().config(); + if (const PrintRegionConfig &config = region->region().config(); // color_idx == 0 means "don't know" extruder aka the underlying extruder. // As this region may split existing regions, we collect statistics over all regions for color_idx == 0. color_idx == 0 || config.perimeter_extruder == int(color_idx)) { - out.extrusion_width = std::max(out.extrusion_width, config.perimeter_extrusion_width); - out.top_solid_layers = std::max(out.top_solid_layers, config.top_solid_layers); - out.bottom_solid_layers = std::max(out.bottom_solid_layers, config.bottom_solid_layers); - out.small_region_threshold = config.gap_fill_enabled.value && config.gap_fill_speed.value > 0 ? - // Gap fill enabled. Enable a single line of 1/2 extrusion width. - 0.5 * config.perimeter_extrusion_width : - // Gap fill disabled. Enable two lines slightly overlapping. - config.perimeter_extrusion_width + 0.7f * Flow::rounded_rectangle_extrusion_spacing(config.perimeter_extrusion_width, layer.height); + out.extrusion_width = std::max(out.extrusion_width, float(config.perimeter_extrusion_width)); + out.top_solid_layers = std::max(out.top_solid_layers, config.top_solid_layers); + out.bottom_solid_layers = std::max(out.bottom_solid_layers, config.bottom_solid_layers); + out.small_region_threshold = config.gap_fill_enabled.value && config.gap_fill_speed.value > 0 ? + // Gap fill enabled. Enable a single line of 1/2 extrusion width. + 0.5f * float(config.perimeter_extrusion_width) : + // Gap fill disabled. Enable two lines slightly overlapping. + float(config.perimeter_extrusion_width) + 0.7f * Flow::rounded_rectangle_extrusion_spacing(float(config.perimeter_extrusion_width), float(layer.height)); out.small_region_threshold = scaled(out.small_region_threshold * 0.5f); ++ out.num_regions; } @@ -1603,14 +1660,70 @@ static std::vector>> merge_segmented_la return segmented_regions_merged; } +#ifdef MMU_SEGMENTATION_DEBUG_REGIONS +static void export_regions_to_svg(const std::string &path, const std::vector> ®ions, const ExPolygons &lslices) +{ + const std::vector colors = {"blue", "cyan", "red", "orange", "magenta", "pink", "purple", "yellow"}; + coordf_t stroke_width = scale_(0.05); + BoundingBox bbox = get_extents(lslices); + bbox.offset(scale_(1.)); + ::Slic3r::SVG svg(path.c_str(), bbox); + + svg.draw_outline(lslices, "green", "lime", stroke_width); + for (const std::pair ®ion : regions) { + int region_color = region.second; + if (region_color >= 0 && region_color < int(colors.size())) + svg.draw(region.first, colors[region_color]); + else + svg.draw(region.first, "black"); + } +} +#endif // MMU_SEGMENTATION_DEBUG_REGIONS + +#ifdef MMU_SEGMENTATION_DEBUG_GRAPH +static void export_graph_to_svg(const std::string &path, const MMU_Graph &graph, const ExPolygons &lslices) +{ + const std::vector colors = {"blue", "cyan", "red", "orange", "magenta", "pink", "purple", "green", "yellow"}; + coordf_t stroke_width = scale_(0.05); + BoundingBox bbox = get_extents(lslices); + bbox.offset(scale_(1.)); + ::Slic3r::SVG svg(path.c_str(), bbox); + for (const MMU_Graph::Node &node : graph.nodes) + for (const size_t &arc_idx : node.arc_idxs) { + const MMU_Graph::Arc &arc = graph.arcs[arc_idx]; + Line arc_line(node.point, graph.nodes[arc.to_idx].point); + if (arc.type == MMU_Graph::ARC_TYPE::BORDER && arc.color >= 0 && arc.color < int(colors.size())) + svg.draw(arc_line, colors[arc.color], stroke_width); + else + svg.draw(arc_line, "black", stroke_width); + } +} +#endif // MMU_SEGMENTATION_DEBUG_GRAPH + +#ifdef MMU_SEGMENTATION_DEBUG_INPUT +void export_processed_input_expolygons_to_svg(const std::string &path, const LayerRegionPtrs ®ions, const ExPolygons &processed_input_expolygons) +{ + coordf_t stroke_width = scale_(0.05); + BoundingBox bbox = get_extents(regions); + bbox.merge(get_extents(processed_input_expolygons)); + bbox.offset(scale_(1.)); + ::Slic3r::SVG svg(path.c_str(), bbox); + + for (LayerRegion *region : regions) + svg.draw_outline(region->slices.surfaces, "blue", "cyan", stroke_width); + + svg.draw_outline(processed_input_expolygons, "red", "pink", stroke_width); +} +#endif // MMU_SEGMENTATION_DEBUG_INPUT + std::vector>> multi_material_segmentation_by_painting(const PrintObject &print_object, const std::function &throw_on_cancel_callback) { std::vector>> segmented_regions(print_object.layers().size()); std::vector> painted_lines(print_object.layers().size()); + std::array painted_lines_mutex; std::vector edge_grids(print_object.layers().size()); const ConstLayerPtrsAdaptor layers = print_object.layers(); std::vector input_expolygons(layers.size()); - std::vector input_polygons(layers.size()); throw_on_cancel_callback(); @@ -1636,86 +1749,99 @@ std::vector>> multi_material_segmentati // This consequently leads to issues with the extraction of colored segments by function extract_colored_segments. // Calling expolygons_simplify fixed these issues. input_expolygons[layer_idx] = smooth_outward(expolygons_simplify(offset_ex(ex_polygons, -10.f * float(SCALED_EPSILON)), 5 * SCALED_EPSILON), 10 * coord_t(SCALED_EPSILON)); - input_polygons[layer_idx] = to_polygons(input_expolygons[layer_idx]); + +#ifdef MMU_SEGMENTATION_DEBUG_INPUT + { + static int iRun = 0; + export_processed_input_expolygons_to_svg(debug_out_path("mm-input-%d-%d.svg", layer_idx, iRun++), layers[layer_idx]->regions(), input_expolygons[layer_idx]); + } +#endif // MMU_SEGMENTATION_DEBUG_INPUT } }); // end of parallel_for BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - slices preparation in parallel - end"; for (size_t layer_idx = 0; layer_idx < layers.size(); ++layer_idx) { throw_on_cancel_callback(); - BoundingBox bbox(get_extents(input_polygons[layer_idx])); + BoundingBox bbox(get_extents(layers[layer_idx]->regions())); + bbox.merge(get_extents(input_expolygons[layer_idx])); // Projected triangles may slightly exceed the input polygons. bbox.offset(20 * SCALED_EPSILON); edge_grids[layer_idx].set_bbox(bbox); - edge_grids[layer_idx].create(input_polygons[layer_idx], coord_t(scale_(10.))); + edge_grids[layer_idx].create(input_expolygons[layer_idx], coord_t(scale_(10.))); } BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - projection of painted triangles - begin"; for (const ModelVolume *mv : print_object.model_object()->volumes) { const size_t num_extruders = print_object.print()->config().nozzle_diameter.size() + 1; - for (size_t extruder_idx = 1; extruder_idx < num_extruders; ++extruder_idx) { - throw_on_cancel_callback(); - const indexed_triangle_set custom_facets = mv->mmu_segmentation_facets.get_facets(*mv, EnforcerBlockerType(extruder_idx)); - if (!mv->is_model_part() || custom_facets.indices.empty()) - continue; + tbb::parallel_for(tbb::blocked_range(1, num_extruders), [&mv, &print_object, &edge_grids, &painted_lines, &painted_lines_mutex, &input_expolygons, &throw_on_cancel_callback](const tbb::blocked_range &range) { + for (size_t extruder_idx = range.begin(); extruder_idx < range.end(); ++extruder_idx) { + throw_on_cancel_callback(); + const indexed_triangle_set custom_facets = mv->mmu_segmentation_facets.get_facets(*mv, EnforcerBlockerType(extruder_idx)); + if (!mv->is_model_part() || custom_facets.indices.empty()) + continue; - const Transform3f tr = print_object.trafo().cast() * mv->get_matrix().cast(); - for (size_t facet_idx = 0; facet_idx < custom_facets.indices.size(); ++facet_idx) { - float min_z = std::numeric_limits::max(); - float max_z = std::numeric_limits::lowest(); + const Transform3f tr = print_object.trafo().cast() * mv->get_matrix().cast(); + tbb::parallel_for(tbb::blocked_range(0, custom_facets.indices.size()), [&tr, &custom_facets, &print_object, &edge_grids, &input_expolygons, &painted_lines, &painted_lines_mutex, &extruder_idx](const tbb::blocked_range &range) { + for (size_t facet_idx = range.begin(); facet_idx < range.end(); ++facet_idx) { + float min_z = std::numeric_limits::max(); + float max_z = std::numeric_limits::lowest(); - std::array facet; - for (int p_idx = 0; p_idx < 3; ++p_idx) { - facet[p_idx] = tr * custom_facets.vertices[custom_facets.indices[facet_idx](p_idx)]; - max_z = std::max(max_z, facet[p_idx].z()); - min_z = std::min(min_z, facet[p_idx].z()); - } + std::array facet; + for (int p_idx = 0; p_idx < 3; ++p_idx) { + facet[p_idx] = tr * custom_facets.vertices[custom_facets.indices[facet_idx](p_idx)]; + max_z = std::max(max_z, facet[p_idx].z()); + min_z = std::min(min_z, facet[p_idx].z()); + } - // Sort the vertices by z-axis for simplification of projected_facet on slices - std::sort(facet.begin(), facet.end(), [](const Vec3f &p1, const Vec3f &p2) { return p1.z() < p2.z(); }); + // Sort the vertices by z-axis for simplification of projected_facet on slices + std::sort(facet.begin(), facet.end(), [](const Vec3f &p1, const Vec3f &p2) { return p1.z() < p2.z(); }); - // Find lowest slice not below the triangle. - auto first_layer = std::upper_bound(print_object.layers().begin(), print_object.layers().end(), float(min_z - EPSILON), - [](float z, const Layer *l1) { return z < l1->slice_z; }); - auto last_layer = std::upper_bound(print_object.layers().begin(), print_object.layers().end(), float(max_z + EPSILON), - [](float z, const Layer *l1) { return z < l1->slice_z; }); - --last_layer; + // Find lowest slice not below the triangle. + auto first_layer = std::upper_bound(print_object.layers().begin(), print_object.layers().end(), float(min_z - EPSILON), + [](float z, const Layer *l1) { return z < l1->slice_z; }); + auto last_layer = std::upper_bound(print_object.layers().begin(), print_object.layers().end(), float(max_z + EPSILON), + [](float z, const Layer *l1) { return z < l1->slice_z; }); + --last_layer; - for (auto layer_it = first_layer; layer_it != (last_layer + 1); ++layer_it) { - const Layer *layer = *layer_it; - size_t layer_idx = layer_it - print_object.layers().begin(); - if (facet[0].z() > layer->slice_z || layer->slice_z > facet[2].z()) - continue; + for (auto layer_it = first_layer; layer_it != (last_layer + 1); ++layer_it) { + const Layer *layer = *layer_it; + size_t layer_idx = layer_it - print_object.layers().begin(); + if (input_expolygons[layer_idx].empty() || facet[0].z() > layer->slice_z || layer->slice_z > facet[2].z()) + continue; - // https://kandepet.com/3d-printing-slicing-3d-objects/ - float t = (float(layer->slice_z) - facet[0].z()) / (facet[2].z() - facet[0].z()); - Vec3f line_start_f = facet[0] + t * (facet[2] - facet[0]); - Vec3f line_end_f; + // https://kandepet.com/3d-printing-slicing-3d-objects/ + float t = (float(layer->slice_z) - facet[0].z()) / (facet[2].z() - facet[0].z()); + Vec3f line_start_f = facet[0] + t * (facet[2] - facet[0]); + Vec3f line_end_f; - if (facet[1].z() > layer->slice_z) { - // [P0, P2] a [P0, P1] - float t1 = (float(layer->slice_z) - facet[0].z()) / (facet[1].z() - facet[0].z()); - line_end_f = facet[0] + t1 * (facet[1] - facet[0]); - } else { - // [P0, P2] a [P1, P2] - float t2 = (float(layer->slice_z) - facet[1].z()) / (facet[2].z() - facet[1].z()); - line_end_f = facet[1] + t2 * (facet[2] - facet[1]); + if (facet[1].z() > layer->slice_z) { + // [P0, P2] and [P0, P1] + float t1 = (float(layer->slice_z) - facet[0].z()) / (facet[1].z() - facet[0].z()); + line_end_f = facet[0] + t1 * (facet[1] - facet[0]); + } else { + // [P0, P2] and [P1, P2] + float t2 = (float(layer->slice_z) - facet[1].z()) / (facet[2].z() - facet[1].z()); + line_end_f = facet[1] + t2 * (facet[2] - facet[1]); + } + + Point line_start(scale_(line_start_f.x()), scale_(line_start_f.y())); + Point line_end(scale_(line_end_f.x()), scale_(line_end_f.y())); + line_start -= print_object.center_offset(); + line_end -= print_object.center_offset(); + + size_t mutex_idx = layer_idx & 0x3F; + assert(mutex_idx < painted_lines_mutex.size()); + + PaintedLineVisitor visitor(edge_grids[layer_idx], painted_lines[layer_idx], painted_lines_mutex[mutex_idx], 16); + visitor.line_to_test.a = line_start; + visitor.line_to_test.b = line_end; + visitor.color = int(extruder_idx); + edge_grids[layer_idx].visit_cells_intersecting_line(line_start, line_end, visitor); + } } - - Point line_start(scale_(line_start_f.x()), scale_(line_start_f.y())); - Point line_end(scale_(line_end_f.x()), scale_(line_end_f.y())); - line_start -= print_object.center_offset(); - line_end -= print_object.center_offset(); - - PaintedLineVisitor visitor(edge_grids[layer_idx], painted_lines[layer_idx], 16); - visitor.reset(); - visitor.line_to_test.a = line_start; - visitor.line_to_test.b = line_end; - visitor.color = int(extruder_idx); - edge_grids[layer_idx].visit_cells_intersecting_line(line_start, line_end, visitor); - } + }); } - } + }); } BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - projection of painted triangles - end"; BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - painted layers count: " @@ -1725,8 +1851,8 @@ std::vector>> multi_material_segmentati tbb::parallel_for(tbb::blocked_range(0, print_object.layers().size()), [&](const tbb::blocked_range &range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { throw_on_cancel_callback(); - auto comp = [&input_polygons, layer_idx](const PaintedLine &first, const PaintedLine &second) { - Point first_start_p = input_polygons[layer_idx][first.contour_idx][first.line_idx]; + auto comp = [&edge_grids, layer_idx](const PaintedLine &first, const PaintedLine &second) { + Point first_start_p = edge_grids[layer_idx].contours()[first.contour_idx].segment_start(first.line_idx); return first.contour_idx < second.contour_idx || (first.contour_idx == second.contour_idx && (first.line_idx < second.line_idx || @@ -1740,13 +1866,28 @@ std::vector>> multi_material_segmentati std::vector &painted_lines_single = painted_lines[layer_idx]; if (!painted_lines_single.empty()) { - std::vector> color_poly = colorize_polygons(input_polygons[layer_idx], painted_lines_single); + std::vector> color_poly = colorize_polygons(edge_grids[layer_idx].contours(), painted_lines_single); MMU_Graph graph = build_graph(layer_idx, color_poly); remove_multiple_edges_in_vertices(graph, color_poly); graph.remove_nodes_with_one_arc(); + +#ifdef MMU_SEGMENTATION_DEBUG_GRAPH + { + static int iRun = 0; + export_graph_to_svg(debug_out_path("mm-graph-final-%d-%d.svg", layer_idx, iRun++), graph, input_expolygons[layer_idx]); + } +#endif // MMU_SEGMENTATION_DEBUG_GRAPH + std::vector> segmentation = extract_colored_segments(graph); for (std::pair ®ion : segmentation) segmented_regions[layer_idx].emplace_back(std::move(region)); + +#ifdef MMU_SEGMENTATION_DEBUG_REGIONS + { + static int iRun = 0; + export_regions_to_svg(debug_out_path("mm-regions-sides-%d-%d.svg", layer_idx, iRun++), segmented_regions[layer_idx], input_expolygons[layer_idx]); + } +#endif // MMU_SEGMENTATION_DEBUG_REGIONS } } }); // end of parallel_for @@ -1765,6 +1906,14 @@ std::vector>> multi_material_segmentati std::vector>> segmented_regions_merged = merge_segmented_layers(segmented_regions, std::move(top_and_bottom_layers), throw_on_cancel_callback); throw_on_cancel_callback(); +#ifdef MMU_SEGMENTATION_DEBUG_REGIONS + { + static int iRun = 0; + for (size_t layer_idx = 0; layer_idx < print_object.layers().size(); ++layer_idx) + export_regions_to_svg(debug_out_path("mm-regions-merged-%d-%d.svg", layer_idx, iRun++), segmented_regions_merged[layer_idx], input_expolygons[layer_idx]); + } +#endif // MMU_SEGMENTATION_DEBUG_REGIONS + return segmented_regions_merged; } diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 0c1ff112f..1283d0ac1 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -625,17 +625,13 @@ const std::vector& Preset::sla_printer_options() PresetCollection::PresetCollection(Preset::Type type, const std::vector &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &default_name) : m_type(type), m_edited_preset(type, "", false), -#if ENABLE_PROJECT_DIRTY_STATE m_saved_preset(type, "", false), -#endif // ENABLE_PROJECT_DIRTY_STATE m_idx_selected(0) { // Insert just the default preset. this->add_default_preset(keys, defaults, default_name); m_edited_preset.config.apply(m_presets.front().config); -#if ENABLE_PROJECT_DIRTY_STATE update_saved_preset_from_current_preset(); -#endif // ENABLE_PROJECT_DIRTY_STATE } void PresetCollection::reset(bool delete_files) @@ -816,10 +812,8 @@ std::pair PresetCollection::load_external_preset( // The source config may contain keys from many possible preset types. Just copy those that relate to this preset. this->get_edited_preset().config.apply_only(combined_config, keys, true); this->update_dirty(); -#if ENABLE_PROJECT_DIRTY_STATE update_saved_preset_from_current_preset(); -#endif // ENABLE_PROJECT_DIRTY_STATE - assert(this->get_edited_preset().is_dirty); + assert(this->get_edited_preset().is_dirty); return std::make_pair(&(*it), this->get_edited_preset().is_dirty); } if (inherits.empty()) { @@ -1229,9 +1223,7 @@ Preset& PresetCollection::select_preset(size_t idx) idx = first_visible_idx(); m_idx_selected = idx; m_edited_preset = m_presets[idx]; -#if ENABLE_PROJECT_DIRTY_STATE update_saved_preset_from_current_preset(); -#endif // ENABLE_PROJECT_DIRTY_STATE bool default_visible = ! m_default_suppressed || m_idx_selected < m_num_default_presets; for (size_t i = 0; i < m_num_default_presets; ++i) m_presets[i].is_visible = default_visible; diff --git a/src/libslic3r/Preset.hpp b/src/libslic3r/Preset.hpp index eeb1c84ee..9d5597cac 100644 --- a/src/libslic3r/Preset.hpp +++ b/src/libslic3r/Preset.hpp @@ -370,10 +370,8 @@ public: Preset& get_edited_preset() { return m_edited_preset; } const Preset& get_edited_preset() const { return m_edited_preset; } -#if ENABLE_PROJECT_DIRTY_STATE // Return the last saved preset. const Preset& get_saved_preset() const { return m_saved_preset; } -#endif // ENABLE_PROJECT_DIRTY_STATE // Return vendor of the first parent profile, for which the vendor is defined, or null if such profile does not exist. PresetWithVendorProfile get_preset_with_vendor_profile(const Preset &preset) const; @@ -394,15 +392,11 @@ public: // Return a preset by an index. If the preset is active, a temporary copy is returned. Preset& preset(size_t idx) { return (idx == m_idx_selected) ? m_edited_preset : m_presets[idx]; } const Preset& preset(size_t idx) const { return const_cast(this)->preset(idx); } -#if ENABLE_PROJECT_DIRTY_STATE void discard_current_changes() { m_presets[m_idx_selected].reset_dirty(); m_edited_preset = m_presets[m_idx_selected]; update_saved_preset_from_current_preset(); } -#else - void discard_current_changes() { m_presets[m_idx_selected].reset_dirty(); m_edited_preset = m_presets[m_idx_selected]; } -#endif // ENABLE_PROJECT_DIRTY_STATE // Return a preset by its name. If the preset is active, a temporary copy is returned. // If a preset is not found by its name, null is returned. @@ -477,7 +471,6 @@ public: std::vector current_different_from_parent_options(const bool deep_compare = false) const { return dirty_options(&this->get_edited_preset(), this->get_selected_preset_parent(), deep_compare); } -#if ENABLE_PROJECT_DIRTY_STATE // Compare the content of get_saved_preset() with get_edited_preset() configs, return true if they differ. bool saved_is_dirty() const { return !this->saved_dirty_options().empty(); } // Compare the content of get_saved_preset() with get_edited_preset() configs, return the list of keys where they differ. @@ -485,7 +478,6 @@ public: { return dirty_options(&this->get_edited_preset(), &this->get_saved_preset(), deep_compare); } // Copy edited preset into saved preset. void update_saved_preset_from_current_preset() { m_saved_preset = m_edited_preset; } -#endif // ENABLE_PROJECT_DIRTY_STATE // Return a sorted list of system preset names. // Used for validating the "inherits" flag when importing user's config bundles. @@ -574,10 +566,8 @@ private: std::map m_map_system_profile_renamed; // Initially this preset contains a copy of the selected preset. Later on, this copy may be modified by the user. Preset m_edited_preset; -#if ENABLE_PROJECT_DIRTY_STATE // Contains a copy of the last saved selected preset. Preset m_saved_preset; -#endif // ENABLE_PROJECT_DIRTY_STATE // Selected preset. size_t m_idx_selected; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index e6603e36e..b3a1bc993 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -373,7 +373,6 @@ bool Print::sequential_print_horizontal_clearance_valid(const Print& print, Poly // FIXME: Arrangement has different parameters for offsetting (jtMiter, limit 2) // which causes that the warning will be showed after arrangement with the // appropriate object distance. Even if I set this to jtMiter the warning still shows up. -#if ENABLE_ALLOW_NEGATIVE_Z it_convex_hull = map_model_object_to_convex_hull.emplace_hint(it_convex_hull, model_object_id, offset(print_object->model_object()->convex_hull_2d( Geometry::assemble_transform({ 0.0, 0.0, model_instance0->get_offset().z() }, model_instance0->get_rotation(), model_instance0->get_scaling_factor(), model_instance0->get_mirror())), @@ -381,15 +380,6 @@ bool Print::sequential_print_horizontal_clearance_valid(const Print& print, Poly // exactly by satisfying the extruder_clearance_radius, this test will not trigger collision. float(scale_(0.5 * print.config().extruder_clearance_radius.value - EPSILON)), jtRound, scale_(0.1)).front()); -#else - it_convex_hull = map_model_object_to_convex_hull.emplace_hint(it_convex_hull, model_object_id, - offset(print_object->model_object()->convex_hull_2d( - Geometry::assemble_transform(Vec3d::Zero(), model_instance0->get_rotation(), model_instance0->get_scaling_factor(), model_instance0->get_mirror())), - // Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects - // exactly by satisfying the extruder_clearance_radius, this test will not trigger collision. - float(scale_(0.5 * print.config().extruder_clearance_radius.value - EPSILON)), - jtRound, float(scale_(0.1))).front()); -#endif // ENABLE_ALLOW_NEGATIVE_Z } // Make a copy, so it may be rotated for instances. Polygon convex_hull0 = it_convex_hull->second; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 3c5ff3859..512843110 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1279,7 +1279,7 @@ void PrintConfigDef::init_fff_params() def->enum_labels.push_back("Teacup"); def->enum_labels.push_back("MakerWare (MakerBot)"); def->enum_labels.push_back("Marlin (legacy)"); - def->enum_labels.push_back("Marlin Firmware"); + def->enum_labels.push_back("Marlin 2"); def->enum_labels.push_back("Sailfish (MakerBot)"); def->enum_labels.push_back("Mach3/LinuxCNC"); def->enum_labels.push_back("Machinekit"); @@ -1457,6 +1457,7 @@ void PrintConfigDef::init_fff_params() def->tooltip = L("Maximum width of a segmented region. Zero disables this feature."); def->sidetext = L("mm (zero to disable)"); def->min = 0; + def->category = L("Advanced"); def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0.f)); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index e1d4096bf..7aa39c823 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1600,15 +1600,9 @@ PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &defau void PrintObject::update_slicing_parameters() { -#if ENABLE_ALLOW_NEGATIVE_Z if (!m_slicing_params.valid) m_slicing_params = SlicingParameters::create_from_config( this->print()->config(), m_config, this->model_object()->bounding_box().max.z(), this->object_extruders()); -#else - if (! m_slicing_params.valid) - m_slicing_params = SlicingParameters::create_from_config( - this->print()->config(), m_config, unscale(this->height()), this->object_extruders()); -#endif // ENABLE_ALLOW_NEGATIVE_Z } SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full_config, const ModelObject& model_object, float object_max_z) @@ -1670,7 +1664,6 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c updated = true; } -#if ENABLE_ALLOW_NEGATIVE_Z // Verify the layer_height_profile. if (!layer_height_profile.empty() && // Must not be of even length. @@ -1678,15 +1671,6 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c // Last entry must be at the top of the object. std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_parameters.object_print_z_max) > 1e-3)) layer_height_profile.clear(); -#else - // Verify the layer_height_profile. - if (! layer_height_profile.empty() && - // Must not be of even length. - ((layer_height_profile.size() & 1) != 0 || - // Last entry must be at the top of the object. - std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_parameters.object_print_z_height()) > 1e-3)) - layer_height_profile.clear(); -#endif // ENABLE_ALLOW_NEGATIVE_Z if (layer_height_profile.empty()) { //layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_config_ranges, model_object.volumes); diff --git a/src/libslic3r/SLA/Hollowing.cpp b/src/libslic3r/SLA/Hollowing.cpp index 770e52a35..55dae9430 100644 --- a/src/libslic3r/SLA/Hollowing.cpp +++ b/src/libslic3r/SLA/Hollowing.cpp @@ -112,7 +112,7 @@ InteriorPtr generate_interior(const TriangleMesh & mesh, const HollowingConfig &hc, const JobController & ctl) { - static const double MIN_OVERSAMPL = 3.; + static const double MIN_OVERSAMPL = 3.5; static const double MAX_OVERSAMPL = 8.; // I can't figure out how to increase the grid resolution through openvdb diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index e11926c7e..0cd80f20b 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -323,6 +323,7 @@ private: { support_tree_ptr = sla::SupportTree::create(*this, ctl); tree_mesh = TriangleMesh{support_tree_ptr->retrieve_mesh(sla::MeshType::Support)}; + tree_mesh.require_shared_vertices(); return support_tree_ptr; } diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 716e61a60..f6366c18e 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -10,8 +10,6 @@ #define ENABLE_SELECTION_DEBUG_OUTPUT 0 // Renders a small sphere in the center of the bounding box of the current selection when no gizmo is active #define ENABLE_RENDER_SELECTION_CENTER 0 -// Shows an imgui dialog with render related data -#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) @@ -26,6 +24,8 @@ #define ENABLE_GCODE_VIEWER_STATISTICS 0 // Enable G-Code viewer comparison between toolpaths height and width detected from gcode and calculated at gcode generation #define ENABLE_GCODE_VIEWER_DATA_CHECKING 0 +// Enable project dirty state manager debug window +#define ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW 0 // Enable rendering of objects using environment map @@ -41,33 +41,12 @@ //==================== #define ENABLE_2_4_0_ALPHA0 1 -// Enable reload from disk command for 3mf files -#define ENABLE_RELOAD_FROM_DISK_FOR_3MF (1 && ENABLE_2_4_0_ALPHA0) -// Enable showing gcode line numbers in preview horizontal slider -#define ENABLE_GCODE_LINES_ID_IN_H_SLIDER (1 && ENABLE_2_4_0_ALPHA0) -// Enable validation of custom gcode against gcode processor reserved keywords -#define ENABLE_VALIDATE_CUSTOM_GCODE (1 && ENABLE_2_4_0_ALPHA0) -// Enable showing a imgui window containing gcode in preview -#define ENABLE_GCODE_WINDOW (1 && ENABLE_2_4_0_ALPHA0) -// Enable exporting lines M73 for remaining time to next printer stop to gcode -#define ENABLE_EXTENDED_M73_LINES (1 && ENABLE_VALIDATE_CUSTOM_GCODE) -// Enable a modified version of automatic downscale on load of objects too big -#define ENABLE_MODIFIED_DOWNSCALE_ON_LOAD_OBJECTS_TOO_BIG (1 && ENABLE_2_4_0_ALPHA0) -// Enable scrollable legend in preview -#define ENABLE_SCROLLABLE_LEGEND (1 && ENABLE_2_4_0_ALPHA0) -// Enable visualization of start gcode as regular toolpaths -#define ENABLE_START_GCODE_VISUALIZATION (1 && ENABLE_2_4_0_ALPHA0) -// Enable visualization of seams in preview -#define ENABLE_SEAMS_VISUALIZATION (1 && ENABLE_2_4_0_ALPHA0) -// Enable project dirty state manager -#define ENABLE_PROJECT_DIRTY_STATE (1 && ENABLE_2_4_0_ALPHA0) -// Enable project dirty state manager debug window -#define ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW (0 && ENABLE_PROJECT_DIRTY_STATE) -// Enable to push object instances under the bed -#define ENABLE_ALLOW_NEGATIVE_Z (1 && ENABLE_2_4_0_ALPHA0) -#define DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA (1 && ENABLE_ALLOW_NEGATIVE_Z) // Enable delayed rendering of transparent volumes #define ENABLE_DELAYED_TRANSPARENT_VOLUMES_RENDERING (1 && ENABLE_2_4_0_ALPHA0) +// Enable the fix of importing color print view from gcode files into GCodeViewer +#define ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER (1 && ENABLE_2_4_0_ALPHA0) +// Enable drawing contours, at cut level, for sinking volumes +#define ENABLE_SINKING_CONTOURS (1 && ENABLE_2_4_0_ALPHA0) #endif // _prusaslicer_technologies_h_ diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index d709a67cd..360a8b14e 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -698,27 +698,29 @@ struct EdgeToFace { bool operator<(const EdgeToFace &other) const { return vertex_low < other.vertex_low || (vertex_low == other.vertex_low && vertex_high < other.vertex_high); } }; -template +template static std::vector create_edge_map( - const indexed_triangle_set &its, ThrowOnCancelCallback throw_on_cancel) + const indexed_triangle_set &its, FaceFilter face_filter, ThrowOnCancelCallback throw_on_cancel) { std::vector edges_map; - edges_map.assign(its.indices.size() * 3, EdgeToFace()); + edges_map.reserve(its.indices.size() * 3); for (uint32_t facet_idx = 0; facet_idx < its.indices.size(); ++ facet_idx) - for (int i = 0; i < 3; ++ i) { - EdgeToFace &e2f = edges_map[facet_idx * 3 + i]; - e2f.vertex_low = its.indices[facet_idx][i]; - e2f.vertex_high = its.indices[facet_idx][(i + 1) % 3]; - e2f.face = facet_idx; - // 1 based indexing, to be always strictly positive. - e2f.face_edge = i + 1; - if (e2f.vertex_low > e2f.vertex_high) { - // Sort the vertices - std::swap(e2f.vertex_low, e2f.vertex_high); - // and make the face_edge negative to indicate a flipped edge. - e2f.face_edge = - e2f.face_edge; + if (face_filter(facet_idx)) + for (int i = 0; i < 3; ++ i) { + edges_map.push_back({}); + EdgeToFace &e2f = edges_map.back(); + e2f.vertex_low = its.indices[facet_idx][i]; + e2f.vertex_high = its.indices[facet_idx][(i + 1) % 3]; + e2f.face = facet_idx; + // 1 based indexing, to be always strictly positive. + e2f.face_edge = i + 1; + if (e2f.vertex_low > e2f.vertex_high) { + // Sort the vertices + std::swap(e2f.vertex_low, e2f.vertex_high); + // and make the face_edge negative to indicate a flipped edge. + e2f.face_edge = - e2f.face_edge; + } } - } throw_on_cancel(); std::sort(edges_map.begin(), edges_map.end()); @@ -727,12 +729,12 @@ static std::vector create_edge_map( // Map from a face edge to a unique edge identifier or -1 if no neighbor exists. // Two neighbor faces share a unique edge identifier even if they are flipped. -template -static inline std::vector its_face_edge_ids_impl(const indexed_triangle_set &its, ThrowOnCancelCallback throw_on_cancel) +template +static inline std::vector its_face_edge_ids_impl(const indexed_triangle_set &its, FaceFilter face_filter, ThrowOnCancelCallback throw_on_cancel) { std::vector out(its.indices.size(), Vec3i(-1, -1, -1)); - std::vector edges_map = create_edge_map(its, throw_on_cancel); + std::vector edges_map = create_edge_map(its, face_filter, throw_on_cancel); // Assign a unique common edge id to touching triangle edges. int num_edges = 0; @@ -780,12 +782,17 @@ static inline std::vector its_face_edge_ids_impl(const indexed_triangle_s std::vector its_face_edge_ids(const indexed_triangle_set &its) { - return its_face_edge_ids_impl(its, [](){}); + return its_face_edge_ids_impl(its, [](const uint32_t){ return true; }, [](){}); } std::vector its_face_edge_ids(const indexed_triangle_set &its, std::function throw_on_cancel_callback) { - return its_face_edge_ids_impl(its, throw_on_cancel_callback); + return its_face_edge_ids_impl(its, [](const uint32_t){ return true; }, throw_on_cancel_callback); +} + +std::vector its_face_edge_ids(const indexed_triangle_set &its, const std::vector &face_mask) +{ + return its_face_edge_ids_impl(its, [&face_mask](const uint32_t idx){ return face_mask[idx]; }, [](){}); } // Having the face neighbors available, assign unique edge IDs to face edges for chaining of polygons over slices. diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 7aef3055a..c8c7e0dd7 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -118,6 +118,7 @@ private: // Used for chaining slice lines into polygons. std::vector its_face_edge_ids(const indexed_triangle_set &its); std::vector its_face_edge_ids(const indexed_triangle_set &its, std::function throw_on_cancel_callback); +std::vector its_face_edge_ids(const indexed_triangle_set &its, const std::vector &face_mask); // Having the face neighbors available, assign unique edge IDs to face edges for chaining of polygons over slices. std::vector its_face_edge_ids(const indexed_triangle_set &its, std::vector &face_neighbors, bool assign_unbound_edges = false, int *num_edges = nullptr); diff --git a/src/libslic3r/TriangleMeshSlicer.cpp b/src/libslic3r/TriangleMeshSlicer.cpp index 681ec32f0..ef90402a9 100644 --- a/src/libslic3r/TriangleMeshSlicer.cpp +++ b/src/libslic3r/TriangleMeshSlicer.cpp @@ -362,6 +362,35 @@ static inline std::vector slice_make_lines( return lines; } +template +static inline IntersectionLines slice_make_lines( + const std::vector &mesh_vertices, + const TransformVertex &transform_vertex_fn, + const std::vector &mesh_faces, + const std::vector &face_edge_ids, + const float plane_z, + FaceFilter face_filter) +{ + IntersectionLines lines; + for (int face_idx = 0; face_idx < mesh_faces.size(); ++ face_idx) + if (face_filter(face_idx)) { + const Vec3i &indices = mesh_faces[face_idx]; + stl_vertex vertices[3] { transform_vertex_fn(mesh_vertices[indices(0)]), transform_vertex_fn(mesh_vertices[indices(1)]), transform_vertex_fn(mesh_vertices[indices(2)]) }; + // find facet extents + const float min_z = fminf(vertices[0].z(), fminf(vertices[1].z(), vertices[2].z())); + const float max_z = fmaxf(vertices[0].z(), fmaxf(vertices[1].z(), vertices[2].z())); + assert(min_z <= plane_z && max_z >= plane_z); + int idx_vertex_lowest = (vertices[1].z() == min_z) ? 1 : ((vertices[2].z() == min_z) ? 2 : 0); + IntersectionLine il; + // Ignore horizontal triangles. Any valid horizontal triangle must have a vertical triangle connected, otherwise the part has zero volume. + if (min_z != max_z && slice_facet(plane_z, vertices, indices, face_edge_ids[face_idx], idx_vertex_lowest, false, il) == FacetSliceType::Slicing) { + assert(il.edge_type != IntersectionLine::FacetEdgeType::Horizontal); + lines.emplace_back(il); + } + } + return lines; +} + // For projecting triangle sets onto slice slabs. struct SlabLines { // Intersection lines of a slice with a triangle set, CCW oriented. @@ -1720,6 +1749,69 @@ std::vector slice_mesh( return layers; } +// Specialized version for a single slicing plane only, running on a single thread. +Polygons slice_mesh( + const indexed_triangle_set &mesh, + // Unscaled Zs + const float plane_z, + const MeshSlicingParams ¶ms) +{ + std::vector lines; + + { + bool trafo_identity = is_identity(params.trafo); + Transform3f tf; + std::vector face_mask(mesh.indices.size(), false); + + { + // 1) Mark vertices as below or above the slicing plane. + std::vector vertex_side(mesh.vertices.size(), 0); + if (trafo_identity) { + for (size_t i = 0; i < mesh.vertices.size(); ++ i) { + float z = mesh.vertices[i].z(); + char s = z < plane_z ? -1 : z == plane_z ? 0 : 1; + vertex_side[i] = s; + } + } else { + tf = make_trafo_for_slicing(params.trafo); + for (size_t i = 0; i < mesh.vertices.size(); ++ i) { + //FIXME don't need to transform x & y, just Z. + float z = (tf * mesh.vertices[i]).z(); + char s = z < plane_z ? -1 : z == plane_z ? 0 : 1; + vertex_side[i] = s; + } + } + + // 2) Mark faces crossing the plane. + for (size_t i = 0; i < mesh.indices.size(); ++ i) { + const Vec3i &face = mesh.indices[i]; + int sides[3] = { vertex_side[face(0)], vertex_side[face(1)], vertex_side[face(2)] }; + face_mask[i] = sides[0] * sides[1] <= 0 || sides[1] * sides[2] <= 0 || sides[0] * sides[2] <= 0; + } + } + + // 3) Calculate face neighbors for just the faces in face_mask. + std::vector face_edge_ids = its_face_edge_ids(mesh, face_mask); + + // 4) Slice "face_mask" triangles, collect line segments. + // It likely is not worthwile to copy the vertices. Apply the transformation in place. + if (trafo_identity) { + lines.emplace_back(slice_make_lines( + mesh.vertices, [](const Vec3f &p) { return Vec3f(scaled(p.x()), scaled(p.y()), p.z()); }, + mesh.indices, face_edge_ids, plane_z, [&face_mask](int face_idx) { return face_mask[face_idx]; })); + } else { + // Transform the vertices, scale up in XY, not in Z. + lines.emplace_back(slice_make_lines(mesh.vertices, [tf](const Vec3f& p) { return tf * p; }, mesh.indices, face_edge_ids, plane_z, + [&face_mask](int face_idx) { return face_mask[face_idx]; })); + } + } + + // 5) Chain the line segments. + std::vector layers = make_loops(lines, params, [](){}); + assert(layers.size() == 1); + return layers.front(); +} + std::vector slice_mesh_ex( const indexed_triangle_set &mesh, const std::vector &zs, diff --git a/src/libslic3r/TriangleMeshSlicer.hpp b/src/libslic3r/TriangleMeshSlicer.hpp index 9b02f5573..7ea7ac3a9 100644 --- a/src/libslic3r/TriangleMeshSlicer.hpp +++ b/src/libslic3r/TriangleMeshSlicer.hpp @@ -52,6 +52,12 @@ std::vector slice_mesh( const MeshSlicingParams ¶ms, std::function throw_on_cancel = []{}); +// Specialized version for a single slicing plane only, running on a single thread. +Polygons slice_mesh( + const indexed_triangle_set &mesh, + const float plane_z, + const MeshSlicingParams ¶ms); + std::vector slice_mesh_ex( const indexed_triangle_set &mesh, const std::vector &zs, diff --git a/src/libslic3r/TriangleSelector.cpp b/src/libslic3r/TriangleSelector.cpp index a349fe35a..ad823c55d 100644 --- a/src/libslic3r/TriangleSelector.cpp +++ b/src/libslic3r/TriangleSelector.cpp @@ -228,7 +228,7 @@ void TriangleSelector::seed_fill_select_triangles(const Vec3f &hit, int facet_st } } -void TriangleSelector::precompute_all_level_neighbors_recursive(const int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector &neighbors_out) const +void TriangleSelector::precompute_all_neighbors_recursive(const int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector &neighbors_out, std::vector &neighbors_propagated_out) const { assert(facet_idx < int(m_triangles.size())); @@ -236,7 +236,8 @@ void TriangleSelector::precompute_all_level_neighbors_recursive(const int facet_ if (!tr->valid()) return; - neighbors_out[facet_idx] = neighbors_propagated; + neighbors_out[facet_idx] = neighbors; + neighbors_propagated_out[facet_idx] = neighbors_propagated; if (tr->is_split()) { assert(this->verify_triangle_neighbors(*tr, neighbors)); @@ -247,67 +248,51 @@ void TriangleSelector::precompute_all_level_neighbors_recursive(const int facet_ assert(tr->children[i] < int(m_triangles.size())); // Recursion, deep first search over the children of this triangle. // All children of this triangle were created by splitting a single source triangle of the original mesh. - this->precompute_all_level_neighbors_recursive(tr->children[i], this->child_neighbors(*tr, neighbors, i), this->child_neighbors_propagated(*tr, neighbors_propagated, i), neighbors_out); + this->precompute_all_neighbors_recursive(tr->children[i], this->child_neighbors(*tr, neighbors, i), + this->child_neighbors_propagated(*tr, neighbors_propagated, i), neighbors_out, + neighbors_propagated_out); } } } } -std::vector TriangleSelector::precompute_all_level_neighbors() const +std::pair, std::vector> TriangleSelector::precompute_all_neighbors() const { std::vector neighbors(m_triangles.size(), Vec3i(-1, -1, -1)); + std::vector neighbors_propagated(m_triangles.size(), Vec3i(-1, -1, -1)); for (int facet_idx = 0; facet_idx < this->m_orig_size_indices; ++facet_idx) { - neighbors[facet_idx] = root_neighbors(*m_mesh, facet_idx); + neighbors[facet_idx] = root_neighbors(*m_mesh, facet_idx); + neighbors_propagated[facet_idx] = neighbors[facet_idx]; assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors[facet_idx])); if (m_triangles[facet_idx].is_split()) - this->precompute_all_level_neighbors_recursive(facet_idx, neighbors[facet_idx], neighbors[facet_idx], neighbors); + this->precompute_all_neighbors_recursive(facet_idx, neighbors[facet_idx], neighbors_propagated[facet_idx], neighbors, neighbors_propagated); } - return neighbors; + return std::make_pair(std::move(neighbors), std::move(neighbors_propagated)); } -bool TriangleSelector::are_triangles_touching(const int first_facet_idx, const int second_facet_idx) const +// It appends all triangles that are touching the edge (vertexi, vertexj) of the triangle. +// It doesn't append the triangles that are touching the triangle only by part of the edge that means the triangles are from lower depth. +void TriangleSelector::append_touching_subtriangles(int itriangle, int vertexi, int vertexj, std::vector &touching_subtriangles_out) const { - std::array sides_facet = {Linef3(m_vertices[m_triangles[first_facet_idx].verts_idxs[0]].v.cast(), m_vertices[m_triangles[first_facet_idx].verts_idxs[1]].v.cast()), - Linef3(m_vertices[m_triangles[first_facet_idx].verts_idxs[1]].v.cast(), m_vertices[m_triangles[first_facet_idx].verts_idxs[2]].v.cast()), - Linef3(m_vertices[m_triangles[first_facet_idx].verts_idxs[2]].v.cast(), m_vertices[m_triangles[first_facet_idx].verts_idxs[0]].v.cast())}; + if (itriangle == -1) + return; - const Vec3d p0 = m_vertices[m_triangles[second_facet_idx].verts_idxs[0]].v.cast(); - const Vec3d p1 = m_vertices[m_triangles[second_facet_idx].verts_idxs[1]].v.cast(); - const Vec3d p2 = m_vertices[m_triangles[second_facet_idx].verts_idxs[2]].v.cast(); + auto process_subtriangle = [this, &itriangle, &vertexi, &vertexj, &touching_subtriangles_out](const int subtriangle_idx) -> void { + assert(subtriangle_idx == -1); + if (!m_triangles[subtriangle_idx].is_split()) + touching_subtriangles_out.emplace_back(subtriangle_idx); + else if (int midpoint = this->triangle_midpoint(itriangle, vertexi, vertexj); midpoint != -1) + append_touching_subtriangles(subtriangle_idx, vertexi, midpoint, touching_subtriangles_out); + else + append_touching_subtriangles(subtriangle_idx, vertexi, vertexj, touching_subtriangles_out); + }; - for (size_t idx = 0; idx < 3; ++idx) - if (line_alg::distance_to_squared(sides_facet[idx], p0) <= EPSILON && (line_alg::distance_to_squared(sides_facet[idx], p1) <= EPSILON || line_alg::distance_to_squared(sides_facet[idx], p2) <= EPSILON)) - return true; - else if (line_alg::distance_to_squared(sides_facet[idx], p1) <= EPSILON && line_alg::distance_to_squared(sides_facet[idx], p2) <= EPSILON) - return true; + std::pair touching = this->triangle_subtriangles(itriangle, vertexi, vertexj); + if (touching.first != -1) + process_subtriangle(touching.first); - return false; -} - -std::vector TriangleSelector::neighboring_triangles(const int first_facet_idx, const int second_facet_idx, EnforcerBlockerType second_facet_state) const -{ - assert(first_facet_idx < int(m_triangles.size())); - - const Triangle *tr = &m_triangles[first_facet_idx]; - if (!tr->valid()) - return {}; - - if (!tr->is_split() && tr->get_state() == second_facet_state && (are_triangles_touching(second_facet_idx, first_facet_idx) || are_triangles_touching(first_facet_idx, second_facet_idx))) - return {first_facet_idx}; - - std::vector neighbor_facets_out; - int num_of_children = tr->number_of_split_sides() + 1; - if (num_of_children != 1) { - for (int i = 0; i < num_of_children; ++i) { - assert(i < int(tr->children.size())); - assert(tr->children[i] < int(m_triangles.size())); - - if (std::vector neighbor_facets = neighboring_triangles(tr->children[i], second_facet_idx, second_facet_state); !neighbor_facets.empty()) - Slic3r::append(neighbor_facets_out, std::move(neighbor_facets)); - } - } - - return neighbor_facets_out; + if (touching.second != -1) + process_subtriangle(touching.second); } void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_start, bool propagate) @@ -326,7 +311,23 @@ void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_ return; } - std::vector all_level_neighbors = this->precompute_all_level_neighbors(); + auto get_all_touching_triangles = [this](int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated) -> std::vector { + assert(facet_idx != -1 && facet_idx < m_triangles.size()); + assert(this->verify_triangle_neighbors(m_triangles[facet_idx], neighbors)); + std::vector touching_triangles; + Vec3i vertices = {m_triangles[facet_idx].verts_idxs[0], m_triangles[facet_idx].verts_idxs[1], m_triangles[facet_idx].verts_idxs[2]}; + append_touching_subtriangles(neighbors(0), vertices(1), vertices(0), touching_triangles); + append_touching_subtriangles(neighbors(1), vertices(2), vertices(1), touching_triangles); + append_touching_subtriangles(neighbors(2), vertices(0), vertices(2), touching_triangles); + + for (int neighbor_idx : neighbors_propagated) + if (neighbor_idx != -1 && !m_triangles[neighbor_idx].is_split()) + touching_triangles.emplace_back(neighbor_idx); + + return touching_triangles; + }; + + auto [neighbors, neighbors_propagated] = this->precompute_all_neighbors(); std::vector visited(m_triangles.size(), false); std::queue facet_queue; @@ -338,17 +339,14 @@ void TriangleSelector::bucket_fill_select_triangles(const Vec3f& hit, int facet_ if (!visited[current_facet]) { m_triangles[current_facet].select_by_seed_fill(); - for (int neighbor_idx : all_level_neighbors[current_facet]) { - if (neighbor_idx < 0 || visited[neighbor_idx]) + + std::vector touching_triangles = get_all_touching_triangles(current_facet, neighbors[current_facet], neighbors_propagated[current_facet]); + for(const int tr_idx : touching_triangles) { + if (tr_idx < 0 || visited[tr_idx] || m_triangles[tr_idx].get_state() != start_facet_state) continue; - if (!m_triangles[neighbor_idx].is_split()) { - if (m_triangles[neighbor_idx].get_state() == start_facet_state) - facet_queue.push(neighbor_idx); - } else { - for (int neighbor_facet_idx : neighboring_triangles(neighbor_idx, current_facet, start_facet_state)) - facet_queue.push(neighbor_facet_idx); - } + assert(!m_triangles[tr_idx].is_split()); + facet_queue.push(tr_idx); } } @@ -437,6 +435,40 @@ int TriangleSelector::neighbor_child(int itriangle, int vertexi, int vertexj, Pa return itriangle == -1 ? -1 : this->neighbor_child(m_triangles[itriangle], vertexi, vertexj, partition); } +std::pair TriangleSelector::triangle_subtriangles(int itriangle, int vertexi, int vertexj) const +{ + return itriangle == -1 ? std::make_pair(-1, -1) : this->triangle_subtriangles(m_triangles[itriangle], vertexi, vertexj); +} + +std::pair TriangleSelector::triangle_subtriangles(const Triangle &tr, int vertexi, int vertexj) +{ + if (tr.number_of_split_sides() == 0) + // If this triangle is not split, then there is no subtriangles touching the edge. + return std::make_pair(-1, -1); + + // Find the triangle edge. + int edge = tr.verts_idxs[0] == vertexi ? 0 : tr.verts_idxs[1] == vertexi ? 1 : 2; + assert(tr.verts_idxs[edge] == vertexi); + assert(tr.verts_idxs[next_idx_modulo(edge, 3)] == vertexj); + + if (tr.number_of_split_sides() == 1) { + return edge == next_idx_modulo(tr.special_side(), 3) ? std::make_pair(tr.children[0], tr.children[1]) : + std::make_pair(tr.children[edge == tr.special_side() ? 0 : 1], -1); + } else if (tr.number_of_split_sides() == 2) { + return edge == next_idx_modulo(tr.special_side(), 3) ? std::make_pair(tr.children[2], -1) : + edge == tr.special_side() ? std::make_pair(tr.children[0], tr.children[1]) : + std::make_pair(tr.children[2], tr.children[0]); + } else { + assert(tr.number_of_split_sides() == 3); + assert(tr.special_side() == 0); + return edge == 0 ? std::make_pair(tr.children[0], tr.children[1]) : + edge == 1 ? std::make_pair(tr.children[1], tr.children[2]) : + std::make_pair(tr.children[2], tr.children[0]); + } + + return std::make_pair(-1, -1); +} + // Return existing midpoint of CCW oriented side (vertexi, vertexj). // If itriangle == -1 or if the side sharing (vertexi, vertexj) is not split, return -1. int TriangleSelector::triangle_midpoint(const Triangle &tr, int vertexi, int vertexj) const @@ -524,12 +556,8 @@ Vec3i TriangleSelector::child_neighbors(const Triangle &tr, const Vec3i &neighbo assert(child_idx >= 0 && child_idx <= tr.number_of_split_sides()); int i = tr.special_side(); - int j = i + 1; - if (j >= 3) - j = 0; - int k = j + 1; - if (k >= 3) - k = 0; + int j = next_idx_modulo(i, 3); + int k = next_idx_modulo(j, 3); Vec3i out; switch (tr.number_of_split_sides()) { @@ -612,23 +640,28 @@ Vec3i TriangleSelector::child_neighbors(const Triangle &tr, const Vec3i &neighbo Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec3i &neighbors, int child_idx) const { int i = tr.special_side(); - int j = i + 1; - if (j >= 3) j = 0; - int k = j + 1; - if (k >= 3) k = 0; + int j = next_idx_modulo(i, 3); + int k = next_idx_modulo(j, 3); Vec3i out; + auto replace_if_not_exists = [&out](int index_to_replace, int neighbor) { + if (out(index_to_replace) == -1) + out(index_to_replace) = neighbor; + }; + switch (tr.number_of_split_sides()) { case 1: switch (child_idx) { case 0: out(0) = neighbors(i); - out(1) = neighbors(j); + out(1) = this->neighbor_child(neighbors(j), tr.verts_idxs[k], tr.verts_idxs[j], Partition::Second); + replace_if_not_exists(1, neighbors(j)); out(2) = tr.children[1]; break; default: assert(child_idx == 1); - out(0) = neighbors(j); + out(0) = this->neighbor_child(neighbors(j), tr.verts_idxs[k], tr.verts_idxs[j], Partition::First); + replace_if_not_exists(0, neighbors(j)); out(1) = neighbors(k); out(2) = tr.children[0]; break; @@ -638,20 +671,24 @@ Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec case 2: switch (child_idx) { case 0: - out(0) = neighbors(i); + out(0) = this->neighbor_child(neighbors(i), tr.verts_idxs[j], tr.verts_idxs[i], Partition::Second); + replace_if_not_exists(0, neighbors(i)); out(1) = tr.children[1]; - out(2) = neighbors(k); + out(2) = this->neighbor_child(neighbors(k), tr.verts_idxs[i], tr.verts_idxs[k], Partition::First); + replace_if_not_exists(2, neighbors(k)); break; case 1: assert(child_idx == 1); - out(0) = neighbors(i); + out(0) = this->neighbor_child(neighbors(i), tr.verts_idxs[j], tr.verts_idxs[i], Partition::First); + replace_if_not_exists(0, neighbors(i)); out(1) = tr.children[2]; out(2) = tr.children[0]; break; default: assert(child_idx == 2); out(0) = neighbors(j); - out(1) = neighbors(k); + out(1) = this->neighbor_child(neighbors(k), tr.verts_idxs[i], tr.verts_idxs[k], Partition::Second); + replace_if_not_exists(1, neighbors(k)); out(2) = tr.children[1]; break; } @@ -661,18 +698,24 @@ Vec3i TriangleSelector::child_neighbors_propagated(const Triangle &tr, const Vec assert(tr.special_side() == 0); switch (child_idx) { case 0: - out(0) = neighbors(0); + out(0) = this->neighbor_child(neighbors(0), tr.verts_idxs[1], tr.verts_idxs[0], Partition::Second); + replace_if_not_exists(0, neighbors(0)); out(1) = tr.children[3]; - out(2) = neighbors(2); + out(2) = this->neighbor_child(neighbors(2), tr.verts_idxs[0], tr.verts_idxs[2], Partition::First); + replace_if_not_exists(2, neighbors(2)); break; case 1: - out(0) = neighbors(0); - out(1) = neighbors(1); + out(0) = this->neighbor_child(neighbors(0), tr.verts_idxs[1], tr.verts_idxs[0], Partition::First); + replace_if_not_exists(0, neighbors(0)); + out(1) = this->neighbor_child(neighbors(1), tr.verts_idxs[2], tr.verts_idxs[1], Partition::Second); + replace_if_not_exists(1, neighbors(1)); out(2) = tr.children[3]; break; case 2: - out(0) = neighbors(1); - out(1) = neighbors(2); + out(0) = this->neighbor_child(neighbors(1), tr.verts_idxs[2], tr.verts_idxs[1], Partition::First); + replace_if_not_exists(0, neighbors(1)); + out(1) = this->neighbor_child(neighbors(2), tr.verts_idxs[0], tr.verts_idxs[2], Partition::Second); + replace_if_not_exists(1, neighbors(2)); out(2) = tr.children[3]; break; default: @@ -886,13 +929,13 @@ void TriangleSelector::undivide_triangle(int facet_idx) Triangle& tr = m_triangles[facet_idx]; if (tr.is_split()) { - for (int i=0; i<=tr.number_of_split_sides(); ++i) { + for (int i = 0; i <= tr.number_of_split_sides(); ++i) { int child = tr.children[i]; Triangle &child_tr = m_triangles[child]; assert(child_tr.valid()); undivide_triangle(child); - for (int i = 0; i < 3; ++ i) { - int iv = child_tr.verts_idxs[i]; + for (int j = 0; j < 3; ++j) { + int iv = child_tr.verts_idxs[j]; Vertex &v = m_vertices[iv]; assert(v.ref_cnt > 0); if (-- v.ref_cnt == 0) { @@ -1231,7 +1274,7 @@ void TriangleSelector::get_facets_strict_recursive( this->get_facets_split_by_tjoints({tr.verts_idxs[0], tr.verts_idxs[1], tr.verts_idxs[2]}, neighbors, out_triangles); } -void TriangleSelector::get_facets_split_by_tjoints(const Vec3i vertices, const Vec3i neighbors, std::vector &out_triangles) const +void TriangleSelector::get_facets_split_by_tjoints(const Vec3i &vertices, const Vec3i &neighbors, std::vector &out_triangles) const { // Export this triangle, but first collect the T-joint vertices along its edges. Vec3i midpoints( @@ -1393,9 +1436,10 @@ std::pair>, std::vector> TriangleSelector: return out.data; } -void TriangleSelector::deserialize(const std::pair>, std::vector> &data) +void TriangleSelector::deserialize(const std::pair>, std::vector> &data, bool needs_reset) { - reset(); // dump any current state + if (needs_reset) + reset(); // dump any current state // Reserve number of triangles as if each triangle was saved with 4 bits. // With MMU painting this estimate may be somehow low, but better than nothing. diff --git a/src/libslic3r/TriangleSelector.hpp b/src/libslic3r/TriangleSelector.hpp index 643daba45..eeb479dee 100644 --- a/src/libslic3r/TriangleSelector.hpp +++ b/src/libslic3r/TriangleSelector.hpp @@ -22,8 +22,8 @@ public: POINTER }; - [[nodiscard]] std::vector precompute_all_level_neighbors() const; - void precompute_all_level_neighbors_recursive(const int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector &neighbors_out) const; + std::pair, std::vector> precompute_all_neighbors() const; + void precompute_all_neighbors_recursive(int facet_idx, const Vec3i &neighbors, const Vec3i &neighbors_propagated, std::vector &neighbors_out, std::vector &neighbors_normal_out) const; // Set a limit to the edge length, below which the edge will not be split by select_patch(). // Called by select_patch() internally. Made public for debugging purposes, see TriangleSelectorGUI::render_debug(). @@ -37,10 +37,6 @@ public: [[nodiscard]] int select_unsplit_triangle(const Vec3f &hit, int facet_idx) const; [[nodiscard]] int select_unsplit_triangle(const Vec3f &hit, int facet_idx, const Vec3i &neighbors) const; - [[nodiscard]] bool are_triangles_touching(int first_facet_idx, int second_facet_idx) const; - - [[nodiscard]] std::vector neighboring_triangles(int first_facet_idx, int second_facet_idx, EnforcerBlockerType second_facet_state) const; - // Select all triangles fully inside the circle, subdivide where needed. void select_patch(const Vec3f &hit, // point where to start int facet_start, // facet of the original mesh (unsplit) that the hit point belongs to @@ -60,7 +56,7 @@ public: bool propagate); // if bucket fill is propagated to neighbor faces or if it fills the only facet of the modified mesh that the hit point belongs to. bool has_facets(EnforcerBlockerType state) const; - static bool has_facets(const std::pair>, std::vector> &data, const EnforcerBlockerType test_state); + static bool has_facets(const std::pair>, std::vector> &data, EnforcerBlockerType test_state); int num_facets(EnforcerBlockerType state) const; // Get facets at a given state. Don't triangulate T-joints. indexed_triangle_set get_facets(EnforcerBlockerType state) const; @@ -81,7 +77,7 @@ public: std::pair>, std::vector> serialize() const; // Load serialized data. Assumes that correct mesh is loaded. - void deserialize(const std::pair>, std::vector> &data); + void deserialize(const std::pair>, std::vector> &data, bool needs_reset = true); // For all triangles, remove the flag indicating that the triangle was selected by seed fill. void seed_fill_unselect_all_triangles(); @@ -128,11 +124,11 @@ protected: bool is_selected_by_seed_fill() const { assert(! is_split()); return m_selected_by_seed_fill; } // Is this triangle valid or marked to be removed? - bool valid() const throw() { return m_valid; } + bool valid() const noexcept { return m_valid; } // Get info on how it's split. - bool is_split() const throw() { return number_of_split_sides() != 0; } - int number_of_split_sides() const throw() { return number_of_splits; } - int special_side() const throw() { assert(is_split()); return special_side_idx; } + bool is_split() const noexcept { return number_of_split_sides() != 0; } + int number_of_split_sides() const noexcept { return number_of_splits; } + int special_side() const noexcept { assert(is_split()); return special_side_idx; } private: friend TriangleSelector; @@ -205,7 +201,7 @@ private: void remove_useless_children(int facet_idx); // No hidden meaning. Triangles are meant. bool is_pointer_in_triangle(int facet_idx) const; bool is_edge_inside_cursor(int facet_idx) const; - int push_triangle(int a, int b, int c, int source_triangle, const EnforcerBlockerType state = EnforcerBlockerType{0}); + int push_triangle(int a, int b, int c, int source_triangle, EnforcerBlockerType state = EnforcerBlockerType{0}); void perform_split(int facet_idx, const Vec3i &neighbors, EnforcerBlockerType old_state); Vec3i child_neighbors(const Triangle &tr, const Vec3i &neighbors, int child_idx) const; Vec3i child_neighbors_propagated(const Triangle &tr, const Vec3i &neighbors, int child_idx) const; @@ -221,6 +217,11 @@ private: int triangle_midpoint(int itriangle, int vertexi, int vertexj) const; int triangle_midpoint_or_allocate(int itriangle, int vertexi, int vertexj); + static std::pair triangle_subtriangles(const Triangle &tr, int vertexi, int vertexj); + std::pair triangle_subtriangles(int itriangle, int vertexi, int vertexj) const; + + void append_touching_subtriangles(int itriangle, int vertexi, int vertexj, std::vector &touching_subtriangles_out) const; + #ifndef NDEBUG bool verify_triangle_neighbors(const Triangle& tr, const Vec3i& neighbors) const; bool verify_triangle_midpoints(const Triangle& tr) const; @@ -231,7 +232,7 @@ private: const Vec3i &neighbors, EnforcerBlockerType state, std::vector &out_triangles) const; - void get_facets_split_by_tjoints(const Vec3i vertices, const Vec3i neighbors, std::vector &out_triangles) const; + void get_facets_split_by_tjoints(const Vec3i &vertices, const Vec3i &neighbors, std::vector &out_triangles) const; int m_free_triangles_head { -1 }; int m_free_vertices_head { -1 }; diff --git a/src/libslic3r/TryCatchSignal.hpp b/src/libslic3r/TryCatchSignal.hpp index 69c50d8cd..19a53fd4a 100644 --- a/src/libslic3r/TryCatchSignal.hpp +++ b/src/libslic3r/TryCatchSignal.hpp @@ -10,9 +10,9 @@ using SignalT = decltype (SIGSEGV); template -void try_catch_signal(const SignalT (&/*sigs*/)[N], TryFn &&/*fn*/, CatchFn &&/*cfn*/) +void try_catch_signal(const SignalT (&/*sigs*/)[N], TryFn &&fn, CatchFn &&/*cfn*/) { - // TODO + fn(); } #endif diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 330f05ec8..81897553c 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -50,6 +50,9 @@ void set_sys_shapes_dir(const std::string &path); // Return a full path to the system shapes gallery directory. const std::string& sys_shapes_dir(); +// Return a full path to the custom shapes gallery directory. +std::string custom_shapes_dir(); + // Set a path with preset files. void set_data_dir(const std::string &path); // Return a full path to the GUI resource files. @@ -99,6 +102,7 @@ extern bool is_gcode_file(const std::string &path); extern bool is_img_file(const std::string& path); extern bool is_stl_file(const boost::filesystem::directory_entry& path); extern bool is_stl_file(const std::string& path); +extern bool is_shapes_dir(const std::string& dir); // File path / name / extension splitting utilities, working with UTF-8, // to be published to Perl. diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 8f1cf07f2..085db8705 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -202,6 +202,11 @@ const std::string& data_dir() return g_data_dir; } +std::string custom_shapes_dir() +{ + return (boost::filesystem::path(g_data_dir) / "shapes").string(); +} + #ifdef _WIN32 // The following helpers are borrowed from the LLVM project https://github.com/llvm namespace WindowsSupport @@ -771,6 +776,11 @@ bool is_stl_file(const std::string &path) return boost::iends_with(path, ".stl"); } +bool is_shapes_dir(const std::string& dir) +{ + return dir == sys_shapes_dir() || dir == custom_shapes_dir(); +} + } // namespace Slic3r #ifdef WIN32 diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 19dd597d1..3d89025cc 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -203,6 +203,8 @@ set(SLIC3R_GUI_SOURCES GUI/ProjectDirtyStateManager.cpp GUI/DesktopIntegrationDialog.cpp GUI/DesktopIntegrationDialog.hpp + GUI/HintNotification.cpp + GUI/HintNotification.hpp Utils/Http.cpp Utils/Http.hpp Utils/FixModelByWin10.cpp diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 4bbffbcac..1e85a10b6 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -20,6 +20,8 @@ #include static const float GROUND_Z = -0.02f; +static const std::array DEFAULT_MODEL_COLOR = { 0.235f, 0.235f, 0.235f, 1.0f }; +static const std::array PICKING_MODEL_COLOR = { 0.0f, 0.0f, 0.0f, 1.0f }; namespace Slic3r { namespace GUI { @@ -211,8 +213,18 @@ Point Bed3D::point_projection(const Point& point) const return m_polygon.point_projection(point); } -void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, - bool show_axes, bool show_texture) const +void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, bool show_axes, bool show_texture) +{ + render_internal(canvas, bottom, scale_factor, show_axes, show_texture, false); +} + +void Bed3D::render_for_picking(GLCanvas3D& canvas, bool bottom, float scale_factor) +{ + render_internal(canvas, bottom, scale_factor, false, false, true); +} + +void Bed3D::render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor, + bool show_axes, bool show_texture, bool picking) { float* factor = const_cast(&m_scale_factor); *factor = scale_factor; @@ -222,11 +234,13 @@ void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor, glsafe(::glEnable(GL_DEPTH_TEST)); + m_model.set_color(-1, picking ? PICKING_MODEL_COLOR : DEFAULT_MODEL_COLOR); + switch (m_type) { case System: { render_system(canvas, bottom, show_texture); break; } default: - case Custom: { render_custom(canvas, bottom, show_texture); break; } + case Custom: { render_custom(canvas, bottom, show_texture, picking); break; } } glsafe(::glDisable(GL_DEPTH_TEST)); @@ -237,7 +251,7 @@ void Bed3D::calc_bounding_boxes() const BoundingBoxf3* bounding_box = const_cast(&m_bounding_box); *bounding_box = BoundingBoxf3(); for (const Vec2d& p : m_shape) { - bounding_box->merge({ p(0), p(1), 0.0 }); + bounding_box->merge({ p.x(), p.y(), 0.0 }); } BoundingBoxf3* extended_bounding_box = const_cast(&m_extended_bounding_box); @@ -264,16 +278,16 @@ 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.x(); x <= bed_bbox.max.x(); x += scale_(10.0)) { Polyline line; - line.append(Point(x, bed_bbox.min(1))); - line.append(Point(x, bed_bbox.max(1))); + line.append(Point(x, bed_bbox.min.y())); + line.append(Point(x, bed_bbox.max.y())); 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.y(); y <= bed_bbox.max.y(); y += scale_(10.0)) { Polyline line; - line.append(Point(bed_bbox.min(0), y)); - line.append(Point(bed_bbox.max(0), y)); + line.append(Point(bed_bbox.min.x(), y)); + line.append(Point(bed_bbox.max.x(), y)); axes_lines.push_back(line); } @@ -333,7 +347,7 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const if (m_texture_filename.empty()) { texture->reset(); - render_default(bottom); + render_default(bottom, false); return; } @@ -346,7 +360,7 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const if (temp_texture->get_id() == 0 || temp_texture->get_source() != m_texture_filename) { // generate a temporary lower resolution texture to show while no main texture levels have been compressed if (!temp_texture->load_from_svg_file(m_texture_filename, false, false, false, max_tex_size / 8)) { - render_default(bottom); + render_default(bottom, false); return; } canvas.request_extra_frame(); @@ -354,7 +368,7 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const // starts generating the main texture, compression will run asynchronously if (!texture->load_from_svg_file(m_texture_filename, true, true, true, max_tex_size)) { - render_default(bottom); + render_default(bottom, false); return; } } @@ -362,7 +376,7 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const // generate a temporary lower resolution texture to show while no main texture levels have been compressed if (temp_texture->get_id() == 0 || temp_texture->get_source() != m_texture_filename) { if (!temp_texture->load_from_file(m_texture_filename, false, GLTexture::None, false)) { - render_default(bottom); + render_default(bottom, false); return; } canvas.request_extra_frame(); @@ -370,12 +384,12 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const // starts generating the main texture, compression will run asynchronously if (!texture->load_from_file(m_texture_filename, true, GLTexture::MultiThreaded, true)) { - render_default(bottom); + render_default(bottom, false); return; } } else { - render_default(bottom); + render_default(bottom, false); return; } } @@ -388,7 +402,6 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const temp_texture->reset(); canvas.request_extra_frame(); - } if (m_triangles.get_vertices_count() > 0) { @@ -470,7 +483,7 @@ void Bed3D::render_model() const GLModel* model = const_cast(&m_model); if (model->get_filename() != m_model_filename && model->init_from_file(m_model_filename)) { - model->set_color(-1, m_model_color); + model->set_color(-1, DEFAULT_MODEL_COLOR); // 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(); @@ -495,10 +508,10 @@ void Bed3D::render_model() const } } -void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture) const +void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture, bool picking) const { if (m_texture_filename.empty() && m_model_filename.empty()) { - render_default(bottom); + render_default(bottom, picking); return; } @@ -509,7 +522,7 @@ void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture) co render_texture(bottom, canvas); } -void Bed3D::render_default(bool bottom) const +void Bed3D::render_default(bool bottom, bool picking) const { const_cast(&m_texture)->reset(); @@ -526,21 +539,23 @@ void Bed3D::render_default(bool bottom) const if (!has_model && !bottom) { // draw background glsafe(::glDepthMask(GL_FALSE)); - glsafe(::glColor4fv(m_model_color.data())); + glsafe(::glColor4fv(picking ? PICKING_MODEL_COLOR.data() : DEFAULT_MODEL_COLOR.data())); 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)); glsafe(::glDepthMask(GL_TRUE)); } - // draw grid - glsafe(::glLineWidth(1.5f * m_scale_factor)); - if (has_model && !bottom) - glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 1.0f)); - else - 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())); + if (!picking) { + // draw grid + glsafe(::glLineWidth(1.5f * m_scale_factor)); + if (has_model && !bottom) + glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 1.0f)); + else + 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())); + } glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index 71382315d..a2a643519 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -84,7 +84,6 @@ private: GLTexture m_temp_texture; GLModel m_model; Vec3d m_model_offset{ Vec3d::Zero() }; - std::array m_model_color{ 0.235f, 0.235f, 0.235f, 1.0f }; unsigned int m_vbo_id{ 0 }; Axes m_axes; @@ -110,19 +109,23 @@ public: Point point_projection(const Point& point) const; void render(GLCanvas3D& canvas, bool bottom, float scale_factor, - bool show_axes, bool show_texture) const; + bool show_axes, bool show_texture); + + void render_for_picking(GLCanvas3D& canvas, bool bottom, float scale_factor); private: void calc_bounding_boxes() const; void calc_triangles(const ExPolygon& poly); void calc_gridlines(const ExPolygon& poly, const BoundingBox& bed_bbox); std::tuple detect_type(const Pointfs& shape) const; + void render_internal(GLCanvas3D& canvas, bool bottom, float scale_factor, + bool show_axes, bool show_texture, bool picking); void render_axes() const; void render_system(GLCanvas3D& canvas, bool bottom, bool show_texture) const; void render_texture(bool bottom, GLCanvas3D& canvas) const; void render_model() const; - void render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture) const; - void render_default(bool bottom) const; + void render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture, bool picking) const; + void render_default(bool bottom, bool picking) const; void reset(); }; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index fb464ce02..2babc516a 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -9,9 +9,9 @@ #include "3DScene.hpp" #include "GLShader.hpp" #include "GUI_App.hpp" -#if ENABLE_ENVIRONMENT_MAP +#if ENABLE_ENVIRONMENT_MAP || ENABLE_SINKING_CONTOURS #include "Plater.hpp" -#endif // ENABLE_ENVIRONMENT_MAP +#endif // ENABLE_ENVIRONMENT_MAP || ENABLE_SINKING_CONTOURS #include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/ExtrusionEntityCollection.hpp" @@ -23,9 +23,11 @@ #include "libslic3r/Format/STL.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/AppConfig.hpp" -#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA #include "libslic3r/PresetBundle.hpp" -#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA +#include "libslic3r/ClipperUtils.hpp" +#if ENABLE_SINKING_CONTOURS +#include "libslic3r/Tesselate.hpp" +#endif // ENABLE_SINKING_CONTOURS #include #include @@ -286,6 +288,74 @@ void GLIndexedVertexArray::render( glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } +#if ENABLE_SINKING_CONTOURS +const float GLVolume::SinkingContours::HalfWidth = 0.25f; + +void GLVolume::SinkingContours::render() +{ + update(); + + glsafe(::glPushMatrix()); + glsafe(::glTranslated(m_shift.x(), m_shift.y(), m_shift.z())); + m_model.render(); + glsafe(::glPopMatrix()); +} + +void GLVolume::SinkingContours::update() +{ + if (m_parent.is_sinking() && !m_parent.is_below_printbed()) { + const BoundingBoxf3& box = m_parent.transformed_convex_hull_bounding_box(); + if (!m_old_box.size().isApprox(box.size()) || m_old_box.min.z() != box.min.z()) { + m_old_box = box; + m_shift = Vec3d::Zero(); + + const TriangleMesh& mesh = GUI::wxGetApp().plater()->model().objects[m_parent.object_idx()]->volumes[m_parent.volume_idx()]->mesh(); + assert(mesh.has_shared_vertices()); + + m_model.reset(); + GUI::GLModel::InitializationData init_data; + MeshSlicingParams slicing_params; + slicing_params.trafo = m_parent.world_matrix(); + Polygons polygons = union_(slice_mesh(mesh.its, 0.0f, slicing_params)); + for (Polygon& polygon : polygons) { + if (polygon.is_clockwise()) + polygon.reverse(); + Polygons outer_polys = offset(polygon, float(scale_(HalfWidth))); + assert(outer_polys.size() == 1); + if (outer_polys.empty()) + // no outer contour, skip + continue; + + ExPolygon expoly(std::move(outer_polys.front())); + expoly.holes = offset(polygon, -float(scale_(HalfWidth))); + polygons_reverse(expoly.holes); + + GUI::GLModel::InitializationData::Entity entity; + entity.type = GUI::GLModel::PrimitiveType::Triangles; + const std::vector triangulation = triangulate_expolygon_3d(expoly); + for (const Vec3d& v : triangulation) { + entity.positions.emplace_back(v.cast() + Vec3f(0.0f, 0.0f, 0.015f)); // add a small positive z to avoid z-fighting + entity.normals.emplace_back(Vec3f::UnitZ()); + const size_t positions_count = entity.positions.size(); + if (positions_count % 3 == 0) { + entity.indices.emplace_back(positions_count - 3); + entity.indices.emplace_back(positions_count - 2); + entity.indices.emplace_back(positions_count - 1); + } + } + init_data.entities.emplace_back(entity); + } + + m_model.init_from(init_data); + } + else + m_shift = box.center() - m_old_box.center(); + } + else + m_model.reset(); +} +#endif // ENABLE_SINKING_CONTOURS + const std::array GLVolume::SELECTED_COLOR = { 0.0f, 1.0f, 0.0f, 1.0f }; const std::array GLVolume::HOVER_SELECT_COLOR = { 0.4f, 0.9f, 0.1f, 1.0f }; const std::array GLVolume::HOVER_DESELECT_COLOR = { 1.0f, 0.75f, 0.75f, 1.0f }; @@ -306,6 +376,9 @@ GLVolume::GLVolume(float r, float g, float b, float a) : m_transformed_bounding_box_dirty(true) , m_sla_shift_z(0.0) , m_transformed_convex_hull_bounding_box_dirty(true) +#if ENABLE_SINKING_CONTOURS + , m_sinking_contours(*this) +#endif // ENABLE_SINKING_CONTOURS // geometry_id == 0 -> invalid , geometry_id(std::pair(0, 0)) , extruder_id(0) @@ -323,6 +396,9 @@ GLVolume::GLVolume(float r, float g, float b, float a) , force_transparent(false) , force_native_color(false) , force_neutral_color(false) +#if ENABLE_SINKING_CONTOURS + , force_sinking_contours(false) +#endif // ENABLE_SINKING_CONTOURS , tverts_range(0, size_t(-1)) , qverts_range(0, size_t(-1)) { @@ -342,16 +418,10 @@ void GLVolume::set_render_color(const std::array& rgba) void GLVolume::set_render_color() { -#if ENABLE_ALLOW_NEGATIVE_Z bool outside = is_outside || is_below_printbed(); -#endif // ENABLE_ALLOW_NEGATIVE_Z if (force_native_color || force_neutral_color) { -#if ENABLE_ALLOW_NEGATIVE_Z if (outside && shader_outside_printer_detection_enabled) -#else - if (is_outside && shader_outside_printer_detection_enabled) -#endif // ENABLE_ALLOW_NEGATIVE_Z set_render_color(OUTSIDE_COLOR); else { if (force_native_color) @@ -366,18 +436,10 @@ void GLVolume::set_render_color() else if (hover == HS_Deselect) set_render_color(HOVER_DESELECT_COLOR); else if (selected) -#if ENABLE_ALLOW_NEGATIVE_Z set_render_color(outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR); -#else - set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR); -#endif // ENABLE_ALLOW_NEGATIVE_Z else if (disabled) set_render_color(DISABLED_COLOR); -#if ENABLE_ALLOW_NEGATIVE_Z else if (outside && shader_outside_printer_detection_enabled) -#else - else if (is_outside && shader_outside_printer_detection_enabled) -#endif // ENABLE_ALLOW_NEGATIVE_Z set_render_color(OUTSIDE_COLOR); else set_render_color(color); @@ -520,14 +582,9 @@ void GLVolume::render() const bool GLVolume::is_sla_support() const { return this->composite_id.volume_id == -int(slaposSupportTree); } bool GLVolume::is_sla_pad() const { return this->composite_id.volume_id == -int(slaposPad); } -#if ENABLE_ALLOW_NEGATIVE_Z bool GLVolume::is_sinking() const { -#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA if (is_modifier || GUI::wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) -#else - if (is_modifier) -#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA return false; const BoundingBoxf3& box = transformed_convex_hull_bounding_box(); return box.min.z() < SINKING_Z_THRESHOLD && box.max.z() >= SINKING_Z_THRESHOLD; @@ -537,7 +594,13 @@ bool GLVolume::is_below_printbed() const { return transformed_convex_hull_bounding_box().max(2) < 0.0; } -#endif // ENABLE_ALLOW_NEGATIVE_Z + +#if ENABLE_SINKING_CONTOURS +void GLVolume::render_sinking_contours() +{ + m_sinking_contours.render(); +} +#endif // ENABLE_SINKING_CONTOURS std::vector GLVolumeCollection::load_object( const ModelObject *model_object, @@ -774,6 +837,68 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab if (disable_cullface) glsafe(::glDisable(GL_CULL_FACE)); +#if ENABLE_SINKING_CONTOURS + GLVolumeWithIdAndZList to_render = volumes_to_render(volumes, type, view_matrix, filter_func); + for (GLVolumeWithIdAndZ& volume : to_render) { + volume.first->set_render_color(); + + // render sinking contours of non-hovered volumes + if (volume.first->is_sinking() && !volume.first->is_below_printbed() && + volume.first->hover == GLVolume::HS_None && !volume.first->force_sinking_contours) { + shader->stop_using(); + volume.first->render_sinking_contours(); + shader->start_using(); + } + + glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); + + shader->set_uniform("uniform_color", volume.first->render_color); + shader->set_uniform("z_range", m_z_range, 2); + shader->set_uniform("clipping_plane", m_clipping_plane, 4); + 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("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(volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast())); + shader->set_uniform("slope.normal_z", m_slope.normal_z); + +#if ENABLE_ENVIRONMENT_MAP + unsigned int environment_texture_id = GUI::wxGetApp().plater()->get_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(); + + volume.first->render(); + +#if ENABLE_ENVIRONMENT_MAP + if (use_environment_texture) + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); +#endif // ENABLE_ENVIRONMENT_MAP + + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + + glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); + glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); + } + + for (GLVolumeWithIdAndZ& volume : to_render) { + // render sinking contours of hovered/displaced volumes + if (volume.first->is_sinking() && !volume.first->is_below_printbed() && + (volume.first->hover != GLVolume::HS_None || volume.first->force_sinking_contours)) { + shader->stop_using(); + glsafe(::glDepthFunc(GL_ALWAYS)); + volume.first->render_sinking_contours(); + glsafe(::glDepthFunc(GL_LESS)); + shader->start_using(); + } + } +#else glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); @@ -813,6 +938,7 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); +#endif // ENABLE_SINKING_CONTOURS if (disable_cullface) glsafe(::glEnable(GL_CULL_FACE)); @@ -879,8 +1005,8 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, b if (opt == nullptr) return false; - BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values)); - BoundingBoxf3 print_volume(Vec3d(unscale(bed_box_2D.min(0)), unscale(bed_box_2D.min(1)), 0.0), Vec3d(unscale(bed_box_2D.max(0)), unscale(bed_box_2D.max(1)), config->opt_float("max_print_height"))); + const BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values)); + BoundingBoxf3 print_volume(Vec3d(unscale(bed_box_2D.min.x()), unscale(bed_box_2D.min.y()), 0.0), Vec3d(unscale(bed_box_2D.max.x()), unscale(bed_box_2D.max.y()), config->opt_float("max_print_height"))); // Allow the objects to protrude below the print bed print_volume.min(2) = -1e10; print_volume.min(0) -= BedEpsilon; diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 217d39746..a257db56a 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -8,6 +8,10 @@ #include "libslic3r/Utils.hpp" #include "libslic3r/Geometry.hpp" +#if ENABLE_SINKING_CONTOURS +#include "GLModel.hpp" +#endif // ENABLE_SINKING_CONTOURS + #include #define HAS_GLSAFE @@ -250,6 +254,9 @@ public: enum EHoverState : unsigned char { HS_None, +#if ENABLE_SINKING_CONTOURS + HS_Hover, +#endif // ENABLE_SINKING_CONTOURS HS_Select, HS_Deselect }; @@ -262,7 +269,7 @@ private: Geometry::Transformation m_volume_transformation; // Shift in z required by sla supports+pad - double m_sla_shift_z; + double m_sla_shift_z; // Bounding box of this volume, in unscaled coordinates. BoundingBoxf3 m_transformed_bounding_box; // Whether or not is needed to recalculate the transformed bounding box. @@ -274,6 +281,26 @@ private: // Whether or not is needed to recalculate the transformed convex hull bounding box. bool m_transformed_convex_hull_bounding_box_dirty; +#if ENABLE_SINKING_CONTOURS + class SinkingContours + { + static const float HalfWidth; + GLVolume& m_parent; + GUI::GLModel m_model; + BoundingBoxf3 m_old_box; + Vec3d m_shift{ Vec3d::Zero() }; + + public: + SinkingContours(GLVolume& volume) : m_parent(volume) {} + void render(); + + private: + void update(); + }; + + SinkingContours m_sinking_contours; +#endif // ENABLE_SINKING_CONTOURS + public: // Color of the triangles / quads held by this volume. std::array color; @@ -334,7 +361,11 @@ public: bool force_native_color : 1; // Whether or not render this volume in neutral bool force_neutral_color : 1; - }; +#if ENABLE_SINKING_CONTOURS + // Whether or not to force rendering of sinking contours + bool force_sinking_contours : 1; +#endif // ENABLE_SINKING_CONTOURS + }; // Is mouse or rectangle selection over this object to select/deselect it ? EHoverState hover; @@ -459,10 +490,11 @@ public: bool is_sla_support() const; bool is_sla_pad() const; -#if ENABLE_ALLOW_NEGATIVE_Z bool is_sinking() const; bool is_below_printbed() const; -#endif // ENABLE_ALLOW_NEGATIVE_Z +#if ENABLE_SINKING_CONTOURS + void render_sinking_contours(); +#endif // ENABLE_SINKING_CONTOURS // Return an estimate of the memory consumed by this class. size_t cpu_memory_used() const { diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 5503eefbf..c48b8f2aa 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -155,19 +155,15 @@ void BackgroundSlicingProcess::process_fff() if (! m_export_path.empty()) { wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id)); -#if ENABLE_GCODE_WINDOW // let the gcode window to unmap the temporary .gcode file (m_temp_output_path) // because the scripts may want to modify it GUI::wxGetApp().plater()->stop_mapping_gcode_window(); -#endif // ENABLE_GCODE_WINDOW m_print->set_status(95, _utf8(L("Running post-processing scripts"))); run_post_process_scripts(m_temp_output_path, m_fff_print->full_print_config()); -#if ENABLE_GCODE_WINDOW // let the gcode window to reload and remap the temporary .gcode file (m_temp_output_path) GUI::wxGetApp().plater()->start_mapping_gcode_window(); -#endif // ENABLE_GCODE_WINDOW //FIXME localize the messages // Perform the final post-processing of the export path by applying the print statistics over the file name. diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index aec5d3839..8bf8cd3d7 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -40,6 +40,7 @@ #include "slic3r/Utils/PresetUpdater.hpp" #include "format.hpp" #include "MsgDialog.hpp" +#include "libslic3r/libslic3r.h" #if defined(__linux__) && defined(__WXGTK3__) #define wxLinux_gtk3 true @@ -65,6 +66,7 @@ bool Bundle::load(fs::path source_path, bool ais_in_resources, bool ais_prusa_bu std::string path_string = source_path.string(); auto [config_substitutions, presets_loaded] = preset_bundle->load_configbundle(path_string, PresetBundle::LoadConfigBundleAttribute::LoadSystem); + UNUSED(config_substitutions); // No substitutions shall be reported when loading a system config bundle, no substitutions are allowed. assert(config_substitutions.empty()); auto first_vendor = preset_bundle->vendors.begin(); @@ -1604,25 +1606,17 @@ ConfigWizardIndex::ConfigWizardIndex(wxWindow *parent) , item_hover(NO_ITEM) , last_page((size_t)-1) { +#ifndef __WXOSX__ + SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX +#endif //__WXOSX__ SetMinSize(bg.bmp().GetSize()); const wxSize size = GetTextExtent("m"); em_w = size.x; em_h = size.y; - // Add logo bitmap. - // This could be done in on_paint() along with the index labels, but I've found it tricky - // to get the bitmap rendered well on all platforms with transparent background. - // In some cases it didn't work at all. And so wxStaticBitmap is used here instead, - // because it has all the platform quirks figured out. - auto *sizer = new wxBoxSizer(wxVERTICAL); - logo = new wxStaticBitmap(this, wxID_ANY, bg.bmp()); - sizer->AddStretchSpacer(); - sizer->Add(logo); - SetSizer(sizer); - logo_height = logo->GetBitmap().GetHeight(); - Bind(wxEVT_PAINT, &ConfigWizardIndex::on_paint, this); + Bind(wxEVT_SIZE, [this](wxEvent& e) { e.Skip(); Refresh(); }); Bind(wxEVT_MOTION, &ConfigWizardIndex::on_mouse_move, this); Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent &evt) { @@ -1767,6 +1761,12 @@ void ConfigWizardIndex::on_paint(wxPaintEvent & evt) y += yinc; index_width = std::max(index_width, (int)x + text_size.x); } + + //draw logo + if (int y = size.y - bg.GetBmpHeight(); y>=0) { + dc.DrawBitmap(bg.bmp(), 0, y, false); + index_width = std::max(index_width, bg.GetBmpWidth() + em_w / 2); + } if (GetMinSize().x < index_width) { CallAfter([this, index_width]() { @@ -1774,11 +1774,6 @@ void ConfigWizardIndex::on_paint(wxPaintEvent & evt) Refresh(); }); } - - if ((int)y + logo_height > size.GetHeight()) - logo->Hide(); - else - logo->Show(); } void ConfigWizardIndex::on_mouse_move(wxMouseEvent &evt) @@ -1804,7 +1799,6 @@ void ConfigWizardIndex::msw_rescale() bg.msw_rescale(); SetMinSize(bg.bmp().GetSize()); - logo->SetBitmap(bg.bmp()); bullet_black.msw_rescale(); bullet_blue.msw_rescale(); diff --git a/src/slic3r/GUI/ConfigWizard_private.hpp b/src/slic3r/GUI/ConfigWizard_private.hpp index ea39e04ab..6ca061941 100644 --- a/src/slic3r/GUI/ConfigWizard_private.hpp +++ b/src/slic3r/GUI/ConfigWizard_private.hpp @@ -512,15 +512,12 @@ private: ScalableBitmap bullet_black; ScalableBitmap bullet_blue; ScalableBitmap bullet_white; - wxStaticBitmap* logo; std::vector items; size_t item_active; ssize_t item_hover; size_t last_page; - int logo_height; - int item_height() const { return std::max(bullet_black.bmp().GetSize().GetHeight(), em_w) + em_w; } void on_paint(wxPaintEvent &evt); diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index e39b40ce4..fc93262a2 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -739,16 +739,8 @@ wxString Control::get_label(int tick, LabelType label_type/* = ltHeightWithLayer return size_t(it - m_layers_values.begin()); }; -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER - if (m_draw_mode == dmSequentialGCodeView) { - return (Slic3r::GUI::get_app_config()->get("seq_top_gcode_indices") == "1") ? - wxString::Format("%lu", static_cast(m_alternate_values[value])) : - wxString::Format("%lu", static_cast(m_values[value])); - } -#else if (m_draw_mode == dmSequentialGCodeView) - return wxString::Format("%lu", static_cast(m_values[value])); -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER + return wxString::Format("%lu", static_cast(m_alternate_values[value])); else { if (label_type == ltEstimatedTime) { if (m_is_wipe_tower) { @@ -1556,6 +1548,9 @@ void Control::OnMotion(wxMouseEvent& event) event.Skip(); // Set tooltips with information for each icon +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + if (GUI::wxGetApp().is_editor()) +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER this->SetToolTip(get_tooltip(tick)); if (action) { @@ -2062,6 +2057,10 @@ void Control::auto_color_change() break; if (prev_area - cur_area > delta_area) { + // Check percent of the area decrease. + // Ignore it, if this value is less than 10% + if (cur_area / prev_area > 0.9) + continue; int tick = get_tick_from_value(layer->print_z); if (tick >= 0 && !m_ticks.has_tick(tick)) { if (m_mode == SingleExtruder) { @@ -2180,7 +2179,6 @@ static std::string get_custom_code(const std::string& code_in, double height) wxTextEntryDialogStyle | wxTE_MULTILINE); upgrade_text_entry_dialog(&dlg); -#if ENABLE_VALIDATE_CUSTOM_GCODE bool valid = true; std::string value; do { @@ -2191,12 +2189,6 @@ static std::string get_custom_code(const std::string& code_in, double height) valid = GUI::Tab::validate_custom_gcode("Custom G-code", value); } while (!valid); return value; -#else - if (dlg.ShowModal() != wxID_OK) - return ""; - - return into_u8(dlg.GetValue()); -#endif // ENABLE_VALIDATE_CUSTOM_GCODE } static std::string get_pause_print_msg(const std::string& msg_in, double height) diff --git a/src/slic3r/GUI/DoubleSlider.hpp b/src/slic3r/GUI/DoubleSlider.hpp index 36fa7b660..601cbc708 100644 --- a/src/slic3r/GUI/DoubleSlider.hpp +++ b/src/slic3r/GUI/DoubleSlider.hpp @@ -223,9 +223,7 @@ public: void SetKoefForLabels(const double koef) { m_label_koef = koef; } void SetSliderValues(const std::vector& values); void ChangeOneLayerLock(); -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER void SetSliderAlternateValues(const std::vector& values) { m_alternate_values = values; } -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER Info GetTicksValues() const; void SetTicksValues(const Info &custom_gcode_per_print_z); @@ -409,9 +407,7 @@ private: std::vector m_extruder_colors; std::string m_print_obj_idxs; -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER std::vector m_alternate_values; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER // control's view variables wxCoord SLIDER_MARGIN; // margin around slider diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 1a48562d9..0fd1930d5 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -23,9 +23,7 @@ #include #include -#if ENABLE_GCODE_WINDOW #include -#endif // ENABLE_GCODE_WINDOW #include #include #include @@ -123,9 +121,7 @@ bool GCodeViewer::Path::matches(const GCodeProcessor::MoveVertex& move) const case EMoveType::Custom_GCode: case EMoveType::Retract: case EMoveType::Unretract: -#if ENABLE_SEAMS_VISUALIZATION case EMoveType::Seam: -#endif // ENABLE_SEAMS_VISUALIZATION case EMoveType::Extrude: { // use rounding to reduce the number of generated paths return type == move.type && extruder_id == move.extruder_id && cp_color_id == move.cp_color_id && role == move.extrusion_role && @@ -269,7 +265,6 @@ void GCodeViewer::SequentialView::Marker::render() const ImGui::PopStyleVar(); } -#if ENABLE_GCODE_WINDOW void GCodeViewer::SequentialView::GCodeWindow::load_gcode() { if (m_filename.empty()) @@ -487,7 +482,6 @@ void GCodeViewer::SequentialView::render(float legend_height) const bottom -= wxGetApp().plater()->get_view_toolbar().get_height(); gcode_window.render(legend_height, bottom, static_cast(gcode_ids[current.last])); } -#endif // ENABLE_GCODE_WINDOW const std::vector GCodeViewer::Extrusion_Role_Colors {{ { 0.75f, 0.75f, 0.75f }, // erNone @@ -511,9 +505,7 @@ const std::vector GCodeViewer::Extrusion_Role_Colors {{ const std::vector GCodeViewer::Options_Colors {{ { 0.803f, 0.135f, 0.839f }, // Retractions { 0.287f, 0.679f, 0.810f }, // Unretractions -#if ENABLE_SEAMS_VISUALIZATION { 0.900f, 0.900f, 0.900f }, // Seams -#endif // ENABLE_SEAMS_VISUALIZATION { 0.758f, 0.744f, 0.389f }, // ToolChanges { 0.856f, 0.582f, 0.546f }, // ColorChanges { 0.322f, 0.942f, 0.512f }, // PausePrints @@ -556,20 +548,12 @@ GCodeViewer::GCodeViewer() case EMoveType::Pause_Print: case EMoveType::Custom_GCode: case EMoveType::Retract: -#if ENABLE_SEAMS_VISUALIZATION case EMoveType::Unretract: case EMoveType::Seam: { buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point; buffer.vertices.format = VBuffer::EFormat::Position; break; } -#else - case EMoveType::Unretract: { - buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point; - buffer.vertices.format = VBuffer::EFormat::Position; - break; - } -#endif // ENABLE_SEAMS_VISUALIZATION case EMoveType::Wipe: case EMoveType::Extrude: { buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Triangle; @@ -599,10 +583,13 @@ void GCodeViewer::load(const GCodeProcessor::Result& gcode_result, const Print& // release gpu memory, if used reset(); -#if ENABLE_GCODE_WINDOW m_sequential_view.gcode_window.set_filename(gcode_result.filename); m_sequential_view.gcode_window.load_gcode(); -#endif // ENABLE_GCODE_WINDOW + +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + if (wxGetApp().is_gcode_viewer()) + m_custom_gcode_per_print_z = gcode_result.custom_gcode_per_print_z; +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER load_toolpaths(gcode_result); @@ -761,9 +748,10 @@ void GCodeViewer::reset() m_layers_z_range = { 0, 0 }; m_roles = std::vector(); m_print_statistics.reset(); -#if ENABLE_GCODE_WINDOW +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + m_custom_gcode_per_print_z = std::vector(); +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER m_sequential_view.gcode_window.reset(); -#endif // ENABLE_GCODE_WINDOW #if ENABLE_GCODE_VIEWER_STATISTICS m_statistics.reset_all(); #endif // ENABLE_GCODE_VIEWER_STATISTICS @@ -783,18 +771,11 @@ void GCodeViewer::render() const case EMoveType::Pause_Print: case EMoveType::Custom_GCode: case EMoveType::Retract: -#if ENABLE_SEAMS_VISUALIZATION case EMoveType::Unretract: case EMoveType::Seam: { buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; break; } -#else - case EMoveType::Unretract: { - buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110"; - break; - } -#endif // ENABLE_SEAMS_VISUALIZATION case EMoveType::Wipe: case EMoveType::Extrude: { buffer.shader = "gouraud_light"; @@ -832,20 +813,12 @@ void GCodeViewer::render() const glsafe(::glEnable(GL_DEPTH_TEST)); render_toolpaths(); render_shells(); -#if ENABLE_GCODE_WINDOW float legend_height = 0.0f; render_legend(legend_height); -#else - render_legend(); -#endif // ENABLE_GCODE_WINDOW SequentialView* sequential_view = const_cast(&m_sequential_view); if (sequential_view->current.last != sequential_view->endpoints.last) { sequential_view->marker.set_world_position(sequential_view->current_position); -#if ENABLE_GCODE_WINDOW sequential_view->render(legend_height); -#else - sequential_view->marker.render(); -#endif // ENABLE_GCODE_WINDOW } #if ENABLE_GCODE_VIEWER_STATISTICS render_statistics(); @@ -927,9 +900,7 @@ unsigned int GCodeViewer::get_options_visibility_flags() const flags = set_flag(flags, static_cast(Preview::OptionType::Wipe), is_toolpath_move_type_visible(EMoveType::Wipe)); flags = set_flag(flags, static_cast(Preview::OptionType::Retractions), is_toolpath_move_type_visible(EMoveType::Retract)); flags = set_flag(flags, static_cast(Preview::OptionType::Unretractions), is_toolpath_move_type_visible(EMoveType::Unretract)); -#if ENABLE_SEAMS_VISUALIZATION flags = set_flag(flags, static_cast(Preview::OptionType::Seams), is_toolpath_move_type_visible(EMoveType::Seam)); -#endif // ENABLE_SEAMS_VISUALIZATION flags = set_flag(flags, static_cast(Preview::OptionType::ToolChanges), is_toolpath_move_type_visible(EMoveType::Tool_change)); flags = set_flag(flags, static_cast(Preview::OptionType::ColorChanges), is_toolpath_move_type_visible(EMoveType::Color_change)); flags = set_flag(flags, static_cast(Preview::OptionType::PausePrints), is_toolpath_move_type_visible(EMoveType::Pause_Print)); @@ -950,9 +921,7 @@ void GCodeViewer::set_options_visibility_from_flags(unsigned int flags) set_toolpath_move_type_visible(EMoveType::Wipe, is_flag_set(static_cast(Preview::OptionType::Wipe))); set_toolpath_move_type_visible(EMoveType::Retract, is_flag_set(static_cast(Preview::OptionType::Retractions))); set_toolpath_move_type_visible(EMoveType::Unretract, is_flag_set(static_cast(Preview::OptionType::Unretractions))); -#if ENABLE_SEAMS_VISUALIZATION set_toolpath_move_type_visible(EMoveType::Seam, is_flag_set(static_cast(Preview::OptionType::Seams))); -#endif // ENABLE_SEAMS_VISUALIZATION set_toolpath_move_type_visible(EMoveType::Tool_change, is_flag_set(static_cast(Preview::OptionType::ToolChanges))); set_toolpath_move_type_visible(EMoveType::Color_change, is_flag_set(static_cast(Preview::OptionType::ColorChanges))); set_toolpath_move_type_visible(EMoveType::Pause_Print, is_flag_set(static_cast(Preview::OptionType::PausePrints))); @@ -1122,7 +1091,6 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const fclose(fp); } -#if ENABLE_GCODE_WINDOW void GCodeViewer::start_mapping_gcode_window() { m_sequential_view.gcode_window.load_gcode(); @@ -1132,7 +1100,6 @@ void GCodeViewer::stop_mapping_gcode_window() { m_sequential_view.gcode_window.stop_mapping_file(); } -#endif // ENABLE_GCODE_WINDOW void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) { @@ -1430,11 +1397,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) // for the gcode viewer we need to take in account all moves to correctly size the printbed m_paths_bounding_box.merge(move.position.cast()); else { -#if ENABLE_START_GCODE_VISUALIZATION if (move.type == EMoveType::Extrude && move.extrusion_role != erCustom && move.width != 0.0f && move.height != 0.0f) -#else - if (move.type == EMoveType::Extrude && move.width != 0.0f && move.height != 0.0f) -#endif // ENABLE_START_GCODE_VISUALIZATION m_paths_bounding_box.merge(move.position.cast()); } } @@ -1443,12 +1406,10 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) m_max_bounding_box = m_paths_bounding_box; m_max_bounding_box.merge(m_paths_bounding_box.max + m_sequential_view.marker.get_bounding_box().size()[2] * Vec3d::UnitZ()); -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER m_sequential_view.gcode_ids.clear(); for (const GCodeProcessor::MoveVertex& move : gcode_result.moves) { m_sequential_view.gcode_ids.push_back(move.gcode_id); } -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER std::vector vertices(m_buffers.size()); std::vector indices(m_buffers.size()); @@ -2188,9 +2149,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool case EMoveType::Custom_GCode: { color = Options_Colors[static_cast(EOptionsColors::CustomGCodes)]; break; } case EMoveType::Retract: { color = Options_Colors[static_cast(EOptionsColors::Retractions)]; break; } case EMoveType::Unretract: { color = Options_Colors[static_cast(EOptionsColors::Unretractions)]; break; } -#if ENABLE_SEAMS_VISUALIZATION case EMoveType::Seam: { color = Options_Colors[static_cast(EOptionsColors::Seams)]; break; } -#endif // ENABLE_SEAMS_VISUALIZATION case EMoveType::Extrude: { if (!top_layer_only || m_sequential_view.current.last == global_endpoints.last || @@ -2594,34 +2553,22 @@ void GCodeViewer::render_shells() const // glsafe(::glDepthMask(GL_TRUE)); } -#if ENABLE_GCODE_WINDOW void GCodeViewer::render_legend(float& legend_height) const -#else -void GCodeViewer::render_legend() const -#endif // ENABLE_GCODE_WINDOW { if (!m_legend_enabled) return; -#if ENABLE_SCROLLABLE_LEGEND const Size cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size(); -#endif // ENABLE_SCROLLABLE_LEGEND ImGuiWrapper& imgui = *wxGetApp().imgui(); imgui.set_next_window_pos(0.0f, 0.0f, ImGuiCond_Always); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::SetNextWindowBgAlpha(0.6f); -#if ENABLE_SCROLLABLE_LEGEND const float max_height = 0.75f * static_cast(cnv_size.get_height()); const float child_height = 0.3333f * max_height; ImGui::SetNextWindowSizeConstraints({ 0.0f, 0.0f }, { -1.0f, max_height }); imgui.begin(std::string("Legend"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove); -#else - imgui.begin(std::string("Legend"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); - - ImDrawList* draw_list = ImGui::GetWindowDrawList(); -#endif // ENABLE_SCROLLABLE_LEGEND enum class EItemType : unsigned char { @@ -2632,30 +2579,22 @@ void GCodeViewer::render_legend() const }; const PrintEstimatedStatistics::Mode& time_mode = m_print_statistics.modes[static_cast(m_time_estimate_mode)]; -#if ENABLE_SCROLLABLE_LEGEND bool show_estimated_time = time_mode.time > 0.0f && (m_view_type == EViewType::FeatureType || (m_view_type == EViewType::ColorPrint && !time_mode.custom_gcode_times.empty())); -#endif // ENABLE_SCROLLABLE_LEGEND const float icon_size = ImGui::GetTextLineHeight(); const float percent_bar_size = 2.0f * ImGui::GetTextLineHeight(); bool imperial_units = wxGetApp().app_config->get("use_inches") == "1"; -#if ENABLE_SCROLLABLE_LEGEND auto append_item = [this, icon_size, percent_bar_size, &imgui, imperial_units](EItemType type, const Color& color, const std::string& label, -#else - auto append_item = [this, draw_list, icon_size, percent_bar_size, &imgui, imperial_units](EItemType type, const Color& color, const std::string& label, -#endif // ENABLE_SCROLLABLE_LEGEND bool visible = true, const std::string& time = "", float percent = 0.0f, float max_percent = 0.0f, const std::array& offsets = { 0.0f, 0.0f, 0.0f, 0.0f }, double used_filament_m = 0.0, double used_filament_g = 0.0, std::function callback = nullptr) { if (!visible) ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.3333f); -#if ENABLE_SCROLLABLE_LEGEND ImDrawList* draw_list = ImGui::GetWindowDrawList(); -#endif // ENABLE_SCROLLABLE_LEGEND ImVec2 pos = ImGui::GetCursorScreenPos(); switch (type) { default: @@ -3008,8 +2947,11 @@ void GCodeViewer::render_legend() const } case EViewType::ColorPrint: { -#if ENABLE_SCROLLABLE_LEGEND +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + const std::vector& custom_gcode_per_print_z = wxGetApp().is_editor() ? wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes : m_custom_gcode_per_print_z; +#else const std::vector& custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes; +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER size_t total_items = 1; for (unsigned char i : m_extruder_ids) { total_items += color_print_ranges(i, custom_gcode_per_print_z).size(); @@ -3020,9 +2962,6 @@ void GCodeViewer::render_legend() const // add scrollable region, if needed if (need_scrollable) ImGui::BeginChild("color_prints", { -1.0f, child_height }, false); -#else - const std::vector& custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes; -#endif // ENABLE_SCROLLABLE_LEGEND if (m_extruders_count == 1) { // single extruder use case const std::vector>> cp_values = color_print_ranges(0, custom_gcode_per_print_z); const int items_cnt = static_cast(cp_values.size()); @@ -3073,10 +3012,8 @@ void GCodeViewer::render_legend() const } } } -#if ENABLE_SCROLLABLE_LEGEND if (need_scrollable) ImGui::EndChild(); -#endif // ENABLE_SCROLLABLE_LEGEND break; } @@ -3109,7 +3046,11 @@ void GCodeViewer::render_legend() const auto generate_partial_times = [this, get_used_filament_from_volume](const TimesList& times, const std::vector& used_filaments) { PartialTimes items; +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + std::vector custom_gcode_per_print_z = wxGetApp().is_editor() ? wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes : m_custom_gcode_per_print_z; +#else std::vector custom_gcode_per_print_z = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes; +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER int extruders_count = wxGetApp().extruders_edited_cnt(); std::vector last_color(extruders_count); for (int i = 0; i < extruders_count; ++i) { @@ -3227,12 +3168,10 @@ void GCodeViewer::render_legend() const ImGui::Spacing(); append_headers({ _u8L("Event"), _u8L("Remaining time"), _u8L("Duration"), _u8L("Used filament") }, offsets); -#if ENABLE_SCROLLABLE_LEGEND const bool need_scrollable = static_cast(partial_times.size()) * (icon_size + ImGui::GetStyle().ItemSpacing.y) > child_height; if (need_scrollable) // add scrollable region ImGui::BeginChild("events", { -1.0f, child_height }, false); -#endif // ENABLE_SCROLLABLE_LEGEND for (const PartialTime& item : partial_times) { switch (item.type) @@ -3254,10 +3193,8 @@ void GCodeViewer::render_legend() const } } -#if ENABLE_SCROLLABLE_LEGEND if (need_scrollable) ImGui::EndChild(); -#endif // ENABLE_SCROLLABLE_LEGEND } } @@ -3316,12 +3253,8 @@ void GCodeViewer::render_legend() const available(EMoveType::Pause_Print) || available(EMoveType::Retract) || available(EMoveType::Tool_change) || -#if ENABLE_SEAMS_VISUALIZATION available(EMoveType::Unretract) || available(EMoveType::Seam); -#else - available(EMoveType::Unretract); -#endif // ENABLE_SEAMS_VISUALIZATION }; auto add_option = [this, append_item](EMoveType move_type, EOptionsColors color, const std::string& text) { @@ -3339,9 +3272,7 @@ void GCodeViewer::render_legend() const // items add_option(EMoveType::Retract, EOptionsColors::Retractions, _u8L("Retractions")); add_option(EMoveType::Unretract, EOptionsColors::Unretractions, _u8L("Deretractions")); -#if ENABLE_SEAMS_VISUALIZATION add_option(EMoveType::Seam, EOptionsColors::Seams, _u8L("Seams")); -#endif // ENABLE_SEAMS_VISUALIZATION add_option(EMoveType::Tool_change, EOptionsColors::ToolChanges, _u8L("Tool changes")); add_option(EMoveType::Color_change, EOptionsColors::ColorChanges, _u8L("Color changes")); add_option(EMoveType::Pause_Print, EOptionsColors::PausePrints, _u8L("Print pauses")); @@ -3407,48 +3338,56 @@ void GCodeViewer::render_legend() const } // total estimated printing time section -#if ENABLE_SCROLLABLE_LEGEND if (show_estimated_time) { -#else - if (time_mode.time > 0.0f && (m_view_type == EViewType::FeatureType || - (m_view_type == EViewType::ColorPrint && !time_mode.custom_gcode_times.empty()))) { - - ImGui::Spacing(); -#endif // ENABLE_SCROLLABLE_LEGEND ImGui::Spacing(); std::string time_title = _u8L("Estimated printing times"); - switch (m_time_estimate_mode) - { - case PrintEstimatedStatistics::ETimeMode::Normal: { time_title += " [" + _u8L("Normal mode") + "]:"; break; } - case PrintEstimatedStatistics::ETimeMode::Stealth: { time_title += " [" + _u8L("Stealth mode") + "]:"; break; } - default: { assert(false); break; } + auto can_show_mode_button = [this](PrintEstimatedStatistics::ETimeMode mode) { + bool show = false; + if (m_print_statistics.modes.size() > 1 && m_print_statistics.modes[static_cast(mode)].roles_times.size() > 0) { + for (size_t i = 0; i < m_print_statistics.modes.size(); ++i) { + if (i != static_cast(mode) && + m_print_statistics.modes[i].time > 0.0f && + short_time(get_time_dhms(m_print_statistics.modes[static_cast(mode)].time)) != short_time(get_time_dhms(m_print_statistics.modes[i].time))) { + show = true; + break; + } + } + } + return show; + }; + + if (can_show_mode_button(m_time_estimate_mode)) { + switch (m_time_estimate_mode) + { + case PrintEstimatedStatistics::ETimeMode::Normal: { time_title += " [" + _u8L("Normal mode") + "]"; break; } + case PrintEstimatedStatistics::ETimeMode::Stealth: { time_title += " [" + _u8L("Stealth mode") + "]"; break; } + default: { assert(false); break; } + } } - imgui.title(time_title); + imgui.title(time_title + ":"); std::string first_str = _u8L("First layer"); std::string total_str = _u8L("Total"); - float max_len = 10.0f + ImGui::GetStyle().ItemSpacing.x + std::max(ImGui::CalcTextSize(first_str.c_str()).x, ImGui::CalcTextSize(total_str.c_str()).x); + float max_len = 10.0f + ImGui::GetStyle().ItemSpacing.x; + if (time_mode.layers_times.empty()) + max_len += ImGui::CalcTextSize(total_str.c_str()).x; + else + max_len += std::max(ImGui::CalcTextSize(first_str.c_str()).x, ImGui::CalcTextSize(total_str.c_str()).x); - imgui.text(first_str + ":"); - ImGui::SameLine(max_len); - imgui.text(short_time(get_time_dhms(time_mode.layers_times.front()))); + if (!time_mode.layers_times.empty()) { + imgui.text(first_str + ":"); + ImGui::SameLine(max_len); + imgui.text(short_time(get_time_dhms(time_mode.layers_times.front()))); + } imgui.text(total_str + ":"); ImGui::SameLine(max_len); imgui.text(short_time(get_time_dhms(time_mode.time))); - auto show_mode_button = [this, &imgui](const wxString& label, PrintEstimatedStatistics::ETimeMode mode) { - bool show = false; - for (size_t i = 0; i < m_print_statistics.modes.size(); ++i) { - if (i != static_cast(mode) && - short_time(get_time_dhms(m_print_statistics.modes[static_cast(mode)].time)) != short_time(get_time_dhms(m_print_statistics.modes[i].time))) { - show = true; - break; - } - } - if (show && m_print_statistics.modes[static_cast(mode)].roles_times.size() > 0) { + auto show_mode_button = [this, &imgui, can_show_mode_button](const wxString& label, PrintEstimatedStatistics::ETimeMode mode) { + if (can_show_mode_button(mode)) { if (imgui.button(label)) { *const_cast(&m_time_estimate_mode) = mode; wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); @@ -3470,9 +3409,7 @@ void GCodeViewer::render_legend() const } } -#if ENABLE_GCODE_WINDOW legend_height = ImGui::GetCurrentWindow()->Size.y; -#endif // ENABLE_GCODE_WINDOW imgui.end(); ImGui::PopStyleVar(); diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index b12edadc9..41307bad9 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -5,9 +5,7 @@ #include "libslic3r/GCode/GCodeProcessor.hpp" #include "GLModel.hpp" -#if ENABLE_GCODE_WINDOW #include -#endif // ENABLE_GCODE_WINDOW #include #include @@ -40,9 +38,7 @@ class GCodeViewer { Retractions, Unretractions, -#if ENABLE_SEAMS_VISUALIZATION Seams, -#endif // ENABLE_SEAMS_VISUALIZATION ToolChanges, ColorChanges, PausePrints, @@ -520,7 +516,6 @@ public: void render() const; }; -#if ENABLE_GCODE_WINDOW class GCodeWindow { struct Line @@ -557,7 +552,6 @@ public: void stop_mapping_file(); }; -#endif // ENABLE_GCODE_WINDOW struct Endpoints { @@ -571,16 +565,10 @@ public: Endpoints last_current; Vec3f current_position{ Vec3f::Zero() }; Marker marker; -#if ENABLE_GCODE_WINDOW GCodeWindow gcode_window; -#endif // ENABLE_GCODE_WINDOW -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER std::vector gcode_ids; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER -#if ENABLE_GCODE_WINDOW void render(float legend_height) const; -#endif // ENABLE_GCODE_WINDOW }; enum class EViewType : unsigned char @@ -628,6 +616,10 @@ private: GCodeProcessor::Result::SettingsIds m_settings_ids; std::array m_sequential_range_caps; +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + std::vector m_custom_gcode_per_print_z; +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + public: GCodeViewer(); ~GCodeViewer() { reset(); } @@ -673,11 +665,14 @@ public: void export_toolpaths_to_obj(const char* filename) const; -#if ENABLE_GCODE_WINDOW void start_mapping_gcode_window(); void stop_mapping_gcode_window(); void toggle_gcode_window_visibility() { m_sequential_view.gcode_window.toggle_visibility(); } -#endif // ENABLE_GCODE_WINDOW + +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + std::vector& get_custom_gcode_per_print_z() { return m_custom_gcode_per_print_z; } + size_t get_extruders_count() { return m_extruders_count; } +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER private: void load_toolpaths(const GCodeProcessor::Result& gcode_result); @@ -685,11 +680,7 @@ private: void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const; void render_toolpaths() const; void render_shells() const; -#if ENABLE_GCODE_WINDOW void render_legend(float& legend_height) const; -#else - void render_legend() const; -#endif // ENABLE_GCODE_WINDOW #if ENABLE_GCODE_VIEWER_STATISTICS void render_statistics() const; #endif // ENABLE_GCODE_VIEWER_STATISTICS diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 303d228c7..f366100ac 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -169,17 +169,10 @@ void GLCanvas3D::LayersEditing::set_config(const DynamicPrintConfig* config) void GLCanvas3D::LayersEditing::select_object(const Model &model, int object_id) { const ModelObject *model_object_new = (object_id >= 0) ? model.objects[object_id] : nullptr; -#if ENABLE_ALLOW_NEGATIVE_Z // Maximum height of an object changes when the object gets rotated or scaled. // Changing maximum height of an object will invalidate the layer heigth editing profile. // m_model_object->bounding_box() is cached, therefore it is cheap even if this method is called frequently. const float new_max_z = (model_object_new == nullptr) ? 0.0f : static_cast(model_object_new->bounding_box().max.z()); -#else - // Maximum height of an object changes when the object gets rotated or scaled. - // Changing maximum height of an object will invalidate the layer heigth editing profile. - // m_model_object->raw_bounding_box() is cached, therefore it is cheap even if this method is called frequently. - float new_max_z = (model_object_new == nullptr) ? 0.f : model_object_new->raw_bounding_box().size().z(); -#endif // ENABLE_ALLOW_NEGATIVE_Z if (m_model_object != model_object_new || this->last_object_id != object_id || m_object_max_z != new_max_z || (model_object_new != nullptr && m_model_object->id() != model_object_new->id())) { m_layer_height_profile.clear(); @@ -261,7 +254,7 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const float widget_align = ImGui::GetCursorPosX(); ImGui::PushItemWidth(imgui.get_style_scaling() * 120.0f); m_adaptive_quality = std::clamp(m_adaptive_quality, 0.0f, 1.f); - ImGui::SliderFloat("", &m_adaptive_quality, 0.0f, 1.f, "%.2f"); + imgui.slider_float("", &m_adaptive_quality, 0.0f, 1.f, "%.2f"); ImGui::Separator(); if (imgui.button(_L("Smooth"))) @@ -799,7 +792,7 @@ void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons for (const Polygon& poly : polygons) { triangles_count += poly.points.size() - 2; } - size_t vertices_count = 3 * triangles_count; + const size_t vertices_count = 3 * triangles_count; if (m_render_fill) { GLModel::InitializationData fill_data; @@ -810,13 +803,13 @@ void GLCanvas3D::SequentialPrintClearance::set_polygons(const Polygons& polygons entity.normals.reserve(vertices_count); entity.indices.reserve(vertices_count); - ExPolygons polygons_union = union_ex(polygons); + const ExPolygons polygons_union = union_ex(polygons); for (const ExPolygon& poly : polygons_union) { - std::vector triangulation = triangulate_expolygon_3d(poly, false); + const std::vector triangulation = triangulate_expolygon_3d(poly); for (const Vec3d& v : triangulation) { entity.positions.emplace_back(v.cast() + Vec3f(0.0f, 0.0f, 0.0125f)); // add a small positive z to avoid z-fighting entity.normals.emplace_back(Vec3f::UnitZ()); - size_t positions_count = entity.positions.size(); + const size_t positions_count = entity.positions.size(); if (positions_count % 3 == 0) { entity.indices.emplace_back(positions_count - 3); entity.indices.emplace_back(positions_count - 2); @@ -907,6 +900,8 @@ wxDEFINE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event); wxDEFINE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent); wxDEFINE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_RENDER_TIMER, wxTimerEvent/*RenderTimerEvent*/); +wxDEFINE_EVENT(EVT_GLCANVAS_TOOLBAR_HIGHLIGHTER_TIMER, wxTimerEvent); +wxDEFINE_EVENT(EVT_GLCANVAS_GIZMO_HIGHLIGHTER_TIMER, wxTimerEvent); const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25; @@ -1119,7 +1114,6 @@ int GLCanvas3D::check_volumes_outside_state() const return (int)state; } -#if ENABLE_GCODE_WINDOW void GLCanvas3D::start_mapping_gcode_window() { m_gcode_viewer.start_mapping_gcode_window(); @@ -1129,7 +1123,6 @@ void GLCanvas3D::stop_mapping_gcode_window() { m_gcode_viewer.stop_mapping_gcode_window(); } -#endif // ENABLE_GCODE_WINDOW void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo, int instance_idx) { @@ -1416,10 +1409,6 @@ void GLCanvas3D::render() if (!is_initialized() && !init()) return; -#if ENABLE_RENDER_STATISTICS - auto start_time = std::chrono::high_resolution_clock::now(); -#endif // ENABLE_RENDER_STATISTICS - if (wxGetApp().plater()->get_bed().get_shape().empty()) { // this happens at startup when no data is still saved under <>\AppData\Roaming\Slic3rPE post_event(SimpleEvent(EVT_GLCANVAS_UPDATE_BED_SHAPE)); @@ -1514,19 +1503,12 @@ void GLCanvas3D::render() // draw overlays _render_overlays(); -#if ENABLE_RENDER_STATISTICS if (wxGetApp().plater()->is_render_statistic_dialog_visible()) { ImGuiWrapper& imgui = *wxGetApp().imgui(); imgui.begin(std::string("Render statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); - imgui.text("Last frame:"); + imgui.text("FPS (SwapBuffers() calls per second):"); ImGui::SameLine(); - int64_t average = m_render_stats.get_average(); - imgui.text(std::to_string(average)); - ImGui::SameLine(); - imgui.text("ms"); - imgui.text("FPS:"); - ImGui::SameLine(); - imgui.text(std::to_string((average == 0) ? 0 : static_cast(1000.0f / static_cast(average)))); + imgui.text(std::to_string(m_render_stats.get_fps_and_reset_if_needed())); ImGui::Separator(); imgui.text("Compressed textures:"); ImGui::SameLine(); @@ -1536,7 +1518,6 @@ void GLCanvas3D::render() imgui.text(std::to_string(OpenGLManager::get_gl_info().get_max_tex_size())); imgui.end(); } -#endif // ENABLE_RENDER_STATISTICS #if ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW if (wxGetApp().is_editor() && wxGetApp().plater()->is_view3D_shown()) @@ -1583,11 +1564,7 @@ void GLCanvas3D::render() wxGetApp().imgui()->render(); m_canvas->SwapBuffers(); - -#if ENABLE_RENDER_STATISTICS - auto end_time = std::chrono::high_resolution_clock::now(); - m_render_stats.add_frame(std::chrono::duration_cast(end_time - start_time).count()); -#endif // ENABLE_RENDER_STATISTICS + m_render_stats.increment_fps_counter(); } void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, Camera::EType camera_type) @@ -1625,14 +1602,17 @@ void GLCanvas3D::delete_selected() m_selection.erase(); } -void GLCanvas3D::ensure_on_bed(unsigned int object_idx) +void GLCanvas3D::ensure_on_bed(unsigned int object_idx, bool allow_negative_z) { + if (allow_negative_z) + return; + typedef std::map, double> InstancesToZMap; InstancesToZMap instances_min_z; for (GLVolume* volume : m_volumes.volumes) { if (volume->object_idx() == (int)object_idx && !volume->is_modifier) { - double min_z = volume->transformed_convex_hull_bounding_box().min(2); + double min_z = volume->transformed_convex_hull_bounding_box().min.z(); std::pair instance = std::make_pair(volume->object_idx(), volume->instance_idx()); InstancesToZMap::iterator it = instances_min_z.find(instance); if (it == instances_min_z.end()) @@ -2189,6 +2169,10 @@ void GLCanvas3D::bind_event_handlers() m_canvas->Bind(wxEVT_MOUSEWHEEL, &GLCanvas3D::on_mouse_wheel, this); m_canvas->Bind(wxEVT_TIMER, &GLCanvas3D::on_timer, this); m_canvas->Bind(EVT_GLCANVAS_RENDER_TIMER, &GLCanvas3D::on_render_timer, this); + m_toolbar_highlighter.set_timer_owner(m_canvas, 0); + m_canvas->Bind(EVT_GLCANVAS_TOOLBAR_HIGHLIGHTER_TIMER, [this](wxTimerEvent&) { m_toolbar_highlighter.blink(); }); + m_gizmo_highlighter.set_timer_owner(m_canvas, 0); + m_canvas->Bind(EVT_GLCANVAS_GIZMO_HIGHLIGHTER_TIMER, [this](wxTimerEvent&) { m_gizmo_highlighter.blink(); }); m_canvas->Bind(wxEVT_LEFT_DOWN, &GLCanvas3D::on_mouse, this); m_canvas->Bind(wxEVT_LEFT_UP, &GLCanvas3D::on_mouse, this); m_canvas->Bind(wxEVT_MIDDLE_DOWN, &GLCanvas3D::on_mouse, this); @@ -2419,10 +2403,8 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 'a': { post_event(SimpleEvent(EVT_GLCANVAS_ARRANGE)); break; } case 'B': case 'b': { zoom_to_bed(); break; } -#if ENABLE_GCODE_WINDOW case 'C': case 'c': { m_gcode_viewer.toggle_gcode_window_visibility(); m_dirty = true; request_extra_frame(); break; } -#endif // ENABLE_GCODE_WINDOW case 'E': case 'e': { m_labels.show(!m_labels.is_shown()); m_dirty = true; break; } case 'G': @@ -2449,8 +2431,8 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 'O': case 'o': { _update_camera_zoom(-1.0); break; } #if ENABLE_RENDER_PICKING_PASS - case 'P': - case 'p': { + case 'T': + case 't': { m_show_picking_texture = !m_show_picking_texture; m_dirty = true; break; @@ -2603,15 +2585,11 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) { if (!m_gizmos.on_key(evt)) { if (evt.GetEventType() == wxEVT_KEY_UP) { -#if ENABLE_RENDER_STATISTICS if (evt.ShiftDown() && evt.ControlDown() && keyCode == WXK_SPACE) { wxGetApp().plater()->toggle_render_statistic_dialog(); m_dirty = true; } if (m_tab_down && keyCode == WXK_TAB && !evt.HasAnyModifiers()) { -#else - if (m_tab_down && keyCode == WXK_TAB && !evt.HasAnyModifiers()) { -#endif // ENABLE_RENDER_STATISTICS // Enable switching between 3D and Preview with Tab // m_canvas->HandleAsNavigationKey(evt); // XXX: Doesn't work in some cases / on Linux post_event(SimpleEvent(EVT_GLCANVAS_TAB)); @@ -2969,6 +2947,20 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) return; } +#if ENABLE_SINKING_CONTOURS + for (GLVolume* volume : m_volumes.volumes) { + volume->force_sinking_contours = false; + } + + auto show_sinking_contours = [this]() { + const Selection::IndicesList& idxs = m_selection.get_volume_idxs(); + for (unsigned int idx : idxs) { + m_volumes.volumes[idx]->force_sinking_contours = true; + } + m_dirty = true; + }; +#endif // ENABLE_SINKING_CONTOURS + if (m_gizmos.on_mouse(evt)) { if (wxWindow::FindFocus() != m_canvas) // Grab keyboard focus for input in gizmo dialogs. @@ -2993,6 +2985,21 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) default: { break; } } } +#if ENABLE_SINKING_CONTOURS + else if (evt.Dragging()) { + switch (m_gizmos.get_current_type()) + { + case GLGizmosManager::EType::Move: + case GLGizmosManager::EType::Scale: + case GLGizmosManager::EType::Rotate: + { + show_sinking_contours(); + break; + } + default: { break; } + } + } +#endif // ENABLE_SINKING_CONTOURS return; } @@ -3302,6 +3309,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) else evt.Skip(); +#if ENABLE_SINKING_CONTOURS + if (m_moving) + show_sinking_contours(); +#endif // ENABLE_SINKING_CONTOURS + #ifdef __WXMSW__ if (on_enter_workaround) m_mouse.position = Vec2d(-1., -1.); @@ -3405,37 +3417,22 @@ void GLCanvas3D::do_move(const std::string& snapshot_type) wipe_tower_origin = v->get_volume_offset(); } -#if ENABLE_ALLOW_NEGATIVE_Z // Fixes flying instances -#else - // Fixes sinking/flying instances -#endif // ENABLE_ALLOW_NEGATIVE_Z for (const std::pair& i : done) { ModelObject* m = m_model->objects[i.first]; -#if ENABLE_ALLOW_NEGATIVE_Z const double shift_z = m->get_instance_min_z(i.second); -#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA if (current_printer_technology() == ptSLA || shift_z > SINKING_Z_THRESHOLD) { -#else - if (shift_z > 0.0) { -#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA const Vec3d shift(0.0, 0.0, -shift_z); -#else - const Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second)); -#endif // ENABLE_ALLOW_NEGATIVE_Z - m_selection.translate(i.first, i.second, shift); - m->translate_instance(i.second, shift); -#if ENABLE_ALLOW_NEGATIVE_Z + m_selection.translate(i.first, i.second, shift); + m->translate_instance(i.second, shift); } -#endif // ENABLE_ALLOW_NEGATIVE_Z + wxGetApp().obj_list()->update_info_items(static_cast(i.first)); } -#if ENABLE_ALLOW_NEGATIVE_Z // if the selection is not valid to allow for layer editing after the move, we need to turn off the tool if it is running // similar to void Plater::priv::selection_changed() if (!wxGetApp().plater()->can_layers_editing() && is_layers_editing_enabled()) post_event(SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); -#endif // ENABLE_ALLOW_NEGATIVE_Z if (object_moved) post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MOVED)); @@ -3456,7 +3453,6 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type) if (!snapshot_type.empty()) wxGetApp().plater()->take_snapshot(_(snapshot_type)); -#if ENABLE_ALLOW_NEGATIVE_Z // stores current min_z of instances std::map, double> min_zs; if (!snapshot_type.empty()) { @@ -3467,7 +3463,6 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type) } } } -#endif // ENABLE_ALLOW_NEGATIVE_Z std::set> done; // keeps track of modified instances @@ -3505,19 +3500,15 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type) // Fixes sinking/flying instances for (const std::pair& i : done) { ModelObject* m = m_model->objects[i.first]; -#if ENABLE_ALLOW_NEGATIVE_Z - double shift_z = m->get_instance_min_z(i.second); + const double shift_z = m->get_instance_min_z(i.second); // leave sinking instances as sinking if (min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) { - Vec3d shift(0.0, 0.0, -shift_z); -#else - Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second)); -#endif // ENABLE_ALLOW_NEGATIVE_Z + const Vec3d shift(0.0, 0.0, -shift_z); m_selection.translate(i.first, i.second, shift); m->translate_instance(i.second, shift); -#if ENABLE_ALLOW_NEGATIVE_Z } -#endif // ENABLE_ALLOW_NEGATIVE_Z + + wxGetApp().obj_list()->update_info_items(static_cast(i.first)); } if (!done.empty()) @@ -3534,7 +3525,6 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type) if (!snapshot_type.empty()) wxGetApp().plater()->take_snapshot(_(snapshot_type)); -#if ENABLE_ALLOW_NEGATIVE_Z // stores current min_z of instances std::map, double> min_zs; if (!snapshot_type.empty()) { @@ -3545,7 +3535,6 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type) } } } -#endif // ENABLE_ALLOW_NEGATIVE_Z std::set> done; // keeps track of modified instances @@ -3580,19 +3569,14 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type) // Fixes sinking/flying instances for (const std::pair& i : done) { ModelObject* m = m_model->objects[i.first]; -#if ENABLE_ALLOW_NEGATIVE_Z double shift_z = m->get_instance_min_z(i.second); // leave sinking instances as sinking if (min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) { Vec3d shift(0.0, 0.0, -shift_z); -#else - Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second)); -#endif // ENABLE_ALLOW_NEGATIVE_Z - m_selection.translate(i.first, i.second, shift); - m->translate_instance(i.second, shift); -#if ENABLE_ALLOW_NEGATIVE_Z + m_selection.translate(i.first, i.second, shift); + m->translate_instance(i.second, shift); } -#endif // ENABLE_ALLOW_NEGATIVE_Z + wxGetApp().obj_list()->update_info_items(static_cast(i.first)); } if (!done.empty()) @@ -3618,14 +3602,24 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type) if (!snapshot_type.empty()) wxGetApp().plater()->take_snapshot(_(snapshot_type)); + // stores current min_z of instances + std::map, double> min_zs; + if (!snapshot_type.empty()) { + for (int i = 0; i < static_cast(m_model->objects.size()); ++i) { + const ModelObject* obj = m_model->objects[i]; + for (int j = 0; j < static_cast(obj->instances.size()); ++j) { + min_zs[{ i, j }] = obj->instance_bounding_box(j).min.z(); + } + } + } + std::set> done; // keeps track of modified instances Selection::EMode selection_mode = m_selection.get_mode(); - for (const GLVolume* v : m_volumes.volumes) - { + for (const GLVolume* v : m_volumes.volumes) { int object_idx = v->object_idx(); - if ((object_idx < 0) || ((int)m_model->objects.size() <= object_idx)) + if (object_idx < 0 || (int)m_model->objects.size() <= object_idx) continue; int instance_idx = v->instance_idx(); @@ -3635,8 +3629,7 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type) // Mirror instances/volumes ModelObject* model_object = m_model->objects[object_idx]; - if (model_object != nullptr) - { + if (model_object != nullptr) { if (selection_mode == Selection::Instance) model_object->instances[instance_idx]->set_mirror(v->get_instance_mirror()); else if (selection_mode == Selection::Volume) @@ -3647,12 +3640,16 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type) } // Fixes sinking/flying instances - for (const std::pair& i : done) - { + for (const std::pair& i : done) { ModelObject* m = m_model->objects[i.first]; - Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second)); - m_selection.translate(i.first, i.second, shift); - m->translate_instance(i.second, shift); + double shift_z = m->get_instance_min_z(i.second); + // leave sinking instances as sinking + if (min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) { + Vec3d shift(0.0, 0.0, -shift_z); + m_selection.translate(i.first, i.second, shift); + m->translate_instance(i.second, shift); + } + wxGetApp().obj_list()->update_info_items(static_cast(i.first)); } post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); @@ -3881,6 +3878,15 @@ void GLCanvas3D::update_sequential_clearance() set_sequential_print_clearance_polygons(polygons); } +bool GLCanvas3D::is_object_sinking(int object_idx) const +{ + for (const GLVolume* v : m_volumes.volumes) { + if (v->object_idx() == object_idx && v->is_sinking()) + return true; + } + return false; +} + bool GLCanvas3D::_is_shown_on_screen() const { return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false; @@ -4425,6 +4431,29 @@ bool GLCanvas3D::_init_main_toolbar() m_main_toolbar.set_enabled(false); return true; } + // init arrow + BackgroundTexture::Metadata arrow_data; + arrow_data.filename = "toolbar_arrow.png"; +// arrow_data.filename = "toolbar_arrow.svg"; + //arrow_data.left = 16; + //arrow_data.top = 16; + //arrow_data.right = 16; + //arrow_data.bottom = 16; + + arrow_data.left = 0; + arrow_data.top = 0; + arrow_data.right = 0; + arrow_data.bottom = 0; + + if (!m_main_toolbar.init_arrow(arrow_data)) + { + BOOST_LOG_TRIVIAL(error) << "Main toolbar failed to load arrow texture."; + } + + if (!m_gizmos.init_arrow(arrow_data)) + { + BOOST_LOG_TRIVIAL(error) << "Gizmos manager failed to load arrow texture."; + } // m_main_toolbar.set_layout_type(GLToolbar::Layout::Vertical); m_main_toolbar.set_layout_type(GLToolbar::Layout::Horizontal); @@ -4744,13 +4773,11 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) if (m_canvas == nullptr && m_context == nullptr) return; -#if ENABLE_SCROLLABLE_LEGEND const std::array new_size = { w, h }; if (m_old_size == new_size) return; m_old_size = new_size; -#endif // ENABLE_SCROLLABLE_LEGEND auto *imgui = wxGetApp().imgui(); imgui->set_display_size(static_cast(w), static_cast(h)); @@ -4761,9 +4788,7 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h) imgui->set_scaling(font_size, m_canvas->GetContentScaleFactor(), 1.0f); #endif -#if ENABLE_SCROLLABLE_LEGEND this->request_extra_frame(); -#endif // ENABLE_SCROLLABLE_LEGEND // ensures that this canvas is current _set_current(); @@ -4842,21 +4867,30 @@ void GLCanvas3D::_picking_pass() if (m_camera_clipping_plane.is_active()) ::glDisable(GL_CLIP_PLANE0); + _render_bed_for_picking(!wxGetApp().plater()->get_camera().is_looking_downward()); + m_gizmos.render_current_gizmo_for_picking_pass(); if (m_multisample_allowed) glsafe(::glEnable(GL_MULTISAMPLE)); int volume_id = -1; + int gizmo_id = -1; GLubyte color[4] = { 0, 0, 0, 0 }; const Size& cnv_size = get_canvas_size(); bool inside = 0 <= m_mouse.position(0) && m_mouse.position(0) < cnv_size.get_width() && 0 <= m_mouse.position(1) && m_mouse.position(1) < cnv_size.get_height(); if (inside) { glsafe(::glReadPixels(m_mouse.position(0), cnv_size.get_height() - m_mouse.position(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color)); - if (picking_checksum_alpha_channel(color[0], color[1], color[2]) == color[3]) - // Only non-interpolated colors are valid, those have their lowest three bits zeroed. - volume_id = color[0] + (color[1] << 8) + (color[2] << 16); + if (picking_checksum_alpha_channel(color[0], color[1], color[2]) == color[3]) { + // Only non-interpolated colors are valid, those have their lowest three bits zeroed. + // we reserve color = (0,0,0) for occluders (as the printbed) + // volumes' id are shifted by 1 + // see: _render_volumes_for_picking() + volume_id = color[0] + (color[1] << 8) + (color[2] << 16) - 1; + // gizmos' id are instead properly encoded by the color + gizmo_id = color[0] + (color[1] << 8) + (color[2] << 16); + } } if (0 <= volume_id && volume_id < (int)m_volumes.volumes.size()) { // do not add the volume id if any gizmo is active and CTRL is pressed @@ -4865,7 +4899,7 @@ void GLCanvas3D::_picking_pass() m_gizmos.set_hover_id(-1); } else - m_gizmos.set_hover_id(inside && (unsigned int)volume_id <= GLGizmoBase::BASE_ID ? ((int)GLGizmoBase::BASE_ID - volume_id) : -1); + m_gizmos.set_hover_id(inside && (unsigned int)gizmo_id <= GLGizmoBase::BASE_ID ? ((int)GLGizmoBase::BASE_ID - gizmo_id) : -1); _update_volumes_hover_state(); } @@ -4888,6 +4922,7 @@ void GLCanvas3D::_rectangular_selection_picking_pass() glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); _render_volumes_for_picking(); + _render_bed_for_picking(!wxGetApp().plater()->get_camera().is_looking_downward()); if (m_multisample_allowed) glsafe(::glEnable(GL_MULTISAMPLE)); @@ -4906,7 +4941,10 @@ void GLCanvas3D::_rectangular_selection_picking_pass() std::array data; // Only non-interpolated colors are valid, those have their lowest three bits zeroed. bool valid() const { return picking_checksum_alpha_channel(data[0], data[1], data[2]) == data[3]; } - int id() const { return data[0] + (data[1] << 8) + (data[2] << 16); } + // we reserve color = (0,0,0) for occluders (as the printbed) + // volumes' id are shifted by 1 + // see: _render_volumes_for_picking() + int id() const { return data[0] + (data[1] << 8) + (data[2] << 16) - 1; } }; std::vector frame(px_count); @@ -5028,6 +5066,17 @@ void GLCanvas3D::_render_bed(bool bottom, bool show_axes) wxGetApp().plater()->get_bed().render(*this, bottom, scale_factor, show_axes, show_texture); } +void GLCanvas3D::_render_bed_for_picking(bool bottom) +{ + float scale_factor = 1.0; +#if ENABLE_RETINA_GL + scale_factor = m_retina_helper->get_scale_factor(); +#endif // ENABLE_RETINA_GL + + wxGetApp().plater()->get_bed().render_for_picking(*this, bottom, scale_factor); +} + + #if ENABLE_DELAYED_TRANSPARENT_VOLUMES_RENDERING void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type) #else @@ -5270,50 +5319,30 @@ void GLCanvas3D::_render_volumes_for_picking() const { static const GLfloat INV_255 = 1.0f / 255.0f; -#if ENABLE_ALLOW_NEGATIVE_Z - auto* shader = wxGetApp().get_shader("picking"); - if (!shader) - return; -#endif // ENABLE_ALLOW_NEGATIVE_Z - // do not cull backfaces to show broken geometry, if any glsafe(::glDisable(GL_CULL_FACE)); glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); -#if ENABLE_ALLOW_NEGATIVE_Z - shader->start_using(); - shader->set_uniform("viewed_from_top", wxGetApp().plater()->get_camera().is_looking_downward()); -#endif // ENABLE_ALLOW_NEGATIVE_Z - const Transform3d& view_matrix = wxGetApp().plater()->get_camera().get_view_matrix(); for (size_t type = 0; type < 2; ++ type) { GLVolumeWithIdAndZList to_render = volumes_to_render(m_volumes.volumes, (type == 0) ? GLVolumeCollection::ERenderType::Opaque : GLVolumeCollection::ERenderType::Transparent, view_matrix); for (const GLVolumeWithIdAndZ& volume : to_render) if (!volume.first->disabled && (volume.first->composite_id.volume_id >= 0 || m_render_sla_auxiliaries)) { // Object picking mode. Render the object with a color encoding the object index. - unsigned int id = volume.second.first; - unsigned int r = (id & (0x000000FF << 0)) << 0; + // we reserve color = (0,0,0) for occluders (as the printbed) + // so we shift volumes' id by 1 to get the proper color + unsigned int id = 1 + volume.second.first; + unsigned int r = (id & (0x000000FF << 0)) << 0; unsigned int g = (id & (0x000000FF << 8)) >> 8; unsigned int b = (id & (0x000000FF << 16)) >> 16; unsigned int a = picking_checksum_alpha_channel(r, g, b); -#if ENABLE_ALLOW_NEGATIVE_Z - std::array color = { (float)r * INV_255, (float)g * INV_255, (float)b * INV_255, (float)a * INV_255 }; - shader->set_uniform("uniform_color", color); - shader->set_uniform("world_matrix", volume.first->world_matrix()); -#else glsafe(::glColor4f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255, (GLfloat)a * INV_255)); -#endif // ENABLE_ALLOW_NEGATIVE_Z - volume.first->render(); } } -#if ENABLE_ALLOW_NEGATIVE_Z - shader->stop_using(); -#endif // ENABLE_ALLOW_NEGATIVE_Z - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); @@ -5339,6 +5368,11 @@ void GLCanvas3D::_render_gizmos_overlay() #endif /* __WXMSW__ */ m_gizmos.render_overlay(); + + if (m_gizmo_highlighter.m_render_arrow) + { + m_gizmos.render_arrow(*this, m_gizmo_highlighter.m_gizmo_type); + } } void GLCanvas3D::_render_main_toolbar() @@ -5356,6 +5390,10 @@ void GLCanvas3D::_render_main_toolbar() m_main_toolbar.set_position(top, left); m_main_toolbar.render(*this); + if (m_toolbar_highlighter.m_render_arrow) + { + m_main_toolbar.render_arrow(*this, m_toolbar_highlighter.m_toolbar_item); + } } void GLCanvas3D::_render_undoredo_toolbar() @@ -5639,6 +5677,11 @@ void GLCanvas3D::_update_volumes_hover_state() } } } +#if ENABLE_SINKING_CONTOURS + else if (volume.selected) + volume.hover = GLVolume::HS_Hover; +#endif // ENABLE_SINKING_CONTOURS + } } @@ -6518,6 +6561,24 @@ bool GLCanvas3D::_deactivate_collapse_toolbar_items() return false; } +void GLCanvas3D::highlight_toolbar_item(const std::string& item_name) +{ + GLToolbarItem* item = m_main_toolbar.get_item(item_name); + if (!item) + item = m_undoredo_toolbar.get_item(item_name); + if (!item || !item->is_visible()) + return; + m_toolbar_highlighter.init(item, this); +} + +void GLCanvas3D::highlight_gizmo(const std::string& gizmo_name) +{ + GLGizmosManager::EType gizmo = m_gizmos.get_gizmo_from_name(gizmo_name); + if(gizmo == GLGizmosManager::EType::Undefined) + return; + m_gizmo_highlighter.init(&m_gizmos, gizmo, this); +} + const Print* GLCanvas3D::fff_print() const { return (m_process == nullptr) ? nullptr : m_process->fff_print(); @@ -6537,10 +6598,119 @@ void GLCanvas3D::WipeTowerInfo::apply_wipe_tower() const wxGetApp().get_tab(Preset::TYPE_PRINT)->load_config(cfg); } - -void GLCanvas3D::RenderTimer::Notify() +void GLCanvas3D::RenderTimer::Notify() { wxPostEvent((wxEvtHandler*)GetOwner(), RenderTimerEvent( EVT_GLCANVAS_RENDER_TIMER, *this)); } + +void GLCanvas3D::ToolbarHighlighterTimer::Notify() +{ + wxPostEvent((wxEvtHandler*)GetOwner(), ToolbarHighlighterTimerEvent(EVT_GLCANVAS_TOOLBAR_HIGHLIGHTER_TIMER, *this)); +} + +void GLCanvas3D::GizmoHighlighterTimer::Notify() +{ + wxPostEvent((wxEvtHandler*)GetOwner(), GizmoHighlighterTimerEvent(EVT_GLCANVAS_GIZMO_HIGHLIGHTER_TIMER, *this)); +} + +void GLCanvas3D::ToolbarHighlighter::set_timer_owner(wxEvtHandler* owner, int timerid/* = wxID_ANY*/) +{ + m_timer.SetOwner(owner, timerid); +} + +void GLCanvas3D::ToolbarHighlighter::init(GLToolbarItem* toolbar_item, GLCanvas3D* canvas) +{ + if (m_timer.IsRunning()) + invalidate(); + if (!toolbar_item || !canvas) + return; + + m_timer.Start(300, false); + + m_toolbar_item = toolbar_item; + m_canvas = canvas; +} + +void GLCanvas3D::ToolbarHighlighter::invalidate() +{ + m_timer.Stop(); + + if (m_toolbar_item) { + m_toolbar_item->set_highlight(GLToolbarItem::EHighlightState::NotHighlighted); + } + m_toolbar_item = nullptr; + m_blink_counter = 0; + m_render_arrow = false; +} + +void GLCanvas3D::ToolbarHighlighter::blink() +{ + if (m_toolbar_item) { + char state = m_toolbar_item->get_highlight(); + if (state != (char)GLToolbarItem::EHighlightState::HighlightedShown) + m_toolbar_item->set_highlight(GLToolbarItem::EHighlightState::HighlightedShown); + else + m_toolbar_item->set_highlight(GLToolbarItem::EHighlightState::HighlightedHidden); + + m_render_arrow = !m_render_arrow; + m_canvas->set_as_dirty(); + } + else + invalidate(); + + if ((++m_blink_counter) >= 11) + invalidate(); +} + +void GLCanvas3D::GizmoHighlighter::set_timer_owner(wxEvtHandler* owner, int timerid/* = wxID_ANY*/) +{ + m_timer.SetOwner(owner, timerid); +} + +void GLCanvas3D::GizmoHighlighter::init(GLGizmosManager* manager, GLGizmosManager::EType gizmo, GLCanvas3D* canvas) +{ + if (m_timer.IsRunning()) + invalidate(); + if (!gizmo || !canvas) + return; + + m_timer.Start(300, false); + + m_gizmo_manager = manager; + m_gizmo_type = gizmo; + m_canvas = canvas; +} + +void GLCanvas3D::GizmoHighlighter::invalidate() +{ + m_timer.Stop(); + + if (m_gizmo_manager) { + m_gizmo_manager->set_highlight(GLGizmosManager::EType::Undefined, false); + } + m_gizmo_manager = nullptr; + m_gizmo_type = GLGizmosManager::EType::Undefined; + m_blink_counter = 0; + m_render_arrow = false; +} + +void GLCanvas3D::GizmoHighlighter::blink() +{ + if (m_gizmo_manager) { + if (m_blink_counter % 2 == 0) + m_gizmo_manager->set_highlight(m_gizmo_type, true); + else + m_gizmo_manager->set_highlight(m_gizmo_type, false); + + m_render_arrow = !m_render_arrow; + m_canvas->set_as_dirty(); + } + else + invalidate(); + + if ((++m_blink_counter) >= 11) + invalidate(); +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index e934f9926..d9cd55e35 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -93,6 +93,43 @@ private: wxTimer* m_timer; }; +class ToolbarHighlighterTimerEvent : public wxEvent +{ +public: + ToolbarHighlighterTimerEvent(wxEventType type, wxTimer& timer) + : wxEvent(timer.GetId(), type), + m_timer(&timer) + { + SetEventObject(timer.GetOwner()); + } + int GetInterval() const { return m_timer->GetInterval(); } + wxTimer& GetTimer() const { return *m_timer; } + + virtual wxEvent* Clone() const { return new ToolbarHighlighterTimerEvent(*this); } + virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_TIMER; } +private: + wxTimer* m_timer; +}; + + +class GizmoHighlighterTimerEvent : public wxEvent +{ +public: + GizmoHighlighterTimerEvent(wxEventType type, wxTimer& timer) + : wxEvent(timer.GetId(), type), + m_timer(&timer) + { + SetEventObject(timer.GetOwner()); + } + int GetInterval() const { return m_timer->GetInterval(); } + wxTimer& GetTimer() const { return *m_timer; } + + virtual wxEvent* Clone() const { return new GizmoHighlighterTimerEvent(*this); } + virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_TIMER; } +private: + wxTimer* m_timer; +}; + wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); @@ -137,6 +174,8 @@ wxDECLARE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event); wxDECLARE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent); wxDECLARE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_RENDER_TIMER, wxTimerEvent/*RenderTimerEvent*/); +wxDECLARE_EVENT(EVT_GLCANVAS_TOOLBAR_HIGHLIGHTER_TIMER, wxTimerEvent); +wxDECLARE_EVENT(EVT_GLCANVAS_GIZMO_HIGHLIGHTER_TIMER, wxTimerEvent); class GLCanvas3D { @@ -305,25 +344,27 @@ class GLCanvas3D ObjectClashed }; -#if ENABLE_RENDER_STATISTICS class RenderStats { - std::queue> m_frames; - int64_t m_curr_total{ 0 }; - + private: + std::chrono::time_point m_measuring_start; + int m_fps_out = -1; + int m_fps_running = 0; public: - void add_frame(int64_t frame) { - int64_t now = GLCanvas3D::timestamp_now(); - if (!m_frames.empty() && now - m_frames.front().first > 1000) { - m_curr_total -= m_frames.front().second; - m_frames.pop(); + void increment_fps_counter() { ++m_fps_running; } + int get_fps() { return m_fps_out; } + int get_fps_and_reset_if_needed() { + auto cur_time = std::chrono::high_resolution_clock::now(); + int elapsed_ms = std::chrono::duration_cast(cur_time-m_measuring_start).count(); + if (elapsed_ms > 1000 || m_fps_out == -1) { + m_measuring_start = cur_time; + m_fps_out = int (1000. * m_fps_running / elapsed_ms); + m_fps_running = 0; } - m_curr_total += frame; - m_frames.push({ now, frame }); + return m_fps_out; } - int64_t get_average() const { return m_frames.empty() ? 0 : m_curr_total / m_frames.size(); } + }; -#endif // ENABLE_RENDER_STATISTICS class Labels { @@ -376,6 +417,16 @@ class GLCanvas3D virtual void Notify() override; }; + class ToolbarHighlighterTimer : public wxTimer { + private: + virtual void Notify() override; + }; + + class GizmoHighlighterTimer : public wxTimer { + private: + virtual void Notify() override; + }; + public: enum ECursorType : unsigned char { @@ -427,9 +478,7 @@ private: Model* m_model; BackgroundSlicingProcess *m_process; -#if ENABLE_SCROLLABLE_LEGEND std::array m_old_size{ 0, 0 }; -#endif // ENABLE_SCROLLABLE_LEGEND // Screen is only refreshed from the OnIdle handler if it is dirty. bool m_dirty; @@ -457,9 +506,7 @@ private: bool m_show_picking_texture; #endif // ENABLE_RENDER_PICKING_PASS -#if ENABLE_RENDER_STATISTICS RenderStats m_render_stats; -#endif // ENABLE_RENDER_STATISTICS int m_imgui_undo_redo_hovered_pos{ -1 }; int m_mouse_wheel{ 0 }; @@ -519,6 +566,38 @@ private: SequentialPrintClearance m_sequential_print_clearance; bool m_sequential_print_clearance_first_displacement{ true }; + struct ToolbarHighlighter + { + void set_timer_owner(wxEvtHandler* owner, int timerid = wxID_ANY); + void init(GLToolbarItem* toolbar_item, GLCanvas3D* canvas); + void blink(); + void invalidate(); + bool m_render_arrow{ false }; + GLToolbarItem* m_toolbar_item{ nullptr }; + private: + GLCanvas3D* m_canvas{ nullptr }; + int m_blink_counter{ 0 }; + ToolbarHighlighterTimer m_timer; + } + m_toolbar_highlighter; + + struct GizmoHighlighter + { + void set_timer_owner(wxEvtHandler* owner, int timerid = wxID_ANY); + void init(GLGizmosManager* manager, GLGizmosManager::EType gizmo, GLCanvas3D* canvas); + void blink(); + void invalidate(); + bool m_render_arrow{ false }; + GLGizmosManager::EType m_gizmo_type; + private: + GLGizmosManager* m_gizmo_manager{ nullptr }; + GLCanvas3D* m_canvas{ nullptr }; + int m_blink_counter{ 0 }; + GizmoHighlighterTimer m_timer; + + } + m_gizmo_highlighter; + public: explicit GLCanvas3D(wxGLCanvas* canvas); ~GLCanvas3D(); @@ -544,10 +623,8 @@ public: 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); } -#if ENABLE_GCODE_WINDOW void start_mapping_gcode_window(); void stop_mapping_gcode_window(); -#endif // ENABLE_GCODE_WINDOW 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); @@ -625,7 +702,7 @@ public: void select_all(); void deselect_all(); void delete_selected(); - void ensure_on_bed(unsigned int object_idx); + void ensure_on_bed(unsigned int object_idx, bool allow_negative_z); 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(); } @@ -638,6 +715,10 @@ public: void set_toolpath_view_type(GCodeViewer::EViewType type); void set_volumes_z_range(const std::array& range); void set_toolpaths_z_range(const std::array& range); +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + std::vector& get_custom_gcode_per_print_z() { return m_gcode_viewer.get_custom_gcode_per_print_z(); } + size_t get_gcode_extruders_count() { return m_gcode_viewer.get_extruders_count(); } +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER std::vector load_object(const ModelObject& model_object, int obj_idx, std::vector instance_idxs); std::vector load_object(const Model& model, int obj_idx); @@ -744,6 +825,9 @@ public: void use_slope(bool use) { m_slope.use(use); } void set_slope_normal_angle(float angle_in_deg) { m_slope.set_normal_angle(angle_in_deg); } + void highlight_toolbar_item(const std::string& item_name); + void highlight_gizmo(const std::string& gizmo_name); + ArrangeSettings get_arrange_settings() const { const ArrangeSettings &settings = get_arrange_settings(this); ArrangeSettings ret = settings; @@ -789,9 +873,9 @@ public: const Print* fff_print() const; const SLAPrint* sla_print() const; -#if ENABLE_SCROLLABLE_LEGEND void reset_old_size() { m_old_size = { 0, 0 }; } -#endif // ENABLE_SCROLLABLE_LEGEND + + bool is_object_sinking(int object_idx) const; private: bool _is_shown_on_screen() const; @@ -816,6 +900,7 @@ private: void _rectangular_selection_picking_pass(); void _render_background() const; void _render_bed(bool bottom, bool show_axes); + void _render_bed_for_picking(bool bottom); #if ENABLE_DELAYED_TRANSPARENT_VOLUMES_RENDERING void _render_objects(GLVolumeCollection::ERenderType type); #else diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 6cc09c7ba..6d54ec20e 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -7,6 +7,9 @@ #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/Model.hpp" +#if ENABLE_SINKING_CONTOURS +#include "libslic3r/Polygon.hpp" +#endif // ENABLE_SINKING_CONTOURS #include #include @@ -87,6 +90,35 @@ void GLModel::init_from(const TriangleMesh& mesh) m_render_data.emplace_back(data); } +#if ENABLE_SINKING_CONTOURS +void GLModel::init_from(const Polygons& polygons, float z) +{ + auto append_polygon = [](const Polygon& polygon, float z, GUI::GLModel::InitializationData& data) { + if (!polygon.empty()) { + GUI::GLModel::InitializationData::Entity entity; + entity.type = GUI::GLModel::PrimitiveType::LineLoop; + // contour + entity.positions.reserve(polygon.size() + 1); + entity.indices.reserve(polygon.size() + 1); + unsigned int id = 0; + for (const Point& p : polygon) { + Vec3f position = unscale(p.x(), p.y(), 0.0).cast(); + position.z() = z; + entity.positions.emplace_back(position); + entity.indices.emplace_back(id++); + } + data.entities.emplace_back(entity); + } + }; + + InitializationData init_data; + for (const Polygon& polygon : polygons) { + append_polygon(polygon, z, init_data); + } + init_from(init_data); +} +#endif // ENABLE_SINKING_CONTOURS + bool GLModel::init_from_file(const std::string& filename) { if (!boost::filesystem::exists(filename)) diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index ee3d2f8f9..cab2fe220 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -9,6 +9,10 @@ namespace Slic3r { class TriangleMesh; +#if ENABLE_SINKING_CONTOURS +class Polygon; +using Polygons = std::vector; +#endif // ENABLE_SINKING_CONTOURS namespace GUI { @@ -58,6 +62,9 @@ namespace GUI { void init_from(const InitializationData& data); void init_from(const TriangleMesh& mesh); +#if ENABLE_SINKING_CONTOURS + void init_from(const Polygons& polygons, float z); +#endif // ENABLE_SINKING_CONTOURS bool init_from_file(const std::string& filename); // if entity_id == -1 set the color of all entities diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index d853ef198..5ee14c526 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -50,10 +50,6 @@ std::pair GLShadersManager::init() ); // used to render variable layers heights in 3d editor valid &= append_shader("variable_layer_height", { "variable_layer_height.vs", "variable_layer_height.fs" }); -#if ENABLE_ALLOW_NEGATIVE_Z - // used to render volumes during picking pass - valid &= append_shader("picking", { "picking.vs", "picking.fs" }); -#endif // ENABLE_ALLOW_NEGATIVE_Z return { valid, error }; } diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp index 178c17d15..0167ba3ce 100644 --- a/src/slic3r/GUI/GLToolbar.cpp +++ b/src/slic3r/GUI/GLToolbar.cpp @@ -61,6 +61,7 @@ GLToolbarItem::GLToolbarItem(GLToolbarItem::EType type, const GLToolbarItem::Dat , m_state(Normal) , m_data(data) , m_last_action_type(Undefined) + , m_highlight_state(NotHighlighted) { } @@ -91,7 +92,8 @@ void GLToolbarItem::render(unsigned int tex_id, float left, float right, float b assert((tex_width != 0) && (tex_height != 0)); GLTexture::Quad_UVs ret; // tiles in the texture are spaced by 1 pixel - float icon_size_px = (float)(tex_width - 1) / (float)Num_States; + float icon_size_px = (float)(tex_width - 1) / ((float)Num_States + (float)Num_Rendered_Highlight_States); + char render_state = (m_highlight_state == NotHighlighted ? m_state : Num_States + m_highlight_state); float inv_tex_width = 1.0f / (float)tex_width; float inv_tex_height = 1.0f / (float)tex_height; // tiles in the texture are spaced by 1 pixel @@ -99,7 +101,7 @@ void GLToolbarItem::render(unsigned int tex_id, float left, float right, float b float v_offset = 1.0f * inv_tex_height; float du = icon_size_px * inv_tex_width; float dv = icon_size_px * inv_tex_height; - float left = u_offset + (float)m_state * du; + float left = u_offset + (float)render_state * du; float right = left + du - u_offset; float top = v_offset + (float)m_data.sprite_id * dv; float bottom = top + dv - v_offset; @@ -183,6 +185,24 @@ bool GLToolbar::init(const BackgroundTexture::Metadata& background_texture) return res; } +bool GLToolbar::init_arrow(const BackgroundTexture::Metadata& arrow_texture) +{ + if (m_arrow_texture.texture.get_id() != 0) + return true; + + std::string path = resources_dir() + "/icons/"; + bool res = false; + + if (!arrow_texture.filename.empty()) + res = m_arrow_texture.texture.load_from_file(path + arrow_texture.filename, false, GLTexture::SingleThreaded, false); +// res = m_arrow_texture.texture.load_from_svg_file(path + arrow_texture.filename, false, true, false, 100); + + if (res) + m_arrow_texture.metadata = arrow_texture; + + return res; +} + GLToolbar::Layout::EType GLToolbar::get_layout_type() const { return m_layout.type; @@ -419,6 +439,8 @@ void GLToolbar::render(const GLCanvas3D& parent) } } + + bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent) { if (!m_enabled) @@ -869,6 +891,21 @@ void GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& } } +GLToolbarItem* GLToolbar::get_item(const std::string& item_name) +{ + if (!m_enabled) + return nullptr; + + for (GLToolbarItem* item : m_items) + { + if (item->get_name() == item_name) + { + return item; + } + } + return nullptr; +} + int GLToolbar::contains_mouse(const Vec2d& mouse_pos, const GLCanvas3D& parent) const { if (!m_enabled) @@ -1105,6 +1142,63 @@ void GLToolbar::render_background(float left, float top, float right, float bott } } +void GLToolbar::render_arrow(const GLCanvas3D& parent, GLToolbarItem* highlighted_item) +{ + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); + float factor = inv_zoom * m_layout.scale; + + float scaled_icons_size = m_layout.icons_size * factor; + float scaled_separator_size = m_layout.separator_size * factor; + float scaled_gap_size = m_layout.gap_size * factor; + float border = m_layout.border * factor; + + float separator_stride = scaled_separator_size + scaled_gap_size; + float icon_stride = scaled_icons_size + scaled_gap_size; + + float left = m_layout.left; + float top = m_layout.top - icon_stride; + + for (const GLToolbarItem* item : m_items) { + if (!item->is_visible()) + continue; + + if (item->is_separator()) + left += separator_stride; + else { + if (item->get_name() == highlighted_item->get_name()) + break; + left += icon_stride; + } + } + + left += border; + top -= separator_stride; + float right = left + scaled_icons_size; + + unsigned int tex_id = m_arrow_texture.texture.get_id(); + float tex_width = (float)m_icons_texture.get_width(); + float tex_height = (float)m_icons_texture.get_height(); + + if ((tex_id != 0) && (tex_width > 0) && (tex_height > 0)) { + float inv_tex_width = (tex_width != 0.0f) ? 1.0f / tex_width : 0.0f; + float inv_tex_height = (tex_height != 0.0f) ? 1.0f / tex_height : 0.0f; + + float internal_left = left + border - scaled_icons_size / 2; // add half scaled_icons_size for huge arrow + float internal_right = right - border + scaled_icons_size / 2; + float internal_top = top - border; + // bottom is not moving and should be calculated from arrow texture sides ratio + float arrow_sides_ratio = (float)m_arrow_texture.texture.get_height() / (float)m_arrow_texture.texture.get_width(); + float internal_bottom = internal_top - (internal_right - internal_left) * arrow_sides_ratio; + + float internal_left_uv = (float)m_arrow_texture.metadata.left * inv_tex_width; + float internal_right_uv = 1.0f - (float)m_arrow_texture.metadata.right * inv_tex_width; + float internal_top_uv = 1.0f - (float)m_arrow_texture.metadata.top * inv_tex_height; + float internal_bottom_uv = (float)m_arrow_texture.metadata.bottom * inv_tex_height; + + GLTexture::render_sub_texture(tex_id, internal_left, internal_right, internal_bottom, internal_top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } }); + } +} + void GLToolbar::render_horizontal(const GLCanvas3D& parent) { unsigned int tex_id = m_icons_texture.get_id(); @@ -1217,6 +1311,8 @@ bool GLToolbar::generate_icons_texture() states.push_back({ 0, false }); // Hover states.push_back({ 0, false }); // HoverPressed states.push_back({ 2, false }); // HoverDisabled + states.push_back({ 0, false }); // HighlightedShown + states.push_back({ 2, false }); // HighlightedHidden } else { states.push_back({ 1, false }); // Normal @@ -1225,6 +1321,8 @@ bool GLToolbar::generate_icons_texture() states.push_back({ 0, false }); // Hover states.push_back({ 1, true }); // HoverPressed states.push_back({ 1, false }); // HoverDisabled + states.push_back({ 0, false }); // HighlightedShown + states.push_back({ 1, false }); // HighlightedHidden } unsigned int sprite_size_px = (unsigned int)(m_layout.icons_size * m_layout.scale); diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp index 92df63bfb..5740db3e6 100644 --- a/src/slic3r/GUI/GLToolbar.hpp +++ b/src/slic3r/GUI/GLToolbar.hpp @@ -65,6 +65,14 @@ public: Num_States }; + enum EHighlightState : unsigned char + { + HighlightedShown, + HighlightedHidden, + Num_Rendered_Highlight_States, + NotHighlighted + }; + struct Data { struct Option @@ -104,13 +112,16 @@ private: EState m_state; Data m_data; EActionType m_last_action_type; - + EHighlightState m_highlight_state; public: GLToolbarItem(EType type, const Data& data); EState get_state() const { return m_state; } void set_state(EState state) { m_state = state; } + EHighlightState get_highlight() const { return m_highlight_state; } + void set_highlight(EHighlightState state) { m_highlight_state = state; } + const std::string& get_name() const { return m_data.name; } const std::string& get_icon_filename() const { return m_data.icon_filename; } const std::string& get_tooltip() const { return m_data.tooltip; } @@ -143,7 +154,6 @@ public: bool update_enabled_state(); void render(unsigned int tex_id, float left, float right, float bottom, float top, unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) const; - private: void set_visible(bool visible) { m_data.visible = visible; } @@ -236,6 +246,7 @@ private: GLTexture m_icons_texture; bool m_icons_texture_dirty; BackgroundTexture m_background_texture; + BackgroundTexture m_arrow_texture; Layout m_layout; ItemsList m_items; @@ -262,6 +273,8 @@ public: bool init(const BackgroundTexture::Metadata& background_texture); + bool init_arrow(const BackgroundTexture::Metadata& arrow_texture); + Layout::EType get_layout_type() const; void set_layout_type(Layout::EType type); Layout::EHorizontalOrientation get_horizontal_orientation() const { return m_layout.horizontal_orientation; } @@ -310,9 +323,11 @@ public: bool update_items_state(); void render(const GLCanvas3D& parent); + void render_arrow(const GLCanvas3D& parent, GLToolbarItem* highlighted_item); bool on_mouse(wxMouseEvent& evt, GLCanvas3D& parent); - + // get item pointer for highlighter timer + GLToolbarItem* get_item(const std::string& item_name); private: void calc_layout(); float get_width_horizontal() const; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 4a4711972..4196dfdac 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -661,6 +661,10 @@ void GUI_App::post_init() this->mainframe->load_config(this->init_params->extra_config); } + // show "Did you know" notification + if (app_config->get("show_hints") == "1") + plater_->get_notification_manager()->push_hint_notification(); + // The extra CallAfter() is needed because of Mac, where this is the only way // to popup a modal dialog on start without screwing combo boxes. // This is ugly but I honestly found no better way to do it. @@ -950,12 +954,10 @@ bool GUI_App::on_init_inner() else load_current_presets(); -#if ENABLE_PROJECT_DIRTY_STATE if (plater_ != nullptr) { plater_->reset_project_dirty_initial_presets(); plater_->update_project_dirty_from_presets(); } -#endif // ENABLE_PROJECT_DIRTY_STATE mainframe->Show(true); @@ -1780,7 +1782,7 @@ void GUI_App::update_mode() for (auto tab : tabs_list) tab->update_mode(); - plater()->update_object_menu(); + plater()->update_menus(); plater()->canvas3D()->update_gizmos_on_off_state(); } @@ -1848,11 +1850,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu) #endif case ConfigMenuTakeSnapshot: // Take a configuration snapshot. -#if ENABLE_PROJECT_DIRTY_STATE if (check_and_save_current_preset_changes()) { -#else - if (check_unsaved_changes()) { -#endif // ENABLE_PROJECT_DIRTY_STATE wxTextEntryDialog dlg(nullptr, _L("Taking configuration snapshot"), _L("Snapshot name")); UpdateDlgDarkUI(&dlg); @@ -1868,11 +1866,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu) } break; case ConfigMenuSnapshots: -#if ENABLE_PROJECT_DIRTY_STATE if (check_and_save_current_preset_changes()) { -#else - if (check_unsaved_changes()) { -#endif // ENABLE_PROJECT_DIRTY_STATE std::string on_snapshot; if (Config::SnapshotDB::singleton().is_on_snapshot(*app_config)) on_snapshot = app_config->get("on_snapshot"); @@ -1908,11 +1902,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu) PreferencesDialog dlg(mainframe); dlg.ShowModal(); app_layout_changed = dlg.settings_layout_changed(); -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER - if (dlg.seq_top_layer_only_changed() || dlg.seq_seq_top_gcode_indices_changed()) -#else if (dlg.seq_top_layer_only_changed()) -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER this->plater_->refresh_print(); if (dlg.recreate_GUI()) { @@ -1985,7 +1975,43 @@ void GUI_App::add_config_menu(wxMenuBar *menu) menu->Append(local_menu, _L("&Configuration")); } -#if ENABLE_PROJECT_DIRTY_STATE +void GUI_App::open_preferences(size_t open_on_tab) +{ + bool app_layout_changed = false; + { + // the dialog needs to be destroyed before the call to recreate_GUI() + // or sometimes the application crashes into wxDialogBase() destructor + // so we put it into an inner scope + PreferencesDialog dlg(mainframe, open_on_tab); + dlg.ShowModal(); + app_layout_changed = dlg.settings_layout_changed(); +#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER + if (dlg.seq_top_layer_only_changed() || dlg.seq_seq_top_gcode_indices_changed()) +#else + if (dlg.seq_top_layer_only_changed()) +#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER + this->plater_->refresh_print(); +#ifdef _WIN32 + if (is_editor()) { + if (app_config->get("associate_3mf") == "1") + associate_3mf_files(); + if (app_config->get("associate_stl") == "1") + associate_stl_files(); + } + else { + if (app_config->get("associate_gcode") == "1") + associate_gcode_files(); + } +#endif // _WIN32 + } + if (app_layout_changed) { + // hide full main_sizer for mainFrame + mainframe->GetSizer()->Show(false); + mainframe->update_layout(); + mainframe->select_tab(size_t(0)); + } +} + bool GUI_App::has_unsaved_preset_changes() const { PrinterTechnology printer_technology = preset_bundle->printers.get_edited_preset().printer_technology(); @@ -2027,28 +2053,12 @@ std::vector> GUI_App::get_selected_presets( } return ret; } -#endif // ENABLE_PROJECT_DIRTY_STATE // This is called when closing the application, when loading a config file or when starting the config wizard // to notify the user whether he is aware that some preset changes will be lost. -#if ENABLE_PROJECT_DIRTY_STATE bool GUI_App::check_and_save_current_preset_changes(const wxString& header) { if (this->plater()->model().objects.empty() && has_current_preset_changes()) { -#else -bool GUI_App::check_unsaved_changes(const wxString &header) -{ - PrinterTechnology printer_technology = preset_bundle->printers.get_edited_preset().printer_technology(); - - bool has_unsaved_changes = false; - for (Tab* tab : tabs_list) - if (tab->supports_printer_technology(printer_technology) && tab->current_preset_is_dirty()) { - has_unsaved_changes = true; - break; - } - - if (has_unsaved_changes) { -#endif // ENABLE_PROJECT_DIRTY_STATE UnsavedChangesDialog dlg(header); if (wxGetApp().app_config->get("default_action_on_close_application") == "none" && dlg.ShowModal() == wxID_CANCEL) return false; diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 92bfd67c4..fc62d4c34 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -238,15 +238,11 @@ public: void update_mode(); void add_config_menu(wxMenuBar *menu); -#if ENABLE_PROJECT_DIRTY_STATE bool has_unsaved_preset_changes() const; bool has_current_preset_changes() const; void update_saved_preset_from_current_preset(); std::vector> get_selected_presets() const; bool check_and_save_current_preset_changes(const wxString& header = wxString()); -#else - bool check_unsaved_changes(const wxString& header = wxString()); -#endif // ENABLE_PROJECT_DIRTY_STATE bool check_print_host_queue(); bool checked_tab(Tab* tab); void load_current_presets(bool check_printer_presets = true); @@ -256,6 +252,8 @@ public: wxString current_language_code_safe() const; bool is_localized() const { return m_wxLocale->GetLocale() != "English"; } + void open_preferences(size_t open_on_tab = 0); + virtual bool OnExceptionInMainLoop() override; #ifdef __APPLE__ diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index d494f84f0..014fc4a44 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -964,6 +964,12 @@ void MenuFactory::init(wxWindow* parent) create_instance_menu(); } +void MenuFactory::update() +{ + update_default_menu(); + update_object_menu(); +} + wxMenu* MenuFactory::default_menu() { return &m_default_menu; @@ -1088,6 +1094,14 @@ void MenuFactory::update_object_menu() append_menu_items_add_volume(&m_object_menu); } +void MenuFactory::update_default_menu() +{ + const auto menu_item_id = m_default_menu.FindItem(_("Add Shape")); + if (menu_item_id != wxNOT_FOUND) + m_default_menu.Destroy(menu_item_id); + create_default_menu(); +} + void MenuFactory::msw_rescale() { for (MenuWithSeparators* menu : { &m_object_menu, &m_sla_object_menu, &m_part_menu, &m_default_menu }) diff --git a/src/slic3r/GUI/GUI_Factories.hpp b/src/slic3r/GUI/GUI_Factories.hpp index e0d091ed5..0c478a97b 100644 --- a/src/slic3r/GUI/GUI_Factories.hpp +++ b/src/slic3r/GUI/GUI_Factories.hpp @@ -40,7 +40,9 @@ public: ~MenuFactory() = default; void init(wxWindow* parent); + void update(); void update_object_menu(); + void update_default_menu(); void msw_rescale(); void sys_color_changed(); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 45d7115e9..18711a664 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -9,9 +9,7 @@ #include "Plater.hpp" #include "BitmapComboBox.hpp" #include "GalleryDialog.hpp" -#if ENABLE_PROJECT_DIRTY_STATE #include "MainFrame.hpp" -#endif // ENABLE_PROJECT_DIRTY_STATE #include "OptionsGroup.hpp" #include "Tab.hpp" @@ -20,6 +18,7 @@ #include "GLCanvas3D.hpp" #include "Selection.hpp" #include "format.hpp" +#include "NotificationManager.hpp" #include #include @@ -1672,9 +1671,7 @@ void ObjectList::load_shape_object(const std::string& type_name) BoundingBoxf3 bb; TriangleMesh mesh = create_mesh(type_name, bb); load_mesh_object(mesh, _L("Shape") + "-" + _(type_name)); -#if ENABLE_PROJECT_DIRTY_STATE wxGetApp().mainframe->update_title(); -#endif // ENABLE_PROJECT_DIRTY_STATE } void ObjectList::load_shape_object_from_gallery() @@ -1705,13 +1702,9 @@ void ObjectList::load_shape_object_from_gallery(const wxArrayString& input_files snapshot_label += ", " + wxString::FromUTF8(paths[i].filename().string().c_str()); take_snapshot(snapshot_label); -#if ENABLE_PROJECT_DIRTY_STATE std::vector res = wxGetApp().plater()->load_files(paths, true, false); if (!res.empty()) wxGetApp().mainframe->update_title(); -#else - load_files(paths, true, false); -#endif // ENABLE_PROJECT_DIRTY_STATE } void ObjectList::load_mesh_object(const TriangleMesh &mesh, const wxString &name, bool center) @@ -2386,15 +2379,28 @@ void ObjectList::part_selection_changed() if (type == itInfo) { InfoItemType info_type = m_objects_model->GetInfoItemType(item); - if (info_type != InfoItemType::VariableLayerHeight) { + switch (info_type) + { + case InfoItemType::VariableLayerHeight: + { + wxGetApp().plater()->toggle_layers_editing(true); + break; + } + case InfoItemType::CustomSupports: + case InfoItemType::CustomSeam: + case InfoItemType::MmuSegmentation: + { GLGizmosManager::EType gizmo_type = info_type == InfoItemType::CustomSupports ? GLGizmosManager::EType::FdmSupports : - info_type == InfoItemType::CustomSeam ? GLGizmosManager::EType::Seam : - GLGizmosManager::EType::MmuSegmentation; + info_type == InfoItemType::CustomSeam ? GLGizmosManager::EType::Seam : + GLGizmosManager::EType::MmuSegmentation; GLGizmosManager& gizmos_mgr = wxGetApp().plater()->canvas3D()->get_gizmos_manager(); if (gizmos_mgr.get_current_type() != gizmo_type) gizmos_mgr.open_gizmo(gizmo_type); - } else - wxGetApp().plater()->toggle_layers_editing(true); + break; + } + case InfoItemType::Sinking: { break; } + default: { break; } + } } } else { @@ -2520,6 +2526,7 @@ void ObjectList::update_info_items(size_t obj_idx) for (InfoItemType type : {InfoItemType::CustomSupports, InfoItemType::CustomSeam, InfoItemType::MmuSegmentation, + InfoItemType::Sinking, InfoItemType::VariableLayerHeight}) { wxDataViewItem item = m_objects_model->GetInfoItemByType(item_obj, type); bool shows = item.IsOk(); @@ -2542,12 +2549,20 @@ void ObjectList::update_info_items(size_t obj_idx) should_show = printer_technology() == ptFFF && ! model_object->layer_height_profile.empty(); break; + case InfoItemType::Sinking: + { + should_show = printer_technology() == ptFFF && + wxGetApp().plater()->canvas3D()->is_object_sinking(obj_idx); + break; + } default: break; } if (! shows && should_show) { m_objects_model->AddInfoChild(item_obj, type); Expand(item_obj); + wxGetApp().notification_manager()->push_updated_item_info_notification(type); + } else if (shows && ! should_show) { Unselect(item); @@ -2685,7 +2700,7 @@ void ObjectList::delete_from_model_and_list(const std::vector& it if (obj->get_mesh_errors_count() == 0) m_objects_model->DeleteWarningIcon(parent); } - wxGetApp().plater()->canvas3D()->ensure_on_bed(item->obj_idx); + wxGetApp().plater()->canvas3D()->ensure_on_bed(item->obj_idx, printer_technology() != ptSLA); } else m_objects_model->Delete(m_objects_model->GetItemByInstanceId(item->obj_idx, item->sub_obj_idx)); @@ -4060,7 +4075,7 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) : m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); - wxGetApp().plater()->canvas3D()->ensure_on_bed(obj_idx); + wxGetApp().plater()->canvas3D()->ensure_on_bed(obj_idx, printer_technology() != ptSLA); } // update scene diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index d55acf054..d35def196 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -30,28 +30,9 @@ const double ObjectManipulation::mm_to_in = 0.0393700787; // volume in world coordinate system. static double get_volume_min_z(const GLVolume& volume) { -#if ENABLE_ALLOW_NEGATIVE_Z return volume.transformed_convex_hull_bounding_box().min.z(); -#else - const Transform3f& world_matrix = volume.world_matrix().cast(); - - // need to get the ModelVolume pointer - const ModelObject* mo = wxGetApp().model().objects[volume.composite_id.object_id]; - const ModelVolume* mv = mo->volumes[volume.composite_id.volume_id]; - const TriangleMesh& hull = mv->get_convex_hull(); - - float min_z = std::numeric_limits::max(); - for (const stl_facet& facet : hull.stl.facet_start) { - for (int i = 0; i < 3; ++i) - min_z = std::min(min_z, Vec3f::UnitZ().dot(world_matrix * facet.vertex[i])); - } - - return min_z; -#endif // ENABLE_ALLOW_NEGATIVE_Z } - - static choice_ctrl* create_word_local_combo(wxWindow *parent) { wxSize size(15 * wxGetApp().em_unit(), -1); @@ -358,7 +339,6 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : change_position_value(1, diff.y()); change_position_value(2, diff.z()); } -#if ENABLE_ALLOW_NEGATIVE_Z else if (selection.is_single_full_instance()) { const ModelObjectPtrs& objects = wxGetApp().model().objects; const int idx = selection.get_object_idx(); @@ -371,7 +351,6 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : } } } -#endif // ENABLE_ALLOW_NEGATIVE_Z }); editors_grid_sizer->Add(m_drop_to_bed_button); @@ -526,6 +505,7 @@ void ObjectManipulation::update_ui_from_settings() #else editor->SetBackgroundColour(m_use_colors ? wxColour(axes_color_back[axis_id]) : wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); #endif /* _WIN32 */ + editor->Refresh(); if (++axis_id == 3) axis_id = 0; } @@ -702,10 +682,7 @@ void ObjectManipulation::update_reset_buttons_visibility() if (selection.is_single_full_instance()) { rotation = volume->get_instance_rotation(); scale = volume->get_instance_scaling_factor(); -#if ENABLE_ALLOW_NEGATIVE_Z min_z = wxGetApp().model().objects[volume->composite_id.object_id]->bounding_box().min.z(); -#endif // ENABLE_ALLOW_NEGATIVE_Z - } else { rotation = volume->get_volume_rotation(); @@ -714,11 +691,7 @@ void ObjectManipulation::update_reset_buttons_visibility() } show_rotation = !rotation.isApprox(Vec3d::Zero()); show_scale = !scale.isApprox(Vec3d::Ones()); -#if ENABLE_ALLOW_NEGATIVE_Z show_drop_to_bed = std::abs(min_z) > SINKING_Z_THRESHOLD; -#else - show_drop_to_bed = (std::abs(min_z) > EPSILON); -#endif // ENABLE_ALLOW_NEGATIVE_Z } wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed] { @@ -1122,6 +1095,8 @@ void ManipulationEditor::sys_color_changed(ObjectManipulation* parent) { if (!parent->use_colors()) wxGetApp().UpdateDarkUI(this); + else + SetForegroundColour(*wxBLACK); } double ManipulationEditor::get_value() diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 336ff8f51..d17a277d8 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -264,9 +264,7 @@ bool Preview::init(wxWindow* parent, Model* model) get_option_type_string(OptionType::Wipe) + "|0|" + get_option_type_string(OptionType::Retractions) + "|0|" + get_option_type_string(OptionType::Unretractions) + "|0|" + -#if ENABLE_SEAMS_VISUALIZATION get_option_type_string(OptionType::Seams) + "|0|" + -#endif // ENABLE_SEAMS_VISUALIZATION get_option_type_string(OptionType::ToolChanges) + "|0|" + get_option_type_string(OptionType::ColorChanges) + "|0|" + get_option_type_string(OptionType::PausePrints) + "|0|" + @@ -639,11 +637,25 @@ void Preview::update_layers_slider(const std::vector& layers_z, bool kee update_layers_slider_mode(); Plater* plater = wxGetApp().plater(); +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + CustomGCode::Info ticks_info_from_model; + if (wxGetApp().is_editor()) + ticks_info_from_model = plater->model().custom_gcode_per_print_z; + else { + ticks_info_from_model.mode = CustomGCode::Mode::SingleExtruder; + ticks_info_from_model.gcodes = m_canvas->get_custom_gcode_per_print_z(); + } +#else CustomGCode::Info& ticks_info_from_model = plater->model().custom_gcode_per_print_z; +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER check_layers_slider_values(ticks_info_from_model.gcodes, layers_z); //first of all update extruder colors to avoid crash, when we are switching printer preset from MM to SM +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + m_layers_slider->SetExtruderColors(plater->get_extruder_colors_from_plater_config(wxGetApp().is_editor() ? nullptr : m_gcode_result)); +#else m_layers_slider->SetExtruderColors(plater->get_extruder_colors_from_plater_config()); +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER m_layers_slider->SetSliderValues(layers_z); assert(m_layers_slider->GetMinValue() == 0); @@ -701,8 +713,15 @@ void Preview::update_layers_slider(const std::vector& layers_z, bool kee int i; for (i = 1; i < int(0.3 * num_layers); ++ i) { double cur_area = area(object->get_layer(i)->lslices); - if (cur_area != bottom_area && fabs(cur_area - bottom_area) > scale_(scale_(1))) + if (cur_area != bottom_area && fabs(cur_area - bottom_area) > scale_(scale_(1))) { + // but due to the elephant foot compensation, the first layer may be slightly smaller than the others + if (i == 1 && fabs(cur_area - bottom_area) / bottom_area < 0.1) { + // So, let process this case and use second layer as a bottom + bottom_area = cur_area; + continue; + } break; + } } if (i < int(0.3 * num_layers)) continue; @@ -834,25 +853,17 @@ void Preview::update_moves_slider() return; std::vector values(view.endpoints.last - view.endpoints.first + 1); -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER std::vector alternate_values(view.endpoints.last - view.endpoints.first + 1); -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER unsigned int count = 0; for (unsigned int i = view.endpoints.first; i <= view.endpoints.last; ++i) { -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER values[count] = static_cast(i + 1); if (view.gcode_ids[i] > 0) alternate_values[count] = static_cast(view.gcode_ids[i]); ++count; -#else - values[count++] = static_cast(i + 1); -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER } m_moves_slider->SetSliderValues(values); -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER m_moves_slider->SetSliderAlternateValues(alternate_values); -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER m_moves_slider->SetMaxValue(view.endpoints.last - view.endpoints.first); m_moves_slider->SetSelectionSpan(view.current.first - view.endpoints.first, view.current.last - view.endpoints.first); } @@ -906,6 +917,7 @@ void Preview::load_print_as_fff(bool keep_z_range) GCodeViewer::EViewType gcode_view_type = m_canvas->get_gcode_view_preview_type(); bool gcode_preview_data_valid = !m_gcode_result->moves.empty(); + // Collect colors per extruder. std::vector colors; std::vector color_print_values = {}; @@ -914,7 +926,14 @@ void Preview::load_print_as_fff(bool keep_z_range) colors = wxGetApp().plater()->get_colors_for_color_print(m_gcode_result); if (!gcode_preview_data_valid) { +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + if (wxGetApp().is_editor()) + color_print_values = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes; + else + color_print_values = m_canvas->get_custom_gcode_per_print_z(); +#else color_print_values = wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes; +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER colors.push_back("#808080"); // gray color for pause print or custom G-code } } @@ -923,9 +942,9 @@ void Preview::load_print_as_fff(bool keep_z_range) color_print_values.clear(); } - if (IsShown()) { - std::vector zs; + std::vector zs; + if (IsShown()) { m_canvas->set_selected_extruder(0); if (gcode_preview_data_valid) { // Load the real G-code preview. @@ -936,7 +955,12 @@ void Preview::load_print_as_fff(bool keep_z_range) Refresh(); zs = m_canvas->get_gcode_layers_zs(); m_loaded = true; - } else { + } +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + else if (wxGetApp().is_editor()) { +#else + else { +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER // Load the initial preview based on slices, not the final G-code. m_canvas->load_preview(colors, color_print_values); m_left_sizer->Hide(m_bottom_toolbar_panel); @@ -944,6 +968,33 @@ void Preview::load_print_as_fff(bool keep_z_range) Refresh(); zs = m_canvas->get_volumes_print_zs(true); } + +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + if (!zs.empty() && !m_keep_current_preview_type) { + unsigned int number_extruders = wxGetApp().is_editor() ? + (unsigned int)print->extruders().size() : + m_canvas->get_gcode_extruders_count(); + std::vector gcodes = wxGetApp().is_editor() ? + wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes : + m_canvas->get_custom_gcode_per_print_z(); + const wxString choice = !gcodes.empty() ? + _L("Color Print") : + (number_extruders > 1) ? _L("Tool") : _L("Feature type"); + + int type = m_choice_view_type->FindString(choice); + if (m_choice_view_type->GetSelection() != type) { + if (0 <= type && type < static_cast(GCodeViewer::EViewType::Count)) { + m_choice_view_type->SetSelection(type); + m_canvas->set_gcode_view_preview_type(static_cast(type)); + if (wxGetApp().is_gcode_viewer()) { + m_keep_current_preview_type = true; + refresh_print(); + } + } + } + } +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + if (zs.empty()) { // all layers filtered out hide_layers_slider(); @@ -952,9 +1003,9 @@ void Preview::load_print_as_fff(bool keep_z_range) update_layers_slider(zs, keep_z_range); } - unsigned int number_extruders = (unsigned int)print->extruders().size(); - +#if !ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER if (!m_keep_current_preview_type) { + unsigned int number_extruders = (unsigned int)print->extruders().size(); const wxString choice = !wxGetApp().plater()->model().custom_gcode_per_print_z.gcodes.empty() ? _L("Color Print") : (number_extruders > 1) ? _L("Tool") : _L("Feature type"); @@ -967,6 +1018,7 @@ void Preview::load_print_as_fff(bool keep_z_range) } } } +#endif // !ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER } void Preview::load_print_as_sla() @@ -1041,9 +1093,7 @@ wxString Preview::get_option_type_string(OptionType type) const case OptionType::Wipe: { return _L("Wipe"); } case OptionType::Retractions: { return _L("Retractions"); } case OptionType::Unretractions: { return _L("Deretractions"); } -#if ENABLE_SEAMS_VISUALIZATION case OptionType::Seams: { return _L("Seams"); } -#endif // ENABLE_SEAMS_VISUALIZATION case OptionType::ToolChanges: { return _L("Tool changes"); } case OptionType::ColorChanges: { return _L("Color changes"); } case OptionType::PausePrints: { return _L("Print pauses"); } diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 2165b11c0..f8a41fd92 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -121,9 +121,7 @@ public: Wipe, Retractions, Unretractions, -#if ENABLE_SEAMS_VISUALIZATION Seams, -#endif // ENABLE_SEAMS_VISUALIZATION ToolChanges, ColorChanges, PausePrints, diff --git a/src/slic3r/GUI/GalleryDialog.cpp b/src/slic3r/GUI/GalleryDialog.cpp index 50c828b0f..f306dff98 100644 --- a/src/slic3r/GUI/GalleryDialog.cpp +++ b/src/slic3r/GUI/GalleryDialog.cpp @@ -219,9 +219,7 @@ static void add_default_image(wxImageList* img_list, bool is_system) static fs::path get_dir(bool sys_dir) { - if (sys_dir) - return fs::absolute(fs::path(sys_shapes_dir())).make_preferred(); - return fs::absolute(fs::path(data_dir()) / "shapes").make_preferred(); + return fs::absolute(fs::path(sys_dir ? sys_shapes_dir() : custom_shapes_dir())).make_preferred(); } static std::string get_dir_path(bool sys_dir) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index ac83b794b..2fb9c296a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -154,8 +154,8 @@ public: void update(const UpdateData& data); - void render() const { m_tooltip.clear(); on_render(); } - void render_for_picking() const { on_render_for_picking(); } + void render() { m_tooltip.clear(); on_render(); } + void render_for_picking() { on_render_for_picking(); } void render_input_window(float x, float y, float bottom_limit); virtual std::string get_tooltip() const { return ""; } @@ -175,8 +175,8 @@ protected: virtual void on_start_dragging() {} virtual void on_stop_dragging() {} virtual void on_update(const UpdateData& data) {} - virtual void on_render() const = 0; - virtual void on_render_for_picking() const = 0; + virtual void on_render() = 0; + virtual void on_render_for_picking() = 0; virtual void on_render_input_window(float x, float y, float bottom_limit) {} // Returns the picking color for the given id, based on the BASE_ID constant diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 6fc382cbc..707726e08 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -16,7 +16,9 @@ #include "slic3r/GUI/GUI_ObjectManipulation.hpp" #include "libslic3r/AppConfig.hpp" #include "libslic3r/Model.hpp" - +#if ENABLE_SINKING_CONTOURS +#include "libslic3r/TriangleMeshSlicer.hpp" +#endif // ENABLE_SINKING_CONTOURS namespace Slic3r { namespace GUI { @@ -82,14 +84,18 @@ void GLGizmoCut::on_update(const UpdateData& data) set_cut_z(m_start_z + calc_projection(data.mouse_ray)); } -void GLGizmoCut::on_render() const +void GLGizmoCut::on_render() { - BoundingBoxf3 box = bounding_box(); + const BoundingBoxf3 box = bounding_box(); Vec3d plane_center = box.center(); plane_center.z() = m_cut_z; m_max_z = box.max.z(); set_cut_z(m_cut_z); +#if ENABLE_SINKING_CONTOURS + update_contours(); +#endif // ENABLE_SINKING_CONTOURS + const float min_x = box.min.x() - Margin; const float max_x = box.max.x() + Margin; const float min_y = box.min.y() - Margin; @@ -136,9 +142,17 @@ void GLGizmoCut::on_render() const m_grabbers[0].render(m_hover_id == 0, (float)((box.size().x() + box.size().y() + box.size().z()) / 3.0)); shader->stop_using(); + +#if ENABLE_SINKING_CONTOURS + glsafe(::glPushMatrix()); + glsafe(::glTranslated(m_cut_contours.shift.x(), m_cut_contours.shift.y(), m_cut_contours.shift.z())); + glsafe(::glLineWidth(2.0f)); + m_cut_contours.contours.render(); + glsafe(::glPopMatrix()); +#endif // ENABLE_SINKING_CONTOURS } -void GLGizmoCut::on_render_for_picking() const +void GLGizmoCut::on_render_for_picking() { glsafe(::glDisable(GL_DEPTH_TEST)); render_grabbers_for_picking(m_parent.get_selection().get_bounding_box()); @@ -199,7 +213,7 @@ void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit) perform_cut(m_parent.get_selection()); } -void GLGizmoCut::set_cut_z(double cut_z) const +void GLGizmoCut::set_cut_z(double cut_z) { // Clamp the plane to the object's bounding box m_cut_z = std::clamp(cut_z, 0.0, m_max_z); @@ -261,5 +275,47 @@ BoundingBoxf3 GLGizmoCut::bounding_box() const return ret; } +#if ENABLE_SINKING_CONTOURS +void GLGizmoCut::update_contours() +{ + const Selection& selection = m_parent.get_selection(); + const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin()); + const BoundingBoxf3& box = first_glvolume->transformed_convex_hull_bounding_box(); + + const int object_idx = selection.get_object_idx(); + const int instance_idx = selection.get_instance_idx(); + + if (0.0 < m_cut_z && m_cut_z < m_max_z) { + if (m_cut_contours.cut_z != m_cut_z || m_cut_contours.object_idx != object_idx || m_cut_contours.instance_idx != instance_idx) { + m_cut_contours.cut_z = m_cut_z; + + if (m_cut_contours.object_idx != object_idx) { + m_cut_contours.mesh = wxGetApp().plater()->model().objects[object_idx]->raw_mesh(); + m_cut_contours.mesh.repair(); + } + + m_cut_contours.position = box.center(); + m_cut_contours.shift = Vec3d::Zero(); + m_cut_contours.object_idx = object_idx; + m_cut_contours.instance_idx = instance_idx; + m_cut_contours.contours.reset(); + + MeshSlicingParams slicing_params; + slicing_params.trafo = first_glvolume->get_instance_transformation().get_matrix(); + const Polygons polys = slice_mesh(m_cut_contours.mesh.its, m_cut_z, slicing_params); + if (!polys.empty()) { + m_cut_contours.contours.init_from(polys, static_cast(m_cut_z)); + m_cut_contours.contours.set_color(-1, { 1.0f, 1.0f, 1.0f, 1.0f }); + } + } + else if (box.center() != m_cut_contours.position) { + m_cut_contours.shift = box.center() - m_cut_contours.position; + } + } + else + m_cut_contours.contours.reset(); +} +#endif // ENABLE_SINKING_CONTOURS + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index dd80c4d69..abd879350 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -2,7 +2,10 @@ #define slic3r_GLGizmoCut_hpp_ #include "GLGizmoBase.hpp" - +#if ENABLE_SINKING_CONTOURS +#include "slic3r/GUI/GLModel.hpp" +#include "libslic3r/TriangleMesh.hpp" +#endif // ENABLE_SINKING_CONTOURS namespace Slic3r { namespace GUI { @@ -13,8 +16,8 @@ class GLGizmoCut : public GLGizmoBase static const double Margin; static const std::array GrabberColor; - mutable double m_cut_z{ 0.0 }; - mutable double m_max_z{ 0.0 }; + double m_cut_z{ 0.0 }; + double m_max_z{ 0.0 }; double m_start_z{ 0.0 }; Vec3d m_drag_pos; Vec3d m_drag_center; @@ -22,11 +25,26 @@ class GLGizmoCut : public GLGizmoBase bool m_keep_lower{ true }; bool m_rotate_lower{ false }; +#if ENABLE_SINKING_CONTOURS + struct CutContours + { + TriangleMesh mesh; + GLModel contours; + double cut_z{ 0.0 }; + Vec3d position{ Vec3d::Zero() }; + Vec3d shift{ Vec3d::Zero() }; + int object_idx{ -1 }; + int instance_idx{ -1 }; + }; + + CutContours m_cut_contours; +#endif // ENABLE_SINKING_CONTOURS + public: GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); double get_cut_z() const { return m_cut_z; } - void set_cut_z(double cut_z) const; + void set_cut_z(double cut_z); std::string get_tooltip() const override; @@ -39,14 +57,17 @@ protected: virtual bool on_is_activable() const override; virtual void on_start_dragging() override; virtual void on_update(const UpdateData& data) override; - virtual void on_render() const override; - virtual void on_render_for_picking() const override; + virtual void on_render() override; + virtual void on_render_for_picking() override; virtual void on_render_input_window(float x, float y, float bottom_limit) override; private: void perform_cut(const Selection& selection); double calc_projection(const Linef3& mouse_ray) const; BoundingBoxf3 bounding_box() const; +#if ENABLE_SINKING_CONTOURS + void update_contours(); +#endif // ENABLE_SINKING_CONTOURS }; } // namespace GUI diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index d1927a820..68f0f3f99 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -152,6 +152,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l if (m_imgui->button(m_desc["enforce_button"], buttons_width, 0.f)) { select_facets_by_angle(m_angle_threshold_deg, false); m_angle_threshold_deg = 0.f; + m_parent.use_slope(false); } ImGui::SameLine(window_width - buttons_width); if (m_imgui->button(m_desc["cancel"], buttons_width, 0.f)) { @@ -185,7 +186,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l m_imgui->text(m_desc.at("cursor_size")); ImGui::SameLine(cursor_slider_left); ImGui::PushItemWidth(window_width - cursor_slider_left); - ImGui::SliderFloat(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); + m_imgui->slider_float(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(max_tooltip_width); @@ -193,8 +194,6 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } - // Manually inserted values aren't clamped by ImGui. Zero cursor size results in a crash. - m_cursor_radius = std::clamp(m_cursor_radius, CursorRadiusMin, CursorRadiusMax); ImGui::AlignTextToFramePadding(); @@ -251,7 +250,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l ImGui::SameLine(clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left); auto clp_dist = float(m_c->object_clipper()->get_position()); - if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f")) + if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); if (ImGui::IsItemHovered()) { @@ -347,7 +346,8 @@ void GLGizmoFdmSupports::update_from_model_object() const TriangleMesh* mesh = &mv->mesh(); m_triangle_selectors.emplace_back(std::make_unique(*mesh)); - m_triangle_selectors.back()->deserialize(mv->supported_facets.get_data()); + // Reset of TriangleSelector is done inside TriangleSelectorGUI's constructor, so we don't need it to perform it again in deserialize(). + m_triangle_selectors.back()->deserialize(mv->supported_facets.get_data(), false); m_triangle_selectors.back()->request_update_render_data(); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index fc5edff6d..094805abc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -54,7 +54,7 @@ void GLGizmoFlatten::on_start_dragging() } } -void GLGizmoFlatten::on_render() const +void GLGizmoFlatten::on_render() { const Selection& selection = m_parent.get_selection(); @@ -69,7 +69,7 @@ void GLGizmoFlatten::on_render() const glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z())); glsafe(::glMultMatrixd(m.data())); if (this->is_plane_update_necessary()) - const_cast(this)->update_planes(); + update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { if (i == m_hover_id) glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 0.75f)); @@ -86,7 +86,7 @@ void GLGizmoFlatten::on_render() const glsafe(::glDisable(GL_BLEND)); } -void GLGizmoFlatten::on_render_for_picking() const +void GLGizmoFlatten::on_render_for_picking() { const Selection& selection = m_parent.get_selection(); @@ -99,7 +99,7 @@ void GLGizmoFlatten::on_render_for_picking() const glsafe(::glTranslatef(0.f, 0.f, selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z())); glsafe(::glMultMatrixd(m.data())); if (this->is_plane_update_necessary()) - const_cast(this)->update_planes(); + update_planes(); for (int i = 0; i < (int)m_planes.size(); ++i) { glsafe(::glColor4fv(picking_color_component(i).data())); m_planes[i].vbo.render(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp index f6fe06451..ab3c2c7ba 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.hpp @@ -53,8 +53,8 @@ protected: virtual std::string on_get_name() const override; virtual bool on_is_activable() const override; virtual void on_start_dragging() override; - virtual void on_render() const override; - virtual void on_render_for_picking() const override; + virtual void on_render() override; + virtual void on_render_for_picking() override; virtual void on_set_state() override; virtual CommonGizmosDataID on_get_requirements() const override; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 2fa16bc03..46608b4c7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -61,7 +61,7 @@ void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&) -void GLGizmoHollow::on_render() const +void GLGizmoHollow::on_render() { const Selection& selection = m_parent.get_selection(); const CommonGizmosDataObjects::SelectionInfo* sel_info = m_c->selection_info(); @@ -88,12 +88,12 @@ void GLGizmoHollow::on_render() const } -void GLGizmoHollow::on_render_for_picking() const +void GLGizmoHollow::on_render_for_picking() { const Selection& selection = m_parent.get_selection(); -#if ENABLE_RENDER_PICKING_PASS - m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); -#endif +//#if ENABLE_RENDER_PICKING_PASS +// m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z(); +//#endif glsafe(::glEnable(GL_DEPTH_TEST)); render_points(selection, true); @@ -545,7 +545,7 @@ RENDER_AGAIN: m_imgui->text(m_desc.at("offset")); ImGui::SameLine(settings_sliders_left); ImGui::PushItemWidth(window_width - settings_sliders_left); - ImGui::SliderFloat(" ", &offset, offset_min, offset_max, "%.1f mm"); + m_imgui->slider_float(" ", &offset, offset_min, offset_max, "%.1f mm"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(max_tooltip_width); @@ -560,7 +560,7 @@ RENDER_AGAIN: if (current_mode >= quality_mode) { m_imgui->text(m_desc.at("quality")); ImGui::SameLine(settings_sliders_left); - ImGui::SliderFloat(" ", &quality, quality_min, quality_max, "%.1f"); + m_imgui->slider_float(" ", &quality, quality_min, quality_max, "%.1f"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(max_tooltip_width); @@ -576,7 +576,7 @@ RENDER_AGAIN: if (current_mode >= closing_d_mode) { m_imgui->text(m_desc.at("closing_distance")); ImGui::SameLine(settings_sliders_left); - ImGui::SliderFloat(" ", &closing_d, closing_d_min, closing_d_max, "%.1f mm"); + m_imgui->slider_float(" ", &closing_d, closing_d_min, closing_d_max, "%.1f mm"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(max_tooltip_width); @@ -618,15 +618,19 @@ RENDER_AGAIN: ImGui::Separator(); - float diameter_upper_cap = 15.; - if (m_new_hole_radius > diameter_upper_cap) - m_new_hole_radius = diameter_upper_cap; + float diameter_upper_cap = 60.; + if (m_new_hole_radius * 2.f > diameter_upper_cap) + m_new_hole_radius = diameter_upper_cap / 2.f; m_imgui->text(m_desc.at("hole_diameter")); ImGui::SameLine(diameter_slider_left); ImGui::PushItemWidth(window_width - diameter_slider_left); float diam = 2.f * m_new_hole_radius; - ImGui::SliderFloat("", &diam, 1.f, diameter_upper_cap, "%.1f mm"); + m_imgui->slider_float("", &diam, 1.f, 15.f, "%.1f mm", 1.f, false); + // Let's clamp the value (which could have been entered by keyboard) to a larger range + // than the slider. This allows entering off-scale values and still protects against + //complete non-sense. + diam = std::clamp(diam, 0.1f, diameter_upper_cap); m_new_hole_radius = diam / 2.f; bool clicked = ImGui::IsItemClicked(); bool edited = ImGui::IsItemEdited(); @@ -634,7 +638,9 @@ RENDER_AGAIN: m_imgui->text(m_desc["hole_depth"]); ImGui::SameLine(diameter_slider_left); - ImGui::SliderFloat(" ", &m_new_hole_height, 0.f, 10.f, "%.1f mm"); + m_imgui->slider_float(" ", &m_new_hole_height, 0.f, 10.f, "%.1f mm", 1.f, false); + // Same as above: + m_new_hole_height = std::clamp(m_new_hole_height, 0.f, 100.f); clicked |= ImGui::IsItemClicked(); edited |= ImGui::IsItemEdited(); @@ -699,7 +705,7 @@ RENDER_AGAIN: ImGui::SameLine(clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left); float clp_dist = m_c->object_clipper()->get_position(); - if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f")) + if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); // make sure supports are shown/hidden as appropriate diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp index 1bcf1713e..2cf08de2a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.hpp @@ -39,8 +39,8 @@ public: private: bool on_init() override; void on_update(const UpdateData& data) override; - void on_render() const override; - void on_render_for_picking() const override; + void on_render() override; + void on_render_for_picking() override; void render_points(const Selection& selection, bool picking = false) const; void hollow_mesh(bool postpone_error_messages = false); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 9b28eedd1..f6e7708fa 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -368,8 +368,6 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } - // Manually inserted values aren't clamped by ImGui. Zero cursor size results in a crash. - m_cursor_radius = std::clamp(m_cursor_radius, CursorRadiusMin, CursorRadiusMax); ImGui::Separator(); @@ -427,7 +425,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott m_imgui->text(m_desc.at("cursor_size")); ImGui::SameLine(sliders_width); ImGui::PushItemWidth(window_width - sliders_width); - ImGui::SliderFloat(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); + m_imgui->slider_float(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(max_tooltip_width); @@ -480,7 +478,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott ImGui::SameLine(sliders_width); ImGui::PushItemWidth(window_width - sliders_width); auto clp_dist = float(m_c->object_clipper()->get_position()); - if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f")) + if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); @@ -546,7 +544,8 @@ void GLGizmoMmuSegmentation::init_model_triangle_selectors() int extruder_idx = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0; m_triangle_selectors.emplace_back(std::make_unique(*mesh, m_modified_extruders_colors, m_original_extruders_colors[size_t(extruder_idx)])); - m_triangle_selectors.back()->deserialize(mv->mmu_segmentation_facets.get_data()); + // Reset of TriangleSelector is done inside TriangleSelectorMmGUI's constructor, so we don't need it to perform it again in deserialize(). + m_triangle_selectors.back()->deserialize(mv->mmu_segmentation_facets.get_data(), false); m_triangle_selectors.back()->request_update_render_data(); } m_original_volumes_extruder_idxs = get_extruder_id_for_volumes(*mo); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 7a9e69fac..1211864eb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -87,7 +87,7 @@ void GLGizmoMove3D::on_update(const UpdateData& data) m_displacement.z() = calc_projection(data); } -void GLGizmoMove3D::on_render() const +void GLGizmoMove3D::on_render() { const Selection& selection = m_parent.get_selection(); @@ -151,7 +151,7 @@ void GLGizmoMove3D::on_render() const } } -void GLGizmoMove3D::on_render_for_picking() const +void GLGizmoMove3D::on_render_for_picking() { glsafe(::glDisable(GL_DEPTH_TEST)); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp index 9a86852d6..baa2df739 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.hpp @@ -39,8 +39,8 @@ protected: virtual void on_start_dragging() override; virtual void on_stop_dragging() override; virtual void on_update(const UpdateData& data) override; - virtual void on_render() const override; - virtual void on_render_for_picking() const override; + virtual void on_render() override; + virtual void on_render_for_picking() override; private: double calc_projection(const UpdateData& data) const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 84591ff59..317d7ebca 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -31,7 +31,6 @@ GLGizmoPainterBase::GLGizmoPainterBase(GLCanvas3D& parent, const std::string& ic -#if ENABLE_PROJECT_DIRTY_STATE // port of 948bc382655993721d93d3b9fce9b0186fcfb211 void GLGizmoPainterBase::activate_internal_undo_redo_stack(bool activate) { @@ -66,29 +65,6 @@ void GLGizmoPainterBase::activate_internal_undo_redo_stack(bool activate) m_internal_stack_active = false; } } -#else -void GLGizmoPainterBase::activate_internal_undo_redo_stack(bool activate) -{ - if (activate && ! m_internal_stack_active) { - wxString str = get_painter_type() == PainterGizmoType::FDM_SUPPORTS - ? _L("Entering Paint-on supports") - : (get_painter_type() == PainterGizmoType::MMU_SEGMENTATION ? _L("Entering MMU segmentation") : _L("Entering Seam painting")); - Plater::TakeSnapshot(wxGetApp().plater(), str); - wxGetApp().plater()->enter_gizmos_stack(); - m_internal_stack_active = true; - } - if (! activate && m_internal_stack_active) { - wxString str = get_painter_type() == PainterGizmoType::SEAM - ? _L("Leaving Seam painting") - : (get_painter_type() == PainterGizmoType::MMU_SEGMENTATION ? _L("Leaving MMU segmentation") : _L("Leaving Paint-on supports")); - wxGetApp().plater()->leave_gizmos_stack(); - Plater::TakeSnapshot(wxGetApp().plater(), str); - m_internal_stack_active = false; - } -} -#endif // ENABLE_PROJECT_DIRTY_STATE - - void GLGizmoPainterBase::set_painter_gizmo_data(const Selection& selection) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index a551759b6..04c74c487 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -66,8 +66,8 @@ class GLGizmoPainterBase : public GLGizmoBase private: ObjectID m_old_mo_id; size_t m_old_volumes_size = 0; - void on_render() const override {} - void on_render_for_picking() const override {} + void on_render() override {} + void on_render_for_picking() override {} public: GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 8b12bdc3d..a495db4f1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -125,7 +125,7 @@ void GLGizmoRotate::on_update(const UpdateData& data) m_angle = theta; } -void GLGizmoRotate::on_render() const +void GLGizmoRotate::on_render() { if (!m_grabbers[0].enabled) return; @@ -169,7 +169,7 @@ void GLGizmoRotate::on_render() const glsafe(::glPopMatrix()); } -void GLGizmoRotate::on_render_for_picking() const +void GLGizmoRotate::on_render_for_picking() { const Selection& selection = m_parent.get_selection(); @@ -483,17 +483,17 @@ void GLGizmoRotate3D::on_stop_dragging() m_gizmos[m_hover_id].stop_dragging(); } -void GLGizmoRotate3D::on_render() const +void GLGizmoRotate3D::on_render() { glsafe(::glClear(GL_DEPTH_BUFFER_BIT)); - if ((m_hover_id == -1) || (m_hover_id == 0)) + if (m_hover_id == -1 || m_hover_id == 0) m_gizmos[X].render(); - if ((m_hover_id == -1) || (m_hover_id == 1)) + if (m_hover_id == -1 || m_hover_id == 1) m_gizmos[Y].render(); - if ((m_hover_id == -1) || (m_hover_id == 2)) + if (m_hover_id == -1 || m_hover_id == 2) m_gizmos[Z].render(); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp index 3fc347222..a51f900bf 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.hpp @@ -55,8 +55,8 @@ protected: std::string on_get_name() const override { return ""; } void on_start_dragging() override; void on_update(const UpdateData& data) override; - void on_render() const override; - void on_render_for_picking() const override; + void on_render() override; + void on_render_for_picking() override; private: void render_circle() const; @@ -124,10 +124,10 @@ protected: g.update(data); } } - void on_render() const override; - void on_render_for_picking() const override + void on_render() override; + void on_render_for_picking() override { - for (const GLGizmoRotate& g : m_gizmos) { + for (GLGizmoRotate& g : m_gizmos) { g.render_for_picking(); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index fb1b148b4..849046962 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -115,7 +115,7 @@ void GLGizmoScale3D::on_update(const UpdateData& data) do_scale_uniform(data); } -void GLGizmoScale3D::on_render() const +void GLGizmoScale3D::on_render() { const Selection& selection = m_parent.get_selection(); @@ -294,7 +294,7 @@ void GLGizmoScale3D::on_render() const } } -void GLGizmoScale3D::on_render_for_picking() const +void GLGizmoScale3D::on_render_for_picking() { glsafe(::glDisable(GL_DEPTH_TEST)); render_grabbers_for_picking(m_parent.get_selection().get_bounding_box()); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp index 39021640a..35615df4a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.hpp @@ -52,8 +52,8 @@ protected: virtual bool on_is_activable() const override; virtual void on_start_dragging() override; virtual void on_update(const UpdateData& data) override; - virtual void on_render() const override; - virtual void on_render_for_picking() const override; + virtual void on_render() override; + virtual void on_render_for_picking() override; private: void render_grabbers_connection(unsigned int id_1, unsigned int id_2) const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 9ceb220d4..8854c1a7e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -140,7 +140,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) m_imgui->text(m_desc.at("cursor_size")); ImGui::SameLine(cursor_size_slider_left); ImGui::PushItemWidth(window_width - cursor_size_slider_left); - ImGui::SliderFloat(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); + m_imgui->slider_float(" ", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(max_tooltip_width); @@ -148,9 +148,6 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } - // Manually inserted values aren't clamped by ImGui. Zero cursor size results in a crash. - m_cursor_radius = std::clamp(m_cursor_radius, CursorRadiusMin, CursorRadiusMax); - ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("cursor_type")); @@ -203,7 +200,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) ImGui::SameLine(clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left); auto clp_dist = float(m_c->object_clipper()->get_position()); - if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f")) + if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); if (ImGui::IsItemHovered()) { @@ -259,7 +256,8 @@ void GLGizmoSeam::update_from_model_object() const TriangleMesh* mesh = &mv->mesh(); m_triangle_selectors.emplace_back(std::make_unique(*mesh)); - m_triangle_selectors.back()->deserialize(mv->seam_facets.get_data()); + // Reset of TriangleSelector is done inside TriangleSelectorGUI's constructor, so we don't need it to perform it again in deserialize(). + m_triangle_selectors.back()->deserialize(mv->seam_facets.get_data(), false); m_triangle_selectors.back()->request_update_render_data(); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 20306f182..fa61779ec 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -74,7 +74,7 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S -void GLGizmoSlaSupports::on_render() const +void GLGizmoSlaSupports::on_render() { ModelObject* mo = m_c->selection_info()->model_object(); const Selection& selection = m_parent.get_selection(); @@ -101,7 +101,7 @@ void GLGizmoSlaSupports::on_render() const } -void GLGizmoSlaSupports::on_render_for_picking() const +void GLGizmoSlaSupports::on_render_for_picking() { const Selection& selection = m_parent.get_selection(); //glsafe(::glEnable(GL_DEPTH_TEST)); @@ -671,7 +671,7 @@ RENDER_AGAIN: // - keep updating the head radius during sliding so it is continuosly refreshed in 3D scene // - take correct undo/redo snapshot after the user is done with moving the slider float initial_value = m_new_point_head_diameter; - ImGui::SliderFloat("", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f"); + m_imgui->slider_float("", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f"); if (ImGui::IsItemClicked()) { if (m_old_point_head_diameter == 0.f) m_old_point_head_diameter = initial_value; @@ -731,7 +731,7 @@ RENDER_AGAIN: float density = static_cast(opts[0])->value; float minimal_point_distance = static_cast(opts[1])->value; - ImGui::SliderFloat("", &minimal_point_distance, 0.f, 20.f, "%.f mm"); + m_imgui->slider_float("", &minimal_point_distance, 0.f, 20.f, "%.f mm"); bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider bool slider_edited = ImGui::IsItemEdited(); // someone is dragging the slider bool slider_released = ImGui::IsItemDeactivatedAfterEdit(); // someone has just released the slider @@ -740,7 +740,7 @@ RENDER_AGAIN: m_imgui->text(m_desc.at("points_density")); ImGui::SameLine(settings_sliders_left); - ImGui::SliderFloat(" ", &density, 0.f, 200.f, "%.f %%"); + m_imgui->slider_float(" ", &density, 0.f, 200.f, "%.f %%"); slider_clicked |= ImGui::IsItemClicked(); slider_edited |= ImGui::IsItemEdited(); slider_released |= ImGui::IsItemDeactivatedAfterEdit(); @@ -801,7 +801,7 @@ RENDER_AGAIN: ImGui::SameLine(clipping_slider_left); ImGui::PushItemWidth(window_width - clipping_slider_left); float clp_dist = m_c->object_clipper()->get_position(); - if (ImGui::SliderFloat(" ", &clp_dist, 0.f, 1.f, "%.2f")) + if (m_imgui->slider_float(" ", &clp_dist, 0.f, 1.f, "%.2f")) m_c->object_clipper()->set_position(clp_dist, true); @@ -890,11 +890,7 @@ void GLGizmoSlaSupports::on_set_state() // data are not yet available, the CallAfter will postpone taking the // snapshot until they are. No, it does not feel right. wxGetApp().CallAfter([]() { -#if ENABLE_PROJECT_DIRTY_STATE Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Entering SLA gizmo")); -#else - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("SLA gizmo turned on")); -#endif // ENABLE_PROJECT_DIRTY_STATE }); } @@ -922,11 +918,7 @@ void GLGizmoSlaSupports::on_set_state() else { // we are actually shutting down disable_editing_mode(); // so it is not active next time the gizmo opens -#if ENABLE_PROJECT_DIRTY_STATE Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Leaving SLA gizmo")); -#else - Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("SLA gizmo turned off")); -#endif // ENABLE_PROJECT_DIRTY_STATE m_normal_cache.clear(); m_old_mo_id = -1; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 1859dbfd1..6982ecf76 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -70,8 +70,8 @@ public: private: bool on_init() override; void on_update(const UpdateData& data) override; - void on_render() const override; - void on_render_for_picking() const override; + void on_render() override; + void on_render_for_picking() override; void render_points(const Selection& selection, bool picking = false) const; bool unsaved_changes() const; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 8f7d1d9b0..8871fec23 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -125,10 +125,28 @@ bool GLGizmosManager::init() m_current = Undefined; m_hover = Undefined; + m_highlight = std::pair(Undefined, false); return true; } +bool GLGizmosManager::init_arrow(const BackgroundTexture::Metadata& arrow_texture) +{ + if (m_arrow_texture.texture.get_id() != 0) + return true; + + std::string path = resources_dir() + "/icons/"; + bool res = false; + + if (!arrow_texture.filename.empty()) + res = m_arrow_texture.texture.load_from_file(path + arrow_texture.filename, false, GLTexture::SingleThreaded, false); +// res = m_arrow_texture.texture.load_from_svg_file(path + arrow_texture.filename, false, true, false, 100); + if (res) + m_arrow_texture.metadata = arrow_texture; + + return res; +} + void GLGizmosManager::set_overlay_icon_size(float size) { if (m_layout.icons_size != size) @@ -975,6 +993,46 @@ void GLGizmosManager::render_background(float left, float top, float right, floa } } +void GLGizmosManager::render_arrow(const GLCanvas3D& parent, EType highlighted_type) const +{ + + std::vector selectable_idxs = get_selectable_idxs(); + if (selectable_idxs.empty()) + return; + float cnv_w = (float)m_parent.get_canvas_size().get_width(); + float inv_zoom = (float)wxGetApp().plater()->get_camera().get_inv_zoom(); + float height = get_scaled_total_height(); + float zoomed_border = m_layout.scaled_border() * inv_zoom; + float zoomed_top_x = (-0.5f * cnv_w) * inv_zoom; + float zoomed_top_y = (0.5f * height) * inv_zoom; + zoomed_top_x += zoomed_border; + zoomed_top_y -= zoomed_border; + float icons_size = m_layout.scaled_icons_size(); + float zoomed_icons_size = icons_size * inv_zoom; + float zoomed_stride_y = m_layout.scaled_stride_y() * inv_zoom; + for (size_t idx : selectable_idxs) + { + if (idx == highlighted_type) { + int tex_width = m_icons_texture.get_width(); + int tex_height = m_icons_texture.get_height(); + unsigned int tex_id = m_arrow_texture.texture.get_id(); + float inv_tex_width = (tex_width != 0.0f) ? 1.0f / tex_width : 0.0f; + float inv_tex_height = (tex_height != 0.0f) ? 1.0f / tex_height : 0.0f; + + float internal_left_uv = (float)m_arrow_texture.metadata.left * inv_tex_width; + float internal_right_uv = 1.0f - (float)m_arrow_texture.metadata.right * inv_tex_width; + float internal_top_uv = 1.0f - (float)m_arrow_texture.metadata.top * inv_tex_height; + float internal_bottom_uv = (float)m_arrow_texture.metadata.bottom * inv_tex_height; + + float arrow_sides_ratio = (float)m_arrow_texture.texture.get_height() / (float)m_arrow_texture.texture.get_width(); + + GLTexture::render_sub_texture(tex_id, zoomed_top_x + zoomed_icons_size * 1.2f, zoomed_top_x + zoomed_icons_size * 1.2f + zoomed_icons_size * arrow_sides_ratio, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { internal_left_uv, internal_top_uv }, { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv } }); + break; + } + zoomed_top_y -= zoomed_stride_y; + } +} + void GLGizmosManager::do_render_overlay() const { std::vector selectable_idxs = get_selectable_idxs(); @@ -1014,7 +1072,7 @@ void GLGizmosManager::do_render_overlay() const if ((icons_texture_id == 0) || (tex_width <= 1) || (tex_height <= 1)) return; - float du = (float)(tex_width - 1) / (4.0f * (float)tex_width); // 4 is the number of possible states if the icons + float du = (float)(tex_width - 1) / (6.0f * (float)tex_width); // 6 is the number of possible states if the icons float dv = (float)(tex_height - 1) / (float)(m_gizmos.size() * tex_height); // tiles in the texture are spaced by 1 pixel @@ -1026,9 +1084,9 @@ void GLGizmosManager::do_render_overlay() const for (size_t idx : selectable_idxs) { GLGizmoBase* gizmo = m_gizmos[idx].get(); - unsigned int sprite_id = gizmo->get_sprite_id(); - int icon_idx = (m_current == idx) ? 2 : ((m_hover == idx) ? 1 : (gizmo->is_activable()? 0 : 3)); + // higlighted state needs to be decided first so its highlighting in every other state + int icon_idx = (m_highlight.first == idx ? (m_highlight.second ? 4 : 5) : (m_current == idx) ? 2 : ((m_hover == idx) ? 1 : (gizmo->is_activable()? 0 : 3))); float v_top = v_offset + sprite_id * dv; float u_left = u_offset + icon_idx * du; @@ -1062,13 +1120,26 @@ GLGizmoBase* GLGizmosManager::get_current() const return ((m_current == Undefined) || m_gizmos.empty()) ? nullptr : m_gizmos[m_current].get(); } +GLGizmosManager::EType GLGizmosManager::get_gizmo_from_name(const std::string& gizmo_name) const +{ + std::vector selectable_idxs = get_selectable_idxs(); + for (size_t idx = 0; idx < selectable_idxs.size(); ++idx) + { + std::string filename = m_gizmos[selectable_idxs[idx]]->get_icon_filename(); + filename = filename.substr(0, filename.find_first_of('.')); + if (filename == gizmo_name) + return (GLGizmosManager::EType)selectable_idxs[idx]; + } + return GLGizmosManager::EType::Undefined; +} + bool GLGizmosManager::generate_icons_texture() const { std::string path = resources_dir() + "/icons/"; std::vector filenames; for (size_t idx=0; idxget_icon_filename(); if (!icon_filename.empty()) @@ -1081,6 +1152,8 @@ bool GLGizmosManager::generate_icons_texture() const states.push_back(std::make_pair(0, false)); // Hovered states.push_back(std::make_pair(0, true)); // Selected states.push_back(std::make_pair(2, false)); // Disabled + states.push_back(std::make_pair(0, false)); // HighlightedShown + states.push_back(std::make_pair(2, false)); // HighlightedHidden unsigned int sprite_size_px = (unsigned int)m_layout.scaled_icons_size(); // // force even size diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp index 383d7099f..db628a0b7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp @@ -95,9 +95,11 @@ private: mutable GLTexture m_icons_texture; mutable bool m_icons_texture_dirty; BackgroundTexture m_background_texture; + BackgroundTexture m_arrow_texture; Layout m_layout; EType m_current; EType m_hover; + std::pair m_highlight; // bool true = higlightedShown, false = highlightedHidden std::vector get_selectable_idxs() const; std::vector get_activable_idxs() const; @@ -129,6 +131,8 @@ public: bool init(); + bool init_arrow(const BackgroundTexture::Metadata& arrow_texture); + template void load(Archive& ar) { @@ -183,6 +187,7 @@ public: EType get_current_type() const { return m_current; } GLGizmoBase* get_current() const; + EType get_gizmo_from_name(const std::string& gizmo_name) const; bool is_running() const; bool handle_shortcut(int key); @@ -221,6 +226,8 @@ public: void render_overlay() const; + void render_arrow(const GLCanvas3D& parent, EType highlighted_type) const; + std::string get_tooltip() const; bool on_mouse(wxMouseEvent& evt); @@ -233,8 +240,13 @@ public: int get_selectable_icons_cnt() const { return get_selectable_idxs().size(); } int get_shortcut_key(GLGizmosManager::EType) const; + // To end highlight set gizmo = undefined + void set_highlight(EType gizmo, bool highlight_shown) { m_highlight = std::pair(gizmo, highlight_shown); } + bool get_highlight_state() const { return m_highlight.second; } + private: void render_background(float left, float top, float right, float bottom, float border) const; + void do_render_overlay() const; float get_scaled_total_height() const; diff --git a/src/slic3r/GUI/HintNotification.cpp b/src/slic3r/GUI/HintNotification.cpp new file mode 100644 index 000000000..fe4f3c9ab --- /dev/null +++ b/src/slic3r/GUI/HintNotification.cpp @@ -0,0 +1,673 @@ +#include "HintNotification.hpp" +#include "ImGuiWrapper.hpp" +#include "format.hpp" +#include "I18N.hpp" +#include "GUI_ObjectList.hpp" +#include "libslic3r/AppConfig.hpp" +#include "libslic3r/Utils.hpp" +#include "libslic3r/Config.hpp" +#include "libslic3r/PresetBundle.hpp" + +#include +#include +#include +#include +#include + +namespace Slic3r { +namespace GUI { + +const std::string BOLD_MARKER_START = ""; +const std::string BOLD_MARKER_END = ""; +const std::string HYPERTEXT_MARKER_START = ""; +const std::string HYPERTEXT_MARKER_END = ""; + +namespace { +inline void push_style_color(ImGuiCol idx, const ImVec4& col, bool fading_out, float current_fade_opacity) +{ + if (fading_out) + ImGui::PushStyleColor(idx, ImVec4(col.x, col.y, col.z, col.w * current_fade_opacity)); + else + ImGui::PushStyleColor(idx, col); +} +// return true if NOT in disabled mode. +inline bool disabled_modes_check(const std::string& disabled_modes) +{ + if (disabled_modes.empty()) + return true; + + // simple / advanced / expert + ConfigOptionMode config_mode = wxGetApp().get_mode(); + std::string mode_name; + if (config_mode == ConfigOptionMode::comSimple) mode_name = "simple"; + else if (config_mode == ConfigOptionMode::comAdvanced) mode_name = "advanced"; + else if (config_mode == ConfigOptionMode::comExpert) mode_name = "expert"; + + if (!mode_name.empty() && disabled_modes.find(mode_name) != std::string::npos) + return false; + + // fff / sla + const PrinterTechnology tech = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology(); + if (tech == ptFFF) { + if (disabled_modes.find("FFF") != std::string::npos) + return false; + } else { + if (disabled_modes.find("SLA") != std::string::npos) + return false; + } + + return true; +} +} //namespace + +void HintDatabase::init() +{ + + load_hints_from_file(std::move(boost::filesystem::path(resources_dir()) / "data" / "hints.ini")); + + const AppConfig* app_config = wxGetApp().app_config; + m_hint_id = std::atoi(app_config->get("last_hint").c_str()); + m_initialized = true; + +} +void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) +{ + namespace pt = boost::property_tree; + pt::ptree tree; + boost::nowide::ifstream ifs(path.string()); + try { + pt::read_ini(ifs, tree); + } + catch (const boost::property_tree::ini_parser::ini_parser_error& err) { + throw Slic3r::RuntimeError(format("Failed loading hints file \"%1%\"\nError: \"%2%\" at line %3%", path, err.message(), err.line()).c_str()); + } + + for (const auto& section : tree) { + if (boost::starts_with(section.first, "hint:")) { + // create std::map with tree data + std::map dict; + for (const auto& data : section.second) { + dict.emplace(data.first, data.second.data()); + } + + //unescaping a translating all texts + //unescape text1 + std::string fulltext; + std::string text1; + std::string hypertext_text; + std::string follow_text; + std::string disabled_modes; + unescape_string_cstyle(_utf8(dict["text"]), fulltext); + // replace and for imgui markers + std::string marker_s(1, ImGui::ColorMarkerStart); + std::string marker_e(1, ImGui::ColorMarkerEnd); + // start marker + size_t marker_pos = fulltext.find(BOLD_MARKER_START); + while (marker_pos != std::string::npos) { + fulltext.replace(marker_pos, 3, marker_s); + marker_pos = fulltext.find(BOLD_MARKER_START, marker_pos); + } + // end marker + marker_pos = fulltext.find(BOLD_MARKER_END); + while (marker_pos != std::string::npos) { + fulltext.replace(marker_pos, 4, marker_e); + marker_pos = fulltext.find(BOLD_MARKER_END, marker_pos); + } + // divide fulltext + size_t hypertext_start = fulltext.find(HYPERTEXT_MARKER_START); + if (hypertext_start != std::string::npos) { + //hypertext exists + fulltext.erase(hypertext_start, HYPERTEXT_MARKER_START.size()); + if (fulltext.find(HYPERTEXT_MARKER_START) != std::string::npos) { + // This must not happen - only 1 hypertext allowed + BOOST_LOG_TRIVIAL(error) << "Hint notification with multiple hypertexts: " << _utf8(dict["text"]); + continue; + } + size_t hypertext_end = fulltext.find(HYPERTEXT_MARKER_END); + if (hypertext_end == std::string::npos) { + // hypertext was not correctly ended + BOOST_LOG_TRIVIAL(error) << "Hint notification without hypertext end marker: " << _utf8(dict["text"]); + continue; + } + fulltext.erase(hypertext_end, HYPERTEXT_MARKER_END.size()); + if (fulltext.find(HYPERTEXT_MARKER_END) != std::string::npos) { + // This must not happen - only 1 hypertext end allowed + BOOST_LOG_TRIVIAL(error) << "Hint notification with multiple hypertext end markers: " << _utf8(dict["text"]); + continue; + } + + text1 = fulltext.substr(0, hypertext_start); + hypertext_text = fulltext.substr(hypertext_start, hypertext_end - hypertext_start); + follow_text = fulltext.substr(hypertext_end); + } else { + text1 = fulltext; + } + + if (dict.find("disabled_modes") != dict.end()) { + disabled_modes = dict["disabled_modes"]; + } + + // create HintData + if (dict.find("hypertext_type") != dict.end()) { + //link to internet + if(dict["hypertext_type"] == "link") { + std::string hypertext_link = dict["hypertext_link"]; + HintData hint_data{ text1, hypertext_text, follow_text, disabled_modes, false, [hypertext_link]() { wxLaunchDefaultBrowser(hypertext_link); } }; + m_loaded_hints.emplace_back(hint_data); + // highlight settings + } else if (dict["hypertext_type"] == "settings") { + std::string opt = dict["hypertext_settings_opt"]; + Preset::Type type = static_cast(std::atoi(dict["hypertext_settings_type"].c_str())); + std::wstring category = boost::nowide::widen(dict["hypertext_settings_category"]); + HintData hint_data{ text1, hypertext_text, follow_text, disabled_modes, true, [opt, type, category]() { GUI::wxGetApp().sidebar().jump_to_option(opt, type, category); } }; + m_loaded_hints.emplace_back(hint_data); + // open preferences + } else if(dict["hypertext_type"] == "preferences") { + int page = static_cast(std::atoi(dict["hypertext_preferences_page"].c_str())); + HintData hint_data{ text1, hypertext_text, follow_text, disabled_modes, false, [page]() { wxGetApp().open_preferences(page); } }; + m_loaded_hints.emplace_back(hint_data); + + } else if (dict["hypertext_type"] == "plater") { + std::string item = dict["hypertext_plater_item"]; + HintData hint_data{ text1, hypertext_text, follow_text, disabled_modes, true, [item]() { wxGetApp().plater()->canvas3D()->highlight_toolbar_item(item); } }; + m_loaded_hints.emplace_back(hint_data); + } else if (dict["hypertext_type"] == "gizmo") { + std::string item = dict["hypertext_gizmo_item"]; + HintData hint_data{ text1, hypertext_text, follow_text, disabled_modes, true, [item]() { wxGetApp().plater()->canvas3D()->highlight_gizmo(item); } }; + m_loaded_hints.emplace_back(hint_data); + } + else if (dict["hypertext_type"] == "gallery") { + HintData hint_data{ text1, hypertext_text, follow_text, disabled_modes, false, []() { wxGetApp().obj_list()->load_shape_object_from_gallery(); } }; + m_loaded_hints.emplace_back(hint_data); + } + } else { + // plain text without hypertext + HintData hint_data{ text1 }; + m_loaded_hints.emplace_back(hint_data); + } + } + } +} +HintData* HintDatabase::get_hint(bool up) +{ + if (! m_initialized) { + init(); + //return false; + } + // shift id + m_hint_id = (up ? m_hint_id + 1 : (m_hint_id == 0 ? m_loaded_hints.size() - 1 : m_hint_id - 1)); + m_hint_id %= m_loaded_hints.size(); + + AppConfig* app_config = wxGetApp().app_config; + app_config->set("last_hint", std::to_string(m_hint_id)); + + //data = &m_loaded_hints[m_hint_id]; + /* + data.text = m_loaded_hints[m_hint_id].text; + data.hypertext = m_loaded_hints[m_hint_id].hypertext; + data.follow_text = m_loaded_hints[m_hint_id].follow_text; + data.callback = m_loaded_hints[m_hint_id].callback; + */ + return &m_loaded_hints[m_hint_id]; +} + +void NotificationManager::HintNotification::count_spaces() +{ + //determine line width + m_line_height = ImGui::CalcTextSize("A").y; + + + std::string text; + text = ImGui::WarningMarker; + float picture_width = ImGui::CalcTextSize(text.c_str()).x; + m_left_indentation = picture_width + m_line_height / 2; + + // no left button picture + //m_left_indentation = m_line_height; + + m_window_width_offset = m_left_indentation + m_line_height * 3.f;// 5.5f; // no right arrow + m_window_width = m_line_height * 25; +} + +void NotificationManager::HintNotification::count_lines() +{ + std::string text = m_text1; + size_t last_end = 0; + m_lines_count = 0; + + if (text.empty()) + return; + + m_endlines.clear(); + while (last_end < text.length() - 1) + { + size_t next_hard_end = text.find_first_of('\n', last_end); + if (next_hard_end != std::string::npos && ImGui::CalcTextSize(text.substr(last_end, next_hard_end - last_end).c_str()).x < m_window_width - m_window_width_offset) { + //next line is ended by '/n' + m_endlines.push_back(next_hard_end); + last_end = next_hard_end + 1; + } + else { + // find next suitable endline + if (ImGui::CalcTextSize(text.substr(last_end).c_str()).x >= m_window_width - m_window_width_offset) { + // more than one line till end + size_t next_space = text.find_first_of(' ', last_end); + if (next_space > 0 && next_space < text.length()) { + size_t next_space_candidate = text.find_first_of(' ', next_space + 1); + while (next_space_candidate > 0 && ImGui::CalcTextSize(text.substr(last_end, next_space_candidate - last_end).c_str()).x < m_window_width - m_window_width_offset) { + next_space = next_space_candidate; + next_space_candidate = text.find_first_of(' ', next_space + 1); + } + } else { + next_space = text.length(); + } + // when one word longer than line. + if (ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x > m_window_width - m_window_width_offset || + ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x < (m_window_width - m_window_width_offset) / 4 * 3 + ) { + float width_of_a = ImGui::CalcTextSize("a").x; + int letter_count = (int)((m_window_width - m_window_width_offset) / width_of_a); + while (last_end + letter_count < text.size() && ImGui::CalcTextSize(text.substr(last_end, letter_count).c_str()).x < m_window_width - m_window_width_offset) { + letter_count++; + } + m_endlines.push_back(last_end + letter_count); + last_end += letter_count; + } else { + m_endlines.push_back(next_space); + last_end = next_space + 1; + } + } + else { + m_endlines.push_back(text.length()); + last_end = text.length(); + } + + } + m_lines_count++; + } + int prev_end = m_endlines.size() > 1 ? m_endlines[m_endlines.size() - 2] : 0; + int size_of_last_line = ImGui::CalcTextSize(text.substr(prev_end, last_end - prev_end).c_str()).x; + // hypertext calculation + if (!m_hypertext.empty()) { + if (size_of_last_line + ImGui::CalcTextSize(m_hypertext.c_str()).x > m_window_width - m_window_width_offset) { + // hypertext on new line + size_of_last_line = ImGui::CalcTextSize((m_hypertext + " ").c_str()).x; + m_endlines.push_back(last_end); + m_lines_count++; + } else { + size_of_last_line += ImGui::CalcTextSize((m_hypertext + " ").c_str()).x; + } + } + if (!m_text2.empty()) { + text = m_text2; + last_end = 0; + m_endlines2.clear(); + // if size_of_last_line too large to fit anything + size_t first_end = std::min(text.find_first_of('\n'), text.find_first_of(' ')); + if (size_of_last_line >= m_window_width - m_window_width_offset - ImGui::CalcTextSize(text.substr(0, first_end).c_str()).x) { + m_endlines2.push_back(0); + size_of_last_line = 0; + } + while (last_end < text.length() - 1) + { + size_t next_hard_end = text.find_first_of('\n', last_end); + if (next_hard_end != std::string::npos && ImGui::CalcTextSize(text.substr(last_end, next_hard_end - last_end).c_str()).x < m_window_width - m_window_width_offset - size_of_last_line) { + //next line is ended by '/n' + m_endlines2.push_back(next_hard_end); + last_end = next_hard_end + 1; + } + else { + // find next suitable endline + if (ImGui::CalcTextSize(text.substr(last_end).c_str()).x >= m_window_width - m_window_width_offset - size_of_last_line) { + // more than one line till end + size_t next_space = text.find_first_of(' ', last_end); + if (next_space > 0) { + size_t next_space_candidate = text.find_first_of(' ', next_space + 1); + while (next_space_candidate > 0 && ImGui::CalcTextSize(text.substr(last_end, next_space_candidate - last_end).c_str()).x < m_window_width - m_window_width_offset - size_of_last_line) { + next_space = next_space_candidate; + next_space_candidate = text.find_first_of(' ', next_space + 1); + } + } + else { + next_space = text.length(); + } + // when one word longer than line. + if (ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x > m_window_width - m_window_width_offset - size_of_last_line || + ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x + size_of_last_line < (m_window_width - m_window_width_offset) / 4 * 3 + ) { + float width_of_a = ImGui::CalcTextSize("a").x; + int letter_count = (int)((m_window_width - m_window_width_offset - size_of_last_line) / width_of_a); + while (last_end + letter_count < text.size() && ImGui::CalcTextSize(text.substr(last_end, letter_count).c_str()).x < m_window_width - m_window_width_offset - size_of_last_line) { + letter_count++; + } + m_endlines2.push_back(last_end + letter_count); + last_end += letter_count; + } + else { + m_endlines2.push_back(next_space); + last_end = next_space + 1; + } + } + else { + m_endlines2.push_back(text.length()); + last_end = text.length(); + } + + } + if (size_of_last_line == 0) // if first line is continuation of previous text, do not add to line count. + m_lines_count++; + size_of_last_line = 0; // should countain value only for first line (with hypertext) + + } + } +} + +void NotificationManager::HintNotification::init() +{ + // Do not init closing notification + if (is_finished()) + return; + + count_spaces(); + count_lines(); + + m_multiline = true; + + m_notification_start = GLCanvas3D::timestamp_now(); + if (m_state == EState::Unknown) + m_state = EState::Shown; +} + +void NotificationManager::HintNotification::set_next_window_size(ImGuiWrapper& imgui) +{ + /* + m_window_height = m_multiline ? + (m_lines_count + 1.f) * m_line_height : + 4.f * m_line_height; + m_window_height += 1 * m_line_height; // top and bottom + */ + + m_window_height = std::max((m_lines_count + 1.f) * m_line_height, 4.f * m_line_height); +} + +bool NotificationManager::HintNotification::on_text_click() +{ + if (m_hypertext_callback != nullptr && (!m_runtime_disable || disabled_modes_check(m_disabled_modes))) + m_hypertext_callback(); + return false; +} + +void NotificationManager::HintNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) +{ + if (!m_has_hint_data) { + retrieve_data(); + } + + float x_offset = m_left_indentation; + int last_end = 0; + float starting_y = (m_lines_count == 2 ? win_size_y / 2 - m_line_height :(m_lines_count == 1 ? win_size_y / 2 - m_line_height / 2: m_line_height / 2)); + float shift_y = m_line_height; + std::string line; + + for (size_t i = 0; i < (m_multiline ? /*m_lines_count*/m_endlines.size() : 2); i++) { + line.clear(); + ImGui::SetCursorPosX(x_offset); + ImGui::SetCursorPosY(starting_y + i * shift_y); + if (m_endlines.size() > i && m_text1.size() >= m_endlines[i]) { + if (i == 1 && m_endlines.size() > 2 && !m_multiline) { + // second line with "more" hypertext + line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0), m_endlines[1] - m_endlines[0] - (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0)); + while (ImGui::CalcTextSize(line.c_str()).x > m_window_width - m_window_width_offset - ImGui::CalcTextSize((".." + _u8L("More")).c_str()).x) { + line = line.substr(0, line.length() - 1); + } + line += ".."; + } else { + // regural line + line = m_text1.substr(last_end, m_endlines[i] - last_end); + } + // first line is headline + if (i == 0) { + line = ImGui::ColorMarkerStart + line + ImGui::ColorMarkerEnd; + } + // Add ImGui::ColorMarkerStart if there is ImGui::ColorMarkerEnd first (start was at prev line) + if (line.find_first_of(ImGui::ColorMarkerEnd) < line.find_first_of(ImGui::ColorMarkerStart)) { + line = ImGui::ColorMarkerStart + line; + } + + last_end = m_endlines[i]; + if (m_text1.size() > m_endlines[i]) + last_end += (m_text1[m_endlines[i]] == '\n' || m_text1[m_endlines[i]] == ' ' ? 1 : 0); + imgui.text(line.c_str()); + } + + } + //hyperlink text + if (!m_multiline && m_lines_count > 2) { + render_hypertext(imgui, x_offset + ImGui::CalcTextSize((line + " ").c_str()).x, starting_y + shift_y, _u8L("More"), true); + } else if (!m_hypertext.empty()) { + render_hypertext(imgui, x_offset + ImGui::CalcTextSize((line + (line.empty()? "": " ")).c_str()).x, starting_y + (m_endlines.size() - 1) * shift_y, m_hypertext); + } + + // text2 + if (!m_text2.empty() && m_multiline) { + starting_y += (m_endlines.size() - 1) * shift_y; + last_end = 0; + for (size_t i = 0; i < (m_multiline ? m_endlines2.size() : 2); i++) { + if (i == 0) //first line X is shifted by hypertext + ImGui::SetCursorPosX(x_offset + ImGui::CalcTextSize((line + m_hypertext + (line.empty() ? " " : " ")).c_str()).x); + else + ImGui::SetCursorPosX(x_offset); + + ImGui::SetCursorPosY(starting_y + i * shift_y); + line.clear(); + if (m_endlines2.size() > i && m_text2.size() >= m_endlines2[i]) { + + // regural line + line = m_text2.substr(last_end, m_endlines2[i] - last_end); + + // Add ImGui::ColorMarkerStart if there is ImGui::ColorMarkerEnd first (start was at prev line) + if (line.find_first_of(ImGui::ColorMarkerEnd) < line.find_first_of(ImGui::ColorMarkerStart)) { + line = ImGui::ColorMarkerStart + line; + } + + last_end = m_endlines2[i]; + if (m_text2.size() > m_endlines2[i]) + last_end += (m_text2[m_endlines2[i]] == '\n' || m_text2[m_endlines2[i]] == ' ' ? 1 : 0); + imgui.text(line.c_str()); + } + + } + } +} + +void NotificationManager::HintNotification::render_close_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) +{ + ImVec2 win_size(win_size_x, win_size_y); + ImVec2 win_pos(win_pos_x, win_pos_y); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); + push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); + + + std::string button_text; + button_text = ImGui::CloseNotifButton; + + if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - win_size.x / 10.f, win_pos.y), + ImVec2(win_pos.x, win_pos.y + win_size.y - 2 * m_line_height), + true)) + { + button_text = ImGui::CloseNotifHoverButton; + } + ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str()); + ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f); + m_close_b_w = button_size.y; + if (m_lines_count <= 3) { + m_close_b_y = win_size.y / 2 - button_size.y * 1.25f; + ImGui::SetCursorPosX(win_size.x - m_line_height * 2.75f); + ImGui::SetCursorPosY(m_close_b_y); + } else { + ImGui::SetCursorPosX(win_size.x - m_line_height * 2.75f); + ImGui::SetCursorPosY(win_size.y / 2 - button_size.y); + } + if (imgui.button(button_text.c_str(), button_size.x, button_size.y)) + { + close(); + } + + //invisible large button + ImGui::SetCursorPosX(win_size.x - m_line_height * 2.35f); + ImGui::SetCursorPosY(0); + if (imgui.button(" ", m_line_height * 2.125, win_size.y - 2 * m_line_height)) + { + close(); + } + + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + + + render_right_arrow_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + render_logo(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + render_preferences_button(imgui, win_pos_x, win_pos_y); +} + +void NotificationManager::HintNotification::render_preferences_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y) +{ + + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); + push_style_color(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + + std::string button_text; + button_text = ImGui::PreferencesButton; + //hover + if (ImGui::IsMouseHoveringRect(ImVec2(win_pos_x - m_window_width / 10.f, win_pos_y + m_window_height - 2 * m_line_height + 1), + ImVec2(win_pos_x, win_pos_y + m_window_height), + true)) + { + button_text = ImGui::PreferencesHoverButton; + } + + ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str()); + ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f); + ImGui::SetCursorPosX(m_window_width - m_line_height * 1.75f); + if (m_lines_count <= 3) { + ImGui::SetCursorPosY(m_close_b_y + m_close_b_w / 4.f * 7.f); + } else { + ImGui::SetCursorPosY(m_window_height - button_size.y - m_close_b_w / 4.f); + } + if (imgui.button(button_text.c_str(), button_size.x, button_size.y)) + { + wxGetApp().open_preferences(2); + } + + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + // preferences button is in place of minimize button + m_minimize_b_visible = true; +} + +void NotificationManager::HintNotification::render_right_arrow_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) +{ + // Used for debuging + + ImVec2 win_size(win_size_x, win_size_y); + ImVec2 win_pos(win_pos_x, win_pos_y); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); + push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); + + std::string button_text; + button_text = ImGui::RightArrowButton; + + ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str()); + ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f); + + ImGui::SetCursorPosX(m_window_width - m_line_height * 3.f); + if (m_lines_count <= 3) + ImGui::SetCursorPosY(m_close_b_y + m_close_b_w / 4.f * 7.f); + else + ImGui::SetCursorPosY(m_window_height - button_size.y - m_close_b_w / 4.f); + if (imgui.button(button_text.c_str(), button_size.x * 0.8f, button_size.y * 1.f)) + { + retrieve_data(); + } + + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); +} +void NotificationManager::HintNotification::render_logo(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) +{ + ImVec2 win_size(win_size_x, win_size_y); + ImVec2 win_pos(win_pos_x, win_pos_y); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); + push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); + + std::string button_text; + button_text = ImGui::ErrorMarker;//LeftArrowButton; + + ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str()); + ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f); + ImGui::SetCursorPosY(win_size.y / 2 - button_size.y); + ImGui::SetCursorPosX(0); + // shouldnt it render as text? + if (imgui.button(button_text.c_str(), button_size.x, button_size.y)) + { + } + + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); +} +void NotificationManager::HintNotification::retrieve_data(size_t recursion_counter) +{ + HintData* hint_data = HintDatabase::get_instance().get_hint(true); + if (hint_data != nullptr && !disabled_modes_check(hint_data->disabled_modes)) + { + // Content for different user - retrieve another + size_t count = HintDatabase::get_instance().get_count(); + if (count < recursion_counter) { + BOOST_LOG_TRIVIAL(error) << "Hint notification failed to load data due to recursion counter."; + } else { + retrieve_data(recursion_counter + 1); + } + return; + } + if(hint_data != nullptr) + { + NotificationData nd { NotificationType::DidYouKnowHint, + NotificationLevel::RegularNotification, + 0, + hint_data->text, + hint_data->hypertext, nullptr, + hint_data->follow_text }; + update(nd); + m_hypertext_callback = hint_data->callback; + m_disabled_modes = hint_data->disabled_modes; + m_runtime_disable = hint_data->runtime_disable; + m_has_hint_data = true; + + } +} +} //namespace Slic3r +} //namespace GUI \ No newline at end of file diff --git a/src/slic3r/GUI/HintNotification.hpp b/src/slic3r/GUI/HintNotification.hpp new file mode 100644 index 000000000..125420fb6 --- /dev/null +++ b/src/slic3r/GUI/HintNotification.hpp @@ -0,0 +1,97 @@ +#ifndef slic3r_GUI_HintNotification_hpp_ +#define slic3r_GUI_HintNotification_hpp_ + +#include "NotificationManager.hpp" + +namespace Slic3r { +namespace GUI { + +// Database of hints updatable +struct HintData +{ + std::string text; + std::string hypertext; + std::string follow_text; + std::string disabled_modes; + bool runtime_disable; // if true - hyperlink will check before every click if not in disabled mode + std::function callback{ nullptr }; +}; + +class HintDatabase +{ +public: + static HintDatabase& get_instance() + { + static HintDatabase instance; // Guaranteed to be destroyed. + // Instantiated on first use. + return instance; + } +private: + HintDatabase() + : m_hint_id(0) + {} +public: + HintDatabase(HintDatabase const&) = delete; + void operator=(HintDatabase const&) = delete; + + // return true if HintData filled; + HintData* get_hint(bool up = true); + size_t get_count() { + if (!m_initialized) + return 0; + return m_loaded_hints.size(); + } +private: + void init(); + void load_hints_from_file(const boost::filesystem::path& path); + size_t m_hint_id; + bool m_initialized { false }; + std::vector m_loaded_hints; + +}; +// Notification class - shows current Hint ("Did you know") +class NotificationManager::HintNotification : public NotificationManager::PopNotification +{ +public: + HintNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler) + : PopNotification(n, id_provider, evt_handler) + { + retrieve_data(); + } + virtual void init() override; +protected: + virtual void set_next_window_size(ImGuiWrapper& imgui) override; + virtual void count_spaces() override; + virtual void count_lines() override; + virtual bool on_text_click() override; + virtual void render_text(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y) override; + virtual void render_close_button(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y) override; + virtual void render_minimize_button(ImGuiWrapper& imgui, + const float win_pos_x, const float win_pos_y) override {} + void render_preferences_button(ImGuiWrapper& imgui, + const float win_pos_x, const float win_pos_y); + void render_right_arrow_button(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y); + void render_logo(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y); + + void retrieve_data(size_t recursion_counter = 0); + + bool m_has_hint_data { false }; + std::function m_hypertext_callback; + std::string m_disabled_modes; + bool m_runtime_disable; + float m_close_b_y { 0 }; + float m_close_b_w { 0 }; +}; + +} //namespace Slic3r +} //namespace GUI + +#endif //slic3r_GUI_HintNotification_hpp_ \ No newline at end of file diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 799b5be4a..79e34ba85 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -43,7 +43,11 @@ static const std::map font_icons = { {ImGui::FilamentIconMarker , "spool" }, {ImGui::MaterialIconMarker , "resin" }, {ImGui::MinimalizeButton , "notification_minimalize" }, - {ImGui::MinimalizeHoverButton , "notification_minimalize_hover" } + {ImGui::MinimalizeHoverButton , "notification_minimalize_hover" }, + {ImGui::RightArrowButton , "notification_right" }, + {ImGui::RightArrowHoverButton , "notification_right_hover" }, + {ImGui::PreferencesButton , "notification_preferences" }, + {ImGui::PreferencesHoverButton , "notification_preferences_hover"}, }; static const std::map font_icons_large = { {ImGui::CloseNotifButton , "notification_close" }, @@ -54,6 +58,12 @@ static const std::map font_icons_large = { {ImGui::ErrorMarker , "notification_error" }, {ImGui::CancelButton , "notification_cancel" }, {ImGui::CancelHoverButton , "notification_cancel_hover" }, + {ImGui::SinkingObjectMarker , "move" }, + {ImGui::CustomSupportsMarker , "fdm_supports" }, + {ImGui::CustomSeamMarker , "seam" }, + {ImGui::MmuSegmentationMarker , "move" }, + {ImGui::VarLayerHeightMarker , "layers" }, + }; const ImVec4 ImGuiWrapper::COL_GREY_DARK = { 0.333f, 0.333f, 0.333f, 1.0f }; @@ -204,7 +214,8 @@ bool ImGuiWrapper::update_mouse_data(wxMouseEvent& evt) unsigned buttons = (evt.LeftIsDown() ? 1 : 0) | (evt.RightIsDown() ? 2 : 0) | (evt.MiddleIsDown() ? 4 : 0); m_mouse_buttons = buttons; - new_frame(); + if (want_mouse()) + new_frame(); return want_mouse(); } @@ -222,9 +233,6 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt) if (key != 0) { io.AddInputCharacter(key); } - - new_frame(); - return want_keyboard() || want_text_input(); } else { // Key up/down event int key = evt.GetKeyCode(); @@ -235,10 +243,11 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt) io.KeyCtrl = evt.ControlDown(); io.KeyAlt = evt.AltDown(); io.KeySuper = evt.MetaDown(); - - new_frame(); - return want_keyboard() || want_text_input(); } + bool ret = want_keyboard() || want_text_input(); + if (ret) + new_frame(); + return ret; } void ImGuiWrapper::new_frame() @@ -407,20 +416,23 @@ void ImGuiWrapper::text_colored(const ImVec4& color, const wxString& label) this->text_colored(color, label_utf8.c_str()); } -bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float v_max, const char* format/* = "%.3f"*/, float power/* = 1.0f*/) +bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float v_max, const char* format/* = "%.3f"*/, float power/* = 1.0f*/, bool clamp /*= true*/) { - return ImGui::SliderFloat(label, v, v_min, v_max, format, power); + bool ret = ImGui::SliderFloat(label, v, v_min, v_max, format, power); + if (clamp) + *v = std::clamp(*v, v_min, v_max); + return ret; } -bool ImGuiWrapper::slider_float(const std::string& label, float* v, float v_min, float v_max, const char* format/* = "%.3f"*/, float power/* = 1.0f*/) +bool ImGuiWrapper::slider_float(const std::string& label, float* v, float v_min, float v_max, const char* format/* = "%.3f"*/, float power/* = 1.0f*/, bool clamp /*= true*/) { - return this->slider_float(label.c_str(), v, v_min, v_max, format, power); + return this->slider_float(label.c_str(), v, v_min, v_max, format, power, clamp); } -bool ImGuiWrapper::slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format/* = "%.3f"*/, float power/* = 1.0f*/) +bool ImGuiWrapper::slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format/* = "%.3f"*/, float power/* = 1.0f*/, bool clamp /*= true*/) { auto label_utf8 = into_u8(label); - return this->slider_float(label_utf8.c_str(), v, v_min, v_max, format, power); + return this->slider_float(label_utf8.c_str(), v, v_min, v_max, format, power, clamp); } bool ImGuiWrapper::combo(const wxString& label, const std::vector& options, int& selection) @@ -1118,6 +1130,11 @@ void ImGuiWrapper::init_style() set_color(ImGuiCol_TabActive, COL_ORANGE_LIGHT); set_color(ImGuiCol_TabUnfocused, COL_GREY_DARK); set_color(ImGuiCol_TabUnfocusedActive, COL_GREY_LIGHT); + + // Scrollbars + set_color(ImGuiCol_ScrollbarGrab, COL_ORANGE_DARK); + set_color(ImGuiCol_ScrollbarGrabHovered, COL_ORANGE_LIGHT); + set_color(ImGuiCol_ScrollbarGrabActive, COL_ORANGE_LIGHT); } void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 5484e46c6..441d26ccc 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -79,9 +79,12 @@ public: void text_colored(const ImVec4& color, const char* label); void text_colored(const ImVec4& color, const std::string& label); void text_colored(const ImVec4& color, const wxString& label); - bool slider_float(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); - bool slider_float(const std::string& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); - bool slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f); + + // Float sliders: Manually inserted values aren't clamped by ImGui.Using this wrapper function does (when clamp==true). + bool slider_float(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true); + bool slider_float(const std::string& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true); + bool slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f, bool clamp = true); + bool combo(const wxString& label, const std::vector& options, int& selection); // Use -1 to not mark any option as selected bool undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool, int, const char**), int& hovered, int& selected, int& mouse_wheel); void search_list(const ImVec2& size, bool (*items_getter)(int, const char** label, const char** tooltip), char* search_str, diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index 23df99bd9..77ce3d83e 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -221,9 +221,7 @@ void KBShortcutsDialog::fill_shortcuts() { "D", L("Horizontal slider - Move active thumb Right") }, { "X", L("On/Off one layer mode of the vertical slider") }, { "L", L("Show/Hide Legend and Estimated printing time") }, -#if ENABLE_GCODE_WINDOW { "C", L("Show/Hide G-code window") }, -#endif // ENABLE_GCODE_WINDOW }; m_full_shortcuts.push_back({ { _L("Preview"), "" }, preview_shortcuts }); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index c81a49569..5cf0d8573 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -213,7 +213,6 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S // declare events Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& event) { -#if ENABLE_PROJECT_DIRTY_STATE if (event.CanVeto() && m_plater->canvas3D()->get_gizmos_manager().is_in_editing_mode(true)) { // prevents to open the save dirty project dialog event.Veto(); @@ -226,9 +225,6 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S } if (event.CanVeto() && !wxGetApp().check_and_save_current_preset_changes()) { -#else - if (event.CanVeto() && !wxGetApp().check_unsaved_changes()) { -#endif // ENABLE_PROJECT_DIRTY_STATE event.Veto(); return; } @@ -616,14 +612,9 @@ void MainFrame::update_title() // m_plater->get_project_filename() produces file name including path, but excluding extension. // Don't try to remove the extension, it would remove part of the file name after the last dot! wxString project = from_path(into_path(m_plater->get_project_filename()).filename()); -#if ENABLE_PROJECT_DIRTY_STATE wxString dirty_marker = (!m_plater->model().objects.empty() && m_plater->is_project_dirty()) ? "*" : ""; if (!dirty_marker.empty() || !project.empty()) title = dirty_marker + project + " - "; -#else - if (!project.empty()) - title += (project + " - "); -#endif // ENABLE_PROJECT_DIRTY_STATE } std::string build_id = wxGetApp().is_editor() ? SLIC3R_BUILD_ID : GCODEVIEWER_BUILD_ID; @@ -675,14 +666,12 @@ void MainFrame::init_tabpanel() #else m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [this](wxBookCtrlEvent& e) { #endif -#if ENABLE_VALIDATE_CUSTOM_GCODE if (int old_selection = e.GetOldSelection(); old_selection != wxNOT_FOUND && old_selection < static_cast(m_tabpanel->GetPageCount())) { Tab* old_tab = dynamic_cast(m_tabpanel->GetPage(old_selection)); if (old_tab) old_tab->validate_custom_gcodes(); } -#endif // ENABLE_VALIDATE_CUSTOM_GCODE wxWindow* panel = m_tabpanel->GetCurrentPage(); Tab* tab = dynamic_cast(panel); @@ -825,7 +814,6 @@ bool MainFrame::can_start_new_project() const return (m_plater != nullptr) && (!m_plater->get_project_filename(".3mf").IsEmpty() || !m_plater->model().objects.empty()); } -#if ENABLE_PROJECT_DIRTY_STATE bool MainFrame::can_save() const { return (m_plater != nullptr) && !m_plater->model().objects.empty() && @@ -852,12 +840,6 @@ void MainFrame::save_project_as(const wxString& filename) m_plater->reset_project_dirty_after_save(); } } -#else -bool MainFrame::can_save() const -{ - return (m_plater != nullptr) && !m_plater->model().objects.empty(); -} -#endif // ENABLE_PROJECT_DIRTY_STATE bool MainFrame::can_export_model() const { @@ -1177,27 +1159,16 @@ void MainFrame::init_menubar_as_editor() Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_recent_projects.GetCount() > 0); }, recent_projects_submenu->GetId()); -#if ENABLE_PROJECT_DIRTY_STATE append_menu_item(fileMenu, wxID_ANY, _L("&Save Project") + "\tCtrl+S", _L("Save current project file"), [this](wxCommandEvent&) { save_project(); }, "save", nullptr, [this](){return m_plater != nullptr && can_save(); }, this); -#else - append_menu_item(fileMenu, wxID_ANY, _L("&Save Project") + "\tCtrl+S", _L("Save current project file"), - [this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename(".3mf"))); }, "save", nullptr, - [this](){return m_plater != nullptr && can_save(); }, this); -#endif // ENABLE_PROJECT_DIRTY_STATE #ifdef __APPLE__ append_menu_item(fileMenu, wxID_ANY, _L("Save Project &as") + dots + "\tCtrl+Shift+S", _L("Save current project file as"), #else append_menu_item(fileMenu, wxID_ANY, _L("Save Project &as") + dots + "\tCtrl+Alt+S", _L("Save current project file as"), #endif // __APPLE__ -#if ENABLE_PROJECT_DIRTY_STATE [this](wxCommandEvent&) { save_project_as(); }, "save", nullptr, [this](){return m_plater != nullptr && can_save_as(); }, this); -#else - [this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(); }, "save", nullptr, - [this](){return m_plater != nullptr && can_save(); }, this); -#endif // ENABLE_PROJECT_DIRTY_STATE fileMenu->AppendSeparator(); @@ -1752,11 +1723,7 @@ void MainFrame::export_config() // Load a config file containing a Print, Filament & Printer preset. void MainFrame::load_config_file() { -#if ENABLE_PROJECT_DIRTY_STATE if (!wxGetApp().check_and_save_current_preset_changes()) -#else - if (!wxGetApp().check_unsaved_changes()) -#endif // ENABLE_PROJECT_DIRTY_STATE return; wxFileDialog dlg(this, _L("Select configuration to load:"), !m_last_config.IsEmpty() ? get_dir_name(m_last_config) : wxGetApp().app_config->get_last_dir(), @@ -1791,11 +1758,7 @@ bool MainFrame::load_config_file(const std::string &path) void MainFrame::export_configbundle(bool export_physical_printers /*= false*/) { -#if ENABLE_PROJECT_DIRTY_STATE if (!wxGetApp().check_and_save_current_preset_changes()) -#else - if (!wxGetApp().check_unsaved_changes()) -#endif // ENABLE_PROJECT_DIRTY_STATE return; // validate current configuration in case it's dirty auto err = wxGetApp().preset_bundle->full_config().validate(); @@ -1827,11 +1790,7 @@ void MainFrame::export_configbundle(bool export_physical_printers /*= false*/) // but that behavior was not documented and likely buggy. void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool reset_user_profile*/) { -#if ENABLE_PROJECT_DIRTY_STATE if (!wxGetApp().check_and_save_current_preset_changes()) -#else - if (!wxGetApp().check_unsaved_changes()) -#endif // ENABLE_PROJECT_DIRTY_STATE return; if (file.IsEmpty()) { wxFileDialog dlg(this, _L("Select configuration to load:"), @@ -1985,7 +1944,7 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/) m_main_sizer->Show(m_tabpanel, tab != 0); // plater should be focused for correct navigation inside search window - if (tab == 0 && m_plater->canvas3D()->is_search_pressed()) + if (tab == 0) m_plater->SetFocus(); Layout(); } diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index a5c6b57ca..aced5efbe 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -91,9 +91,6 @@ class MainFrame : public DPIFrame void on_value_changed(wxCommandEvent&); bool can_start_new_project() const; -#if !ENABLE_PROJECT_DIRTY_STATE - bool can_save() const; -#endif // !ENABLE_PROJECT_DIRTY_STATE bool can_export_model() const; bool can_export_toolpaths() const; bool can_export_supports() const; @@ -188,12 +185,10 @@ public: // Propagate changed configuration from the Tab to the Plater and save changes to the AppConfig void on_config_changed(DynamicPrintConfig* cfg) const ; -#if ENABLE_PROJECT_DIRTY_STATE bool can_save() const; bool can_save_as() const; void save_project(); void save_project_as(const wxString& filename = wxString()); -#endif // ENABLE_PROJECT_DIRTY_STATE void add_to_recent_projects(const wxString& filename); void technology_changed(); diff --git a/src/slic3r/GUI/Notebook.cpp b/src/slic3r/GUI/Notebook.cpp index afc0241d8..bcc1d2e59 100644 --- a/src/slic3r/GUI/Notebook.cpp +++ b/src/slic3r/GUI/Notebook.cpp @@ -50,7 +50,7 @@ void ButtonsListCtrl::OnPaint(wxPaintEvent&) const wxColour& selected_btn_bg = Slic3r::GUI::wxGetApp().get_color_selected_btn_bg(); const wxColour& default_btn_bg = Slic3r::GUI::wxGetApp().get_highlight_default_clr(); const wxColour& btn_marker_color = Slic3r::GUI::wxGetApp().get_color_hovered_btn_label(); - for (int idx = 0; idx < m_pageButtons.size(); idx++) { + for (int idx = 0; idx < int(m_pageButtons.size()); idx++) { wxButton* btn = m_pageButtons[idx]; btn->SetBackgroundColour(idx == m_selection ? selected_btn_bg : default_btn_bg); diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 6f51f0cf8..61b5d8f43 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -1,10 +1,12 @@ #include "NotificationManager.hpp" - +#include "HintNotification.hpp" #include "GUI.hpp" #include "ImGuiWrapper.hpp" #include "PrintHostDialogs.hpp" #include "wxExtensions.hpp" +#include "ObjectDataViewModel.hpp" +#include "libslic3r/Config.hpp" #include "../Utils/PrintHost.hpp" #include "libslic3r/Config.hpp" @@ -30,7 +32,37 @@ wxDEFINE_EVENT(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, EjectDriveNotificationClicke wxDEFINE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClickedEvent); wxDEFINE_EVENT(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, PresetUpdateAvailableClickedEvent); -namespace Notifications_Internal{ +const NotificationManager::NotificationData NotificationManager::basic_notifications[] = { + {NotificationType::Mouse3dDisconnected, NotificationLevel::RegularNotification, 10, _u8L("3D Mouse disconnected.") }, + {NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 20, _u8L("Configuration update is available."), _u8L("See more."), + [](wxEvtHandler* evnthndlr) { + if (evnthndlr != nullptr) + wxPostEvent(evnthndlr, PresetUpdateAvailableClickedEvent(EVT_PRESET_UPDATE_AVAILABLE_CLICKED)); + return true; + } + }, + {NotificationType::NewAppAvailable, NotificationLevel::ImportantNotification, 20, _u8L("New version is available."), _u8L("See Releases page."), [](wxEvtHandler* evnthndlr) { + wxLaunchDefaultBrowser("https://github.com/prusa3d/PrusaSlicer/releases"); return true; }}, + {NotificationType::EmptyColorChangeCode, NotificationLevel::RegularNotification, 10, + _u8L("You have just added a G-code for color change, but its value is empty.\n" + "To export the G-code correctly, check the \"Color Change G-code\" in \"Printer Settings > Custom G-code\"") }, + {NotificationType::EmptyAutoColorChange, NotificationLevel::RegularNotification, 10, + _u8L("This model doesn't allow to automatically add the color changes") }, + {NotificationType::DesktopIntegrationSuccess, NotificationLevel::RegularNotification, 10, + _u8L("Desktop integration was successful.") }, + {NotificationType::DesktopIntegrationFail, NotificationLevel::WarningNotification, 10, + _u8L("Desktop integration failed.") }, + {NotificationType::UndoDesktopIntegrationSuccess, NotificationLevel::RegularNotification, 10, + _u8L("Undo desktop integration was successful.") }, + {NotificationType::UndoDesktopIntegrationFail, NotificationLevel::WarningNotification, 10, + _u8L("Undo desktop integration failed.") }, + //{NotificationType::NewAppAvailable, NotificationLevel::ImportantNotification, 20, _u8L("New vesion of PrusaSlicer is available.", _u8L("Download page.") }, + //{NotificationType::LoadingFailed, NotificationLevel::RegularNotification, 20, _u8L("Loading of model has Failed") }, + //{NotificationType::DeviceEjected, NotificationLevel::RegularNotification, 10, _u8L("Removable device has been safely ejected")} // if we want changeble text (like here name of device), we need to do it as CustomNotification +}; + +namespace { + /* // not used? ImFont* add_default_font(float pixel_size) { ImGuiIO& io = ImGui::GetIO(); @@ -41,8 +73,8 @@ namespace Notifications_Internal{ ImFont* font = io.Fonts->AddFontDefault(&config); return font; } - - static inline void push_style_color(ImGuiCol idx, const ImVec4& col, bool fading_out, float current_fade_opacity) + */ + inline void push_style_color(ImGuiCol idx, const ImVec4& col, bool fading_out, float current_fade_opacity) { if (fading_out) ImGui::PushStyleColor(idx, ImVec4(col.x, col.y, col.z, col.w * current_fade_opacity)); @@ -129,8 +161,8 @@ NotificationManager::PopNotification::PopNotification(const NotificationData &n, m_data (n) , m_id_provider (id_provider) , m_text1 (n.text1) - , m_hypertext (n.hypertext) - , m_text2 (n.text2) + , m_hypertext (n.hypertext) + , m_text2 (n.text2) , m_evt_handler (evt_handler) , m_notification_start (GLCanvas3D::timestamp_now()) {} @@ -184,8 +216,8 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init // color change based on fading out if (m_state == EState::FadingOut) { - Notifications_Internal::push_style_color(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), true, m_current_fade_opacity); - Notifications_Internal::push_style_color(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text), true, m_current_fade_opacity); + push_style_color(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), true, m_current_fade_opacity); + push_style_color(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text), true, m_current_fade_opacity); fading_pop = true; } @@ -219,20 +251,20 @@ bool NotificationManager::PopNotification::push_background_color() { if (m_is_gray) { ImVec4 backcolor(0.7f, 0.7f, 0.7f, 0.5f); - Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity); return true; } if (m_data.level == NotificationLevel::ErrorNotification) { ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); backcolor.x += 0.3f; - Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity); return true; } if (m_data.level == NotificationLevel::WarningNotification) { ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); backcolor.x += 0.3f; backcolor.y += 0.15f; - Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity); return true; } return false; @@ -259,6 +291,9 @@ void NotificationManager::PopNotification::count_lines() size_t last_end = 0; m_lines_count = 0; + if (text.empty()) + return; + m_endlines.clear(); while (last_end < text.length() - 1) { @@ -272,9 +307,9 @@ void NotificationManager::PopNotification::count_lines() // find next suitable endline if (ImGui::CalcTextSize(text.substr(last_end).c_str()).x >= m_window_width - m_window_width_offset) { // more than one line till end - int next_space = text.find_first_of(' ', last_end); + size_t next_space = text.find_first_of(' ', last_end); if (next_space > 0 && next_space < text.length()) { - int next_space_candidate = text.find_first_of(' ', next_space + 1); + size_t next_space_candidate = text.find_first_of(' ', next_space + 1); while (next_space_candidate > 0 && ImGui::CalcTextSize(text.substr(last_end, next_space_candidate - last_end).c_str()).x < m_window_width - m_window_width_offset) { next_space = next_space_candidate; next_space_candidate = text.find_first_of(' ', next_space + 1); @@ -283,7 +318,9 @@ void NotificationManager::PopNotification::count_lines() next_space = text.length(); } // when one word longer than line. - if (ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x > m_window_width - m_window_width_offset) { + if (ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x > m_window_width - m_window_width_offset || + ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x < (m_window_width - m_window_width_offset) / 4 * 3 + ) { float width_of_a = ImGui::CalcTextSize("a").x; int letter_count = (int)((m_window_width - m_window_width_offset) / width_of_a); while (last_end + letter_count < text.size() && ImGui::CalcTextSize(text.substr(last_end, letter_count).c_str()).x < m_window_width - m_window_width_offset) { @@ -312,6 +349,9 @@ void NotificationManager::PopNotification::count_lines() m_lines_count++; } } + + // m_text_2 (text after hypertext) is not used for regular notifications right now. + // its caluculation is in HintNotification::count_lines() } void NotificationManager::PopNotification::init() @@ -339,105 +379,45 @@ void NotificationManager::PopNotification::set_next_window_size(ImGuiWrapper& im void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { - ImVec2 win_size(win_size_x, win_size_y); - float x_offset = m_left_indentation; - std::string fulltext = m_text1 + m_hypertext; //+ m_text2; - ImVec2 text_size = ImGui::CalcTextSize(fulltext.c_str()); - // text posistions are calculated by lines count - // large texts has "more" button or are displayed whole - // smaller texts are divided as one liners and two liners - if (m_lines_count > 2) { - if (m_multiline) { - - int last_end = 0; - float starting_y = m_line_height/2; - float shift_y = m_line_height; - std::string line; + float x_offset = m_left_indentation; + int last_end = 0; + float starting_y = (m_lines_count == 2 ? win_size_y / 2 - m_line_height : (m_lines_count == 1 ? win_size_y / 2 - m_line_height / 2 : m_line_height / 2)); + float shift_y = m_line_height; + std::string line; - for (size_t i = 0; i < m_lines_count; i++) { - line.clear(); - ImGui::SetCursorPosX(x_offset); - ImGui::SetCursorPosY(starting_y + i * shift_y); - if (m_endlines.size() > i && m_text1.size() >= m_endlines[i]) { - line = m_text1.substr(last_end, m_endlines[i] - last_end); - last_end = m_endlines[i]; - if (m_text1.size() > m_endlines[i]) - last_end += (m_text1[m_endlines[i]] == '\n' || m_text1[m_endlines[i]] == ' ' ? 1 : 0); - imgui.text(line.c_str()); - } - } - //hyperlink text - if (!m_hypertext.empty()) { - render_hypertext(imgui, x_offset + ImGui::CalcTextSize((line + (line.empty() ? "" : " ")).c_str()).x, starting_y + (m_lines_count - 1) * shift_y, m_hypertext); - } - - - } else { - // line1 - if (m_text1.size() >= m_endlines[0]) { - ImGui::SetCursorPosX(x_offset); - ImGui::SetCursorPosY(win_size.y / 2 - win_size.y / 6 - m_line_height / 2); - imgui.text(m_text1.substr(0, m_endlines[0]).c_str()); - } - // line2 - std::string line; - ImGui::SetCursorPosX(x_offset); - ImGui::SetCursorPosY(win_size.y / 2 + win_size.y / 6 - m_line_height / 2); - if (m_text1.size() >= m_endlines[1]) { + for (size_t i = 0; i < (m_multiline ? m_endlines.size() : std::min(m_endlines.size(), (size_t)2)); i++) { + line.clear(); + ImGui::SetCursorPosX(x_offset); + ImGui::SetCursorPosY(starting_y + i * shift_y); + if (m_endlines.size() > i && m_text1.size() >= m_endlines[i]) { + if (i == 1 && m_endlines.size() > 2 && !m_multiline) { + // second line with "more" hypertext line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0), m_endlines[1] - m_endlines[0] - (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0)); - if (ImGui::CalcTextSize(line.c_str()).x > m_window_width - m_window_width_offset - ImGui::CalcTextSize((".." + _u8L("More")).c_str()).x) { - line = line.substr(0, line.length() - 6); - line += ".."; - } else - line += " "; - imgui.text(line.c_str()); + while (ImGui::CalcTextSize(line.c_str()).x > m_window_width - m_window_width_offset - ImGui::CalcTextSize((".." + _u8L("More")).c_str()).x) { + line = line.substr(0, line.length() - 1); + } + line += ".."; } - // "More" hypertext - render_hypertext(imgui, x_offset + ImGui::CalcTextSize(line.c_str()).x, win_size.y / 2 + win_size.y / 6 - m_line_height / 2, _u8L("More"), true); - } - } else { - //text 1 - float cursor_y = win_size.y / 2 - text_size.y / 2; - float cursor_x = x_offset; - if(m_lines_count > 1) { - // line1 - if (m_text1.length() >= m_endlines[0]) { // could be equal than substr takes whole string - ImGui::SetCursorPosX(x_offset); - ImGui::SetCursorPosY(win_size.y / 2 - win_size.y / 6 - m_line_height / 2); - imgui.text(m_text1.substr(0, m_endlines[0]).c_str()); + else { + // regural line + line = m_text1.substr(last_end, m_endlines[i] - last_end); } - // line2 - ImGui::SetCursorPosX(x_offset); - cursor_y = win_size.y / 2 + win_size.y / 6 - m_line_height / 2; - ImGui::SetCursorPosY(cursor_y); - if (m_text1.length() > m_endlines[0]) { // must be greater otherwise theres nothing to show and m_text1[m_endlines[0]] is beyond last letter - std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0)); - imgui.text(line.c_str()); - cursor_x = x_offset + ImGui::CalcTextSize(line.c_str()).x; - } - } else { - ImGui::SetCursorPosX(x_offset); - ImGui::SetCursorPosY(cursor_y); - imgui.text(m_text1.c_str()); - cursor_x = x_offset + ImGui::CalcTextSize(m_text1.c_str()).x; + last_end = m_endlines[i]; + if (m_text1.size() > m_endlines[i]) + last_end += (m_text1[m_endlines[i]] == '\n' || m_text1[m_endlines[i]] == ' ' ? 1 : 0); + imgui.text(line.c_str()); } - //hyperlink text - if (!m_hypertext.empty()) { - render_hypertext(imgui, cursor_x + 4, cursor_y, m_hypertext); - } - - //notification text 2 - //text 2 is suposed to be after the hyperlink - currently it is not used - /* - if (!m_text2.empty()) - { - ImVec2 part_size = ImGui::CalcTextSize(m_hypertext.c_str()); - ImGui::SetCursorPosX(win_size.x / 2 + text_size.x / 2 - part_size.x + 8 - x_offset); - ImGui::SetCursorPosY(cursor_y); - imgui.text(m_text2.c_str()); - } - */ } + //hyperlink text + if (!m_multiline && m_lines_count > 2) { + render_hypertext(imgui, x_offset + ImGui::CalcTextSize((line + " ").c_str()).x, starting_y + shift_y, _u8L("More"), true); + } + else if (!m_hypertext.empty()) { + render_hypertext(imgui, x_offset + ImGui::CalcTextSize((line + (line.empty() ? "" : " ")).c_str()).x, starting_y + (m_endlines.size() - 1) * shift_y, m_hypertext); + } + + // text2 (text after hypertext) is not rendered for regular notifications + // its rendering is in HintNotification::render_text } void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui, const float text_x, const float text_y, const std::string text, bool more) @@ -470,7 +450,7 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui, orange_color.y += 0.2f; //text - Notifications_Internal::push_style_color(ImGuiCol_Text, orange_color, m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_Text, orange_color, m_state == EState::FadingOut, m_current_fade_opacity); ImGui::SetCursorPosX(text_x); ImGui::SetCursorPosY(text_y); imgui.text(text.c_str()); @@ -491,8 +471,8 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img ImVec2 win_pos(win_pos_x, win_pos_y); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); - Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); - Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); @@ -542,9 +522,9 @@ void NotificationManager::PopNotification::render_minimize_button(ImGuiWrapper& { ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); - Notifications_Internal::push_style_color(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_state == EState::FadingOut, m_current_fade_opacity); - Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); - Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); //button - if part if treggered @@ -762,8 +742,8 @@ void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiW ImVec2 win_pos(win_pos_x, win_pos_y); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); - Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); - Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); std::string button_text; @@ -818,7 +798,7 @@ void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiW } bool NotificationManager::ExportFinishedNotification::on_text_click() { - Notifications_Internal::open_folder(m_export_dir_path); + open_folder(m_export_dir_path); return false; } //------ProgressBar---------------- @@ -961,7 +941,7 @@ bool NotificationManager::PrintHostUploadNotification::push_background_color() if (m_uj_state == UploadJobState::PB_ERROR) { ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); backcolor.x += 0.3f; - Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity); return true; } return false; @@ -1031,8 +1011,8 @@ void NotificationManager::PrintHostUploadNotification::render_cancel_button(ImGu ImVec2 win_pos(win_pos_x, win_pos_y); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); - Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); - Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); std::string button_text; @@ -1079,8 +1059,37 @@ void NotificationManager::PrintHostUploadNotification::render_cancel_button(ImGu ImGui::PopStyleColor(); ImGui::PopStyleColor(); ImGui::PopStyleColor(); - } +//------UpdatedItemsInfoNotification------- +void NotificationManager::UpdatedItemsInfoNotification::count_spaces() +{ + //determine line width + m_line_height = ImGui::CalcTextSize("A").y; + + std::string text; + text = ImGui::WarningMarker; + float picture_width = ImGui::CalcTextSize(text.c_str()).x; + m_left_indentation = picture_width + m_line_height / 2; + + m_window_width_offset = m_left_indentation + m_line_height * 3.f; + m_window_width = m_line_height * 25; +} +void NotificationManager::UpdatedItemsInfoNotification::render_left_sign(ImGuiWrapper& imgui) +{ + std::string text; + switch (m_info_item_type) { + case InfoItemType::CustomSupports: text = ImGui::CustomSupportsMarker; break; + case InfoItemType::CustomSeam: text = ImGui::CustomSeamMarker; break; + case InfoItemType::MmuSegmentation: text = ImGui::MmuSegmentationMarker; break; + case InfoItemType::VariableLayerHeight: text = ImGui::VarLayerHeightMarker; break; + case InfoItemType::Sinking: text = ImGui::SinkingObjectMarker; break; + default: break; + } + ImGui::SetCursorPosX(m_line_height / 3); + ImGui::SetCursorPosY(m_window_height / 2 - m_line_height); + imgui.text(text.c_str()); +} + //------NotificationManager-------- NotificationManager::NotificationManager(wxEvtHandler* evt_handler) : m_evt_handler(evt_handler) @@ -1088,10 +1097,10 @@ NotificationManager::NotificationManager(wxEvtHandler* evt_handler) : } void NotificationManager::push_notification(const NotificationType type, int timestamp) { - auto it = std::find_if(basic_notifications.begin(), basic_notifications.end(), + auto it = std::find_if(std::begin(basic_notifications), std::end(basic_notifications), boost::bind(&NotificationData::type, boost::placeholders::_1) == type); - assert(it != basic_notifications.end()); - if (it != basic_notifications.end()) + assert(it != std::end(basic_notifications)); + if (it != std::end(basic_notifications)) push_notification_data(*it, timestamp); } void NotificationManager::push_notification(const std::string& text, int timestamp) @@ -1108,15 +1117,22 @@ void NotificationManager::push_notification(NotificationType type, { int duration = 0; switch (level) { - case NotificationLevel::RegularNotification: duration = 10; break; - case NotificationLevel::ErrorNotification: break; - case NotificationLevel::ImportantNotification: break; + case NotificationLevel::RegularNotification: duration = 10; break; + case NotificationLevel::ErrorNotification: break; + case NotificationLevel::WarningNotification: break; + case NotificationLevel::ImportantNotification: break; + case NotificationLevel::ProgressBarNotification: break; default: assert(false); return; } push_notification_data({ type, level, duration, text, hypertext, callback }, timestamp); } +void NotificationManager::push_validate_error_notification(const std::string& text) +{ + push_notification_data({ NotificationType::ValidateError, NotificationLevel::ErrorNotification, 0, _u8L("ERROR:") + "\n" + text }, 0); +} + void NotificationManager::push_slicing_error_notification(const std::string& text) { set_all_slicing_errors_gray(false); @@ -1331,6 +1347,32 @@ void NotificationManager::upload_job_notification_show_error(int id, const std:: } } } +void NotificationManager::push_hint_notification() +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::DidYouKnowHint) + return; + } + NotificationData data{ NotificationType::DidYouKnowHint, NotificationLevel::RegularNotification, 0, "" }; + push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler), 0); +} + +void NotificationManager::push_updated_item_info_notification(InfoItemType type) +{ + std::string text = _utf8("Object(s) were loaded with "); + switch (type) { + case InfoItemType::CustomSupports: text += _utf8("custom supports."); break; + case InfoItemType::CustomSeam: text += _utf8("custom seam."); break; + case InfoItemType::MmuSegmentation: text += _utf8("MMU segmentation."); break; + case InfoItemType::VariableLayerHeight: text += _utf8("variable layer height."); break; + case InfoItemType::Sinking: text = _utf8("Partially sinking object(s) were loaded."); break; + default: text.clear(); break; + } + if (!text.empty()) { + NotificationData data{ NotificationType::UpdatedItemsInfo, NotificationLevel::RegularNotification, 10, text }; + push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler, type), 0); + } +} bool NotificationManager::push_notification_data(const NotificationData& notification_data, int timestamp) { return push_notification_data(std::make_unique(notification_data, m_id_provider, m_evt_handler), timestamp); diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 17db606c0..2c5c85b19 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -29,6 +29,7 @@ wxDECLARE_EVENT(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, PresetUpdateAvailableClicke class GLCanvas3D; class ImGuiWrapper; +enum class InfoItemType; enum class NotificationType { @@ -55,8 +56,11 @@ enum class NotificationType // Contains a hyperlink to execute installation of the new system profiles. PresetUpdateAvailable, // LoadingFailed, - // Not used - instead Slicing error is used for both slicing and validate errors. -// ValidateError, + // Errors emmited by Print::validate + // difference from Slicing error is that they disappear not grey out at update_background_process + ValidateError, + // Notification emitted by Print::validate + ValidateWarning, // Slicing error produced by BackgroundSlicingProcess::validate() or by the BackgroundSlicingProcess background // thread thowing a SlicingError exception. SlicingError, @@ -79,8 +83,6 @@ enum class NotificationType EmptyAutoColorChange, // Notification about detected sign SignDetected, - // Notification emitted by Print::validate - PrintValidateWarning, // Notification telling user to quit SLA supports manual editing QuitSLAManualMode, // Desktop integration basic info @@ -89,8 +91,12 @@ enum class NotificationType UndoDesktopIntegrationSuccess, UndoDesktopIntegrationFail, // Notification that a printer has more extruders than are supported by MM Gizmo/segmentation. - MmSegmentationExceededExtrudersLimit - + MmSegmentationExceededExtrudersLimit, + // Did you know Notification appearing on startup with arrows to change hint + DidYouKnowHint, + // Shows when ObjectList::update_info_items finds information that should be stressed to the user + // Might contain logo taken from gizmos + UpdatedItemsInfo }; class NotificationManager @@ -122,6 +128,8 @@ public: // ErrorNotification and ImportantNotification are never faded out. void push_notification(NotificationType type, NotificationLevel level, const std::string& text, const std::string& hypertext = "", std::function callback = std::function(), int timestamp = 0); + // Creates Validate Error notification with a custom text and no fade out. + void push_validate_error_notification(const std::string& text); // Creates Slicing Error notification with a custom text and no fade out. void push_slicing_error_notification(const std::string& text); // Creates Slicing Warning notification with a custom text and no fade out. @@ -160,6 +168,9 @@ public: void set_upload_job_notification_percentage(int id, const std::string& filename, const std::string& host, float percentage); void upload_job_notification_show_canceled(int id, const std::string& filename, const std::string& host); void upload_job_notification_show_error(int id, const std::string& filename, const std::string& host); + // Hint (did you know) notification + void push_hint_notification(); + void push_updated_item_info_notification(InfoItemType type); // Close old notification ExportFinished. void new_export_began(bool on_removable); // finds ExportFinished notification and closes it if it was to removable device @@ -188,7 +199,7 @@ private: // Callback for hypertext - returns true if notification should close after triggering // Usually sends event to UI thread thru wxEvtHandler. // Examples in basic_notifications. - std::function callback { nullptr }; + std::function callback; const std::string text2; }; @@ -237,7 +248,7 @@ private: //returns top in actual frame float get_current_top() const { return m_top_y; } const NotificationType get_type() const { return m_data.type; } - const NotificationData get_data() const { return m_data; } + const NotificationData& get_data() const { return m_data; } const bool is_gray() const { return m_is_gray; } void set_gray(bool g) { m_is_gray = g; } virtual bool compare_text(const std::string& text) const; @@ -318,7 +329,10 @@ private: float m_top_y { 0.0f }; // Height of text - Used as basic scaling unit! float m_line_height; + // endlines for text1, hypertext excluded std::vector m_endlines; + // endlines for text2 + std::vector m_endlines2; // Gray are f.e. eorrors when its uknown if they are still valid bool m_is_gray { false }; //if multiline = true, notification is showing all lines(>2) @@ -337,7 +351,7 @@ private: void set_large(bool l); bool get_large() { return m_is_large; } void set_print_info(const std::string &info); - virtual void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width) override + void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width) override { // This notification is always hidden if !large (means side bar is collapsed) if (!get_large() && !is_finished()) @@ -345,7 +359,7 @@ private: PopNotification::render(canvas, initial_y, move_from_overlay, overlay_width); } protected: - virtual void render_text(ImGuiWrapper& imgui, + void render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) override; @@ -366,7 +380,7 @@ private: { public: PlaterWarningNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler) : PopNotification(n, id_provider, evt_handler) {} - virtual void close() override { if(is_finished()) return; m_state = EState::Hidden; wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); } + void close() override { if(is_finished()) return; m_state = EState::Hidden; wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); } void real_close() { m_state = EState::ClosePending; wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); } void show() { m_state = EState::Unknown; } }; @@ -382,17 +396,17 @@ private: virtual void init() override; virtual void count_lines() override; - virtual void render_text(ImGuiWrapper& imgui, + virtual void render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) override; - virtual void render_bar(ImGuiWrapper& imgui, + virtual void render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) ; - virtual void render_cancel_button(ImGuiWrapper& imgui, + virtual void render_cancel_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) {} - virtual void render_minimize_button(ImGuiWrapper& imgui, + void render_minimize_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y) override {} float m_percentage; @@ -421,22 +435,22 @@ private: m_has_cancel_button = true; } static std::string get_upload_job_text(int id, const std::string& filename, const std::string& host) { return /*"[" + std::to_string(id) + "] " + */filename + " -> " + host; } - virtual void set_percentage(float percent) override; + void set_percentage(float percent) override; void cancel() { m_uj_state = UploadJobState::PB_CANCELLED; m_has_cancel_button = false; } void error() { m_uj_state = UploadJobState::PB_ERROR; m_has_cancel_button = false; init(); } bool compare_job_id(const int other_id) const { return m_job_id == other_id; } - virtual bool compare_text(const std::string& text) const override { return false; } + bool compare_text(const std::string& text) const override { return false; } protected: - virtual void init() override; - virtual void count_spaces() override; - virtual bool push_background_color() override; - virtual void render_bar(ImGuiWrapper& imgui, + void init() override; + void count_spaces() override; + bool push_background_color() override; + void render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) override; - virtual void render_cancel_button(ImGuiWrapper& imgui, + void render_cancel_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) override; - virtual void render_left_sign(ImGuiWrapper& imgui) override; + void render_left_sign(ImGuiWrapper& imgui) override; // Identifies job in cancel callback int m_job_id; // Size of uploaded size to be displayed in MB @@ -461,24 +475,41 @@ private: std::string m_export_dir_path; protected: // Reserves space on right for more buttons - virtual void count_spaces() override; - virtual void render_text(ImGuiWrapper& imgui, - const float win_size_x, const float win_size_y, - const float win_pos_x, const float win_pos_y) override; + void count_spaces() override; + void render_text(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y) override; // Renders also button to open directory with exported path and eject removable media - virtual void render_close_button(ImGuiWrapper& imgui, - const float win_size_x, const float win_size_y, - const float win_pos_x, const float win_pos_y) override; + void render_close_button(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y) override; void render_eject_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y); - virtual void render_minimize_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y) override + void render_minimize_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y) override { m_minimize_b_visible = false; } - virtual bool on_text_click() override; + bool on_text_click() override; // local time of last hover for showing tooltip long m_hover_time { 0 }; }; + class UpdatedItemsInfoNotification : public PopNotification + { + public: + UpdatedItemsInfoNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, InfoItemType info_item_type) + : PopNotification(n, id_provider, evt_handler) + , m_info_item_type(info_item_type) + { + } + void count_spaces() override; + protected: + void render_left_sign(ImGuiWrapper& imgui) override; + InfoItemType m_info_item_type; + }; + + // in HintNotification.hpp + class HintNotification; + //pushes notification into the queue of notifications that are rendered //can be used to create custom notification bool push_notification_data(const NotificationData& notification_data, int timestamp); @@ -504,36 +535,9 @@ private: // Timestamp of last rendering int64_t m_last_render { 0LL }; // Notification types that can be shown multiple types at once (compared by text) - const std::vector m_multiple_types = { NotificationType::CustomNotification, NotificationType::PlaterWarning, NotificationType::ProgressBar, NotificationType::PrintHostUpload }; + const std::vector m_multiple_types = { NotificationType::CustomNotification, NotificationType::PlaterWarning, NotificationType::ProgressBar, NotificationType::PrintHostUpload, NotificationType::UpdatedItemsInfo }; //prepared (basic) notifications - const std::vector basic_notifications = { - {NotificationType::Mouse3dDisconnected, NotificationLevel::RegularNotification, 10, _u8L("3D Mouse disconnected.") }, - {NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 20, _u8L("Configuration update is available."), _u8L("See more."), - [](wxEvtHandler* evnthndlr) { - if (evnthndlr != nullptr) - wxPostEvent(evnthndlr, PresetUpdateAvailableClickedEvent(EVT_PRESET_UPDATE_AVAILABLE_CLICKED)); - return true; - } - }, - {NotificationType::NewAppAvailable, NotificationLevel::ImportantNotification, 20, _u8L("New version is available."), _u8L("See Releases page."), [](wxEvtHandler* evnthndlr){ - wxLaunchDefaultBrowser("https://github.com/prusa3d/PrusaSlicer/releases"); return true; }}, - {NotificationType::EmptyColorChangeCode, NotificationLevel::RegularNotification, 10, - _u8L("You have just added a G-code for color change, but its value is empty.\n" - "To export the G-code correctly, check the \"Color Change G-code\" in \"Printer Settings > Custom G-code\"") }, - {NotificationType::EmptyAutoColorChange, NotificationLevel::RegularNotification, 10, - _u8L("This model doesn't allow to automatically add the color changes") }, - {NotificationType::DesktopIntegrationSuccess, NotificationLevel::RegularNotification, 10, - _u8L("Desktop integration was successful.") }, - {NotificationType::DesktopIntegrationFail, NotificationLevel::WarningNotification, 10, - _u8L("Desktop integration failed.") }, - {NotificationType::UndoDesktopIntegrationSuccess, NotificationLevel::RegularNotification, 10, - _u8L("Undo desktop integration was successful.") }, - {NotificationType::UndoDesktopIntegrationFail, NotificationLevel::WarningNotification, 10, - _u8L("Undo desktop integration failed.") }, - //{NotificationType::NewAppAvailable, NotificationLevel::ImportantNotification, 20, _u8L("New vesion of PrusaSlicer is available.", _u8L("Download page.") }, - //{NotificationType::LoadingFailed, NotificationLevel::RegularNotification, 20, _u8L("Loading of model has Failed") }, - //{NotificationType::DeviceEjected, NotificationLevel::RegularNotification, 10, _u8L("Removable device has been safely ejected")} // if we want changeble text (like here name of device), we need to do it as CustomNotification - }; + static const NotificationData basic_notifications[]; }; }//namespace GUI diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index ec09731c5..8f65e4f90 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -65,6 +65,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent m_name = info_type == InfoItemType::CustomSupports ? _L("Paint-on supports") : info_type == InfoItemType::CustomSeam ? _L("Paint-on seam") : info_type == InfoItemType::MmuSegmentation ? _L("Paint-on segmentation") : + info_type == InfoItemType::Sinking ? _L("Sinking") : _L("Variable layer height"); m_info_item_type = info_type; } diff --git a/src/slic3r/GUI/ObjectDataViewModel.hpp b/src/slic3r/GUI/ObjectDataViewModel.hpp index 7d3b132ba..664cf7ff5 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.hpp +++ b/src/slic3r/GUI/ObjectDataViewModel.hpp @@ -51,6 +51,7 @@ enum class InfoItemType CustomSupports, CustomSeam, MmuSegmentation, + Sinking, VariableLayerHeight }; diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index 7d20b15e5..f7593ba16 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -47,7 +47,7 @@ PresetForPrinter::PresetForPrinter(PhysicalPrinterDialog* parent, const std::str { m_sizer = new wxBoxSizer(wxVERTICAL); - m_delete_preset_btn = new ScalableButton(parent, wxID_ANY, "cross", "", wxDefaultSize, wxDefaultPosition, /*wxBU_LEFT | */wxBU_EXACTFIT); + m_delete_preset_btn = new ScalableButton(parent, wxID_ANY, "cross"); m_delete_preset_btn->SetFont(wxGetApp().normal_font()); m_delete_preset_btn->SetToolTip(_L("Delete this preset from this printer device")); m_delete_preset_btn->Bind(wxEVT_BUTTON, &PresetForPrinter::DeletePreset, this); @@ -175,7 +175,7 @@ PhysicalPrinterDialog::PhysicalPrinterDialog(wxWindow* parent, wxString printer_ wxStaticText* label_top = new wxStaticText(this, wxID_ANY, _L("Descriptive name for the printer") + ":"); - m_add_preset_btn = new ScalableButton(this, wxID_ANY, "add_copies", "", wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT); + m_add_preset_btn = new ScalableButton(this, wxID_ANY, "add_copies"); m_add_preset_btn->SetFont(wxGetApp().normal_font()); m_add_preset_btn->SetToolTip(_L("Add preset for this printer device")); m_add_preset_btn->Bind(wxEVT_BUTTON, &PhysicalPrinterDialog::AddPreset, this); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 25749334d..209604afb 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -82,9 +82,7 @@ #include "NotificationManager.hpp" #include "PresetComboBoxes.hpp" #include "MsgDialog.hpp" -#if ENABLE_PROJECT_DIRTY_STATE #include "ProjectDirtyStateManager.hpp" -#endif // ENABLE_PROJECT_DIRTY_STATE #ifdef __APPLE__ #include "Gizmos/GLGizmosManager.hpp" @@ -1045,6 +1043,12 @@ void Sidebar::search() p->searcher.search(); } +void Sidebar::jump_to_option(const std::string& opt_key, Preset::Type type, const std::wstring& category) +{ + //const Search::Option& opt = p->searcher.get_option(opt_key, type); + wxGetApp().get_tab(type)->activate_option(opt_key, category); +} + void Sidebar::jump_to_option(size_t selected) { const Search::Option& opt = p->searcher.get_option(selected); @@ -1454,13 +1458,9 @@ bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &fi this->MSWUpdateDragImageOnLeave(); #endif // WIN32 -#if ENABLE_PROJECT_DIRTY_STATE bool res = (m_plater != nullptr) ? m_plater->load_files(filenames) : false; wxGetApp().mainframe->update_title(); return res; -#else - return (m_plater != nullptr) ? m_plater->load_files(filenames) : false; -#endif // ENABLE_PROJECT_DIRTY_STATE } // State to manage showing after export notifications and device ejecting @@ -1504,9 +1504,7 @@ struct Plater::priv Preview *preview; NotificationManager* notification_manager { nullptr }; -#if ENABLE_PROJECT_DIRTY_STATE ProjectDirtyStateManager dirty_state; -#endif // ENABLE_PROJECT_DIRTY_STATE BackgroundSlicingProcess background_process; bool suppressed_backround_processing_update { false }; @@ -1565,9 +1563,7 @@ struct Plater::priv std::string label_btn_export; std::string label_btn_send; -#if ENABLE_RENDER_STATISTICS bool show_render_statistic_dialog{ false }; -#endif // ENABLE_RENDER_STATISTICS static const std::regex pattern_bundle; static const std::regex pattern_3mf; @@ -1578,7 +1574,6 @@ struct Plater::priv priv(Plater *q, MainFrame *main_frame); ~priv(); -#if ENABLE_PROJECT_DIRTY_STATE bool is_project_dirty() const { return dirty_state.is_dirty(); } void update_project_dirty_from_presets() { dirty_state.update_from_presets(); } bool save_project_if_dirty() { @@ -1602,7 +1597,6 @@ struct Plater::priv #if ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW void render_project_state_debug_window() const { dirty_state.render_debug_window(); } #endif // ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW -#endif // ENABLE_PROJECT_DIRTY_STATE enum class UpdateParams { FORCE_FULL_SCREEN_REFRESH = 1, @@ -1650,11 +1644,8 @@ struct Plater::priv BoundingBox scaled_bed_shape_bb() const; std::vector load_files(const std::vector& input_files, bool load_model, bool load_config, bool used_inches = false); -#if ENABLE_ALLOW_NEGATIVE_Z std::vector load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false); -#else - std::vector load_model_objects(const ModelObjectPtrs &model_objects); -#endif // ENABLE_ALLOW_NEGATIVE_Z + wxString get_export_file(GUI::FileType file_type); const Selection& get_selection() const; @@ -2418,19 +2409,11 @@ std::vector Plater::priv::load_files(const std::vector& input_ return obj_idxs; } -#if ENABLE_ALLOW_NEGATIVE_Z for (ModelObject* model_object : model.objects) { if (!type_3mf && !type_zip_amf) model_object->center_around_origin(false); model_object->ensure_on_bed(is_project_file); } -#else - for (ModelObject* model_object : model.objects) { - if (!type_3mf && !type_zip_amf) - model_object->center_around_origin(false); - model_object->ensure_on_bed(); - } -#endif // ENABLE_ALLOW_NEGATIVE_Z // check multi-part object adding for the SLA-printing if (printer_technology == ptSLA) { @@ -2444,11 +2427,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ } if (one_by_one) { -#if ENABLE_ALLOW_NEGATIVE_Z auto loaded_idxs = load_model_objects(model.objects, is_project_file); -#else - auto loaded_idxs = load_model_objects(model.objects); -#endif // ENABLE_ALLOW_NEGATIVE_Z obj_idxs.insert(obj_idxs.end(), loaded_idxs.begin(), loaded_idxs.end()); } else { // This must be an .stl or .obj file, which may contain a maximum of one volume. @@ -2501,11 +2480,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ // #define AUTOPLACEMENT_ON_LOAD -#if ENABLE_ALLOW_NEGATIVE_Z std::vector Plater::priv::load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z) -#else -std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &model_objects) -#endif // ENABLE_ALLOW_NEGATIVE_Z { const BoundingBoxf bed_shape = bed_shape_bb(); const Vec3d bed_size = Slic3r::to_3d(bed_shape.size().cast(), 1.0) - 2.0 * Vec3d::Ones(); @@ -2540,7 +2515,6 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &mode #endif /* AUTOPLACEMENT_ON_LOAD */ } -#if ENABLE_MODIFIED_DOWNSCALE_ON_LOAD_OBJECTS_TOO_BIG for (size_t i = 0; i < object->instances.size(); ++i) { ModelInstance* instance = object->instances[i]; const Vec3d size = object->instance_bounding_box(i).size(); @@ -2562,32 +2536,8 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &mode scaled_down = true; } } -#else - const Vec3d size = object->bounding_box().size(); - const Vec3d ratio = size.cwiseQuotient(bed_size); - const double max_ratio = std::max(ratio(0), ratio(1)); - if (max_ratio > 10000) { - // the size of the object is too big -> this could lead to overflow when moving to clipper coordinates, - // so scale down the mesh - double inv = 1. / max_ratio; - object->scale_mesh_after_creation(Vec3d(inv, inv, inv)); - object->origin_translation = Vec3d::Zero(); - object->center_around_origin(); - scaled_down = true; - } else if (max_ratio > 5) { - const Vec3d inverse = 1.0 / max_ratio * Vec3d::Ones(); - for (ModelInstance *instance : object->instances) { - instance->set_scaling_factor(inverse); - } - scaled_down = true; - } -#endif // ENABLE_MODIFIED_DOWNSCALE_ON_LOAD_OBJECTS_TOO_BIG -#if ENABLE_ALLOW_NEGATIVE_Z object->ensure_on_bed(allow_negative_z); -#else - object->ensure_on_bed(); -#endif // ENABLE_ALLOW_NEGATIVE_Z } #ifdef AUTOPLACEMENT_ON_LOAD @@ -2698,8 +2648,10 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type) default: break; } + std::string out_dir = (boost::filesystem::path(output_file).parent_path()).string(); + wxFileDialog dlg(q, dlg_title, - from_path(output_file.parent_path()), from_path(output_file.filename()), + is_shapes_dir(out_dir) ? from_u8(wxGetApp().app_config->get_last_dir()) : from_path(output_file.parent_path()), from_path(output_file.filename()), wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); if (dlg.ShowModal() != wxID_OK) @@ -2936,7 +2888,7 @@ void Plater::priv::update_print_volume_state() void Plater::priv::process_validation_warning(const std::string& warning) const { if (warning.empty()) - notification_manager->close_notification_of_type(NotificationType::PrintValidateWarning); + notification_manager->close_notification_of_type(NotificationType::ValidateWarning); else { std::string text = warning; std::string hypertext = ""; @@ -2959,9 +2911,9 @@ void Plater::priv::process_validation_warning(const std::string& warning) const } notification_manager->push_notification( - NotificationType::PrintValidateWarning, - NotificationManager::NotificationLevel::ImportantNotification, - text, hypertext, action_fn + NotificationType::ValidateWarning, + NotificationManager::NotificationLevel::WarningNotification, + _u8L("WARNING:") + "\n" + text, hypertext, action_fn ); } } @@ -3013,6 +2965,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool std::string err = background_process.validate(&warning); if (err.empty()) { notification_manager->set_all_slicing_errors_gray(true); + notification_manager->close_notification_of_type(NotificationType::ValidateError); if (invalidated != Print::APPLY_STATUS_UNCHANGED && background_processing_enabled()) return_state |= UPDATE_BACKGROUND_PROCESS_RESTART; @@ -3028,7 +2981,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool else { // The print is not valid. // Show error as notification. - notification_manager->push_slicing_error_notification(err); + notification_manager->push_validate_error_notification(err); return_state |= UPDATE_BACKGROUND_PROCESS_INVALID; if (printer_technology == ptFFF) { const Print* print = background_process.fff_print(); @@ -3248,9 +3201,7 @@ void Plater::priv::replace_with_stl() ModelObject* old_model_object = model.objects[object_idx]; ModelVolume* old_volume = old_model_object->volumes[volume_idx]; -#if ENABLE_ALLOW_NEGATIVE_Z bool sinking = old_model_object->bounding_box().min.z() < SINKING_Z_THRESHOLD; -#endif // ENABLE_ALLOW_NEGATIVE_Z ModelObject* new_model_object = new_model.objects[0]; old_model_object->add_volume(*new_model_object->volumes[0]); @@ -3270,9 +3221,7 @@ void Plater::priv::replace_with_stl() new_volume->mmu_segmentation_facets.assign(old_volume->mmu_segmentation_facets); std::swap(old_model_object->volumes[volume_idx], old_model_object->volumes.back()); old_model_object->delete_volume(old_model_object->volumes.size() - 1); -#if ENABLE_ALLOW_NEGATIVE_Z if (!sinking) -#endif // ENABLE_ALLOW_NEGATIVE_Z old_model_object->ensure_on_bed(); old_model_object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1"); @@ -3423,9 +3372,7 @@ void Plater::priv::reload_from_disk() ModelObject* old_model_object = model.objects[sel_v.object_idx]; ModelVolume* old_volume = old_model_object->volumes[sel_v.volume_idx]; -#if ENABLE_ALLOW_NEGATIVE_Z bool sinking = old_model_object->bounding_box().min.z() < SINKING_Z_THRESHOLD; -#endif // ENABLE_ALLOW_NEGATIVE_Z bool has_source = !old_volume->source.input_file.empty() && boost::algorithm::iequals(fs::path(old_volume->source.input_file).filename().string(), fs::path(path).filename().string()); bool has_name = !old_volume->name.empty() && boost::algorithm::iequals(old_volume->name, fs::path(path).filename().string()); @@ -3482,9 +3429,7 @@ void Plater::priv::reload_from_disk() new_volume->mmu_segmentation_facets.assign(old_volume->mmu_segmentation_facets); std::swap(old_model_object->volumes[sel_v.volume_idx], old_model_object->volumes.back()); old_model_object->delete_volume(old_model_object->volumes.size() - 1); -#if ENABLE_ALLOW_NEGATIVE_Z if (!sinking) -#endif // ENABLE_ALLOW_NEGATIVE_Z old_model_object->ensure_on_bed(); old_model_object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1"); @@ -3613,10 +3558,8 @@ void Plater::priv::set_current_panel(wxPanel* panel) // sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably) view3D->set_as_dirty(); -#if ENABLE_SCROLLABLE_LEGEND // reset cached size to force a resize on next call to render() to keep imgui in synch with canvas size view3D->get_canvas3d()->reset_old_size(); -#endif // ENABLE_SCROLLABLE_LEGEND view_toolbar.select_item("3D"); if (notification_manager != nullptr) notification_manager->set_in_preview(false); @@ -3637,10 +3580,8 @@ void Plater::priv::set_current_panel(wxPanel* panel) preview->reload_print(true); preview->set_as_dirty(); -#if ENABLE_SCROLLABLE_LEGEND // reset cached size to force a resize on next call to render() to keep imgui in synch with canvas size preview->get_canvas3d()->reset_old_size(); -#endif // ENABLE_SCROLLABLE_LEGEND view_toolbar.select_item("Preview"); if (notification_manager != nullptr) notification_manager->set_in_preview(true); @@ -4243,12 +4184,8 @@ bool Plater::priv::layers_height_allowed() const return false; int obj_idx = get_selected_object_idx(); -#if ENABLE_ALLOW_NEGATIVE_Z return 0 <= obj_idx && obj_idx < (int)model.objects.size() && model.objects[obj_idx]->bounding_box().max.z() > SINKING_Z_THRESHOLD && config->opt_bool("variable_layer_height") && view3D->is_layers_editing_allowed(); -#else - return 0 <= obj_idx && obj_idx < (int)model.objects.size() && config->opt_bool("variable_layer_height") && view3D->is_layers_editing_allowed(); -#endif // ENABLE_ALLOW_NEGATIVE_Z } bool Plater::priv::can_mirror() const @@ -4482,9 +4419,7 @@ void Plater::priv::take_snapshot(const std::string& snapshot_name) this->undo_redo_stack().take_snapshot(snapshot_name, model, view3D->get_canvas3d()->get_selection(), view3D->get_canvas3d()->get_gizmos_manager(), snapshot_data); this->undo_redo_stack().release_least_recently_used(); -#if ENABLE_PROJECT_DIRTY_STATE dirty_state.update_from_undo_redo_stack(ProjectDirtyStateManager::UpdateType::TakeSnapshot); -#endif // ENABLE_PROJECT_DIRTY_STATE // Save the last active preset name of a particular printer technology. ((this->printer_technology == ptFFF) ? m_last_fff_printer_profile_name : m_last_sla_printer_profile_name) = wxGetApp().preset_bundle->printers.get_selected_preset_name(); @@ -4526,13 +4461,8 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator if (printer_technology_changed) { // Switching the printer technology when jumping forwards / backwards in time. Switch to the last active printer profile of the other type. std::string s_pt = (it_snapshot->snapshot_data.printer_technology == ptFFF) ? "FFF" : "SLA"; -#if ENABLE_PROJECT_DIRTY_STATE if (!wxGetApp().check_and_save_current_preset_changes(format_wxstr(_L( "%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets."), s_pt))) -#else - if (! wxGetApp().check_unsaved_changes(format_wxstr(_L( - "%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets."), s_pt))) -#endif // ENABLE_PROJECT_DIRTY_STATE // Don't switch the profiles. return; } @@ -4624,9 +4554,7 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting")); } -#if ENABLE_PROJECT_DIRTY_STATE dirty_state.update_from_undo_redo_stack(ProjectDirtyStateManager::UpdateType::UndoRedoTo); -#endif // ENABLE_PROJECT_DIRTY_STATE } void Plater::priv::update_after_undo_redo(const UndoRedo::Snapshot& snapshot, bool /* temp_snapshot_was_taken */) @@ -4710,7 +4638,6 @@ Plater::Plater(wxWindow *parent, MainFrame *main_frame) // Initialization performed in the private c-tor } -#if ENABLE_PROJECT_DIRTY_STATE bool Plater::is_project_dirty() const { return p->is_project_dirty(); } void Plater::update_project_dirty_from_presets() { p->update_project_dirty_from_presets(); } bool Plater::save_project_if_dirty() { return p->save_project_if_dirty(); } @@ -4719,9 +4646,9 @@ void Plater::reset_project_dirty_initial_presets() { p->reset_project_dirty_init #if ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW void Plater::render_project_state_debug_window() const { p->render_project_state_debug_window(); } #endif // ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW -#endif // ENABLE_PROJECT_DIRTY_STATE Sidebar& Plater::sidebar() { return *p->sidebar; } +const Model& Plater::model() const { return p->model; } Model& Plater::model() { return p->model; } const Print& Plater::fff_print() const { return p->fff_print; } Print& Plater::fff_print() { return p->fff_print; } @@ -4730,29 +4657,21 @@ SLAPrint& Plater::sla_print() { return p->sla_print; } void Plater::new_project() { -#if ENABLE_PROJECT_DIRTY_STATE if (!p->save_project_if_dirty()) return; -#endif // ENABLE_PROJECT_DIRTY_STATE p->select_view_3D("3D"); -#if ENABLE_PROJECT_DIRTY_STATE take_snapshot(_L("New Project")); Plater::SuppressSnapshots suppress(this); reset(); reset_project_dirty_initial_presets(); update_project_dirty_from_presets(); -#else - wxPostEvent(p->view3D->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_DELETE_ALL)); -#endif // ENABLE_PROJECT_DIRTY_STATE } void Plater::load_project() { -#if ENABLE_PROJECT_DIRTY_STATE if (!p->save_project_if_dirty()) return; -#endif // ENABLE_PROJECT_DIRTY_STATE // Ask user for a project file name. wxString input_file; @@ -4777,16 +4696,11 @@ void Plater::load_project(const wxString& filename) std::vector res = load_files(input_paths); // if res is empty no data has been loaded -#if ENABLE_PROJECT_DIRTY_STATE if (!res.empty()) { p->set_project_filename(filename); reset_project_dirty_initial_presets(); update_project_dirty_from_presets(); } -#else - if (!res.empty()) - p->set_project_filename(filename); -#endif // ENABLE_PROJECT_DIRTY_STATE } void Plater::add_model(bool imperial_units/* = false*/) @@ -4817,13 +4731,9 @@ void Plater::add_model(bool imperial_units/* = false*/) } Plater::TakeSnapshot snapshot(this, snapshot_label); -#if ENABLE_PROJECT_DIRTY_STATE std::vector res = load_files(paths, true, false, imperial_units); if (!res.empty()) wxGetApp().mainframe->update_title(); -#else - load_files(paths, true, false, imperial_units); -#endif // ENABLE_PROJECT_DIRTY_STATE } void Plater::import_sl1_archive() @@ -4871,7 +4781,15 @@ void Plater::load_gcode(const wxString& filename) // process gcode GCodeProcessor processor; processor.enable_producers(true); - processor.process_file(filename.ToUTF8().data(), false); + try + { + processor.process_file(filename.ToUTF8().data(), false); + } + catch (const std::exception& ex) + { + show_error(this, ex.what()); + return; + } p->gcode_result = std::move(processor.extract_result()); // show results @@ -5573,38 +5491,22 @@ void Plater::export_amf() } } -#if ENABLE_PROJECT_DIRTY_STATE bool Plater::export_3mf(const boost::filesystem::path& output_path) -#else -void Plater::export_3mf(const boost::filesystem::path& output_path) -#endif // ENABLE_PROJECT_DIRTY_STATE { if (p->model.objects.empty()) -#if ENABLE_PROJECT_DIRTY_STATE return false; -#else - return; -#endif // ENABLE_PROJECT_DIRTY_STATE wxString path; bool export_config = true; if (output_path.empty()) { path = p->get_export_file(FT_3MF); -#if ENABLE_PROJECT_DIRTY_STATE if (path.empty()) { return false; } -#else - if (path.empty()) { return; } -#endif // ENABLE_PROJECT_DIRTY_STATE } else path = from_path(output_path); if (!path.Lower().EndsWith(".3mf")) -#if ENABLE_PROJECT_DIRTY_STATE return false; -#else - return; -#endif // ENABLE_PROJECT_DIRTY_STATE DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure(); const std::string path_u8 = into_u8(path); @@ -5613,7 +5515,6 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) ThumbnailData thumbnail_data; ThumbnailsParams thumbnail_params = { {}, false, true, true, true }; p->generate_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, thumbnail_params, Camera::EType::Ortho); -#if ENABLE_PROJECT_DIRTY_STATE bool ret = Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames, &thumbnail_data); if (ret) { // Success @@ -5625,17 +5526,6 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) p->statusbar()->set_status_text(format_wxstr(_L("Error exporting 3MF file %s"), path)); } return ret; -#else - if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames, &thumbnail_data)) { - // Success - p->statusbar()->set_status_text(format_wxstr(_L("3MF file exported to %s"), path)); - p->set_project_filename(path); - } - else { - // Failure - p->statusbar()->set_status_text(format_wxstr(_L("Error exporting 3MF file %s"), path)); - } -#endif // ENABLE_PROJECT_DIRTY_STATE } void Plater::reload_from_disk() @@ -6083,9 +5973,22 @@ std::vector Plater::get_colors_for_color_print(const GCodeProcessor std::vector colors = get_extruder_colors_from_plater_config(result); colors.reserve(colors.size() + p->model.custom_gcode_per_print_z.gcodes.size()); - for (const CustomGCode::Item& code : p->model.custom_gcode_per_print_z.gcodes) - if (code.type == CustomGCode::ColorChange) - colors.emplace_back(code.color); +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + if (wxGetApp().is_gcode_viewer() && result != nullptr) { + for (const CustomGCode::Item& code : result->custom_gcode_per_print_z) { + if (code.type == CustomGCode::ColorChange) + colors.emplace_back(code.color); + } + } + else { +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + for (const CustomGCode::Item& code : p->model.custom_gcode_per_print_z.gcodes) { + if (code.type == CustomGCode::ColorChange) + colors.emplace_back(code.color); + } +#if ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER + } +#endif // ENABLE_FIX_IMPORTING_COLOR_PRINT_VIEW_INTO_GCODEVIEWER return colors; } @@ -6140,7 +6043,6 @@ BoundingBoxf Plater::bed_shape_bb() const return p->bed_shape_bb(); } -#if ENABLE_GCODE_WINDOW void Plater::start_mapping_gcode_window() { p->preview->get_canvas3d()->start_mapping_gcode_window(); @@ -6150,7 +6052,6 @@ void Plater::stop_mapping_gcode_window() { p->preview->get_canvas3d()->stop_mapping_gcode_window(); } -#endif // ENABLE_GCODE_WINDOW void Plater::arrange() { @@ -6189,13 +6090,11 @@ bool Plater::set_printer_technology(PrinterTechnology printer_technology) //FIXME for SLA synchronize //p->background_process.apply(Model)! -#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA if (printer_technology == ptSLA) { for (ModelObject* model_object : p->model.objects) { model_object->ensure_on_bed(); } } -#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA p->label_btn_export = printer_technology == ptFFF ? L("Export G-code") : L("Export"); p->label_btn_send = printer_technology == ptFFF ? L("Send G-code") : L("Send to printer"); @@ -6261,15 +6160,7 @@ void Plater::changed_object(int obj_idx) return; // recenter and re - align to Z = 0 auto model_object = p->model.objects[obj_idx]; -#if ENABLE_ALLOW_NEGATIVE_Z -#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA model_object->ensure_on_bed(this->p->printer_technology != ptSLA); -#else - model_object->ensure_on_bed(true); -#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA -#else - model_object->ensure_on_bed(); -#endif // ENABLE_ALLOW_NEGATIVE_Z if (this->p->printer_technology == ptSLA) { // Update the SLAPrint from the current Model, so that the reload_scene() // pulls the correct data, update the 3D scene. @@ -6288,17 +6179,11 @@ void Plater::changed_objects(const std::vector& object_idxs) return; for (size_t obj_idx : object_idxs) { -#if ENABLE_ALLOW_NEGATIVE_Z if (obj_idx < p->model.objects.size()) { if (p->model.objects[obj_idx]->bounding_box().min.z() >= SINKING_Z_THRESHOLD) // re - align to Z = 0 p->model.objects[obj_idx]->ensure_on_bed(); } -#else - if (obj_idx < p->model.objects.size()) - // recenter and re - align to Z = 0 - p->model.objects[obj_idx]->ensure_on_bed(); -#endif // ENABLE_ALLOW_NEGATIVE_Z } if (this->p->printer_technology == ptSLA) { // Update the SLAPrint from the current Model, so that the reload_scene() @@ -6340,7 +6225,7 @@ void Plater::mirror(Axis axis) { p->mirror(axis); } void Plater::split_object() { p->split_object(); } void Plater::split_volume() { p->split_volume(); } void Plater::optimize_rotation() { p->m_ui_jobs.optimize_rotation();} -void Plater::update_object_menu() { p->menus.update_object_menu(); } +void Plater::update_menus() { p->menus.update(); } void Plater::show_action_buttons(const bool ready_to_slice) const { p->show_action_buttons(ready_to_slice); } void Plater::copy_selection_to_clipboard() @@ -6582,14 +6467,11 @@ bool Plater::can_mirror() const { return p->can_mirror(); } bool Plater::can_split(bool to_objects) const { return p->can_split(to_objects); } const UndoRedo::Stack& Plater::undo_redo_stack_main() const { return p->undo_redo_stack_main(); } void Plater::clear_undo_redo_stack_main() { p->undo_redo_stack_main().clear(); } -#if ENABLE_PROJECT_DIRTY_STATE const UndoRedo::Stack& Plater::undo_redo_stack_active() const { return p->undo_redo_stack(); } -#endif // ENABLE_PROJECT_DIRTY_STATE void Plater::enter_gizmos_stack() { p->enter_gizmos_stack(); } void Plater::leave_gizmos_stack() { p->leave_gizmos_stack(); } bool Plater::inside_snapshot_capture() { return p->inside_snapshot_capture(); } -#if ENABLE_RENDER_STATISTICS void Plater::toggle_render_statistic_dialog() { p->show_render_statistic_dialog = !p->show_render_statistic_dialog; @@ -6599,7 +6481,6 @@ bool Plater::is_render_statistic_dialog_visible() const { return p->show_render_statistic_dialog; } -#endif // ENABLE_RENDER_STATISTICS // Wrapper around wxWindow::PopupMenu to suppress error messages popping out while tracking the popup menu. bool Plater::PopupMenu(wxMenu *menu, const wxPoint& pos) diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 61a2da93d..2b1a83ba2 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -83,6 +83,7 @@ public: void sys_color_changed(); void search(); void jump_to_option(size_t selected); + void jump_to_option(const std::string& opt_key, Preset::Type type, const std::wstring& category); ObjectManipulation* obj_manipul(); ObjectList* obj_list(); @@ -137,7 +138,6 @@ public: Plater &operator=(const Plater &) = delete; ~Plater() = default; -#if ENABLE_PROJECT_DIRTY_STATE bool is_project_dirty() const; void update_project_dirty_from_presets(); bool save_project_if_dirty(); @@ -146,9 +146,9 @@ public: #if ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW void render_project_state_debug_window() const; #endif // ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW -#endif // ENABLE_PROJECT_DIRTY_STATE Sidebar& sidebar(); + const Model& model() const; Model& model(); const Print& fff_print() const; Print& fff_print(); @@ -216,11 +216,7 @@ public: void export_gcode(bool prefer_removable); void export_stl(bool extended = false, bool selection_only = false); void export_amf(); -#if ENABLE_PROJECT_DIRTY_STATE bool export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path()); -#else - void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path()); -#endif // ENABLE_PROJECT_DIRTY_STATE void reload_from_disk(); void replace_with_stl(); void reload_all_from_disk(); @@ -255,9 +251,7 @@ public: // For the memory statistics. const Slic3r::UndoRedo::Stack& undo_redo_stack_main() const; void clear_undo_redo_stack_main(); -#if ENABLE_PROJECT_DIRTY_STATE const Slic3r::UndoRedo::Stack& undo_redo_stack_active() const; -#endif // ENABLE_PROJECT_DIRTY_STATE // Enter / leave the Gizmos specific Undo / Redo stack. To be used by the SLA support point editing gizmo. void enter_gizmos_stack(); void leave_gizmos_stack(); @@ -272,7 +266,7 @@ public: std::vector get_extruder_colors_from_plater_config(const GCodeProcessor::Result* const result = nullptr) const; std::vector get_colors_for_color_print(const GCodeProcessor::Result* const result = nullptr) const; - void update_object_menu(); + void update_menus(); void show_action_buttons(const bool is_ready_to_slice) const; wxString get_project_filename(const wxString& extension = wxEmptyString) const; @@ -288,10 +282,8 @@ public: GLCanvas3D* get_current_canvas3D(); BoundingBoxf bed_shape_bb() const; -#if ENABLE_GCODE_WINDOW void start_mapping_gcode_window(); void stop_mapping_gcode_window(); -#endif // ENABLE_GCODE_WINDOW void arrange(); void find_new_position(const ModelInstancePtrs &instances); @@ -410,10 +402,8 @@ public: bool inside_snapshot_capture(); -#if ENABLE_RENDER_STATISTICS void toggle_render_statistic_dialog(); bool is_render_statistic_dialog_visible() const; -#endif // ENABLE_RENDER_STATISTICS // Wrapper around wxWindow::PopupMenu to suppress error messages popping out while tracking the popup menu. bool PopupMenu(wxMenu *menu, const wxPoint& pos = wxDefaultPosition); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 933737f2f..7ae10c577 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -11,14 +11,14 @@ namespace Slic3r { namespace GUI { -PreferencesDialog::PreferencesDialog(wxWindow* parent) : +PreferencesDialog::PreferencesDialog(wxWindow* parent, int selected_tab) : DPIDialog(parent, wxID_ANY, _L("Preferences"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) { #ifdef __WXOSX__ isOSX = true; #endif - build(); + build(selected_tab); } static std::shared_ptrcreate_options_tab(const wxString& title, wxBookCtrlBase* tabs) @@ -44,7 +44,7 @@ static void activate_options_tab(std::shared_ptr optgroup) sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 10); } -void PreferencesDialog::build() +void PreferencesDialog::build(size_t selected_tab) { #ifdef _WIN32 wxGetApp().UpdateDarkUI(this); @@ -292,16 +292,6 @@ void PreferencesDialog::build() option = Option(def, "seq_top_layer_only"); m_optgroup_gui->append_single_option_line(option); -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER - def.label = L("Sequential slider shows gcode line numbers"); - def.type = coBool; - def.tooltip = L("If enabled, the sequential slider, in preview, shows the gcode lines numbers." - "If disabled, the sequential slider, in preview, shows the move index."); - def.set_default_value(new ConfigOptionBool{ app_config->get("seq_top_gcode_indices") == "1" }); - option = Option(def, "seq_top_gcode_indices"); - m_optgroup_gui->append_single_option_line(option); -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER - if (is_editor) { def.label = L("Show sidebar collapse/expand button"); def.type = coBool; @@ -351,13 +341,20 @@ void PreferencesDialog::build() option = Option(def, "tabs_as_menu"); m_optgroup_gui->append_single_option_line(option); #endif + + def.label = L("Show \"Did you know\" hints after start"); + def.type = coBool; + def.tooltip = L("If enabled, useful hints are displayed at startup."); + def.set_default_value(new ConfigOptionBool{ app_config->get("show_hints") == "1" }); + option = Option(def, "show_hints"); + m_optgroup_gui->append_single_option_line(option); def.label = L("Use custom size for toolbar icons"); def.type = coBool; def.tooltip = L("If enabled, you can change size of toolbar icons manually."); def.set_default_value(new ConfigOptionBool{ app_config->get("use_custom_toolbar_size") == "1" }); option = Option(def, "use_custom_toolbar_size"); - m_optgroup_gui->append_single_option_line(option); + m_optgroup_gui->append_single_option_line(option); } activate_options_tab(m_optgroup_gui); @@ -389,6 +386,9 @@ void PreferencesDialog::build() } #endif // ENABLE_ENVIRONMENT_MAP + if (selected_tab < tabs->GetPageCount()) + tabs->SetSelection(selected_tab); + auto sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(tabs, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5); @@ -438,12 +438,6 @@ void PreferencesDialog::accept(wxEvent&) if (auto it = m_values.find("seq_top_layer_only"); it != m_values.end()) m_seq_top_layer_only_changed = app_config->get("seq_top_layer_only") != it->second; -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER - m_seq_top_gcode_indices_changed = false; - if (auto it = m_values.find("seq_top_gcode_indices"); it != m_values.end()) - m_seq_top_gcode_indices_changed = app_config->get("seq_top_gcode_indices") != it->second; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER - m_settings_layout_changed = false; for (const std::string& key : { "old_settings_layout_mode", "new_settings_layout_mode", diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp index 92e54ec9c..4e5b58df0 100644 --- a/src/slic3r/GUI/Preferences.hpp +++ b/src/slic3r/GUI/Preferences.hpp @@ -29,22 +29,16 @@ class PreferencesDialog : public DPIDialog bool isOSX {false}; bool m_settings_layout_changed {false}; bool m_seq_top_layer_only_changed{ false }; -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER - bool m_seq_top_gcode_indices_changed{ false }; -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER bool m_recreate_GUI{false}; public: - explicit PreferencesDialog(wxWindow* parent); + explicit PreferencesDialog(wxWindow* parent, int selected_tab = 0); ~PreferencesDialog() = default; bool settings_layout_changed() const { return m_settings_layout_changed; } bool seq_top_layer_only_changed() const { return m_seq_top_layer_only_changed; } -#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER - bool seq_seq_top_gcode_indices_changed() const { return m_seq_top_gcode_indices_changed; } -#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER bool recreate_GUI() const { return m_recreate_GUI; } - void build(); + void build(size_t selected_tab = 0); void accept(wxEvent&); protected: diff --git a/src/slic3r/GUI/ProjectDirtyStateManager.cpp b/src/slic3r/GUI/ProjectDirtyStateManager.cpp index a671070fb..9efc1dd90 100644 --- a/src/slic3r/GUI/ProjectDirtyStateManager.cpp +++ b/src/slic3r/GUI/ProjectDirtyStateManager.cpp @@ -13,8 +13,6 @@ #include #include -#if ENABLE_PROJECT_DIRTY_STATE - namespace Slic3r { namespace GUI { @@ -411,5 +409,3 @@ void ProjectDirtyStateManager::update_from_undo_redo_gizmo_stack(UpdateType type } // namespace GUI } // namespace Slic3r -#endif // ENABLE_PROJECT_DIRTY_STATE - diff --git a/src/slic3r/GUI/ProjectDirtyStateManager.hpp b/src/slic3r/GUI/ProjectDirtyStateManager.hpp index f7ce81a62..2151c9717 100644 --- a/src/slic3r/GUI/ProjectDirtyStateManager.hpp +++ b/src/slic3r/GUI/ProjectDirtyStateManager.hpp @@ -3,8 +3,6 @@ #include "libslic3r/Preset.hpp" -#if ENABLE_PROJECT_DIRTY_STATE - namespace Slic3r { namespace UndoRedo { class Stack; @@ -90,7 +88,5 @@ private: } // namespace GUI } // namespace Slic3r -#endif // ENABLE_PROJECT_DIRTY_STATE - #endif // slic3r_ProjectDirtyStateManager_hpp_ diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index f2e879605..dbc259444 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -13,9 +13,7 @@ #include "libslic3r/LocalesUtils.hpp" #include "libslic3r/Model.hpp" -#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA #include "libslic3r/PresetBundle.hpp" -#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA #include @@ -701,14 +699,14 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ int rot_axis_max = 0; if (rotation.isApprox(Vec3d::Zero())) { for (unsigned int i : m_list) { - GLVolume &volume = *(*m_volumes)[i]; + GLVolume &v = *(*m_volumes)[i]; if (m_mode == Instance) { - volume.set_instance_rotation(m_cache.volumes_data[i].get_instance_rotation()); - volume.set_instance_offset(m_cache.volumes_data[i].get_instance_position()); + v.set_instance_rotation(m_cache.volumes_data[i].get_instance_rotation()); + v.set_instance_offset(m_cache.volumes_data[i].get_instance_position()); } else if (m_mode == Volume) { - volume.set_volume_rotation(m_cache.volumes_data[i].get_volume_rotation()); - volume.set_volume_offset(m_cache.volumes_data[i].get_volume_position()); + v.set_volume_rotation(m_cache.volumes_data[i].get_volume_rotation()); + v.set_volume_offset(m_cache.volumes_data[i].get_volume_position()); } } } @@ -749,22 +747,22 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ }; for (unsigned int i : m_list) { - GLVolume &volume = *(*m_volumes)[i]; + GLVolume &v = *(*m_volumes)[i]; if (is_single_full_instance()) - rotate_instance(volume, i); + rotate_instance(v, i); else if (is_single_volume() || is_single_modifier()) { if (transformation_type.independent()) - volume.set_volume_rotation(volume.get_volume_rotation() + rotation); + v.set_volume_rotation(v.get_volume_rotation() + rotation); else { const Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); const Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); - volume.set_volume_rotation(new_rotation); + v.set_volume_rotation(new_rotation); } } else { if (m_mode == Instance) - rotate_instance(volume, i); + rotate_instance(v, i); else if (m_mode == Volume) { // extracts rotations from the composed transformation Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); @@ -772,9 +770,9 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ if (transformation_type.joint()) { const Vec3d local_pivot = m_cache.volumes_data[i].get_instance_full_matrix().inverse() * m_cache.dragging_center; const Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() - local_pivot); - volume.set_volume_offset(local_pivot + offset); + v.set_volume_offset(local_pivot + offset); } - volume.set_volume_rotation(new_rotation); + v.set_volume_rotation(new_rotation); } } } @@ -838,21 +836,8 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type if (!m_valid) return; -#if ENABLE_ALLOW_NEGATIVE_Z - bool is_any_volume_sinking = false; -#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA - bool is_sla = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA; -#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA -#endif // ENABLE_ALLOW_NEGATIVE_Z - for (unsigned int i : m_list) { - GLVolume &volume = *(*m_volumes)[i]; -#if ENABLE_ALLOW_NEGATIVE_Z -#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA - if (!is_sla) -#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA - is_any_volume_sinking |= !volume.is_modifier && std::find(m_cache.sinking_volumes.begin(), m_cache.sinking_volumes.end(), i) != m_cache.sinking_volumes.end(); -#endif // ENABLE_ALLOW_NEGATIVE_Z + GLVolume &v = *(*m_volumes)[i]; if (is_single_full_instance()) { if (transformation_type.relative()) { Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale); @@ -860,23 +845,23 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type // extracts scaling factors from the composed transformation Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm()); if (transformation_type.joint()) - volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); + v.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); - volume.set_instance_scaling_factor(new_scale); + v.set_instance_scaling_factor(new_scale); } else { if (transformation_type.world() && (std::abs(scale.x() - scale.y()) > EPSILON || std::abs(scale.x() - scale.z()) > EPSILON)) { // Non-uniform scaling. Transform the scaling factors into the local coordinate system. // This is only possible, if the instance rotation is mulitples of ninety degrees. - assert(Geometry::is_rotation_ninety_degrees(volume.get_instance_rotation())); - volume.set_instance_scaling_factor((volume.get_instance_transformation().get_matrix(true, false, true, true).matrix().block<3, 3>(0, 0).transpose() * scale).cwiseAbs()); + assert(Geometry::is_rotation_ninety_degrees(v.get_instance_rotation())); + v.set_instance_scaling_factor((v.get_instance_transformation().get_matrix(true, false, true, true).matrix().block<3, 3>(0, 0).transpose() * scale).cwiseAbs()); } else - volume.set_instance_scaling_factor(scale); + v.set_instance_scaling_factor(scale); } } else if (is_single_volume() || is_single_modifier()) - volume.set_volume_scaling_factor(scale); + v.set_volume_scaling_factor(scale); else { Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), scale); if (m_mode == Instance) { @@ -884,9 +869,9 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type // extracts scaling factors from the composed transformation Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm()); if (transformation_type.joint()) - volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); + v.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); - volume.set_instance_scaling_factor(new_scale); + v.set_instance_scaling_factor(new_scale); } else if (m_mode == Volume) { Eigen::Matrix new_matrix = (m * m_cache.volumes_data[i].get_volume_scale_matrix()).matrix().block(0, 0, 3, 3); @@ -894,9 +879,9 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm()); if (transformation_type.joint()) { Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center); - volume.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset); + v.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset); } - volume.set_volume_scaling_factor(new_scale); + v.set_volume_scaling_factor(new_scale); } } } @@ -907,13 +892,9 @@ void Selection::scale(const Vec3d& scale, TransformationType transformation_type else if (m_mode == Volume) synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH - -#if ENABLE_ALLOW_NEGATIVE_Z - if (!is_any_volume_sinking) - ensure_on_bed(); -#endif // ENABLE_ALLOW_NEGATIVE_Z - this->set_bounding_boxes_dirty(); + ensure_on_bed(); + set_bounding_boxes_dirty(); } void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config) @@ -964,14 +945,12 @@ void Selection::mirror(Axis axis) if (!m_valid) return; - bool single_full_instance = is_single_full_instance(); - for (unsigned int i : m_list) { GLVolume& v = *(*m_volumes)[i]; - if (single_full_instance) - v.set_instance_mirror(axis, -(*m_volumes)[i]->get_instance_mirror(axis)); + if (is_single_full_instance()) + v.set_instance_mirror(axis, -v.get_instance_mirror(axis)); else if (m_mode == Volume) - v.set_volume_mirror(axis, -(*m_volumes)[i]->get_volume_mirror(axis)); + v.set_volume_mirror(axis, -v.get_volume_mirror(axis)); } #if !DISABLE_INSTANCES_SYNCH @@ -981,7 +960,7 @@ void Selection::mirror(Axis axis) synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH - this->set_bounding_boxes_dirty(); + set_bounding_boxes_dirty(); } void Selection::translate(unsigned int object_idx, const Vec3d& displacement) @@ -1657,16 +1636,12 @@ void Selection::update_type() void Selection::set_caches() { m_cache.volumes_data.clear(); -#if ENABLE_ALLOW_NEGATIVE_Z m_cache.sinking_volumes.clear(); -#endif // ENABLE_ALLOW_NEGATIVE_Z for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) { const GLVolume& v = *(*m_volumes)[i]; m_cache.volumes_data.emplace(i, VolumeCache(v.get_volume_transformation(), v.get_instance_transformation())); -#if ENABLE_ALLOW_NEGATIVE_Z if (v.is_sinking()) m_cache.sinking_volumes.push_back(i); -#endif // ENABLE_ALLOW_NEGATIVE_Z } m_cache.dragging_center = get_bounding_box().center(); } @@ -2071,21 +2046,12 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ assert(is_rotation_xy_synchronized(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation())); switch (sync_rotation_type) { case SYNC_ROTATION_NONE: { -#if ENABLE_ALLOW_NEGATIVE_Z // z only rotation -> synch instance z // The X,Y rotations should be synchronized from start to end of the rotation. assert(is_rotation_xy_synchronized(rotation, v->get_instance_rotation())); -#if DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA) -#endif // DISABLE_ALLOW_NEGATIVE_Z_FOR_SLA v->set_instance_offset(Z, volume->get_instance_offset().z()); break; -#else - // z only rotation -> keep instance z - // The X,Y rotations should be synchronized from start to end of the rotation. - assert(is_rotation_xy_synchronized(rotation, v->get_instance_rotation())); - break; -#endif // ENABLE_ALLOW_NEGATIVE_Z } case SYNC_ROTATION_FULL: // rotation comes from place on face -> force given z @@ -2146,9 +2112,11 @@ void Selection::ensure_on_bed() typedef std::map, double> InstancesToZMap; InstancesToZMap instances_min_z; - for (GLVolume* volume : *m_volumes) { - if (!volume->is_wipe_tower && !volume->is_modifier) { - double min_z = volume->transformed_convex_hull_bounding_box().min(2); + for (size_t i = 0; i < m_volumes->size(); ++i) { + GLVolume* volume = (*m_volumes)[i]; + if (!volume->is_wipe_tower && !volume->is_modifier && + std::find(m_cache.sinking_volumes.begin(), m_cache.sinking_volumes.end(), i) == m_cache.sinking_volumes.end()) { + const double min_z = volume->transformed_convex_hull_bounding_box().min.z(); std::pair instance = std::make_pair(volume->object_idx(), volume->instance_idx()); InstancesToZMap::iterator it = instances_min_z.find(instance); if (it == instances_min_z.end()) diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index c6409f9f2..0e0e869ef 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -186,10 +186,8 @@ private: // to a set of indices of ModelVolume instances in ModelObject::instances // Here the index means a position inside the respective std::vector, not ObjectID. ObjectIdxsToInstanceIdxsMap content; -#if ENABLE_ALLOW_NEGATIVE_Z // List of ids of the volumes which are sinking when starting dragging std::vector sinking_volumes; -#endif // ENABLE_ALLOW_NEGATIVE_Z }; // Volumes owned by GLCanvas3D. diff --git a/src/slic3r/GUI/SysInfoDialog.cpp b/src/slic3r/GUI/SysInfoDialog.cpp index 2b835a96b..6f8eeedcc 100644 --- a/src/slic3r/GUI/SysInfoDialog.cpp +++ b/src/slic3r/GUI/SysInfoDialog.cpp @@ -14,7 +14,8 @@ #include "GUI_App.hpp" #include "MainFrame.hpp" #include "wxExtensions.hpp" -#include "../libslic3r/LibraryCheck.hpp" +#include "../libslic3r/BlacklistedLibraryCheck.hpp" +#include "format.hpp" #ifdef _WIN32 // The standard Windows includes. @@ -142,19 +143,23 @@ SysInfoDialog::SysInfoDialog() m_opengl_info_html->SetMinSize(wxSize(-1, 16 * wxGetApp().em_unit())); m_opengl_info_html->SetFonts(font.GetFaceName(), font.GetFaceName(), size); m_opengl_info_html->SetBorders(10); - const auto text = wxString::Format( + wxString blacklisted_libraries_message; +#ifdef WIN32 + std::wstring blacklisted_libraries = BlacklistedLibraryCheck::get_instance().get_blacklisted_string().c_str(); + if (! blacklisted_libraries.empty()) + blacklisted_libraries_message = wxString("
") + _L("Blacklisted libraries loaded into PrusaSlicer process:") + "
" + blacklisted_libraries; +#endif // WIN32 + const auto text = GUI::format_wxstr( "" "" "" - "%s" + "%s
%s
%s
%s" "
" "" "", bgr_clr_str, text_clr_str, text_clr_str, - get_mem_info(true) + "
" + wxGetApp().get_gl_info(true, true) + "
Eigen vectorization supported: " + Eigen::SimdInstructionSetsInUse() -#ifdef WIN32 - + "

Blacklisted loaded libraries:
" + LibraryCheck::get_instance().get_blacklisted_string().c_str() -#endif - ); + blacklisted_libraries_message, + get_mem_info(true), wxGetApp().get_gl_info(true, true), + "" + _L("Eigen vectorization supported:") + " " + Eigen::SimdInstructionSetsInUse()); m_opengl_info_html->SetPage(text); main_sizer->Add(m_opengl_info_html, 1, wxEXPAND | wxBOTTOM, 15); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index b642610d8..0d1ce1092 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -5,9 +5,7 @@ #include "libslic3r/PresetBundle.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/Model.hpp" -#if ENABLE_VALIDATE_CUSTOM_GCODE #include "libslic3r/GCode/GCodeProcessor.hpp" -#endif // ENABLE_VALIDATE_CUSTOM_GCODE #include "slic3r/Utils/Http.hpp" #include "slic3r/Utils/PrintHost.hpp" @@ -1172,9 +1170,13 @@ void Tab::activate_option(const std::string& opt_key, const wxString& category) wxString page_title = translate_category(category, m_type); auto cur_item = m_treectrl->GetFirstVisibleItem(); - if (!cur_item || !m_treectrl->IsVisible(cur_item)) + if (!cur_item) return; + // We should to activate a tab with searched option, if it doesn't. + // And do it before finding of the cur_item to avoid a case when Tab isn't activated jet and all treeItems are invisible + wxGetApp().mainframe->select_tab(this); + while (cur_item) { auto title = m_treectrl->GetItemText(cur_item); if (page_title != title) { @@ -1186,8 +1188,6 @@ void Tab::activate_option(const std::string& opt_key, const wxString& category) break; } - // we should to activate a tab with searched option, if it doesn't. - wxGetApp().mainframe->select_tab(this); Field* field = get_field(opt_key); // focused selected field @@ -1254,9 +1254,7 @@ void Tab::on_presets_changed() // to avoid needless preset loading from update() function m_dependent_tabs.clear(); -#if ENABLE_PROJECT_DIRTY_STATE wxGetApp().plater()->update_project_dirty_from_presets(); -#endif // ENABLE_PROJECT_DIRTY_STATE } void Tab::build_preset_description_line(ConfigOptionsGroup* optgroup) @@ -1744,7 +1742,6 @@ void TabPrint::clear_pages() m_top_bottom_shell_thickness_explanation = nullptr; } -#if ENABLE_VALIDATE_CUSTOM_GCODE bool Tab::validate_custom_gcode(const wxString& title, const std::string& gcode) { std::vector tags; @@ -1770,7 +1767,6 @@ static void validate_custom_gcode_cb(Tab* tab, ConfigOptionsGroupShp opt_group, tab->update_dirty(); tab->on_value_change(opt_key, value); } -#endif // ENABLE_VALIDATE_CUSTOM_GCODE void TabFilament::add_filament_overrides_page() { @@ -1996,11 +1992,9 @@ void TabFilament::build() page = add_options_page(L("Custom G-code"), "cog"); optgroup = page->new_optgroup(L("Start G-code"), 0); -#if ENABLE_VALIDATE_CUSTOM_GCODE optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { validate_custom_gcode_cb(this, optgroup, opt_key, value); }; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE option = optgroup->get_option("start_filament_gcode"); option.opt.full_width = true; option.opt.is_code = true; @@ -2008,11 +2002,9 @@ void TabFilament::build() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("End G-code"), 0); -#if ENABLE_VALIDATE_CUSTOM_GCODE optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { validate_custom_gcode_cb(this, optgroup, opt_key, value); }; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE option = optgroup->get_option("end_filament_gcode"); option.opt.full_width = true; option.opt.is_code = true; @@ -2139,16 +2131,9 @@ wxSizer* Tab::description_line_widget(wxWindow* parent, ogStaticText* *StaticTex return sizer; } -#if ENABLE_PROJECT_DIRTY_STATE bool Tab::saved_preset_is_dirty() const { return m_presets->saved_is_dirty(); } void Tab::update_saved_preset_from_current_preset() { m_presets->update_saved_preset_from_current_preset(); } bool Tab::current_preset_is_dirty() const { return m_presets->current_is_dirty(); } -#else -bool Tab::current_preset_is_dirty() -{ - return m_presets->current_is_dirty(); -} -#endif // ENABLE_PROJECT_DIRTY_STATE void TabPrinter::build() { @@ -2323,11 +2308,9 @@ void TabPrinter::build_fff() const int notes_field_height = 25; // 250 page = add_options_page(L("Custom G-code"), "cog"); optgroup = page->new_optgroup(L("Start G-code"), 0); -#if ENABLE_VALIDATE_CUSTOM_GCODE optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { validate_custom_gcode_cb(this, optgroup, opt_key, value); }; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE option = optgroup->get_option("start_gcode"); option.opt.full_width = true; option.opt.is_code = true; @@ -2335,11 +2318,9 @@ void TabPrinter::build_fff() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("End G-code"), 0); -#if ENABLE_VALIDATE_CUSTOM_GCODE optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { validate_custom_gcode_cb(this, optgroup, opt_key, value); }; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE option = optgroup->get_option("end_gcode"); option.opt.full_width = true; option.opt.is_code = true; @@ -2347,11 +2328,9 @@ void TabPrinter::build_fff() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Before layer change G-code"), 0); -#if ENABLE_VALIDATE_CUSTOM_GCODE optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { validate_custom_gcode_cb(this, optgroup, opt_key, value); }; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE option = optgroup->get_option("before_layer_gcode"); option.opt.full_width = true; option.opt.is_code = true; @@ -2359,11 +2338,9 @@ void TabPrinter::build_fff() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("After layer change G-code"), 0); -#if ENABLE_VALIDATE_CUSTOM_GCODE optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { validate_custom_gcode_cb(this, optgroup, opt_key, value); }; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE option = optgroup->get_option("layer_gcode"); option.opt.full_width = true; option.opt.is_code = true; @@ -2371,11 +2348,9 @@ void TabPrinter::build_fff() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Tool change G-code"), 0); -#if ENABLE_VALIDATE_CUSTOM_GCODE optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { validate_custom_gcode_cb(this, optgroup, opt_key, value); }; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE option = optgroup->get_option("toolchange_gcode"); option.opt.full_width = true; option.opt.is_code = true; @@ -2383,11 +2358,9 @@ void TabPrinter::build_fff() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Between objects G-code (for sequential printing)"), 0); -#if ENABLE_VALIDATE_CUSTOM_GCODE optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { validate_custom_gcode_cb(this, optgroup, opt_key, value); }; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE option = optgroup->get_option("between_objects_gcode"); option.opt.full_width = true; option.opt.is_code = true; @@ -2395,33 +2368,27 @@ void TabPrinter::build_fff() optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Color Change G-code"), 0); -#if ENABLE_VALIDATE_CUSTOM_GCODE optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { validate_custom_gcode_cb(this, optgroup, opt_key, value); }; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE option = optgroup->get_option("color_change_gcode"); option.opt.is_code = true; option.opt.height = gcode_field_height;//150; optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Pause Print G-code"), 0); -#if ENABLE_VALIDATE_CUSTOM_GCODE optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { validate_custom_gcode_cb(this, optgroup, opt_key, value); }; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE option = optgroup->get_option("pause_print_gcode"); option.opt.is_code = true; option.opt.height = gcode_field_height;//150; optgroup->append_single_option_line(option); optgroup = page->new_optgroup(L("Template Custom G-code"), 0); -#if ENABLE_VALIDATE_CUSTOM_GCODE optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) { validate_custom_gcode_cb(this, optgroup, opt_key, value); }; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE option = optgroup->get_option("template_custom_gcode"); option.opt.is_code = true; option.opt.height = gcode_field_height;//150; @@ -3083,6 +3050,7 @@ void Tab::load_current_preset() if (!wxGetApp().tabs_as_menu()) { std::string bmp_name = tab->type() == Slic3r::Preset::TYPE_FILAMENT ? "spool" : tab->type() == Slic3r::Preset::TYPE_SLA_MATERIAL ? "resin" : "cog"; + tab->Hide(); // #ys_WORKAROUND : Hide tab before inserting to avoid unwanted rendering of the tab dynamic_cast(wxGetApp().tab_panel())->InsertPage(wxGetApp().tab_panel()->FindPage(this), tab, tab->title(), bmp_name); } else @@ -3904,7 +3872,6 @@ void TabPrinter::apply_extruder_cnt_from_cache() } } -#if ENABLE_VALIDATE_CUSTOM_GCODE bool Tab::validate_custom_gcodes() { if (m_type != Preset::TYPE_FILAMENT && @@ -3930,7 +3897,6 @@ bool Tab::validate_custom_gcodes() } return valid; } -#endif // ENABLE_VALIDATE_CUSTOM_GCODE void TabPrinter::update_machine_limits_description(const MachineLimitsUsage usage) { @@ -4157,7 +4123,6 @@ ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_la return optgroup; } -#if ENABLE_VALIDATE_CUSTOM_GCODE const ConfigOptionsGroupShp Page::get_optgroup(const wxString& title) const { for (ConfigOptionsGroupShp optgroup : m_optgroups) { @@ -4167,7 +4132,6 @@ const ConfigOptionsGroupShp Page::get_optgroup(const wxString& title) const return nullptr; } -#endif // ENABLE_VALIDATE_CUSTOM_GCODE void TabSLAMaterial::build() { diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 80b9cd873..74585f2aa 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -79,9 +79,7 @@ public: Field* get_field(const t_config_option_key& opt_key, int opt_index = -1) const; bool set_value(const t_config_option_key& opt_key, const boost::any& value); ConfigOptionsGroupShp new_optgroup(const wxString& title, int noncommon_label_width = -1); -#if ENABLE_VALIDATE_CUSTOM_GCODE const ConfigOptionsGroupShp get_optgroup(const wxString& title) const; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE bool set_item_colour(const wxColour *clr) { if (m_item_color != clr) { @@ -269,11 +267,7 @@ public: Preset::Type type() const { return m_type; } // The tab is already constructed. bool completed() const { return m_completed; } -#if ENABLE_PROJECT_DIRTY_STATE virtual bool supports_printer_technology(const PrinterTechnology tech) const = 0; -#else - virtual bool supports_printer_technology(const PrinterTechnology tech) = 0; -#endif // ENABLE_PROJECT_DIRTY_STATE void create_preset_tab(); void add_scaled_button(wxWindow* parent, ScalableButton** btn, const std::string& icon_name, @@ -336,13 +330,9 @@ public: Field* get_field(const t_config_option_key &opt_key, Page** selected_page, int opt_index = -1); void toggle_option(const std::string& opt_key, bool toggle, int opt_index = -1); wxSizer* description_line_widget(wxWindow* parent, ogStaticText** StaticText, wxString text = wxEmptyString); -#if ENABLE_PROJECT_DIRTY_STATE bool current_preset_is_dirty() const; bool saved_preset_is_dirty() const; void update_saved_preset_from_current_preset(); -#else - bool current_preset_is_dirty(); -#endif // ENABLE_PROJECT_DIRTY_STATE DynamicPrintConfig* get_config() { return m_config; } PresetCollection* get_presets() { return m_presets; } @@ -357,11 +347,9 @@ public: const std::map& get_category_icon_map() { return m_category_icon; } -#if ENABLE_VALIDATE_CUSTOM_GCODE static bool validate_custom_gcode(const wxString& title, const std::string& gcode); bool validate_custom_gcodes(); - bool validate_custom_gcodes_was_shown { false }; -#endif // ENABLE_VALIDATE_CUSTOM_GCODE + bool validate_custom_gcodes_was_shown{ false }; protected: void create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, const wxString& path, widget_t widget); @@ -395,11 +383,7 @@ public: void toggle_options() override; void update() override; void clear_pages() override; -#if ENABLE_PROJECT_DIRTY_STATE bool supports_printer_technology(const PrinterTechnology tech) const override { return tech == ptFFF; } -#else - bool supports_printer_technology(const PrinterTechnology tech) override { return tech == ptFFF; } -#endif // ENABLE_PROJECT_DIRTY_STATE private: ogStaticText* m_recommended_thin_wall_thickness_description_line = nullptr; @@ -428,11 +412,7 @@ public: void toggle_options() override; void update() override; void clear_pages() override; -#if ENABLE_PROJECT_DIRTY_STATE bool supports_printer_technology(const PrinterTechnology tech) const override { return tech == ptFFF; } -#else - bool supports_printer_technology(const PrinterTechnology tech) override { return tech == ptFFF; } -#endif // ENABLE_PROJECT_DIRTY_STATE }; class TabPrinter : public Tab @@ -485,11 +465,7 @@ public: void on_preset_loaded() override; void init_options_list() override; void msw_rescale() override; -#if ENABLE_PROJECT_DIRTY_STATE bool supports_printer_technology(const PrinterTechnology /* tech */) const override { return true; } -#else - bool supports_printer_technology(const PrinterTechnology /* tech */) override { return true; } -#endif // ENABLE_PROJECT_DIRTY_STATE wxSizer* create_bed_shape_widget(wxWindow* parent); void cache_extruder_cnt(); @@ -508,11 +484,7 @@ public: void toggle_options() override {}; void update() override; void init_options_list() override; -#if ENABLE_PROJECT_DIRTY_STATE bool supports_printer_technology(const PrinterTechnology tech) const override { return tech == ptSLA; } -#else - bool supports_printer_technology(const PrinterTechnology tech) override { return tech == ptSLA; } -#endif // ENABLE_PROJECT_DIRTY_STATE }; class TabSLAPrint : public Tab @@ -530,11 +502,7 @@ public: void toggle_options() override; void update() override; void clear_pages() override; -#if ENABLE_PROJECT_DIRTY_STATE bool supports_printer_technology(const PrinterTechnology tech) const override { return tech == ptSLA; } -#else - bool supports_printer_technology(const PrinterTechnology tech) override { return tech == ptSLA; } -#endif // ENABLE_PROJECT_DIRTY_STATE }; } // GUI diff --git a/src/slic3r/Utils/FixModelByWin10.cpp b/src/slic3r/Utils/FixModelByWin10.cpp index e2970acf1..cfe8b68b3 100644 --- a/src/slic3r/Utils/FixModelByWin10.cpp +++ b/src/slic3r/Utils/FixModelByWin10.cpp @@ -36,6 +36,8 @@ #include "../GUI/GUI.hpp" #include "../GUI/I18N.hpp" #include "../GUI/MsgDialog.hpp" +#include "../GUI/GUI_App.hpp" +#include "../GUI/Mainframe.hpp" #include #include @@ -341,7 +343,7 @@ void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx) wxProgressDialog progress_dialog( _L("Model fixing"), _L("Exporting model") + "...", - 100, nullptr, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT); + 100, GUI::wxGetApp().mainframe, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT); // Executing the calculation in a background thread, so that the COM context could be created with its own threading model. // (It seems like wxWidgets initialize the COM contex as single threaded and we need a multi-threaded context). bool success = false; @@ -423,12 +425,10 @@ void fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx) if (canceled) { // Nothing to show. } else if (success) { - //wxMessageDialog dlg(nullptr, _(L("Model repaired successfully")), _(L("Model Repair by the Netfabb service")), wxICON_INFORMATION | wxOK_DEFAULT); - Slic3r::GUI::MessageDialog dlg(nullptr, _(L("Model repaired successfully")), _(L("Model Repair by the Netfabb service")), wxICON_INFORMATION | wxOK_DEFAULT); + Slic3r::GUI::MessageDialog dlg(nullptr, _L("Model repaired successfully"), _L("Model Repair by the Netfabb service"), wxICON_INFORMATION | wxOK); dlg.ShowModal(); } else { - //wxMessageDialog dlg(nullptr, _(L("Model repair failed:")) + " \n" + _(progress.message), _(L("Model Repair by the Netfabb service")), wxICON_ERROR | wxOK_DEFAULT); - Slic3r::GUI::MessageDialog dlg(nullptr, _(L("Model repair failed:")) + " \n" + _(progress.message), _(L("Model Repair by the Netfabb service")), wxICON_ERROR | wxOK_DEFAULT); + Slic3r::GUI::MessageDialog dlg(nullptr, _L("Model repair failed:") + " \n" + _(progress.message), _L("Model Repair by the Netfabb service"), wxICON_ERROR | wxOK); dlg.ShowModal(); } worker_thread.join();