mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-30 12:21:05 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12b6d6b9ba | ||
|
|
c6d89d6978 | ||
|
|
abecef53b0 | ||
|
|
44d5a22a32 | ||
|
|
dec146f1e6 | ||
|
|
a9fec0ffc4 | ||
|
|
9ab6bbebf0 |
@@ -189,7 +189,8 @@ the presets to a base is in [shared-bases.md](shared-bases.md#variant-arrays-on-
|
|||||||
2. Every key in `filament_options_with_variant` ([the full list](#the-four-key-sets)) that reaches the
|
2. Every key in `filament_options_with_variant` ([the full list](#the-four-key-sets)) that reaches the
|
||||||
preset, whether written, included or inherited, is resized to its variant count: write it at exactly
|
preset, whether written, included or inherited, is resized to its variant count: write it at exactly
|
||||||
that width, or leave it out. Keys outside the set
|
that width, or leave it out. Keys outside the set
|
||||||
(`filament_type`, plate temperatures, `fan_max_speed`, `slow_down_min_speed`, …) are never addressed by variant index; the preset contributes their first value however wide a
|
(`filament_type`, plate temperatures, `fan_max_speed`, `slow_down_min_speed`, `pressure_advance`,
|
||||||
|
…) are never addressed by variant index; the preset contributes their first value however wide a
|
||||||
file writes them.
|
file writes them.
|
||||||
3. Cover every variant the material is meant to print on across its `compatible_printers`. Leave out
|
3. Cover every variant the material is meant to print on across its `compatible_printers`. Leave out
|
||||||
a variant deliberately when the material should not be tuned for it (e.g. a TPU High Flow variant
|
a variant deliberately when the material should not be tuned for it (e.g. a TPU High Flow variant
|
||||||
@@ -454,7 +455,7 @@ no set: the variant-length resize leaves it alone, and only the pair rebuild of
|
|||||||
last for contrast; it is not a variant set.
|
last for contrast; it is not a variant set.
|
||||||
|
|
||||||
`check` and `fix-variant` read the four sets from `PrintConfig.cpp` on every run, so they follow the
|
`check` and `fix-variant` read the four sets from `PrintConfig.cpp` on every run, so they follow the
|
||||||
engine. The lists below are from the 2026-09-29 checkout; regenerate them from the repository root
|
engine. The lists below are from the 2026-09-25 checkout; regenerate them from the repository root
|
||||||
before relying on them (the recipe strips comments, since an initializer can carry a commented-out entry):
|
before relying on them (the recipe strips comments, since an initializer can carry a commented-out entry):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -477,7 +478,7 @@ EOF
|
|||||||
|
|
||||||
**`print_options_with_variant`**, process, stride 1 (45): `bridge_acceleration`, `bridge_speed`, `default_acceleration`, `default_jerk`, `default_junction_deviation`, `enable_overhang_speed`, `gap_infill_speed`, `infill_jerk`, `initial_layer_acceleration`, `initial_layer_infill_speed`, `initial_layer_jerk`, `initial_layer_speed`, `initial_layer_travel_acceleration`, `initial_layer_travel_jerk`, `initial_layer_travel_speed`, `inner_wall_acceleration`, `inner_wall_jerk`, `inner_wall_speed`, `internal_bridge_speed`, `internal_solid_infill_acceleration`, `internal_solid_infill_speed`, `outer_wall_acceleration`, `outer_wall_jerk`, `outer_wall_speed`, `overhang_1_4_speed`, `overhang_2_4_speed`, `overhang_3_4_speed`, `overhang_4_4_speed`, `print_extruder_id`, `print_extruder_variant`, `slowdown_for_curled_perimeters`, `small_perimeter_speed`, `small_perimeter_threshold`, `sparse_infill_acceleration`, `sparse_infill_speed`, `support_interface_speed`, `support_speed`, `top_solid_infill_flow_ratio`, `top_surface_acceleration`, `top_surface_jerk`, `top_surface_speed`, `travel_acceleration`, `travel_jerk`, `travel_speed`, `travel_speed_z`
|
**`print_options_with_variant`**, process, stride 1 (45): `bridge_acceleration`, `bridge_speed`, `default_acceleration`, `default_jerk`, `default_junction_deviation`, `enable_overhang_speed`, `gap_infill_speed`, `infill_jerk`, `initial_layer_acceleration`, `initial_layer_infill_speed`, `initial_layer_jerk`, `initial_layer_speed`, `initial_layer_travel_acceleration`, `initial_layer_travel_jerk`, `initial_layer_travel_speed`, `inner_wall_acceleration`, `inner_wall_jerk`, `inner_wall_speed`, `internal_bridge_speed`, `internal_solid_infill_acceleration`, `internal_solid_infill_speed`, `outer_wall_acceleration`, `outer_wall_jerk`, `outer_wall_speed`, `overhang_1_4_speed`, `overhang_2_4_speed`, `overhang_3_4_speed`, `overhang_4_4_speed`, `print_extruder_id`, `print_extruder_variant`, `slowdown_for_curled_perimeters`, `small_perimeter_speed`, `small_perimeter_threshold`, `sparse_infill_acceleration`, `sparse_infill_speed`, `support_interface_speed`, `support_speed`, `top_solid_infill_flow_ratio`, `top_surface_acceleration`, `top_surface_jerk`, `top_surface_speed`, `travel_acceleration`, `travel_jerk`, `travel_speed`, `travel_speed_z`
|
||||||
|
|
||||||
**`filament_options_with_variant`**, filament, stride 1 (54): `activate_air_filtration`, `activate_air_filtration_during_print`, `activate_air_filtration_on_completion`, `adaptive_pressure_advance`, `adaptive_pressure_advance_bridges`, `adaptive_pressure_advance_model`, `adaptive_pressure_advance_overhangs`, `complete_print_exhaust_fan_speed`, `during_print_exhaust_fan_speed`, `enable_pressure_advance`, `filament_adaptive_volumetric_speed`, `filament_cooling_before_tower`, `filament_deretraction_speed`, `filament_extruder_variant`, `filament_flow_ratio`, `filament_flush_temp`, `filament_flush_volumetric_speed`, `filament_ironing_flow`, `filament_ironing_inset`, `filament_ironing_spacing`, `filament_ironing_speed`, `filament_long_retractions_when_cut`, `filament_max_volumetric_speed`, `filament_pre_cooling_temperature`, `filament_pre_cooling_temperature_nc`, `filament_preheat_temperature_delta`, `filament_ramming_travel_time`, `filament_ramming_travel_time_nc`, `filament_ramming_volumetric_speed`, `filament_ramming_volumetric_speed_nc`, `filament_retract_after_wipe`, `filament_retract_before_wipe`, `filament_retract_length_nc`, `filament_retract_length_toolchange`, `filament_retract_lift_above`, `filament_retract_lift_below`, `filament_retract_lift_enforce`, `filament_retract_restart_extra`, `filament_retract_restart_extra_toolchange`, `filament_retract_when_changing_layer`, `filament_retraction_distances_when_cut`, `filament_retraction_length`, `filament_retraction_minimum_travel`, `filament_retraction_speed`, `filament_wipe`, `filament_wipe_distance`, `filament_z_hop`, `filament_z_hop_types`, `long_retractions_when_ec`, `nozzle_temperature`, `nozzle_temperature_initial_layer`, `pressure_advance`, `retraction_distances_when_ec`, `volumetric_speed_coefficients`
|
**`filament_options_with_variant`**, filament, stride 1 (48): `activate_air_filtration`, `activate_air_filtration_during_print`, `activate_air_filtration_on_completion`, `complete_print_exhaust_fan_speed`, `during_print_exhaust_fan_speed`, `filament_adaptive_volumetric_speed`, `filament_cooling_before_tower`, `filament_deretraction_speed`, `filament_extruder_variant`, `filament_flow_ratio`, `filament_flush_temp`, `filament_flush_volumetric_speed`, `filament_ironing_flow`, `filament_ironing_inset`, `filament_ironing_spacing`, `filament_ironing_speed`, `filament_long_retractions_when_cut`, `filament_max_volumetric_speed`, `filament_pre_cooling_temperature`, `filament_pre_cooling_temperature_nc`, `filament_preheat_temperature_delta`, `filament_ramming_travel_time`, `filament_ramming_travel_time_nc`, `filament_ramming_volumetric_speed`, `filament_ramming_volumetric_speed_nc`, `filament_retract_after_wipe`, `filament_retract_before_wipe`, `filament_retract_length_nc`, `filament_retract_length_toolchange`, `filament_retract_lift_above`, `filament_retract_lift_below`, `filament_retract_lift_enforce`, `filament_retract_restart_extra`, `filament_retract_restart_extra_toolchange`, `filament_retract_when_changing_layer`, `filament_retraction_distances_when_cut`, `filament_retraction_length`, `filament_retraction_minimum_travel`, `filament_retraction_speed`, `filament_wipe`, `filament_wipe_distance`, `filament_z_hop`, `filament_z_hop_types`, `long_retractions_when_ec`, `nozzle_temperature`, `nozzle_temperature_initial_layer`, `retraction_distances_when_ec`, `volumetric_speed_coefficients`
|
||||||
|
|
||||||
**`printer_extruder_options`**, machine, one value per extruder, not a variant set (8):
|
**`printer_extruder_options`**, machine, one value per extruder, not a variant set (8):
|
||||||
`default_nozzle_volume_type`, `extruder_max_nozzle_count`, `extruder_printable_area`,
|
`default_nozzle_volume_type`, `extruder_max_nozzle_count`, `extruder_printable_area`,
|
||||||
|
|||||||
@@ -244,10 +244,10 @@ preset for a 0.2 nozzle, explicitly revisit flow limits; do not infer a pressure
|
|||||||
required direction of change, from diameter alone.
|
required direction of change, from diameter alone.
|
||||||
|
|
||||||
On a printer with extruder variants, a filament tunes these per variant too:
|
On a printer with extruder variants, a filament tunes these per variant too:
|
||||||
`filament_max_volumetric_speed`, `filament_flow_ratio`, `nozzle_temperature`, pressure advance and the
|
`filament_max_volumetric_speed`, `filament_flow_ratio`, `nozzle_temperature` and the retraction
|
||||||
retraction overrides carry one value per variant of `filament_extruder_variant` (Standard, High Flow, …). The
|
overrides carry one value per variant of `filament_extruder_variant` (Standard, High Flow, …). The
|
||||||
exact key set is [`filament_options_with_variant`](extruder-variants.md#the-four-key-sets);
|
exact key set is [`filament_options_with_variant`](extruder-variants.md#the-four-key-sets);
|
||||||
`slow_down_min_speed` and `fan_max_speed` are not in it. Keep every such array at exactly that width, even where the
|
`slow_down_min_speed` and `pressure_advance` are not in it. Keep every such array at exactly that width, even where the
|
||||||
setting does not differ per variant, and measure the High Flow variant rather than copying Standard
|
setting does not differ per variant, and measure the High Flow variant rather than copying Standard
|
||||||
([extruder-variants.md](extruder-variants.md#filament)).
|
([extruder-variants.md](extruder-variants.md#filament)).
|
||||||
|
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ jobs:
|
|||||||
"repos/${{ github.repository }}/actions/workflows/post_merge_profiles.yml/runs" \
|
"repos/${{ github.repository }}/actions/workflows/post_merge_profiles.yml/runs" \
|
||||||
-f branch="$branch" -f event=workflow_dispatch -f per_page=100)"
|
-f branch="$branch" -f event=workflow_dispatch -f per_page=100)"
|
||||||
run_id="$(jq -r --arg marker "[OFL cron $dispatch_id]" \
|
run_id="$(jq -r --arg marker "[OFL cron $dispatch_id]" \
|
||||||
'[.workflow_runs[] | select((.display_title // "") | contains($marker))]
|
'[.workflow_runs[] | select((.display_title // "") | contains($marker))] \
|
||||||
| sort_by(.created_at) | last | .id // empty' <<< "$runs_json")"
|
| sort_by(.created_at) | last | .id // empty' <<< "$runs_json")"
|
||||||
[ -n "$run_id" ] && break
|
[ -n "$run_id" ] && break
|
||||||
sleep 5
|
sleep 5
|
||||||
|
|||||||
+1
-42
@@ -834,37 +834,6 @@ find_package(OpenSSL REQUIRED)
|
|||||||
find_package(CURL REQUIRED)
|
find_package(CURL REQUIRED)
|
||||||
find_package(Freetype REQUIRED)
|
find_package(Freetype REQUIRED)
|
||||||
|
|
||||||
if (SLIC3R_GUI)
|
|
||||||
# LibDataChannel's installed export references its bundled dependencies,
|
|
||||||
# but does not install their CMake targets. Recreate those targets from
|
|
||||||
# the same dependency prefix before loading the LibDataChannel config.
|
|
||||||
if (NOT TARGET Usrsctp::usrsctp)
|
|
||||||
find_library(_ORCA_USRSCTP_LIBRARY NAMES usrsctp
|
|
||||||
PATHS "${CMAKE_PREFIX_PATH}/lib" NO_DEFAULT_PATH)
|
|
||||||
if (_ORCA_USRSCTP_LIBRARY)
|
|
||||||
add_library(Usrsctp::usrsctp UNKNOWN IMPORTED GLOBAL)
|
|
||||||
set_target_properties(Usrsctp::usrsctp PROPERTIES
|
|
||||||
IMPORTED_LOCATION "${_ORCA_USRSCTP_LIBRARY}"
|
|
||||||
IMPORTED_LINK_INTERFACE_LANGUAGES C
|
|
||||||
INTERFACE_LINK_LIBRARIES "Threads::Threads")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT TARGET LibJuice::LibJuice)
|
|
||||||
find_library(_ORCA_LIBJUICE_LIBRARY NAMES juice
|
|
||||||
PATHS "${CMAKE_PREFIX_PATH}/lib" NO_DEFAULT_PATH)
|
|
||||||
if (_ORCA_LIBJUICE_LIBRARY)
|
|
||||||
add_library(LibJuice::LibJuice UNKNOWN IMPORTED GLOBAL)
|
|
||||||
set_target_properties(LibJuice::LibJuice PROPERTIES
|
|
||||||
IMPORTED_LOCATION "${_ORCA_LIBJUICE_LIBRARY}"
|
|
||||||
IMPORTED_LINK_INTERFACE_LANGUAGES C
|
|
||||||
INTERFACE_LINK_LIBRARIES "Threads::Threads")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package(LibDataChannel CONFIG REQUIRED)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
add_library(libcurl INTERFACE)
|
add_library(libcurl INTERFACE)
|
||||||
target_link_libraries(libcurl INTERFACE CURL::libcurl)
|
target_link_libraries(libcurl INTERFACE CURL::libcurl)
|
||||||
@@ -1145,7 +1114,6 @@ function(orcaslicer_copy_dlls target config postfix output_dlls)
|
|||||||
endif ()
|
endif ()
|
||||||
file(COPY ${_occt_dlls}
|
file(COPY ${_occt_dlls}
|
||||||
${CMAKE_PREFIX_PATH}/bin/freetype.dll
|
${CMAKE_PREFIX_PATH}/bin/freetype.dll
|
||||||
${CMAKE_PREFIX_PATH}/bin/avformat-61.dll
|
|
||||||
${CMAKE_PREFIX_PATH}/bin/avcodec-61.dll
|
${CMAKE_PREFIX_PATH}/bin/avcodec-61.dll
|
||||||
${CMAKE_PREFIX_PATH}/bin/swresample-5.dll
|
${CMAKE_PREFIX_PATH}/bin/swresample-5.dll
|
||||||
${CMAKE_PREFIX_PATH}/bin/swscale-8.dll
|
${CMAKE_PREFIX_PATH}/bin/swscale-8.dll
|
||||||
@@ -1158,7 +1126,6 @@ function(orcaslicer_copy_dlls target config postfix output_dlls)
|
|||||||
${_out_dir}/WebView2Loader.dll
|
${_out_dir}/WebView2Loader.dll
|
||||||
|
|
||||||
${_out_dir}/freetype.dll
|
${_out_dir}/freetype.dll
|
||||||
${_out_dir}/avformat-61.dll
|
|
||||||
${_out_dir}/avcodec-61.dll
|
${_out_dir}/avcodec-61.dll
|
||||||
${_out_dir}/swresample-5.dll
|
${_out_dir}/swresample-5.dll
|
||||||
${_out_dir}/swscale-8.dll
|
${_out_dir}/swscale-8.dll
|
||||||
@@ -1182,10 +1149,7 @@ function(orcaslicer_copy_sos target config postfix output_sos)
|
|||||||
set(_out_dir "${CMAKE_CURRENT_BINARY_DIR}")
|
set(_out_dir "${CMAKE_CURRENT_BINARY_DIR}")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
file(COPY ${CMAKE_PREFIX_PATH}/lib/libavformat.so
|
file(COPY ${CMAKE_PREFIX_PATH}/lib/libavcodec.so
|
||||||
${CMAKE_PREFIX_PATH}/lib/libavformat.so.61
|
|
||||||
${CMAKE_PREFIX_PATH}/lib/libavformat.so.61.1.100
|
|
||||||
${CMAKE_PREFIX_PATH}/lib/libavcodec.so
|
|
||||||
${CMAKE_PREFIX_PATH}/lib/libavcodec.so.61
|
${CMAKE_PREFIX_PATH}/lib/libavcodec.so.61
|
||||||
${CMAKE_PREFIX_PATH}/lib/libavcodec.so.61.3.100
|
${CMAKE_PREFIX_PATH}/lib/libavcodec.so.61.3.100
|
||||||
${CMAKE_PREFIX_PATH}/lib/libavutil.so
|
${CMAKE_PREFIX_PATH}/lib/libavutil.so
|
||||||
@@ -1200,9 +1164,6 @@ function(orcaslicer_copy_sos target config postfix output_sos)
|
|||||||
DESTINATION ${_out_dir})
|
DESTINATION ${_out_dir})
|
||||||
|
|
||||||
set(${output_sos}
|
set(${output_sos}
|
||||||
${_out_dir}/libavformat.so
|
|
||||||
${_out_dir}/libavformat.so.61
|
|
||||||
${_out_dir}/libavformat.so.61.1.100
|
|
||||||
${_out_dir}/libavcodec.so
|
${_out_dir}/libavcodec.so
|
||||||
${_out_dir}/libavcodec.so.61
|
${_out_dir}/libavcodec.so.61
|
||||||
${_out_dir}/libavcodec.so.61.3.100
|
${_out_dir}/libavcodec.so.61.3.100
|
||||||
@@ -1332,8 +1293,6 @@ endif ()
|
|||||||
|
|
||||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
set(LIBRARY_FILES
|
set(LIBRARY_FILES
|
||||||
${LIBDIR_BIN}/libavformat.so.61
|
|
||||||
${LIBDIR_BIN}/libavformat.so.61.1.100
|
|
||||||
${LIBDIR_BIN}/libavcodec.so.61
|
${LIBDIR_BIN}/libavcodec.so.61
|
||||||
${LIBDIR_BIN}/libavcodec.so.61.3.100
|
${LIBDIR_BIN}/libavcodec.so.61.3.100
|
||||||
${LIBDIR_BIN}/libavutil.so.59
|
${LIBDIR_BIN}/libavutil.so.59
|
||||||
|
|||||||
Vendored
+11
-23
@@ -164,7 +164,7 @@ if (NOT _is_multi AND NOT CMAKE_BUILD_TYPE)
|
|||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
function(orcaslicer_add_cmake_project projectname)
|
function(orcaslicer_add_cmake_project projectname)
|
||||||
cmake_parse_arguments(P_ARGS "FORWARD_CONFIG" "INSTALL_DIR;BUILD_COMMAND;INSTALL_COMMAND;SOURCE_DIR" "CMAKE_ARGS" ${ARGN})
|
cmake_parse_arguments(P_ARGS "FORWARD_CONFIG" "INSTALL_DIR;BUILD_COMMAND;INSTALL_COMMAND" "CMAKE_ARGS" ${ARGN})
|
||||||
|
|
||||||
# MSVC is true for clang-cl as well, so the sub-build toolchain has to key on the
|
# MSVC is true for clang-cl as well, so the sub-build toolchain has to key on the
|
||||||
# generator. A non-Visual-Studio superbuild passes its own generator down, and with
|
# generator. A non-Visual-Studio superbuild passes its own generator down, and with
|
||||||
@@ -210,18 +210,12 @@ function(orcaslicer_add_cmake_project projectname)
|
|||||||
set(_build_j "-j${NPROC}")
|
set(_build_j "-j${NPROC}")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(_source_dir_arg "")
|
|
||||||
if (P_ARGS_SOURCE_DIR)
|
|
||||||
set(_source_dir_arg SOURCE_DIR ${P_ARGS_SOURCE_DIR})
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (NOT IS_CROSS_COMPILE OR NOT APPLE)
|
if (NOT IS_CROSS_COMPILE OR NOT APPLE)
|
||||||
ExternalProject_Add(
|
ExternalProject_Add(
|
||||||
dep_${projectname}
|
dep_${projectname}
|
||||||
EXCLUDE_FROM_ALL ON
|
EXCLUDE_FROM_ALL ON
|
||||||
INSTALL_DIR ${DESTDIR}
|
INSTALL_DIR ${DESTDIR}
|
||||||
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/${projectname}
|
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/${projectname}
|
||||||
${_source_dir_arg}
|
|
||||||
${_gen}
|
${_gen}
|
||||||
CMAKE_ARGS
|
CMAKE_ARGS
|
||||||
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||||
@@ -255,14 +249,12 @@ if (NOT IS_CROSS_COMPILE OR NOT APPLE)
|
|||||||
# note for future devs: shared libs may actually create a size reduction
|
# note for future devs: shared libs may actually create a size reduction
|
||||||
# but orcaslicer_deps tends to get really funny regarding linking after that (notably boost)
|
# but orcaslicer_deps tends to get really funny regarding linking after that (notably boost)
|
||||||
# so, as much as I would like to use that, it's not happening
|
# so, as much as I would like to use that, it's not happening
|
||||||
if (NOT P_ARGS_SOURCE_DIR)
|
ExternalProject_Add_Step(dep_${projectname} free_download_space
|
||||||
ExternalProject_Add_Step(dep_${projectname} free_download_space
|
DEPENDEES download # do after download
|
||||||
DEPENDEES download # do after download
|
COMMENT "Freeing Space: Removing source archive"
|
||||||
COMMENT "Freeing Space: Removing source archive"
|
WORKING_DIRECTORY ${DEP_DOWNLOAD_DIR}
|
||||||
WORKING_DIRECTORY ${DEP_DOWNLOAD_DIR}
|
COMMAND ${CMAKE_COMMAND} -E rm -r ${projectname}
|
||||||
COMMAND ${CMAKE_COMMAND} -E rm -rf ${projectname}
|
)
|
||||||
)
|
|
||||||
endif ()
|
|
||||||
ExternalProject_Add_Step(dep_${projectname} free_build_space
|
ExternalProject_Add_Step(dep_${projectname} free_build_space
|
||||||
DEPENDEES install # do after install
|
DEPENDEES install # do after install
|
||||||
COMMENT "Freeing Space: Removing source and build files"
|
COMMENT "Freeing Space: Removing source and build files"
|
||||||
@@ -276,7 +268,6 @@ else()
|
|||||||
EXCLUDE_FROM_ALL ON
|
EXCLUDE_FROM_ALL ON
|
||||||
INSTALL_DIR ${DESTDIR}
|
INSTALL_DIR ${DESTDIR}
|
||||||
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/${projectname}
|
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/${projectname}
|
||||||
${_source_dir_arg}
|
|
||||||
${_gen}
|
${_gen}
|
||||||
CMAKE_ARGS
|
CMAKE_ARGS
|
||||||
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
-DCMAKE_POLICY_VERSION_MINIMUM=3.5
|
||||||
@@ -405,6 +396,10 @@ include(libnoise/libnoise.cmake)
|
|||||||
|
|
||||||
include(Draco/Draco.cmake)
|
include(Draco/Draco.cmake)
|
||||||
|
|
||||||
|
include(FFMPEG/FFMPEG.cmake)
|
||||||
|
include(Assimp/Assimp.cmake)
|
||||||
|
|
||||||
|
|
||||||
# I *think* 1.1 is used for *just* md5 hashing?
|
# I *think* 1.1 is used for *just* md5 hashing?
|
||||||
# 3.1 has everything in the right place, but the md5 funcs used are deprecated
|
# 3.1 has everything in the right place, but the md5 funcs used are deprecated
|
||||||
# a grep across the repo shows it is used for other things
|
# a grep across the repo shows it is used for other things
|
||||||
@@ -415,12 +410,6 @@ if(NOT OPENSSL_FOUND)
|
|||||||
set(OPENSSL_PKG dep_OpenSSL)
|
set(OPENSSL_PKG dep_OpenSSL)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(FFMPEG/FFMPEG.cmake)
|
|
||||||
include(Assimp/Assimp.cmake)
|
|
||||||
|
|
||||||
include(DataChannel/DataChannel.cmake)
|
|
||||||
set(DATACHANNEL_PKG dep_DataChannel)
|
|
||||||
|
|
||||||
# we don't want to load a "wrong" openssl when loading curl
|
# we don't want to load a "wrong" openssl when loading curl
|
||||||
# so, just don't even bother
|
# so, just don't even bother
|
||||||
# ...i think this is how it works? change if wrong
|
# ...i think this is how it works? change if wrong
|
||||||
@@ -494,7 +483,6 @@ set(_dep_list
|
|||||||
dep_wxInspector
|
dep_wxInspector
|
||||||
dep_FFMPEG
|
dep_FFMPEG
|
||||||
dep_Assimp
|
dep_Assimp
|
||||||
${DATACHANNEL_PKG}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
|
|||||||
Vendored
-37
@@ -1,37 +0,0 @@
|
|||||||
# libdatachannel is the native ICE/DTLS/SCTP implementation used by the
|
|
||||||
# GUI WebRTC camera controller. Keep the source revision fixed: the signaling
|
|
||||||
# protocol is evolving independently of this transport dependency.
|
|
||||||
#
|
|
||||||
# It vendors plog, usrsctp and libjuice as git submodules, which a plain
|
|
||||||
# GitHub tag tarball does not include. The flatpak sandbox has no network
|
|
||||||
# access during the build, so there the manifest itself clones the repo
|
|
||||||
# (submodules and all) into the dependency download directory before the
|
|
||||||
# sandbox closes. ExternalProject_Add is pointed at that existing checkout
|
|
||||||
# instead of being given its own network-dependent download method.
|
|
||||||
if (FLATPAK)
|
|
||||||
set(_datachannel_source
|
|
||||||
SOURCE_DIR ${DEP_DOWNLOAD_DIR}/DataChannel
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
set(_datachannel_source
|
|
||||||
GIT_REPOSITORY https://github.com/paullouisageneau/libdatachannel.git
|
|
||||||
GIT_TAG v0.24.5
|
|
||||||
GIT_SHALLOW ON
|
|
||||||
GIT_SUBMODULES_RECURSE ON
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
orcaslicer_add_cmake_project(DataChannel
|
|
||||||
DEPENDS ${OPENSSL_PKG}
|
|
||||||
CMAKE_ARGS
|
|
||||||
-DNO_EXAMPLES=ON
|
|
||||||
-DNO_TESTS=ON
|
|
||||||
-DNO_WEBSOCKET=ON
|
|
||||||
-DNO_MEDIA=ON
|
|
||||||
-DUSE_NICE=OFF
|
|
||||||
-DUSE_SYSTEM_JUICE=OFF
|
|
||||||
-DUSE_SYSTEM_USRSCTP=OFF
|
|
||||||
-DOPENSSL_ROOT_DIR:PATH=${DESTDIR}
|
|
||||||
-DOPENSSL_USE_STATIC_LIBS=ON
|
|
||||||
${_datachannel_source}
|
|
||||||
)
|
|
||||||
Vendored
+7
-23
@@ -1,26 +1,14 @@
|
|||||||
set(_conf_cmd ./configure)
|
set(_conf_cmd ./configure)
|
||||||
|
|
||||||
set(_ffmpeg_depends)
|
|
||||||
set(_ffmpeg_configure_command ${_conf_cmd})
|
|
||||||
if (TARGET dep_OpenSSL)
|
|
||||||
set(_ffmpeg_depends DEPENDS dep_OpenSSL)
|
|
||||||
set(_ffmpeg_configure_command
|
|
||||||
${CMAKE_COMMAND} -E env
|
|
||||||
"PKG_CONFIG_PATH=${DESTDIR}/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}"
|
|
||||||
${_conf_cmd}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
set(_source_dir "${CMAKE_BINARY_DIR}/dep_FFMPEG-prefix/src/dep_FFMPEG")
|
set(_source_dir "${CMAKE_BINARY_DIR}/dep_FFMPEG-prefix/src/dep_FFMPEG")
|
||||||
|
|
||||||
set(PREBUILD_URL_arm64 "https://github.com/Noisyfox/FFmpeg-Builds-Orca/releases/download/autobuild-2026-09-18-16-50/ffmpeg-n7.0.3-33-g887d4b4919-winarm64-orca-shared-7.0.zip")
|
set(PREBUILD_URL_arm64 "https://github.com/Noisyfox/FFmpeg-Builds-Orca/releases/download/autobuild-2026-07-17-14-28/ffmpeg-n7.0.3-31-g9b6ffd74b5-winarm64-orca-shared-7.0.zip")
|
||||||
set(PREBUILD_HASH_arm64 "da480cbb39680056de824c57ec4dc3bd577b479ebbc310ff1f9dc55cf014b4c1")
|
set(PREBUILD_HASH_arm64 "12f4140279f2f8469885e1b5b2e8be9d788882914c21523cacd56989f3548054")
|
||||||
set(PREBUILD_URL_x64 "https://github.com/Noisyfox/FFmpeg-Builds-Orca/releases/download/autobuild-2026-09-18-16-50/ffmpeg-n7.0.3-33-g887d4b4919-win64-orca-shared-7.0.zip")
|
set(PREBUILD_URL_x64 "https://github.com/Noisyfox/FFmpeg-Builds-Orca/releases/download/autobuild-2026-07-17-14-28/ffmpeg-n7.0.3-31-g9b6ffd74b5-win64-orca-shared-7.0.zip")
|
||||||
set(PREBUILD_HASH_x64 "85da19daf198f5548259d8aabb349db84997a3f6e6886d8d7764114add9c6dae")
|
set(PREBUILD_HASH_x64 "e65916020ddb9ef84b2666dfbcbfc9b1d67f69d15b4a66db53754637bf2d498c")
|
||||||
|
|
||||||
ExternalProject_Add(dep_FFMPEG
|
ExternalProject_Add(dep_FFMPEG
|
||||||
${_ffmpeg_depends}
|
|
||||||
URL ${PREBUILD_URL_${DEPS_ARCH}}
|
URL ${PREBUILD_URL_${DEPS_ARCH}}
|
||||||
URL_HASH SHA256=${PREBUILD_HASH_${DEPS_ARCH}}
|
URL_HASH SHA256=${PREBUILD_HASH_${DEPS_ARCH}}
|
||||||
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/FFMPEG
|
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/FFMPEG
|
||||||
@@ -33,8 +21,6 @@ if (MSVC)
|
|||||||
)
|
)
|
||||||
|
|
||||||
else ()
|
else ()
|
||||||
set(_openssl_cmd --enable-openssl)
|
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(_minos_cmd
|
set(_minos_cmd
|
||||||
"--extra-cflags=-mmacosx-version-min=${DEP_OSX_TARGET}"
|
"--extra-cflags=-mmacosx-version-min=${DEP_OSX_TARGET}"
|
||||||
@@ -66,11 +52,10 @@ else ()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
ExternalProject_Add(dep_FFMPEG
|
ExternalProject_Add(dep_FFMPEG
|
||||||
${_ffmpeg_depends}
|
|
||||||
URL https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n7.0.3.tar.gz
|
URL https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n7.0.3.tar.gz
|
||||||
URL_HASH SHA256=DEEDCABE339165214A3637DF4C86A507AEF0D793CF8774FF68735F4737E8DDBC
|
URL_HASH SHA256=DEEDCABE339165214A3637DF4C86A507AEF0D793CF8774FF68735F4737E8DDBC
|
||||||
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/FFMPEG
|
DOWNLOAD_DIR ${DEP_DOWNLOAD_DIR}/FFMPEG
|
||||||
CONFIGURE_COMMAND ${_ffmpeg_configure_command}
|
CONFIGURE_COMMAND ${_conf_cmd}
|
||||||
${_cross_cmd}
|
${_cross_cmd}
|
||||||
${_pic_cmd}
|
${_pic_cmd}
|
||||||
${_arch_cmd}
|
${_arch_cmd}
|
||||||
@@ -78,21 +63,20 @@ else ()
|
|||||||
"--prefix=${DESTDIR}"
|
"--prefix=${DESTDIR}"
|
||||||
${_link_cmd}
|
${_link_cmd}
|
||||||
${_minos_cmd}
|
${_minos_cmd}
|
||||||
${_openssl_cmd}
|
|
||||||
--disable-doc
|
--disable-doc
|
||||||
--enable-small
|
--enable-small
|
||||||
--disable-outdevs
|
--disable-outdevs
|
||||||
--disable-filters
|
--disable-filters
|
||||||
--enable-filter=*null*,afade,*fifo,*format,*resample,aeval,allrgb,allyuv,atempo,pan,*bars,color,*key,crop,draw*,eq*,framerate,*_qsv,*_vaapi,*v4l2*,hw*,scale,volume,test*
|
--enable-filter=*null*,afade,*fifo,*format,*resample,aeval,allrgb,allyuv,atempo,pan,*bars,color,*key,crop,draw*,eq*,framerate,*_qsv,*_vaapi,*v4l2*,hw*,scale,volume,test*
|
||||||
--disable-protocols
|
--disable-protocols
|
||||||
--enable-protocol=file,fd,pipe,http,https,rtp,tcp,udp
|
--enable-protocol=file,fd,pipe,rtp,udp
|
||||||
--disable-muxers
|
--disable-muxers
|
||||||
--enable-muxer=rtp
|
--enable-muxer=rtp
|
||||||
--disable-encoders
|
--disable-encoders
|
||||||
--disable-decoders
|
--disable-decoders
|
||||||
--enable-decoder=*aac*,h264*,mp3*,mjpeg,rv*
|
--enable-decoder=*aac*,h264*,mp3*,mjpeg,rv*
|
||||||
--disable-demuxers
|
--disable-demuxers
|
||||||
--enable-demuxer=h264,mp3,mov,mpjpeg,rtsp,sdp
|
--enable-demuxer=h264,mp3,mov
|
||||||
--disable-zlib
|
--disable-zlib
|
||||||
--disable-avdevice
|
--disable-avdevice
|
||||||
BUILD_IN_SOURCE ON
|
BUILD_IN_SOURCE ON
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# G-code preview while dragging
|
||||||
|
|
||||||
|
The sliced preview draws every toolpath segment of the plate as an instanced box. On a large
|
||||||
|
plate that is tens of millions of segments, and the frame is GPU-bound: the cost is the number of
|
||||||
|
instances drawn, not anything the CPU does per frame. Dragging the camera over such a plate cannot
|
||||||
|
keep up. The `preview_reduced_detail_mode` preference (*Graphics > G-code Preview*, off by
|
||||||
|
default) lets the preview draw less while the user drags and put the full toolpaths back when they
|
||||||
|
let go.
|
||||||
|
|
||||||
|
| Preference | Values | Effect |
|
||||||
|
|---|---|---|
|
||||||
|
| `preview_reduced_detail_mode` | `off`, `solid`, `shell` | what is drawn while dragging |
|
||||||
|
|
||||||
|
libvgcode (`src/libvgcode`) builds and binds the reduced toolpath set, `GCodeViewer` maps the
|
||||||
|
preferences onto it and draws the solid model, and `GLCanvas3D` decides when the user is dragging.
|
||||||
|
The OpenGL ES path keeps a single set and ignores the preference.
|
||||||
|
|
||||||
|
## Two sets, one walk
|
||||||
|
|
||||||
|
`ViewerImpl::update_enabled_entities()` walks the visible vertex range once and fills two segment
|
||||||
|
index buffers side by side: the **full** set and the **reduced** set (segments and options).
|
||||||
|
Building them together is what makes switching free: starting or ending a drag is a buffer
|
||||||
|
binding, never a rebuild. A change of mode does rebuild. Nothing is built while the mode
|
||||||
|
is off, and the reduced buffers are then uploaded empty so that the last set does not stay
|
||||||
|
allocated.
|
||||||
|
|
||||||
|
Whatever the mode leaves out, the bottom and top layers of the visible range are kept whole: they
|
||||||
|
are the faces the range cuts open, and the top is what the user is looking at.
|
||||||
|
|
||||||
|
### Modes
|
||||||
|
|
||||||
|
- `EndLayersOnly` (`solid` in the preference) keeps only the two end layers. `GCodeViewer` then
|
||||||
|
draws the sliced objects and the prime tower as opaque solids, see below.
|
||||||
|
- `ShellOnly` (`shell`) keeps every role but the sparse infill, internal solid infill, internal
|
||||||
|
bridge infill and gap fill, which lie under the skins or between the walls. Walls, top and
|
||||||
|
bottom surfaces, bridges, supports and the prime tower are drawn whole, so from outside the
|
||||||
|
print looks as it does at rest. The roles come from
|
||||||
|
the slicer, so the classification is exact wherever the slicer's is; what it cannot express is
|
||||||
|
the inside of the prime tower and of a support, which share one role with their outside and are
|
||||||
|
kept whole. A profile with no top or bottom shell layers, or no walls, leaves the infill on the
|
||||||
|
surface, so `GCodeViewer` turns the hiding off for such a print when it loads it, from the
|
||||||
|
print's default region settings; per-object overrides are not consulted.
|
||||||
|
|
||||||
|
## The solid model
|
||||||
|
|
||||||
|
The preview already loads the sliced objects as shells for its translucent ghost.
|
||||||
|
`GCodeViewer::render_solid_model()` draws those shells opaque, in their filament colors, with the
|
||||||
|
`gouraud` shader, whose z range cuts them to the visible layer range. The two toolpath layers of
|
||||||
|
the reduced set are drawn afterwards and cap the cut with what was really printed there. The
|
||||||
|
shells hold only the objects, so while this mode is on the prime tower is added from its sliced
|
||||||
|
mesh, positioned as the print placed it. It is added or removed on its own when the mode changes,
|
||||||
|
without reloading the objects, keeps its opaque color so that it never appears among the
|
||||||
|
translucent shells, and stays out of their bounding box. Supports have no mesh and are not shown,
|
||||||
|
and `load_shells()` drops every non-model-part volume, so a negative volume is not cut out.
|
||||||
|
|
||||||
|
A plate whose shells are not loaded keeps drawing toolpaths, since the solid model would leave
|
||||||
|
only the end layers.
|
||||||
|
|
||||||
|
## Deciding that the user is dragging
|
||||||
|
|
||||||
|
`GLCanvas3D::_update_preview_interaction()` runs at the top of every preview frame, before the
|
||||||
|
canvas decides whether to reuse its cached scene, so that the switch lands in that frame. Dragging
|
||||||
|
is `GLCanvas3D::is_user_interacting()`, the same answer the scene cache reads: the camera, the
|
||||||
|
navigator, a gizmo, the rectangle selection or either slider being held. A slider reports this from
|
||||||
|
ImGui's active id rather than its dirty flag, which is raised and consumed inside one frame. A
|
||||||
|
wheel step has no duration, so it holds the reduced set for a 150 ms settle time instead, and the
|
||||||
|
frame that restores the toolpaths is scheduled for when that time runs out, since the render timer
|
||||||
|
only wakes the idle loop. A drag cut short by focus or capture loss is ended explicitly, and a
|
||||||
|
button release wakes the idle loop, because on some platforms nothing else would until the next
|
||||||
|
input.
|
||||||
|
|
||||||
|
## Reused scene frames
|
||||||
|
|
||||||
|
`GLCanvas3D` keeps its last scene pass for frames that only rebuild the overlay (`SceneCache`). Its
|
||||||
|
key covers the canvas size, the camera and hover state, not what the toolpath sets draw, so a frame
|
||||||
|
that reuses the scene must never be one on which the set is switched.
|
||||||
|
`_update_preview_interaction()` therefore reports whether the bound set changed, and a frame on
|
||||||
|
which it did redraws the scene. The canvas neither captures nor reuses the scene while the user
|
||||||
|
drags, so no reduced frame outlives a drag, and the frame that ends a wheel's settle time is
|
||||||
|
requested as a full frame.
|
||||||
+19
-45
@@ -28,8 +28,8 @@ Per-vendor granularity is what makes the system practical:
|
|||||||
- A vendor whose profile is bumped invalidates only its own cache. The other 60-odd
|
- A vendor whose profile is bumped invalidates only its own cache. The other 60-odd
|
||||||
vendors keep theirs — even when the bumped vendor is the shared Orca filament
|
vendors keep theirs — even when the bumped vendor is the shared Orca filament
|
||||||
library everyone else inherits from.
|
library everyone else inherits from.
|
||||||
- The setup wizard loads its vendors through the same routine as startup, so it
|
- The setup wizard, which loads vendors one at a time, gets the same speedup as
|
||||||
gets the same speedup without a second code path.
|
startup without a second code path.
|
||||||
- A vendor with no cache, or a broken one, costs only that vendor a parse.
|
- A vendor with no cache, or a broken one, costs only that vendor a parse.
|
||||||
|
|
||||||
A cache holds *system* presets only. User presets, project settings and modified
|
A cache holds *system* presets only. User presets, project settings and modified
|
||||||
@@ -162,20 +162,15 @@ cache nothing can invalidate is worse than no cache.
|
|||||||
|
|
||||||
Vendors load in a fixed order, because filament inheritance crosses exactly one
|
Vendors load in a fixed order, because filament inheritance crosses exactly one
|
||||||
boundary: any vendor's filament may inherit from the shared Orca filament library,
|
boundary: any vendor's filament may inherit from the shared Orca filament library,
|
||||||
and nothing else reaches across vendors — an `include` is always vendor-local. Only
|
and nothing else reaches across vendors — an `include` is always vendor-local. The
|
||||||
installing a vendor's presets crosses it; reading the vendor, from its cache or its
|
library therefore goes first, alone; every other vendor follows in parallel, resolving
|
||||||
JSONs, needs nothing from the library. So every other vendor is read while the library
|
against it; and the results are merged in a stable order:
|
||||||
loads, each is installed against it as soon as both are done, and the results are
|
|
||||||
merged in a stable order:
|
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart LR
|
flowchart LR
|
||||||
lib["1 · OrcaFilamentLibrary loaded;<br/>meanwhile every other vendor read<br/>from its cache or its JSONs"] --> par["2 · every other vendor installed<br/>in parallel, each into its own bundle,<br/>filaments resolving against the library"] --> merge["3 · bundles merged into one,<br/>in one pass per collection,<br/>in stable vendor order"]
|
lib["1 · OrcaFilamentLibrary<br/>loaded first, synchronously"] --> par["2 · every other vendor in parallel,<br/>each into its own bundle, filaments<br/>resolving against the loaded library"] --> merge["3 · bundles merged into one,<br/>sequentially, in stable vendor order"]
|
||||||
```
|
```
|
||||||
|
|
||||||
`PresetBundle::load_vendors` runs these steps for startup and for the setup wizard,
|
|
||||||
which hand it the vendors to load and the directory each is installed in.
|
|
||||||
|
|
||||||
Whether a vendor comes from its cache or from a parse changes nothing in that
|
Whether a vendor comes from its cache or from a parse changes nothing in that
|
||||||
order — both produce the same bundle, so cached and parsed vendors mix freely in
|
order — both produce the same bundle, so cached and parsed vendors mix freely in
|
||||||
one startup.
|
one startup.
|
||||||
@@ -216,12 +211,11 @@ shipped cache answered first, so the profile in `<data_dir>/system/` was never p
|
|||||||
and its cache was never written back.
|
and its cache was never written back.
|
||||||
|
|
||||||
Serving from a cache is not a memory-image restore. The entries are deserialized and
|
Serving from a cache is not a memory-image restore. The entries are deserialized and
|
||||||
then installed by `install_vendor`, the routine the JSON path hands the vendor's entries
|
then installed one by one — inheritance resolved against the presets installed before
|
||||||
to once it has parsed the sub-files: inheritance resolved against the presets installed
|
them and the currently loaded filament library, includes layered in, configs flattened
|
||||||
before them and the currently loaded filament library, includes layered in, configs
|
onto the collection defaults, validated and registered — by the same function the JSON
|
||||||
flattened onto the collection defaults, validated and registered. An `include` layers
|
path calls straight after parsing a sub-file. An `include` layers what the included
|
||||||
what the included base states, between the parent and the preset's own keys: the base's
|
base states, between the parent and the preset's own keys: the base's diff against the
|
||||||
diff against the
|
|
||||||
default, taken when the base itself was installed and before the per-variant padding
|
default, taken when the base itself was installed and before the per-variant padding
|
||||||
`inherits` sees, so only what a template sets reaches the presets including it. The two
|
`inherits` sees, so only what a template sets reaches the presets including it. The two
|
||||||
paths share everything below the parse, which is what makes a cache-loaded bundle
|
paths share everything below the parse, which is what makes a cache-loaded bundle
|
||||||
@@ -229,16 +223,6 @@ indistinguishable from a JSON-loaded one by construction rather than by test cov
|
|||||||
Installation also rebuilds each preset's file path from the local data directory, so a
|
Installation also rebuilds each preset's file path from the local data directory, so a
|
||||||
shipped cache never carries the generating machine's paths.
|
shipped cache never carries the generating machine's paths.
|
||||||
|
|
||||||
Installing an entry is split in two. `resolve_vendor_preset` flattens it, reading only
|
|
||||||
what is registered under the names it inherits and includes, and `commit_vendor_preset`
|
|
||||||
registers it, the only step that writes anything shared. Entries resolve across threads
|
|
||||||
in runs and commit in the order the vendor lists them. A run ends before an entry that
|
|
||||||
inherits or includes one already in it, since that one's commit registers what the
|
|
||||||
entry resolves against, so no entry in a run reads what another in it registers. An
|
|
||||||
entry's parse messages are held until it commits. The bundle, the log's parse and
|
|
||||||
install messages and the error count therefore come out as parsing and installing one
|
|
||||||
entry at a time would leave them, whatever the listing order.
|
|
||||||
|
|
||||||
App upgrades work because a cache normally survives one. Only a deliberate
|
App upgrades work because a cache normally survives one. Only a deliberate
|
||||||
`CACHE_VERSION` bump makes an installed cache unreadable, and that is handled at
|
`CACHE_VERSION` bump makes an installed cache unreadable, and that is handled at
|
||||||
install time rather than at load: a vendor whose cache this build cannot read counts
|
install time rather than at load: a vendor whose cache this build cannot read counts
|
||||||
@@ -270,20 +254,17 @@ the wizard caches the *derived JSON*, not another form of the inputs:
|
|||||||
open, the wizard computes the current stamps (one version peek per vendor) and, when
|
open, the wizard computes the current stamps (one version peek per vendor) and, when
|
||||||
they match, serves the catalog from the file — no bundle built, no preset installed.
|
they match, serves the catalog from the file — no bundle built, no preset installed.
|
||||||
Caching bundle inputs instead was tried and measured: rebuilding the bundle from
|
Caching bundle inputs instead was tried and measured: rebuilding the bundle from
|
||||||
per-vendor caches costs over a second of preset installation whatever feeds it, so
|
per-vendor caches costs ~2 s of preset installation whatever feeds it, so only
|
||||||
only skipping the rebuild entirely wins.
|
skipping the rebuild entirely wins.
|
||||||
|
|
||||||
Any change to the set — a vendor added, removed or updated, or its cache-only
|
Any change to the set — a vendor added, removed or updated, or its cache-only
|
||||||
`.opc` replaced by a newer one — changes the stamps and retires the whole file;
|
`.opc` replaced by a newer one — changes the stamps and retires the whole file;
|
||||||
the wizard then rebuilds the bundle with `PresetBundle::load_vendors`, the load
|
the wizard then rebuilds the bundle vendor by vendor (per-vendor caches serving where
|
||||||
startup uses (per-vendor caches serving where they cover), and writes the catalog
|
they cover) and writes the catalog back. Selections, region and per-open decorations
|
||||||
back. When a vendor fails to load, the filament library included, that open falls
|
are applied downstream of the cache either way, so a served catalog is
|
||||||
back to the wizard's own scan of the vendor JSONs, as when no bundle can be built,
|
indistinguishable from a rebuilt one. Nothing ships this file and the updater never
|
||||||
and writes nothing. Selections, region and per-open decorations are applied
|
touches it; it is a locally written artifact, re-derived whenever stale, written
|
||||||
downstream of the cache either way, so a served catalog is indistinguishable from a
|
through a temp file and rename so half a cache is never readable.
|
||||||
rebuilt one. Nothing ships this file and the updater never touches it; it is a
|
|
||||||
locally written artifact, re-derived whenever stale, written through a temp file and
|
|
||||||
rename so half a cache is never readable.
|
|
||||||
|
|
||||||
The cache lives under `<data_dir>/cache/`, not beside the vendors: everything that
|
The cache lives under `<data_dir>/cache/`, not beside the vendors: everything that
|
||||||
scans `<data_dir>/system/` treats any `.opc` there as a vendor, so a non-vendor
|
scans `<data_dir>/system/` treats any `.opc` there as a vendor, so a non-vendor
|
||||||
@@ -397,13 +378,6 @@ enumerates only `*.json` will find no vendors at all in a packaged build.
|
|||||||
the `CachedPreset` field list — written and read by `visit_entry` in
|
the `CachedPreset` field list — written and read by `visit_entry` in
|
||||||
`PresetCacheFormat.cpp`, one list for the save, the load and the name peek alike — or
|
`PresetCacheFormat.cpp`, one list for the save, the load and the name peek alike — or
|
||||||
the cache's own layout or stamps, requires bumping `CACHE_VERSION` by hand.
|
the cache's own layout or stamps, requires bumping `CACHE_VERSION` by hand.
|
||||||
- **Adding a kind of reference between presets**, as `inherits` and `include` are:
|
|
||||||
parse the names into `CachedPreset` (a field change, so `CACHE_VERSION` is bumped),
|
|
||||||
have `install_vendor_entries` end a run before an entry that names one already in it
|
|
||||||
and retain what the names point at, look them up only in `resolve_vendor_preset`, and
|
|
||||||
register what they point at only in `commit_vendor_preset`. The listing-order test in
|
|
||||||
`test_vendor_cache.cpp` fails for a kind the runs do not check once its fixture uses
|
|
||||||
it.
|
|
||||||
- **The dictionary indexes with a `uint16`**, so `print_config_def` may hold at most
|
- **The dictionary indexes with a `uint16`**, so `print_config_def` may hold at most
|
||||||
65535 options and one cache at most 65535 distinct enum value names.
|
65535 options and one cache at most 65535 distinct enum value names.
|
||||||
`CacheDictionary::save` throws past that, which surfaces when CI generates the
|
`CacheDictionary::save` throws past that, which surfaces when CI generates the
|
||||||
|
|||||||
@@ -1,240 +0,0 @@
|
|||||||
# Printer agents
|
|
||||||
|
|
||||||
Printer agents isolate printer-specific communication from the rest of OrcaSlicer. The GUI and
|
|
||||||
`DeviceManager` operate on a shared set of printer operations and device state; a selected printer
|
|
||||||
agent implements those operations for a particular printer ecosystem. The agent boundary allows
|
|
||||||
Bambu, Moonraker-based printers, built-in integrations, and Python-provided integrations to use the
|
|
||||||
same application workflow without making the GUI understand every printer protocol.
|
|
||||||
|
|
||||||
The current boundary is an adapter boundary around the existing application contract. In particular,
|
|
||||||
some request fields and message payloads still use the Bambu-shaped representation that existing
|
|
||||||
`MachineObject` and `DeviceManager` code consumes. The printer agent is responsible for translating
|
|
||||||
that representation into the protocol spoken by its printer. This is an intentional compatibility
|
|
||||||
constraint of the current design; the interface is not yet a neutral printer protocol.
|
|
||||||
|
|
||||||
The v1 dialect migration path is deliberately narrow. `DeviceManager` currently speaks the Bambu JSON
|
|
||||||
dialect because that is the payload shape already used throughout the command and state workflow. The
|
|
||||||
v1 `OrcaPrinterAgent` also accepts that Bambu dialect. Its transport path places the small translation
|
|
||||||
needed for the target printer at `deliver_to_sink`, keeping the compatibility code at the edge rather
|
|
||||||
than spreading it through `DeviceManager` or the agent interface.
|
|
||||||
|
|
||||||
The eventual direction is for `DeviceManager` to produce an Orca JSON dialect. The Bambu agent will then
|
|
||||||
own the translation from Orca JSON to Bambu's protocol, while `OrcaPrinterAgent` can forward the Orca
|
|
||||||
payload directly to its sink. The v1 translation at `deliver_to_sink` can then be removed without
|
|
||||||
changing `DeviceManager`, the command callers, or the rest of the agent workflow.
|
|
||||||
|
|
||||||
## Components
|
|
||||||
|
|
||||||
The system has four relevant layers:
|
|
||||||
|
|
||||||
```text
|
|
||||||
GUI / DeviceManager / MachineObject
|
|
||||||
|
|
|
||||||
NetworkAgent
|
|
||||||
/ \
|
|
||||||
IPrinterAgent ICloudServiceAgent
|
|
||||||
| |
|
|
||||||
printer protocol authentication and cloud services
|
|
||||||
```
|
|
||||||
|
|
||||||
### `DeviceManager` and `MachineObject`
|
|
||||||
|
|
||||||
`DeviceManager` owns the application-facing printer workflow. It maintains `MachineObject` instances,
|
|
||||||
updates their state, filters devices for the active printer agent, and initiates operations such as
|
|
||||||
homing, temperature changes, printing, subscriptions, and camera playback.
|
|
||||||
|
|
||||||
`MachineObject` remains the shared state model used by the GUI. It does not contain the implementation
|
|
||||||
of a printer protocol. When a device is discovered or returned by a cloud query, the device is tagged
|
|
||||||
with the active `printer_agent_id`. Device lists and selected-machine operations use that tag to avoid
|
|
||||||
sending an operation through an agent that does not own the device.
|
|
||||||
|
|
||||||
### `NetworkAgent`
|
|
||||||
|
|
||||||
`NetworkAgent` is the façade used by the GUI and `DeviceManager`. It owns:
|
|
||||||
|
|
||||||
- the currently selected `IPrinterAgent`;
|
|
||||||
- the registered cloud-service instances, indexed by provider;
|
|
||||||
- callbacks shared by the active printer agent and the application;
|
|
||||||
- the forwarding methods for printer commands and cloud operations.
|
|
||||||
|
|
||||||
There is one active printer agent for the currently selected printer preset. Switching the preset
|
|
||||||
increments the machine-list generation, disconnects the old printer agent, removes its callbacks, and
|
|
||||||
installs the newly selected agent. The façade then forwards printer operations to that agent.
|
|
||||||
|
|
||||||
Cloud operations are selected separately using a provider key. `NetworkAgent` forwards a cloud request
|
|
||||||
to the matching `ICloudServiceAgent`, and forwards cloud camera operations with a device ID. The
|
|
||||||
printer agent receives a cloud-agent pointer through `set_cloud_agent()` when it is created, allowing
|
|
||||||
printer communication to obtain cloud tokens without depending on a concrete cloud implementation.
|
|
||||||
|
|
||||||
### `IPrinterAgent`
|
|
||||||
|
|
||||||
`IPrinterAgent` is the printer-facing contract. It covers:
|
|
||||||
|
|
||||||
- cloud-relay and direct-LAN message delivery;
|
|
||||||
- LAN connection, discovery, binding, and certificates;
|
|
||||||
- printer subscriptions and callbacks;
|
|
||||||
- print operations;
|
|
||||||
- filament synchronization;
|
|
||||||
- camera capability and local camera URL reporting;
|
|
||||||
- printer command methods.
|
|
||||||
|
|
||||||
Concrete built-in implementations include the Bambu wrapper, the native Orca/Moonraker path, and
|
|
||||||
other printer-agent implementations registered by the application. A printer agent may use either
|
|
||||||
the cloud agent, a direct LAN connection, or both.
|
|
||||||
|
|
||||||
### `ICloudServiceAgent`
|
|
||||||
|
|
||||||
`ICloudServiceAgent` owns authentication and services provided by a cloud backend. It covers login
|
|
||||||
state, tokens, user and printer lists, settings synchronization, model services, cloud messages, and
|
|
||||||
cloud camera operations.
|
|
||||||
|
|
||||||
Cloud camera operations are device-scoped:
|
|
||||||
|
|
||||||
- `get_camera_url(dev_id, callback)` obtains a stream URL for one device;
|
|
||||||
- `create_camera_signaling_channel(dev_id)` creates signaling for one device where the provider
|
|
||||||
supports it.
|
|
||||||
|
|
||||||
This is separate from the local camera URL exposed by `IPrinterAgent`, which is currently scoped to
|
|
||||||
the active printer agent because a normal LAN agent represents one physical printer connection.
|
|
||||||
|
|
||||||
## Agent registration and selection
|
|
||||||
|
|
||||||
`NetworkAgentFactory` maintains the printer-agent registry. Each registry entry contains an agent ID,
|
|
||||||
a display name, and a factory function. Built-in agents register during application initialization.
|
|
||||||
Python printer-agent capabilities register dynamically and contribute an agent ID and factory entry.
|
|
||||||
|
|
||||||
The selected printer preset contains the printer-agent choice. If no explicit choice is stored, the
|
|
||||||
application preserves the existing default behavior: Bambu presets select the Bambu agent and other
|
|
||||||
presets select the native Orca agent. When a preset is changed, `GUI_App` resolves the effective agent
|
|
||||||
ID, obtains the corresponding cloud agent, creates the printer agent through the registry, and installs
|
|
||||||
it in `NetworkAgent`.
|
|
||||||
|
|
||||||
The registry rejects conflicting agent IDs. This matters for Python plugins because an agent ID is the
|
|
||||||
stable identity used by presets and device ownership; two enabled plugin capabilities must not claim
|
|
||||||
the same ID.
|
|
||||||
|
|
||||||
## Message and command flow
|
|
||||||
|
|
||||||
There are two low-level message paths:
|
|
||||||
|
|
||||||
- `send_message()` publishes a command through the printer's cloud relay;
|
|
||||||
- `send_message_to_printer()` sends a command directly to the printer over the LAN path.
|
|
||||||
|
|
||||||
Both paths accept a JSON string, quality-of-service and flag values, and return the existing network
|
|
||||||
status code domain. The agent owns the conversion from that JSON contract to its native transport.
|
|
||||||
|
|
||||||
The typed `command_*` methods are the application-facing convenience layer. The five generic defaults
|
|
||||||
currently implemented by `IPrinterAgent` construct the existing JSON dialect and route through the
|
|
||||||
same message path:
|
|
||||||
|
|
||||||
| Method | Default operation |
|
|
||||||
| --- | --- |
|
|
||||||
| `command_xyz_abs()` | Send `G90` for absolute positioning |
|
|
||||||
| `command_auto_leveling()` | Send `G29` for bed leveling |
|
|
||||||
| `command_go_home()` | Use the supported homing operation or send `G28` |
|
|
||||||
| `command_set_bed()` | Use the supported bed control or send `M140` |
|
|
||||||
| `command_set_nozzle()` | Send `M104` for nozzle temperature |
|
|
||||||
|
|
||||||
These are compatibility defaults for common printer workflows, not a guarantee that every firmware
|
|
||||||
implements every command identically. An agent can override a method when its protocol needs another
|
|
||||||
operation. For example, a Klipper configuration may use `BED_MESH_CALIBRATE` instead of `G29`.
|
|
||||||
|
|
||||||
The remaining common command methods default to `ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED` because their
|
|
||||||
existing behavior is vendor-specific or has no portable implementation:
|
|
||||||
|
|
||||||
- AMS RFID refresh;
|
|
||||||
- AMS calibration;
|
|
||||||
- AMS tray selection;
|
|
||||||
- camera start;
|
|
||||||
- axis control.
|
|
||||||
|
|
||||||
The methods remain on the common interface so an agent that supports them can override them explicitly.
|
|
||||||
`sequence_id` remains part of the command contract because `DeviceManager` creates and tracks it as
|
|
||||||
the command ID.
|
|
||||||
|
|
||||||
## Device ownership and stale responses
|
|
||||||
|
|
||||||
Printer-agent ownership is represented by `printer_agent_id` on device records and `MachineObject`
|
|
||||||
instances. The active agent ID is attached when a device is discovered, returned by a cloud list, or
|
|
||||||
reused after a preset switch. Local-machine configuration also persists the agent ID so a saved LAN
|
|
||||||
device is not silently reused by an unrelated agent.
|
|
||||||
|
|
||||||
Cloud printer-list responses carry three pieces of request context added by `NetworkAgent`:
|
|
||||||
|
|
||||||
```text
|
|
||||||
provider cloud provider used for the request
|
|
||||||
agent_id active printer agent when the request was made
|
|
||||||
generation machine-list generation when the request was made
|
|
||||||
```
|
|
||||||
|
|
||||||
`DeviceManager` accepts the response only when those values still match the current provider, active
|
|
||||||
agent, and generation. This prevents a slow response from the previous preset or provider from
|
|
||||||
repopulating the current device list.
|
|
||||||
|
|
||||||
The provider mapping is currently selected by `GUI_App`: the Bambu agent maps to the Bambu cloud
|
|
||||||
provider and other agents map to the Orca cloud provider. The generation check protects that existing
|
|
||||||
selection from races; it does not make cloud-provider ownership intrinsic to an agent. Cloud-printer
|
|
||||||
ownership and the broader Orca cloud services are therefore still separate architectural concerns.
|
|
||||||
|
|
||||||
## Python printer agents
|
|
||||||
|
|
||||||
`PrinterAgentPluginCapability` implements `IPrinterAgent` directly. The live capability object is
|
|
||||||
registered with `NetworkAgentFactory` and handed out as the printer agent when its agent ID is selected.
|
|
||||||
The plugin receives the selected `ICloudServiceAgent` through `set_cloud_agent()` just like a built-in
|
|
||||||
printer agent.
|
|
||||||
|
|
||||||
Python plugins must implement the core communication and lifecycle methods required by the interface,
|
|
||||||
including agent metadata, printer connection, discovery callbacks, and the two message-send methods.
|
|
||||||
Methods that are meaningful only to a particular printer are optional overrides where the C++ base
|
|
||||||
class provides a default.
|
|
||||||
|
|
||||||
All ten `command_*` methods are available in the Python binding and in the trampoline. Their override
|
|
||||||
status is intentionally optional:
|
|
||||||
|
|
||||||
- the five generic commands use the C++ default when Python does not override them;
|
|
||||||
- the five vendor-specific commands return `NOT_SUPPORTED` unless Python supplies an implementation;
|
|
||||||
- a Python implementation can replace either behavior for its own protocol.
|
|
||||||
|
|
||||||
The Python camera binding exposes HTTP, HTTPS, RTSP, and HTTP-snapshot modes. WebRTC remains a
|
|
||||||
built-in C++ camera mode, but is not exposed as a Python mode because the current Python capability
|
|
||||||
does not provide the corresponding cloud signaling-channel contract.
|
|
||||||
|
|
||||||
## Camera playback boundary
|
|
||||||
|
|
||||||
The camera stream mode describes how a stream is obtained; it does not by itself define ownership of
|
|
||||||
the wxWidgets view that renders it. `MediaPlayCtrl` selects and tears down the active backend, while
|
|
||||||
the wx parent owns the child window or renderer. This is important because a web view, native media
|
|
||||||
control, and frame-based/WebRTC renderer have different wx window-lifetime requirements.
|
|
||||||
|
|
||||||
Cloud URL and signaling requests are routed through `NetworkAgent` to the cloud provider selected for
|
|
||||||
the device. Local URL requests are routed to the active printer agent. The distinction keeps cloud
|
|
||||||
account services device-scoped while preserving the current one-LAN-agent/one-printer model.
|
|
||||||
|
|
||||||
## Compatibility constraints
|
|
||||||
|
|
||||||
The printer-agent boundary intentionally preserves several existing application contracts:
|
|
||||||
|
|
||||||
- Bambu-shaped JSON is still the shared command representation;
|
|
||||||
- existing network status codes are reused, with Orca-specific unsupported/capability errors added
|
|
||||||
in the Orca-reserved range;
|
|
||||||
- `MachineObject` remains the shared device-state model;
|
|
||||||
- preset and local-machine data retain compatibility with the existing agent-selection behavior;
|
|
||||||
- Python plugins use the existing capability and pybind11 registration system.
|
|
||||||
|
|
||||||
The agent abstraction is therefore responsible for containing vendor differences, not for pretending
|
|
||||||
that all vendor protocols are identical. The planned Orca JSON dialect is the protocol-neutral command
|
|
||||||
model for the `DeviceManager`/agent boundary. Once it is introduced, Bambu-specific translation remains
|
|
||||||
inside the Bambu agent and the Orca agent's v1 sink adapter can be removed as a self-contained cleanup.
|
|
||||||
|
|
||||||
## Main implementation locations
|
|
||||||
|
|
||||||
- [`IPrinterAgent`](../../src/slic3r/Utils/IPrinterAgent.hpp) — printer-agent contract and generic command defaults
|
|
||||||
- [`ICloudServiceAgent`](../../src/slic3r/Utils/ICloudServiceAgent.hpp) — cloud service and per-device
|
|
||||||
cloud camera contract
|
|
||||||
- [`NetworkAgent`](../../src/slic3r/Utils/NetworkAgent.hpp) — façade and dispatch between active agents
|
|
||||||
- [`NetworkAgentFactory`](../../src/slic3r/Utils/NetworkAgentFactory.hpp) — built-in and Python agent registry
|
|
||||||
- [`DeviceManager`](../../src/slic3r/GUI/DeviceCore/DevManager.cpp) — device ownership, filtering, and
|
|
||||||
stale-response checks
|
|
||||||
- [`PrinterAgentPluginCapability`](../../src/slic3r/plugin/pluginTypes/printerAgent/PrinterAgentPluginCapability.cpp)
|
|
||||||
— Python bindings
|
|
||||||
- [`MediaPlayCtrl`](../../src/slic3r/GUI/MediaPlayCtrl.cpp) — camera backend selection and playback lifecycle
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "OrcaFilamentLibrary",
|
"name": "OrcaFilamentLibrary",
|
||||||
"version": "02.04.00.17",
|
"version": "02.04.00.15",
|
||||||
"force_update": "0",
|
"force_update": "0",
|
||||||
"description": "Orca Filament Library",
|
"description": "Orca Filament Library",
|
||||||
"filament_list": [
|
"filament_list": [
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"filament_id": "OFvgE0Zh",
|
"filament_id": "OFvgE0Zh",
|
||||||
"instantiation": "false",
|
"instantiation": "false",
|
||||||
"fan_cooling_layer_time": [
|
"fan_cooling_layer_time": [
|
||||||
"85"
|
"81"
|
||||||
],
|
],
|
||||||
"fan_min_speed": [
|
"fan_min_speed": [
|
||||||
"50"
|
"50"
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
-2
@@ -111,7 +111,6 @@
|
|||||||
"1"
|
"1"
|
||||||
],
|
],
|
||||||
"enable_pressure_advance": [
|
"enable_pressure_advance": [
|
||||||
"0",
|
|
||||||
"0"
|
"0"
|
||||||
],
|
],
|
||||||
"eng_plate_temp": [
|
"eng_plate_temp": [
|
||||||
@@ -317,7 +316,6 @@
|
|||||||
"2"
|
"2"
|
||||||
],
|
],
|
||||||
"pressure_advance": [
|
"pressure_advance": [
|
||||||
"0.02",
|
|
||||||
"0.02"
|
"0.02"
|
||||||
],
|
],
|
||||||
"reduce_fan_stop_start_freq": [
|
"reduce_fan_stop_start_freq": [
|
||||||
|
|||||||
@@ -575,7 +575,7 @@ function CapabilityCanRun(plugin, capability) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function IsPluginChecked(plugin) {
|
function IsPluginChecked(plugin) {
|
||||||
return plugin.is_loaded;
|
return GetStatus(plugin) === "Activated";
|
||||||
}
|
}
|
||||||
|
|
||||||
function HasMixedCapabilityState(plugin) {
|
function HasMixedCapabilityState(plugin) {
|
||||||
@@ -1347,8 +1347,6 @@ function StatusDescription(plugin) {
|
|||||||
return "This plugin is still loading.";
|
return "This plugin is still loading.";
|
||||||
case "Error":
|
case "Error":
|
||||||
return "This plugin is blocked until its error is fixed.";
|
return "This plugin is blocked until its error is fixed.";
|
||||||
case "RuntimeError":
|
|
||||||
return "This plugin is loaded but a capability reported an error.";
|
|
||||||
case "Inactive":
|
case "Inactive":
|
||||||
default:
|
default:
|
||||||
return "This plugin is inactive. Activate it to install or load it.";
|
return "This plugin is inactive. Activate it to install or load it.";
|
||||||
|
|||||||
@@ -424,11 +424,6 @@ body.pane-resizing {
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-cell.status-runtimeerror {
|
|
||||||
color: var(--plugin-status-warn);
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-cell.status-loading {
|
.status-cell.status-loading {
|
||||||
color: var(--plugin-status-warn);
|
color: var(--plugin-status-warn);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@@ -685,11 +680,6 @@ body.pane-resizing {
|
|||||||
color: var(--plugin-status-danger);
|
color: var(--plugin-status-danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-status-chip.status-runtimeerror {
|
|
||||||
background: var(--plugin-status-warn-bg);
|
|
||||||
color: var(--plugin-status-warn);
|
|
||||||
}
|
|
||||||
|
|
||||||
.detail-status-chip.status-loading {
|
.detail-status-chip.status-loading {
|
||||||
background: var(--plugin-status-warn-bg);
|
background: var(--plugin-status-warn-bg);
|
||||||
color: var(--plugin-status-warn);
|
color: var(--plugin-status-warn);
|
||||||
|
|||||||
+30
-129
@@ -214,9 +214,9 @@ function ShowModelInfo( pModel )
|
|||||||
|
|
||||||
SendWXDebugInfo("Model Name: "+sModelName);
|
SendWXDebugInfo("Model Name: "+sModelName);
|
||||||
|
|
||||||
$('#ModelName').text(sModelName);
|
$('#ModelName').html(sModelName);
|
||||||
$('#ModelName').attr('title',sModelName);
|
$('#ModelName').attr('title',sModelName);
|
||||||
$('#ModelAuthorName').text(sModelAuthor);
|
$('#ModelAuthorName').html(sModelAuthor);
|
||||||
|
|
||||||
switch(UploadType)
|
switch(UploadType)
|
||||||
{
|
{
|
||||||
@@ -268,7 +268,7 @@ function ShowModelInfo( pModel )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#Model_Desc').empty().append( SanitizeDescHtml( html_decode(sModelDesc) ) );
|
$('#Model_Desc').html( html_decode(sModelDesc) );
|
||||||
|
|
||||||
let ModelPreviewList=pModel.preview_img;
|
let ModelPreviewList=pModel.preview_img;
|
||||||
let TotalPreview=ModelPreviewList.length;
|
let TotalPreview=ModelPreviewList.length;
|
||||||
@@ -281,15 +281,16 @@ function ShowModelInfo( pModel )
|
|||||||
|
|
||||||
if(TotalPreview>0)
|
if(TotalPreview>0)
|
||||||
{
|
{
|
||||||
$('#ModelPreviewList').empty();
|
let htmlPreview='';
|
||||||
for(let pn=0;pn<TotalPreview;pn++)
|
for(let pn=0;pn<TotalPreview;pn++)
|
||||||
{
|
{
|
||||||
//let FTmpPath=decodeURIComponent(ModelPreviewList[pn]);
|
//let FTmpPath=decodeURIComponent(ModelPreviewList[pn]);
|
||||||
let FTmpPath=ModelPreviewList[pn]['filepath'];
|
let FTmpPath=ModelPreviewList[pn]['filepath'];
|
||||||
|
|
||||||
$('#ModelPreviewList').append( $('<div class="swiper-slide"></div>').append( $('<img class="Model_PrevImg" />').attr('src',FTmpPath) ) );
|
htmlPreview+='<div class="swiper-slide"><img class="Model_PrevImg" src="'+FTmpPath+'" /></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$('#ModelPreviewList').html(htmlPreview);
|
||||||
$('#Model_Preview_Image').viewer({
|
$('#Model_Preview_Image').viewer({
|
||||||
title: false,
|
title: false,
|
||||||
fullsreen: false,
|
fullsreen: false,
|
||||||
@@ -409,8 +410,7 @@ function ConstructFileHtml( ID, pItem )
|
|||||||
{
|
{
|
||||||
let fTotal=pItem.length;
|
let fTotal=pItem.length;
|
||||||
|
|
||||||
let pBoard=$('#'+ID+' .FileListBoard');
|
let strHtml='';
|
||||||
pBoard.empty();
|
|
||||||
for( let f=0;f<fTotal;f++ )
|
for( let f=0;f<fTotal;f++ )
|
||||||
{
|
{
|
||||||
let pOne=pItem[f];
|
let pOne=pItem[f];
|
||||||
@@ -443,139 +443,39 @@ function ConstructFileHtml( ID, pItem )
|
|||||||
ImgPath='img/default.png';
|
ImgPath='img/default.png';
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add html. File names come from the 3MF, so build the nodes rather than concatenating markup.
|
//Add html
|
||||||
let pIconImg=$('<img />').attr('src',ImgPath);
|
|
||||||
let pMenu=$('<div class="FileMenu"><img src="img/s.svg" /></div>');
|
|
||||||
if( strClass!='ImageIcon' )
|
if( strClass!='ImageIcon' )
|
||||||
{
|
{
|
||||||
pMenu.on('click', function(){ OnClickOpenFile(tPath); });
|
strHtml+='<div class="FileItem">'+
|
||||||
|
' <div class="'+strClass+'"><img src="'+ImgPath+'" /></div>'+
|
||||||
|
' <div class="FileText">'+
|
||||||
|
' <div class="FileName">'+tName+'</div>'+
|
||||||
|
' </div>'+
|
||||||
|
' <div class="FileMenu" onClick="OnClickOpenFile(\''+tPath+'\')"><img src="img/s.svg" /></div>'+
|
||||||
|
'</div>';
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ImgID++;
|
ImgID++;
|
||||||
let TmpImgID="AF"+ImgID;
|
let TmpImgID="AF"+ImgID;
|
||||||
|
|
||||||
pIconImg.attr('id',TmpImgID);
|
strHtml+='<div class="FileItem">'+
|
||||||
pMenu.on('click', function(){ OnClickOpenImage(TmpImgID); });
|
' <div class="'+strClass+'"><img id="'+TmpImgID+'" src="'+ImgPath+'" /></div>'+
|
||||||
|
' <div class="FileText">'+
|
||||||
|
' <div class="FileName">'+tName+'</div>'+
|
||||||
|
' </div>'+
|
||||||
|
' <div class="FileMenu" onClick="OnClickOpenImage(\''+TmpImgID+'\')"><img src="img/s.svg" /></div>'+
|
||||||
|
'</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
let pFileItem=$('<div class="FileItem"></div>');
|
|
||||||
pFileItem.append( $('<div></div>').addClass(strClass).append(pIconImg) );
|
|
||||||
pFileItem.append( $('<div class="FileText"></div>').append( $('<div class="FileName"></div>').text(tName).attr('title',tName) ) );
|
|
||||||
pFileItem.append( pMenu );
|
|
||||||
pBoard.append( pFileItem );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$('#'+ID+' .FileListBoard').html(strHtml);
|
||||||
|
|
||||||
if( fTotal>0 )
|
if( fTotal>0 )
|
||||||
$('#'+ID).show();
|
$('#'+ID).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Descriptions are untrusted 3MF metadata that may carry rich-text HTML (e.g. from MakerWorld).
|
|
||||||
// Rebuild them from an inert parse, keeping only plain formatting tags and http(s) links and images.
|
|
||||||
var DescAllowedTags=['P','BR','B','STRONG','I','EM','U','S','STRIKE','DEL','INS','SUB','SUP','SMALL','MARK',
|
|
||||||
'Q','ABBR','KBD','WBR','H1','H2','H3','H4','H5','H6','UL','OL','LI','DL','DT','DD','BLOCKQUOTE','PRE','CODE',
|
|
||||||
'HR','SPAN','DIV','FIGURE','FIGCAPTION','TABLE','CAPTION','THEAD','TBODY','TFOOT','TR','TH','TD','A','IMG'];
|
|
||||||
// Plain attributes kept per tag; the numeric ones must be plain non-negative integers.
|
|
||||||
var DescAllowedAttrs={'IMG':['alt','title','width','height'],'TD':['colspan','rowspan'],'TH':['colspan','rowspan'],'OL':['start']};
|
|
||||||
var DescNumericAttrs=['width','height','colspan','rowspan','start'];
|
|
||||||
// Dropped together with their content; any other unknown tag is unwrapped to its children.
|
|
||||||
var DescDroppedTags=['SCRIPT','STYLE','TEMPLATE','NOSCRIPT','TEXTAREA','TITLE','IFRAME','FRAME','OBJECT','EMBED','SVG','MATH'];
|
|
||||||
|
|
||||||
function IsHttpUrl( strUrl )
|
|
||||||
{
|
|
||||||
// The scheme must be written as is, so nothing the URL parser would strip can precede or split it.
|
|
||||||
if( typeof strUrl!='string' || !/^https?:/i.test(strUrl) )
|
|
||||||
return false;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
let sProtocol=new URL(strUrl).protocol;
|
|
||||||
return sProtocol=='http:' || sProtocol=='https:';
|
|
||||||
}
|
|
||||||
catch(e)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Images load as soon as the page opens, so only https sources are kept: no plain-http requests to the local network.
|
|
||||||
function IsHttpsUrl( strUrl )
|
|
||||||
{
|
|
||||||
return IsHttpUrl(strUrl) && new URL(strUrl).protocol=='https:';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Embedded YouTube players become a plain link to the video.
|
|
||||||
function GetYouTubeEmbedUrl( pNode )
|
|
||||||
{
|
|
||||||
let sSrc=pNode.getAttribute('src');
|
|
||||||
if( !IsHttpUrl(sSrc) )
|
|
||||||
return null;
|
|
||||||
let pUrl=new URL(sSrc);
|
|
||||||
return ( pUrl.origin=='https://www.youtube.com' && pUrl.pathname.indexOf('/embed/')==0 ) ? pUrl.href : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function CopyDescNodes( pSrc, pDst )
|
|
||||||
{
|
|
||||||
for( let pNode=pSrc.firstChild;pNode!=null;pNode=pNode.nextSibling )
|
|
||||||
{
|
|
||||||
if( pNode.nodeType==Node.TEXT_NODE )
|
|
||||||
{
|
|
||||||
pDst.appendChild( document.createTextNode(pNode.nodeValue) );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if( pNode.nodeType!=Node.ELEMENT_NODE )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
let sTag=pNode.nodeName.toUpperCase();
|
|
||||||
if( sTag=='IFRAME' )
|
|
||||||
{
|
|
||||||
let sVideoUrl=GetYouTubeEmbedUrl(pNode);
|
|
||||||
if( sVideoUrl!=null )
|
|
||||||
{
|
|
||||||
let pLink=document.createElement('A');
|
|
||||||
pLink.setAttribute('href',sVideoUrl);
|
|
||||||
pLink.textContent=sVideoUrl;
|
|
||||||
pDst.appendChild(pLink);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if( $.inArray(sTag,DescDroppedTags)>=0 )
|
|
||||||
continue;
|
|
||||||
if( $.inArray(sTag,DescAllowedTags)<0 )
|
|
||||||
{
|
|
||||||
CopyDescNodes(pNode,pDst);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let pElem=document.createElement(sTag);
|
|
||||||
if( sTag=='A' && IsHttpUrl(pNode.getAttribute('href')) )
|
|
||||||
pElem.setAttribute('href',pNode.getAttribute('href'));
|
|
||||||
else if( sTag=='IMG' )
|
|
||||||
{
|
|
||||||
if( !IsHttpsUrl(pNode.getAttribute('src')) )
|
|
||||||
continue;
|
|
||||||
pElem.setAttribute('src',pNode.getAttribute('src'));
|
|
||||||
}
|
|
||||||
$.each( DescAllowedAttrs[sTag]||[], function(i,sAttr){
|
|
||||||
let sValue=pNode.getAttribute(sAttr);
|
|
||||||
if( sValue!=null && ( $.inArray(sAttr,DescNumericAttrs)<0 || /^\d+$/.test(sValue) ) )
|
|
||||||
pElem.setAttribute(sAttr,sValue);
|
|
||||||
});
|
|
||||||
CopyDescNodes(pNode,pElem);
|
|
||||||
pDst.appendChild(pElem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function SanitizeDescHtml( strHtml )
|
|
||||||
{
|
|
||||||
let pFragment=document.createDocumentFragment();
|
|
||||||
// A DOMParser document is inert: it runs no scripts and loads no resources.
|
|
||||||
let pDoc=new DOMParser().parseFromString(strHtml,'text/html');
|
|
||||||
if( pDoc && pDoc.body )
|
|
||||||
CopyDescNodes(pDoc.body,pFragment);
|
|
||||||
return pFragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
function ShowProfilelInfo( pProfile )
|
function ShowProfilelInfo( pProfile )
|
||||||
{
|
{
|
||||||
//==========Profile Info==========
|
//==========Profile Info==========
|
||||||
@@ -583,10 +483,10 @@ function ShowProfilelInfo( pProfile )
|
|||||||
let sProfileAuthor=decodeURIComponent(pProfile.author);
|
let sProfileAuthor=decodeURIComponent(pProfile.author);
|
||||||
let sProfileDesc=decodeURIComponent(pProfile.description);
|
let sProfileDesc=decodeURIComponent(pProfile.description);
|
||||||
|
|
||||||
$('#ProfileName').text(sProfileName);
|
$('#ProfileName').html(sProfileName);
|
||||||
$('#ProfileAuthor').text(sProfileAuthor);
|
$('#ProfileAuthor').html(sProfileAuthor);
|
||||||
|
|
||||||
$('#Profile_Desc').empty().append( SanitizeDescHtml( html_decode(sProfileDesc) ) );
|
$('#Profile_Desc').html( html_decode(sProfileDesc) );
|
||||||
|
|
||||||
let ProfilePreviewList=pProfile.preview_img;
|
let ProfilePreviewList=pProfile.preview_img;
|
||||||
let TotalPreview=ProfilePreviewList.length;
|
let TotalPreview=ProfilePreviewList.length;
|
||||||
@@ -599,14 +499,15 @@ function ShowProfilelInfo( pProfile )
|
|||||||
|
|
||||||
if(TotalPreview>0)
|
if(TotalPreview>0)
|
||||||
{
|
{
|
||||||
$('#ProfilePreviewList').empty();
|
let htmlPreview='';
|
||||||
for(let pn=0;pn<TotalPreview;pn++)
|
for(let pn=0;pn<TotalPreview;pn++)
|
||||||
{
|
{
|
||||||
let FTmpPath=ProfilePreviewList[pn]['filepath'];
|
let FTmpPath=ProfilePreviewList[pn]['filepath'];
|
||||||
|
|
||||||
$('#ProfilePreviewList').append( $('<div class="swiper-slide"></div>').append( $('<img class="Model_PrevImg" />').attr('src',FTmpPath) ) );
|
htmlPreview+='<div class="swiper-slide"><img class="Model_PrevImg" src="'+FTmpPath+'" /></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$('#ProfilePreviewList').html(htmlPreview);
|
||||||
$('#Profile_Preview_Image').viewer({
|
$('#Profile_Preview_Image').viewer({
|
||||||
title: false,
|
title: false,
|
||||||
fullsreen: false,
|
fullsreen: false,
|
||||||
|
|||||||
@@ -331,15 +331,6 @@ modules:
|
|||||||
sha256: deedcabe339165214a3637df4c86a507aef0d793cf8774ff68735f4737e8ddbc
|
sha256: deedcabe339165214a3637df4c86a507aef0d793cf8774ff68735f4737e8ddbc
|
||||||
dest: external-packages/FFMPEG
|
dest: external-packages/FFMPEG
|
||||||
|
|
||||||
# libdatachannel v0.24.5
|
|
||||||
# The Git checkout includes the submodules that are missing from the
|
|
||||||
# GitHub source archive. DataChannel.cmake consumes it as SOURCE_DIR.
|
|
||||||
- type: git
|
|
||||||
url: https://github.com/paullouisageneau/libdatachannel.git
|
|
||||||
tag: v0.24.5
|
|
||||||
commit: 443f6934d9007eb7076ab7825ba330f355fcbead
|
|
||||||
dest: external-packages/DataChannel
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# Fallback archives for deps normally provided by the GNOME SDK.
|
# Fallback archives for deps normally provided by the GNOME SDK.
|
||||||
# These are only used if find_package() fails to locate them.
|
# These are only used if find_package() fails to locate them.
|
||||||
|
|||||||
+6
-77
@@ -2116,14 +2116,9 @@ int CLI::run(int argc, char **argv)
|
|||||||
|
|
||||||
// One resolver for the whole run, so presets from the same vendor tree share its load.
|
// One resolver for the whole run, so presets from the same vendor tree share its load.
|
||||||
std::unique_ptr<PresetBundle> system_preset_resolver;
|
std::unique_ptr<PresetBundle> system_preset_resolver;
|
||||||
auto ensure_system_preset_resolver = [&system_preset_resolver]() -> PresetBundle & {
|
auto resolve_preset = [&ensure_cli_preset_bundle, &system_preset_resolver](const std::string &file, DynamicPrintConfig &config,
|
||||||
if (!system_preset_resolver)
|
std::string &config_type, const std::string &config_from,
|
||||||
system_preset_resolver = std::make_unique<PresetBundle>();
|
bool probe_type, std::string &error) {
|
||||||
return *system_preset_resolver;
|
|
||||||
};
|
|
||||||
auto resolve_preset = [&ensure_cli_preset_bundle, &ensure_system_preset_resolver](const std::string &file, DynamicPrintConfig &config,
|
|
||||||
std::string &config_type, const std::string &config_from,
|
|
||||||
bool probe_type, std::string &error) {
|
|
||||||
const auto *inherits = config.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS);
|
const auto *inherits = config.option<ConfigOptionString>(BBL_JSON_KEY_INHERITS);
|
||||||
if (!probe_type && (inherits == nullptr || inherits->value.empty()))
|
if (!probe_type && (inherits == nullptr || inherits->value.empty()))
|
||||||
return true;
|
return true;
|
||||||
@@ -2131,7 +2126,9 @@ int CLI::run(int argc, char **argv)
|
|||||||
PresetBundle *bundle = nullptr;
|
PresetBundle *bundle = nullptr;
|
||||||
bool allow_source_manifest = false;
|
bool allow_source_manifest = false;
|
||||||
if (config_from == "system") {
|
if (config_from == "system") {
|
||||||
bundle = &ensure_system_preset_resolver();
|
if (!system_preset_resolver)
|
||||||
|
system_preset_resolver = std::make_unique<PresetBundle>();
|
||||||
|
bundle = system_preset_resolver.get();
|
||||||
allow_source_manifest = true;
|
allow_source_manifest = true;
|
||||||
} else {
|
} else {
|
||||||
bundle = ensure_cli_preset_bundle(error);
|
bundle = ensure_cli_preset_bundle(error);
|
||||||
@@ -3123,44 +3120,6 @@ int CLI::run(int argc, char **argv)
|
|||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load the project's printer and process settings as the GUI loads its presets: over the default preset,
|
|
||||||
// with every key the project does not list as changed, including keys saved before an option existed,
|
|
||||||
// taken from its current system preset.
|
|
||||||
auto load_project_preset = [this, &ensure_system_preset_resolver, ¤t_different_settings, filament_count](const std::string &system_name, Preset::Type type) {
|
|
||||||
if (system_name.empty())
|
|
||||||
return;
|
|
||||||
// Preset bookkeeping the CLI keeps in its own groups, e.g. inherits_group and print_compatible_printers.
|
|
||||||
static const std::set<std::string> bookkeeping_keys = {"inherits", "compatible_printers", "compatible_prints", "compatible_printers_condition",
|
|
||||||
"compatible_prints_condition", "print_settings_id", "printer_settings_id"};
|
|
||||||
const size_t index = type == Preset::TYPE_PRINTER ? filament_count + 1 : 0;
|
|
||||||
PresetBundle &resolver = ensure_system_preset_resolver();
|
|
||||||
DynamicPrintConfig system_config;
|
|
||||||
t_config_option_keys keys;
|
|
||||||
const DynamicPrintConfig config = Preset::load_external_config(type,
|
|
||||||
type == Preset::TYPE_PRINTER ? resolver.printers.default_preset_for(m_print_config).config : resolver.prints.default_preset().config,
|
|
||||||
m_print_config, PresetBundle::project_different_keys(index < current_different_settings.size() ? current_different_settings[index] : std::string()),
|
|
||||||
[&](const std::string &) -> DynamicPrintConfig * {
|
|
||||||
std::string error;
|
|
||||||
if (resolver.resolve_system_preset(system_config, type, system_name, config_substitution_rule, error))
|
|
||||||
return &system_config;
|
|
||||||
BOOST_LOG_TRIVIAL(warning) << boost::format("CLI: system preset '%1%' not resolved (%2%); the project keeps its values") % system_name % error;
|
|
||||||
return nullptr;
|
|
||||||
}, &keys);
|
|
||||||
for (const std::string &key : keys) {
|
|
||||||
const ConfigOption *opt = config.option(key);
|
|
||||||
const ConfigOption *old = m_print_config.option(key);
|
|
||||||
if (bookkeeping_keys.count(key) != 0 || opt == nullptr || (old != nullptr && *old == *opt))
|
|
||||||
continue;
|
|
||||||
BOOST_LOG_TRIVIAL(info) << boost::format("CLI: %1% from '%2%': %3% -> %4%") % key % system_name % (old ? old->serialize() : std::string("(missing)")) % opt->serialize();
|
|
||||||
m_print_config.set_key_value(key, opt->clone());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// The --uptodate path refreshes the project from its own system configs.
|
|
||||||
if (new_printer_name.empty() && load_machine_config.empty())
|
|
||||||
load_project_preset(current_printer_system_name, Preset::TYPE_PRINTER);
|
|
||||||
if (new_process_name.empty() && load_process_config.empty())
|
|
||||||
load_project_preset(current_process_system_name, Preset::TYPE_PRINT);
|
|
||||||
|
|
||||||
std::vector<std::string>& different_settings = m_print_config.option<ConfigOptionStrings>("different_settings_to_system", true)->values;
|
std::vector<std::string>& different_settings = m_print_config.option<ConfigOptionStrings>("different_settings_to_system", true)->values;
|
||||||
std::vector<std::string>& inherits_group = m_print_config.option<ConfigOptionStrings>("inherits_group", true)->values;
|
std::vector<std::string>& inherits_group = m_print_config.option<ConfigOptionStrings>("inherits_group", true)->values;
|
||||||
inherits_group.resize(filament_count + 2, std::string());
|
inherits_group.resize(filament_count + 2, std::string());
|
||||||
@@ -3517,14 +3476,6 @@ int CLI::run(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
new_variant_counts = old_variant_counts;
|
new_variant_counts = old_variant_counts;
|
||||||
//filament_variant_count = old_variant_counts;
|
//filament_variant_count = old_variant_counts;
|
||||||
//ORCA: lay the per-variant options out one value per variant of the current filaments before each
|
|
||||||
// loaded filament replaces its own variants, including an option only a loaded filament
|
|
||||||
// defines, which otherwise starts as a single default value and never reaches the others.
|
|
||||||
for (const DynamicPrintConfig &config : load_filaments_config)
|
|
||||||
for (const std::string &opt_key : filament_options_with_variant)
|
|
||||||
if (opt_key != "filament_extruder_variant" && config.has(opt_key))
|
|
||||||
m_print_config.option(opt_key, true);
|
|
||||||
normalize_filament_values_to_variants(m_print_config);
|
|
||||||
for (int index = 0; index < load_filaments_config.size(); index++) {
|
for (int index = 0; index < load_filaments_config.size(); index++) {
|
||||||
DynamicPrintConfig& config = load_filaments_config[index];
|
DynamicPrintConfig& config = load_filaments_config[index];
|
||||||
int filament_index = load_filaments_index[index];
|
int filament_index = load_filaments_index[index];
|
||||||
@@ -3696,25 +3647,6 @@ int CLI::run(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//ORCA: a per-variant option the loaded filament does not define keeps the values of the
|
|
||||||
// variants the filament already had, and a variant new to it takes its first one's.
|
|
||||||
const int old_start = old_start_indice[filament_index - 1];
|
|
||||||
std::vector<int> kept_variant_indice = new_variant_indice;
|
|
||||||
for (int &i : kept_variant_indice)
|
|
||||||
if (i < 0)
|
|
||||||
i = old_start;
|
|
||||||
for (const std::string &opt_key : filament_options_with_variant) {
|
|
||||||
if (config.has(opt_key))
|
|
||||||
continue;
|
|
||||||
auto *opt_vec_dst = dynamic_cast<ConfigOptionVectorBase *>(m_print_config.option(opt_key));
|
|
||||||
if (opt_vec_dst == nullptr || opt_vec_dst->size() < size_t(old_start + old_variant_count))
|
|
||||||
continue;
|
|
||||||
// set_with_restore_2() pads its source in place
|
|
||||||
std::unique_ptr<ConfigOption> old_values(opt_vec_dst->clone());
|
|
||||||
opt_vec_dst->set_with_restore_2(static_cast<ConfigOptionVectorBase *>(old_values.get()), kept_variant_indice, old_start,
|
|
||||||
old_variant_count, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//update the old index
|
//update the old index
|
||||||
if (old_variant_count != new_variant_count)
|
if (old_variant_count != new_variant_count)
|
||||||
{
|
{
|
||||||
@@ -4149,9 +4081,6 @@ int CLI::run(int argc, char **argv)
|
|||||||
if (printer_technology == ptFFF) {
|
if (printer_technology == ptFFF) {
|
||||||
fff_print_config.apply(m_print_config, true);
|
fff_print_config.apply(m_print_config, true);
|
||||||
m_print_config.apply(fff_print_config, true);
|
m_print_config.apply(fff_print_config, true);
|
||||||
//ORCA: an option no preset or project defines has just come in as its single default value, and a
|
|
||||||
// command line override may hold one value per filament.
|
|
||||||
normalize_filament_values_to_variants(m_print_config);
|
|
||||||
} else {
|
} else {
|
||||||
boost::nowide::cerr << "invalid printer_technology " << std::endl;
|
boost::nowide::cerr << "invalid printer_technology " << std::endl;
|
||||||
record_exit_reson(outfile_dir, CLI_INVALID_PRINTER_TECH, 0, cli_errors[CLI_INVALID_PRINTER_TECH], sliced_info);
|
record_exit_reson(outfile_dir, CLI_INVALID_PRINTER_TECH, 0, cli_errors[CLI_INVALID_PRINTER_TECH], sliced_info);
|
||||||
|
|||||||
@@ -205,6 +205,13 @@ void AppConfig::set_defaults()
|
|||||||
if (get("seq_top_layer_only").empty())
|
if (get("seq_top_layer_only").empty())
|
||||||
set("seq_top_layer_only", "1");
|
set("seq_top_layer_only", "1");
|
||||||
|
|
||||||
|
// what the preview draws while the user drags it
|
||||||
|
{
|
||||||
|
const std::string mode = get("preview_reduced_detail_mode");
|
||||||
|
if (mode != "off" && mode != "solid" && mode != "shell")
|
||||||
|
set("preview_reduced_detail_mode", "off");
|
||||||
|
}
|
||||||
|
|
||||||
// ORCA: darken the layers the preview layer slider is not scrubbed to
|
// ORCA: darken the layers the preview layer slider is not scrubbed to
|
||||||
if (get("preview_dim_previous_layers").empty())
|
if (get("preview_dim_previous_layers").empty())
|
||||||
set_bool("preview_dim_previous_layers", false);
|
set_bool("preview_dim_previous_layers", false);
|
||||||
@@ -511,10 +518,6 @@ void AppConfig::set_defaults()
|
|||||||
set_bool("enable_high_low_temp_mixed_printing", false);
|
set_bool("enable_high_low_temp_mixed_printing", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get("remember_print_action").empty()) {
|
|
||||||
set_bool("remember_print_action", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (get("ignore_ext_filament_in_filament_map").empty()){
|
if (get("ignore_ext_filament_in_filament_map").empty()){
|
||||||
set_bool("ignore_ext_filament_in_filament_map", false);
|
set_bool("ignore_ext_filament_in_filament_map", false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -355,7 +355,6 @@ set(lisbslic3r_sources
|
|||||||
Optimize/Optimizer.hpp
|
Optimize/Optimizer.hpp
|
||||||
Orient.cpp
|
Orient.cpp
|
||||||
Orient.hpp
|
Orient.hpp
|
||||||
ParallelResolve.hpp
|
|
||||||
ParameterUtils.cpp
|
ParameterUtils.cpp
|
||||||
ParameterUtils.hpp
|
ParameterUtils.hpp
|
||||||
pchheader.cpp
|
pchheader.cpp
|
||||||
|
|||||||
+13
-26
@@ -849,19 +849,6 @@ ConfigSubstitutions ConfigBase::load_from_json(const std::string &file, ForwardC
|
|||||||
return std::move(substitutions_ctxt.substitutions);
|
return std::move(substitutions_ctxt.substitutions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case-insensitive compare of a JSON key against a fixed ASCII one, without
|
|
||||||
// boost::iequals, whose std::locale() takes a lock the whole process shares in the
|
|
||||||
// MSVC runtime.
|
|
||||||
static bool ascii_iequals(const std::string &key, const char *literal)
|
|
||||||
{
|
|
||||||
auto lower = [](char c) { return (c >= 'A' && c <= 'Z') ? char(c - 'A' + 'a') : c; };
|
|
||||||
size_t i = 0;
|
|
||||||
for (; i < key.size() && literal[i] != '\0'; ++ i)
|
|
||||||
if (lower(key[i]) != lower(literal[i]))
|
|
||||||
return false;
|
|
||||||
return i == key.size() && literal[i] == '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContext& substitution_context, bool load_inherits_to_config, std::map<std::string, std::string>& key_values, std::string& reason)
|
int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContext& substitution_context, bool load_inherits_to_config, std::map<std::string, std::string>& key_values, std::string& reason)
|
||||||
{
|
{
|
||||||
json j;
|
json j;
|
||||||
@@ -929,44 +916,44 @@ int ConfigBase::load_from_json(const std::string &file, ConfigSubstitutionContex
|
|||||||
}
|
}
|
||||||
//parse the json elements
|
//parse the json elements
|
||||||
for (auto it = j.begin(); it != j.end(); it++) {
|
for (auto it = j.begin(); it != j.end(); it++) {
|
||||||
if (ascii_iequals(it.key(), BBL_JSON_KEY_VERSION)) {
|
if (boost::iequals(it.key(),BBL_JSON_KEY_VERSION)) {
|
||||||
key_values.emplace(BBL_JSON_KEY_VERSION, it.value());
|
key_values.emplace(BBL_JSON_KEY_VERSION, it.value());
|
||||||
}
|
}
|
||||||
else if (ascii_iequals(it.key(), BBL_JSON_KEY_IS_CUSTOM)) {
|
else if (boost::iequals(it.key(), BBL_JSON_KEY_IS_CUSTOM)) {
|
||||||
//skip it
|
//skip it
|
||||||
}
|
}
|
||||||
else if (ascii_iequals(it.key(), BBL_JSON_KEY_NAME)) {
|
else if (boost::iequals(it.key(), BBL_JSON_KEY_NAME)) {
|
||||||
key_values.emplace(BBL_JSON_KEY_NAME, it.value());
|
key_values.emplace(BBL_JSON_KEY_NAME, it.value());
|
||||||
if (it.value() == "project_settings")
|
if (it.value() == "project_settings")
|
||||||
is_project_settings = true;
|
is_project_settings = true;
|
||||||
}
|
}
|
||||||
else if (ascii_iequals(it.key(), BBL_JSON_KEY_URL)) {
|
else if (boost::iequals(it.key(), BBL_JSON_KEY_URL)) {
|
||||||
key_values.emplace(BBL_JSON_KEY_URL, it.value());
|
key_values.emplace(BBL_JSON_KEY_URL, it.value());
|
||||||
}
|
}
|
||||||
else if (ascii_iequals(it.key(), BBL_JSON_KEY_TYPE)) {
|
else if (boost::iequals(it.key(), BBL_JSON_KEY_TYPE)) {
|
||||||
key_values.emplace(BBL_JSON_KEY_TYPE, it.value());
|
key_values.emplace(BBL_JSON_KEY_TYPE, it.value());
|
||||||
}
|
}
|
||||||
else if (ascii_iequals(it.key(), BBL_JSON_KEY_SETTING_ID)) {
|
else if (boost::iequals(it.key(), BBL_JSON_KEY_SETTING_ID)) {
|
||||||
key_values.emplace(BBL_JSON_KEY_SETTING_ID, it.value());
|
key_values.emplace(BBL_JSON_KEY_SETTING_ID, it.value());
|
||||||
}
|
}
|
||||||
else if (ascii_iequals(it.key(), BBL_JSON_KEY_FILAMENT_ID)) {
|
else if (boost::iequals(it.key(), BBL_JSON_KEY_FILAMENT_ID)) {
|
||||||
key_values.emplace(BBL_JSON_KEY_FILAMENT_ID, it.value());
|
key_values.emplace(BBL_JSON_KEY_FILAMENT_ID, it.value());
|
||||||
}
|
}
|
||||||
else if (ascii_iequals(it.key(), BBL_JSON_KEY_FROM)) {
|
else if (boost::iequals(it.key(), BBL_JSON_KEY_FROM)) {
|
||||||
key_values.emplace(BBL_JSON_KEY_FROM, it.value());
|
key_values.emplace(BBL_JSON_KEY_FROM, it.value());
|
||||||
}
|
}
|
||||||
else if (ascii_iequals(it.key(), BBL_JSON_KEY_DESCRIPTION)) {
|
else if (boost::iequals(it.key(), BBL_JSON_KEY_DESCRIPTION)) {
|
||||||
key_values.emplace(BBL_JSON_KEY_DESCRIPTION, it.value());
|
key_values.emplace(BBL_JSON_KEY_DESCRIPTION, it.value());
|
||||||
}
|
}
|
||||||
else if (ascii_iequals(it.key(), BBL_JSON_KEY_INSTANTIATION)) {
|
else if (boost::iequals(it.key(), BBL_JSON_KEY_INSTANTIATION)) {
|
||||||
key_values.emplace(BBL_JSON_KEY_INSTANTIATION, it.value());
|
key_values.emplace(BBL_JSON_KEY_INSTANTIATION, it.value());
|
||||||
}
|
}
|
||||||
else if (!load_inherits_to_config && ascii_iequals(it.key(), BBL_JSON_KEY_INHERITS)) {
|
else if (!load_inherits_to_config && boost::iequals(it.key(), BBL_JSON_KEY_INHERITS)) {
|
||||||
key_values.emplace(BBL_JSON_KEY_INHERITS, it.value());
|
key_values.emplace(BBL_JSON_KEY_INHERITS, it.value());
|
||||||
}
|
}
|
||||||
else if (!load_inherits_to_config && ascii_iequals(it.key(), BBL_JSON_KEY_INCLUDES)) {
|
else if (!load_inherits_to_config && boost::iequals(it.key(), BBL_JSON_KEY_INCLUDES)) {
|
||||||
key_values.emplace(BBL_JSON_KEY_INCLUDES, it.value().dump());
|
key_values.emplace(BBL_JSON_KEY_INCLUDES, it.value().dump());
|
||||||
} else if (ascii_iequals(it.key(), ORCA_JSON_KEY_RENAMED_FROM)) {
|
} else if (boost::iequals(it.key(), ORCA_JSON_KEY_RENAMED_FROM)) {
|
||||||
key_values.emplace(ORCA_JSON_KEY_RENAMED_FROM, it.value());
|
key_values.emplace(ORCA_JSON_KEY_RENAMED_FROM, it.value());
|
||||||
} else {
|
} else {
|
||||||
t_config_option_key opt_key = it.key();
|
t_config_option_key opt_key = it.key();
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::s
|
|||||||
its.indices.emplace_back(indices[0], indices[1], indices[2]);
|
its.indices.emplace_back(indices[0], indices[1], indices[2]);
|
||||||
int face_index =its.indices.size() - 1;
|
int face_index =its.indices.size() - 1;
|
||||||
RGBA face_color;
|
RGBA face_color;
|
||||||
auto set_face_color = [&uvs, &data, &mtl_data, &obj_info, &face_color](int face_index, const std::string mtl_name, const std::array<int, 3> &corners) {
|
auto set_face_color = [&uvs, &data, &mtl_data, &obj_info, &face_color](int face_index, const std::string mtl_name) {
|
||||||
if (mtl_data.new_mtl_unmap.find(mtl_name) != mtl_data.new_mtl_unmap.end()) {
|
if (mtl_data.new_mtl_unmap.find(mtl_name) != mtl_data.new_mtl_unmap.end()) {
|
||||||
bool is_merge_ka_kd = true;
|
bool is_merge_ka_kd = true;
|
||||||
for (size_t n = 0; n < 3; n++) {
|
for (size_t n = 0; n < 3; n++) {
|
||||||
@@ -174,7 +174,7 @@ bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::s
|
|||||||
return Vec2f::Zero();
|
return Vec2f::Zero();
|
||||||
return Vec2f(data.textureCoordinates[idx * OBJ_TEXCOORD_LENGTH], data.textureCoordinates[idx * OBJ_TEXCOORD_LENGTH + 1]);
|
return Vec2f(data.textureCoordinates[idx * OBJ_TEXCOORD_LENGTH], data.textureCoordinates[idx * OBJ_TEXCOORD_LENGTH + 1]);
|
||||||
};
|
};
|
||||||
std::array<Vec2f, 3> uv_array{uv_at(uvs[corners[0]]), uv_at(uvs[corners[1]]), uv_at(uvs[corners[2]])};
|
std::array<Vec2f, 3> uv_array{uv_at(uvs[0]), uv_at(uvs[1]), uv_at(uvs[2])};
|
||||||
obj_info.uvs.emplace_back(uv_array);
|
obj_info.uvs.emplace_back(uv_array);
|
||||||
}
|
}
|
||||||
obj_info.face_colors.emplace_back(face_color);
|
obj_info.face_colors.emplace_back(face_color);
|
||||||
@@ -185,27 +185,27 @@ bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
auto set_face_color_by_mtl = [&data, &set_face_color](int face_index, const std::array<int, 3> &corners) {
|
auto set_face_color_by_mtl = [&data, &set_face_color](int face_index) {
|
||||||
if (data.usemtls.size() == 1) {
|
if (data.usemtls.size() == 1) {
|
||||||
set_face_color(face_index, data.usemtls[0].name, corners);
|
set_face_color(face_index, data.usemtls[0].name);
|
||||||
} else {
|
} else {
|
||||||
for (size_t k = 0; k < data.usemtls.size(); k++) {
|
for (size_t k = 0; k < data.usemtls.size(); k++) {
|
||||||
auto mtl = data.usemtls[k];
|
auto mtl = data.usemtls[k];
|
||||||
if (face_index >= mtl.face_start && face_index <= mtl.face_end) {
|
if (face_index >= mtl.face_start && face_index <= mtl.face_end) {
|
||||||
set_face_color(face_index, data.usemtls[k].name, corners);
|
set_face_color(face_index, data.usemtls[k].name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (exist_mtl) {
|
if (exist_mtl) {
|
||||||
set_face_color_by_mtl(face_index, {0, 1, 2});
|
set_face_color_by_mtl(face_index);
|
||||||
}
|
}
|
||||||
if (cnt == 4) {
|
if (cnt == 4) {
|
||||||
its.indices.emplace_back(indices[0], indices[2], indices[3]);
|
its.indices.emplace_back(indices[0], indices[2], indices[3]);
|
||||||
int face_index = its.indices.size() - 1;
|
int face_index = its.indices.size() - 1;
|
||||||
if (exist_mtl) {
|
if (exist_mtl) {
|
||||||
set_face_color_by_mtl(face_index, {0, 2, 3});
|
set_face_color_by_mtl(face_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,12 +217,8 @@ bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo& obj_info, std::s
|
|||||||
message = _L("This OBJ file couldn't be read because it's empty.");
|
message = _L("This OBJ file couldn't be read because it's empty.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (meshptr->volume() < 0) {
|
if (meshptr->volume() < 0)
|
||||||
meshptr->flip_triangles();
|
meshptr->flip_triangles();
|
||||||
// Flipping swaps corners 1 and 2 of every face, so the UVs have to follow.
|
|
||||||
for (std::array<Vec2f, 3> &uv : obj_info.uvs)
|
|
||||||
std::swap(uv[1], uv[2]);
|
|
||||||
}
|
|
||||||
// Hand the parsed material table back so callers can build a TexturedMesh from it.
|
// Hand the parsed material table back so callers can build a TexturedMesh from it.
|
||||||
if (out_mtl)
|
if (out_mtl)
|
||||||
*out_mtl = mtl_data;
|
*out_mtl = mtl_data;
|
||||||
|
|||||||
+89
-71
@@ -1497,7 +1497,12 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
|||||||
check_add_eol(toolchange_gcode_str);
|
check_add_eol(toolchange_gcode_str);
|
||||||
|
|
||||||
// SoftFever: set new PA for new filament
|
// SoftFever: set new PA for new filament
|
||||||
gcode += gcodegen.set_filament_pressure_advance(new_filament_id);
|
if (gcodegen.config().enable_pressure_advance.get_at(new_filament_id)) {
|
||||||
|
gcode += gcodegen.writer().set_pressure_advance(gcodegen.config().pressure_advance.get_at(new_filament_id));
|
||||||
|
// Orca: Adaptive PA
|
||||||
|
// Reset Adaptive PA processor last PA value
|
||||||
|
gcodegen.m_pa_processor->resetPreviousPA(gcodegen.config().pressure_advance.get_at(new_filament_id));
|
||||||
|
}
|
||||||
|
|
||||||
// A phony move to the end position at the wipe tower.
|
// A phony move to the end position at the wipe tower.
|
||||||
gcodegen.writer().travel_to_xy((end_pos + plate_origin_2d).cast<double>());
|
gcodegen.writer().travel_to_xy((end_pos + plate_origin_2d).cast<double>());
|
||||||
@@ -1821,8 +1826,12 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
|||||||
check_add_eol(toolchange_gcode_str);
|
check_add_eol(toolchange_gcode_str);
|
||||||
|
|
||||||
// SoftFever: set new PA for new filament
|
// SoftFever: set new PA for new filament
|
||||||
if (new_extruder_id != -1)
|
if (new_extruder_id != -1 && gcodegen.config().enable_pressure_advance.get_at(new_extruder_id)) {
|
||||||
gcode += gcodegen.set_filament_pressure_advance(new_extruder_id);
|
gcode += gcodegen.writer().set_pressure_advance(gcodegen.config().pressure_advance.get_at(new_extruder_id));
|
||||||
|
// Orca: Adaptive PA
|
||||||
|
// Reset Adaptive PA processor last PA value
|
||||||
|
gcodegen.m_pa_processor->resetPreviousPA(gcodegen.config().pressure_advance.get_at(new_extruder_id));
|
||||||
|
}
|
||||||
|
|
||||||
// A phony move to the end position at the wipe tower.
|
// A phony move to the end position at the wipe tower.
|
||||||
gcodegen.writer().travel_to_xy((end_pos + plate_origin_2d).cast<double>());
|
gcodegen.writer().travel_to_xy((end_pos + plate_origin_2d).cast<double>());
|
||||||
@@ -3223,7 +3232,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||||||
m_cooling_buffer->set_current_extruder(initial_extruder_id, extruder_id);
|
m_cooling_buffer->set_current_extruder(initial_extruder_id, extruder_id);
|
||||||
|
|
||||||
// Orca: Initialise AdaptivePA processor filter
|
// Orca: Initialise AdaptivePA processor filter
|
||||||
m_pa_processor = std::make_unique<AdaptivePAProcessor>(*this);
|
m_pa_processor = std::make_unique<AdaptivePAProcessor>(*this, tool_ordering.all_extruders());
|
||||||
|
|
||||||
// Update output variables after the extruders were initialized.
|
// Update output variables after the extruders were initialized.
|
||||||
m_placeholder_parser_integration.init(m_writer);
|
m_placeholder_parser_integration.init(m_writer);
|
||||||
@@ -3788,7 +3797,12 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Orca: add missing PA settings for initial filament
|
// Orca: add missing PA settings for initial filament
|
||||||
file.write(set_filament_pressure_advance(initial_non_support_extruder_id));
|
if (m_config.enable_pressure_advance.get_at(initial_non_support_extruder_id)) {
|
||||||
|
file.write(m_writer.set_pressure_advance(m_config.pressure_advance.get_at(initial_non_support_extruder_id)));
|
||||||
|
// Orca: Adaptive PA
|
||||||
|
// Reset Adaptive PA processor last PA value
|
||||||
|
m_pa_processor->resetPreviousPA(m_config.pressure_advance.get_at(initial_non_support_extruder_id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//flush FanMover buffer to avoid modifying the start gcode if it's manual.
|
//flush FanMover buffer to avoid modifying the start gcode if it's manual.
|
||||||
@@ -4174,28 +4188,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||||||
|
|
||||||
print.throw_if_canceled();
|
print.throw_if_canceled();
|
||||||
|
|
||||||
// Some firmwares only scan the last N lines for the time estimate, so the stats are written
|
|
||||||
// after the config block.
|
|
||||||
if (!is_bbl_printers && !skip_config_block) {
|
|
||||||
file.write("; CONFIG_BLOCK_START\n");
|
|
||||||
std::string full_config;
|
|
||||||
append_full_config(print, full_config);
|
|
||||||
if (!full_config.empty())
|
|
||||||
file.write(full_config);
|
|
||||||
|
|
||||||
// SoftFever: write compatiple info
|
|
||||||
int first_layer_bed_temperature = get_bed_temperature(0, true, print.config().curr_bed_type);
|
|
||||||
file.write_format("; first_layer_bed_temperature = %d\n", first_layer_bed_temperature);
|
|
||||||
file.write_format("; bed_shape = %s\n", print.full_print_config().opt_serialize("printable_area").c_str());
|
|
||||||
file.write_format("; first_layer_temperature = %d\n", print.config().nozzle_temperature_initial_layer.get_at(0));
|
|
||||||
file.write_format("; first_layer_height = %.3f\n", print.config().initial_layer_print_height.value);
|
|
||||||
|
|
||||||
//SF TODO
|
|
||||||
// file.write_format("; variable_layer_height = %d\n", print.ad.adaptive_layer_height ? 1 : 0);
|
|
||||||
|
|
||||||
file.write("; CONFIG_BLOCK_END\n\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get filament stats.
|
// Get filament stats.
|
||||||
file.write(DoExport::update_print_stats_and_format_filament_stats(
|
file.write(DoExport::update_print_stats_and_format_filament_stats(
|
||||||
// Const inputs
|
// Const inputs
|
||||||
@@ -4222,6 +4214,26 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
|||||||
GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder)
|
GCodeProcessor::ETags::Estimated_Printing_Time_Placeholder)
|
||||||
.c_str());
|
.c_str());
|
||||||
file.write("\n");
|
file.write("\n");
|
||||||
|
if (!skip_config_block) {
|
||||||
|
file.write("; CONFIG_BLOCK_START\n");
|
||||||
|
std::string full_config;
|
||||||
|
append_full_config(print, full_config);
|
||||||
|
if (!full_config.empty())
|
||||||
|
file.write(full_config);
|
||||||
|
|
||||||
|
// SoftFever: write compatiple info
|
||||||
|
int first_layer_bed_temperature = get_bed_temperature(0, true, print.config().curr_bed_type);
|
||||||
|
file.write_format("; first_layer_bed_temperature = %d\n", first_layer_bed_temperature);
|
||||||
|
file.write_format("; bed_shape = %s\n", print.full_print_config().opt_serialize("printable_area").c_str());
|
||||||
|
file.write_format("; first_layer_temperature = %d\n", print.config().nozzle_temperature_initial_layer.get_at(0));
|
||||||
|
file.write_format("; first_layer_height = %.3f\n", print.config().initial_layer_print_height.value);
|
||||||
|
|
||||||
|
//SF TODO
|
||||||
|
// file.write_format("; variable_layer_height = %d\n", print.ad.adaptive_layer_height ? 1 : 0);
|
||||||
|
|
||||||
|
file.write("; CONFIG_BLOCK_END\n\n");
|
||||||
|
} // !skip_config_block
|
||||||
|
|
||||||
}
|
}
|
||||||
file.write("\n");
|
file.write("\n");
|
||||||
|
|
||||||
@@ -8378,16 +8390,12 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
|
|
||||||
// Orca: Dynamic PA
|
// Orca: Dynamic PA
|
||||||
// If adaptive PA is enabled, by default evaluate PA on all extrusion moves
|
// If adaptive PA is enabled, by default evaluate PA on all extrusion moves
|
||||||
// The PA settings and the PA_CHANGE tags use the filament config index of the filament's extruder variant
|
|
||||||
const unsigned int pa_config_index = (unsigned int) get_filament_config_index(m_writer.filament()->id());
|
|
||||||
const bool adaptive_pa = m_config.adaptive_pressure_advance.get_at(pa_config_index) && m_config.enable_pressure_advance.get_at(pa_config_index);
|
|
||||||
const bool adaptive_pa_overhangs = adaptive_pa && m_config.adaptive_pressure_advance_overhangs.get_at(pa_config_index);
|
|
||||||
bool is_pa_calib = m_curr_print->calib_mode() == CalibMode::Calib_PA_Line ||
|
bool is_pa_calib = m_curr_print->calib_mode() == CalibMode::Calib_PA_Line ||
|
||||||
m_curr_print->calib_mode() == CalibMode::Calib_PA_Pattern ||
|
m_curr_print->calib_mode() == CalibMode::Calib_PA_Pattern ||
|
||||||
m_curr_print->calib_mode() == CalibMode::Calib_PA_Tower;
|
m_curr_print->calib_mode() == CalibMode::Calib_PA_Tower;
|
||||||
bool evaluate_adaptive_pa = false;
|
bool evaluate_adaptive_pa = false;
|
||||||
bool role_change = (m_last_extrusion_role != path.role());
|
bool role_change = (m_last_extrusion_role != path.role());
|
||||||
if (!is_pa_calib && adaptive_pa) {
|
if (!is_pa_calib && FILAMENT_CONFIG(adaptive_pressure_advance) && FILAMENT_CONFIG(enable_pressure_advance)) {
|
||||||
evaluate_adaptive_pa = true;
|
evaluate_adaptive_pa = true;
|
||||||
// If we have already emmited a PA change because the m_multi_flow_segment_path_pa_set is set
|
// If we have already emmited a PA change because the m_multi_flow_segment_path_pa_set is set
|
||||||
// skip re-issuing the PA change tag.
|
// skip re-issuing the PA change tag.
|
||||||
@@ -8470,7 +8478,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
// Post processor flag generation code segment when option to emit only at role changes is enabled
|
// Post processor flag generation code segment when option to emit only at role changes is enabled
|
||||||
// Variables published to the post processor:
|
// Variables published to the post processor:
|
||||||
// 1) Tag to trigger a PA evaluation (because a role change was identified and the user has requested dynamic PA adjustments)
|
// 1) Tag to trigger a PA evaluation (because a role change was identified and the user has requested dynamic PA adjustments)
|
||||||
// 2) Current filament config index (to identify the PA model for the currently used filament and its extruder variant)
|
// 2) Current extruder ID (to identify the PA model for the currently used extruder)
|
||||||
// 3) mm3_per_mm value (to then multiply by the final model print speed after slowdown for cooling is applied)
|
// 3) mm3_per_mm value (to then multiply by the final model print speed after slowdown for cooling is applied)
|
||||||
// 4) the current acceleration (to pass to the model for evaluation)
|
// 4) the current acceleration (to pass to the model for evaluation)
|
||||||
// 5) whether this is an external perimeter (for future use)
|
// 5) whether this is an external perimeter (for future use)
|
||||||
@@ -8481,7 +8489,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
if (m_multi_flow_segment_path_average_mm3_per_mm > 0) {
|
if (m_multi_flow_segment_path_average_mm3_per_mm > 0) {
|
||||||
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
||||||
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
||||||
pa_config_index,
|
m_writer.filament()->id(),
|
||||||
m_multi_flow_segment_path_average_mm3_per_mm,
|
m_multi_flow_segment_path_average_mm3_per_mm,
|
||||||
acceleration_i,
|
acceleration_i,
|
||||||
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
||||||
@@ -8494,7 +8502,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
// to issue a zero flow PA change command for this
|
// to issue a zero flow PA change command for this
|
||||||
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
||||||
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
||||||
pa_config_index,
|
m_writer.filament()->id(),
|
||||||
_mm3_per_mm,
|
_mm3_per_mm,
|
||||||
acceleration_i,
|
acceleration_i,
|
||||||
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
||||||
@@ -8602,7 +8610,11 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
// or a flow change, so emit the flag to evaluate PA for the upcomming extrusion
|
// or a flow change, so emit the flag to evaluate PA for the upcomming extrusion
|
||||||
// Emit tag before new speed is set so the post processor reads the next speed immediately and uses it.
|
// Emit tag before new speed is set so the post processor reads the next speed immediately and uses it.
|
||||||
// Dont emit tag if it has just already been emitted from a role change above
|
// Dont emit tag if it has just already been emitted from a role change above
|
||||||
if(_mm3_per_mm >0 && adaptive_pa_overhangs && !evaluate_adaptive_pa){
|
if(_mm3_per_mm >0 &&
|
||||||
|
FILAMENT_CONFIG(adaptive_pressure_advance) &&
|
||||||
|
FILAMENT_CONFIG(enable_pressure_advance) &&
|
||||||
|
FILAMENT_CONFIG(adaptive_pressure_advance_overhangs) &&
|
||||||
|
!evaluate_adaptive_pa){
|
||||||
if(writer().get_current_speed() > F){ // Ramping down speed - use overhang logic where the minimum speed is used between current and upcoming extrusion
|
if(writer().get_current_speed() > F){ // Ramping down speed - use overhang logic where the minimum speed is used between current and upcoming extrusion
|
||||||
if(m_config.gcode_comments){
|
if(m_config.gcode_comments){
|
||||||
sprintf(buf, "; Ramp down-non-variable\n");
|
sprintf(buf, "; Ramp down-non-variable\n");
|
||||||
@@ -8610,7 +8622,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
}
|
}
|
||||||
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
||||||
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
||||||
pa_config_index,
|
m_writer.filament()->id(),
|
||||||
_mm3_per_mm,
|
_mm3_per_mm,
|
||||||
acceleration_i,
|
acceleration_i,
|
||||||
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
||||||
@@ -8625,7 +8637,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
}
|
}
|
||||||
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
||||||
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
||||||
pa_config_index,
|
m_writer.filament()->id(),
|
||||||
_mm3_per_mm,
|
_mm3_per_mm,
|
||||||
acceleration_i,
|
acceleration_i,
|
||||||
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
||||||
@@ -8831,7 +8843,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
// ORCA: Adaptive PA code segment when adjusting PA within the same feature
|
// ORCA: Adaptive PA code segment when adjusting PA within the same feature
|
||||||
// There is a speed change or flow change so emit the flag to evaluate PA for the upcomming extrusion
|
// There is a speed change or flow change so emit the flag to evaluate PA for the upcomming extrusion
|
||||||
// Emit tag before new speed is set so the post processor reads the next speed immediately and uses it.
|
// Emit tag before new speed is set so the post processor reads the next speed immediately and uses it.
|
||||||
if(_mm3_per_mm >0 && adaptive_pa_overhangs){
|
if(_mm3_per_mm >0 &&
|
||||||
|
EXTRUDER_CONFIG(adaptive_pressure_advance) &&
|
||||||
|
EXTRUDER_CONFIG(enable_pressure_advance) &&
|
||||||
|
EXTRUDER_CONFIG(adaptive_pressure_advance_overhangs) ){
|
||||||
if(last_set_speed > new_speed){ // Ramping down speed - use overhang logic where the minimum speed is used between current and upcoming extrusion
|
if(last_set_speed > new_speed){ // Ramping down speed - use overhang logic where the minimum speed is used between current and upcoming extrusion
|
||||||
if(m_config.gcode_comments) {
|
if(m_config.gcode_comments) {
|
||||||
sprintf(buf, "; Ramp up-variable\n");
|
sprintf(buf, "; Ramp up-variable\n");
|
||||||
@@ -8839,7 +8854,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
}
|
}
|
||||||
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
||||||
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
||||||
pa_config_index,
|
m_writer.filament()->id(),
|
||||||
_mm3_per_mm,
|
_mm3_per_mm,
|
||||||
acceleration_i,
|
acceleration_i,
|
||||||
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
||||||
@@ -8854,7 +8869,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||||||
}
|
}
|
||||||
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
sprintf(buf, ";%sT%u MM3MM:%g ACCEL:%u BR:%d RC:%d OV:%d\n",
|
||||||
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
GCodeProcessor::reserved_tag(GCodeProcessor::ETags::PA_Change).c_str(),
|
||||||
pa_config_index,
|
m_writer.filament()->id(),
|
||||||
_mm3_per_mm,
|
_mm3_per_mm,
|
||||||
acceleration_i,
|
acceleration_i,
|
||||||
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
((path.role() == erBridgeInfill) ||(path.role() == erOverhangPerimeter)),
|
||||||
@@ -9407,29 +9422,33 @@ void GCode::update_placeholder_parser_with_variant_params()
|
|||||||
if (num_filaments == 0)
|
if (num_filaments == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Helper: remap config arrays from variant index space to filament_id index space.
|
// Helpers: remap config arrays from variant index space to filament_id index space.
|
||||||
// After remapping, gcode templates can use param[filament_id] directly.
|
// After remapping, gcode templates can use param[filament_id] directly.
|
||||||
auto remap_by_filament = [&](const auto &src) {
|
auto remap_floats_by_filament = [&](const auto &src) {
|
||||||
std::decay_t<decltype(src.values)> dst(num_filaments);
|
std::vector<double> dst(num_filaments);
|
||||||
|
for (size_t i = 0; i < num_filaments; ++i)
|
||||||
|
dst[i] = src.get_at(get_filament_config_index(i));
|
||||||
|
return dst;
|
||||||
|
};
|
||||||
|
auto remap_ints_by_filament = [&](const auto &src) {
|
||||||
|
std::vector<int> dst(num_filaments);
|
||||||
for (size_t i = 0; i < num_filaments; ++i)
|
for (size_t i = 0; i < num_filaments; ++i)
|
||||||
dst[i] = src.get_at(get_filament_config_index(i));
|
dst[i] = src.get_at(get_filament_config_index(i));
|
||||||
return dst;
|
return dst;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- filament_options_with_variant: gcode indexes by filament_id ---
|
// --- filament_options_with_variant: gcode indexes by filament_id ---
|
||||||
this->placeholder_parser().set("filament_max_volumetric_speed", new ConfigOptionFloats(remap_by_filament(m_config.filament_max_volumetric_speed)));
|
this->placeholder_parser().set("filament_max_volumetric_speed", new ConfigOptionFloats(remap_floats_by_filament(m_config.filament_max_volumetric_speed)));
|
||||||
this->placeholder_parser().set("filament_pre_cooling_temperature", new ConfigOptionInts(remap_by_filament(m_config.filament_pre_cooling_temperature)));
|
this->placeholder_parser().set("filament_pre_cooling_temperature", new ConfigOptionInts(remap_ints_by_filament(m_config.filament_pre_cooling_temperature)));
|
||||||
this->placeholder_parser().set("filament_pre_cooling_temperature_nc", new ConfigOptionInts(remap_by_filament(m_config.filament_pre_cooling_temperature_nc)));
|
this->placeholder_parser().set("filament_pre_cooling_temperature_nc", new ConfigOptionInts(remap_ints_by_filament(m_config.filament_pre_cooling_temperature_nc)));
|
||||||
this->placeholder_parser().set("filament_cooling_before_tower", new ConfigOptionFloats(remap_by_filament(m_config.filament_cooling_before_tower)));
|
this->placeholder_parser().set("filament_cooling_before_tower", new ConfigOptionFloats(remap_floats_by_filament(m_config.filament_cooling_before_tower)));
|
||||||
this->placeholder_parser().set("nozzle_temperature_initial_layer", new ConfigOptionInts(remap_by_filament(m_config.nozzle_temperature_initial_layer)));
|
this->placeholder_parser().set("nozzle_temperature_initial_layer", new ConfigOptionInts(remap_ints_by_filament(m_config.nozzle_temperature_initial_layer)));
|
||||||
this->placeholder_parser().set("nozzle_temperature", new ConfigOptionInts(remap_by_filament(m_config.nozzle_temperature)));
|
this->placeholder_parser().set("nozzle_temperature", new ConfigOptionInts(remap_ints_by_filament(m_config.nozzle_temperature)));
|
||||||
// first_layer_temperature is a legacy alias of nozzle_temperature_initial_layer
|
// first_layer_temperature is a legacy alias of nozzle_temperature_initial_layer
|
||||||
this->placeholder_parser().set("first_layer_temperature", new ConfigOptionInts(remap_by_filament(m_config.nozzle_temperature_initial_layer)));
|
this->placeholder_parser().set("first_layer_temperature", new ConfigOptionInts(remap_ints_by_filament(m_config.nozzle_temperature_initial_layer)));
|
||||||
this->placeholder_parser().set("pressure_advance", new ConfigOptionFloats(remap_by_filament(m_config.pressure_advance)));
|
|
||||||
this->placeholder_parser().set("enable_pressure_advance", new ConfigOptionBools(remap_by_filament(m_config.enable_pressure_advance)));
|
|
||||||
|
|
||||||
// --- printer_options_with_variant_1: in m_config these are already merged as filament-indexed ---
|
// --- printer_options_with_variant_1: in m_config these are already merged as filament-indexed ---
|
||||||
this->placeholder_parser().set("retraction_distances_when_cut", new ConfigOptionFloats(remap_by_filament(m_config.retraction_distances_when_cut)));
|
this->placeholder_parser().set("retraction_distances_when_cut", new ConfigOptionFloats(remap_floats_by_filament(m_config.retraction_distances_when_cut)));
|
||||||
// hotend_cooling_rate / hotend_heating_rate: gcode uses [filament_map[x]-1] (extruder_id), no remap needed
|
// hotend_cooling_rate / hotend_heating_rate: gcode uses [filament_map[x]-1] (extruder_id), no remap needed
|
||||||
|
|
||||||
// --- filament_map: per-layer dynamic, sync from m_config to placeholder_parser ---
|
// --- filament_map: per-layer dynamic, sync from m_config to placeholder_parser ---
|
||||||
@@ -9439,10 +9458,10 @@ void GCode::update_placeholder_parser_with_variant_params()
|
|||||||
{
|
{
|
||||||
// Fast purge mode uses filament_flush_temp_fast; Default is inert.
|
// Fast purge mode uses filament_flush_temp_fast; Default is inert.
|
||||||
bool use_fast_flush = m_config.prime_volume_mode == PrimeVolumeMode::pvmFast;
|
bool use_fast_flush = m_config.prime_volume_mode == PrimeVolumeMode::pvmFast;
|
||||||
auto flush_v_speed = remap_by_filament(m_config.filament_flush_volumetric_speed);
|
auto flush_v_speed = remap_floats_by_filament(m_config.filament_flush_volumetric_speed);
|
||||||
auto filament_max_v = remap_by_filament(m_config.filament_max_volumetric_speed);
|
auto filament_max_v = remap_floats_by_filament(m_config.filament_max_volumetric_speed);
|
||||||
auto flush_temps = remap_by_filament(use_fast_flush ? m_config.filament_flush_temp_fast
|
auto flush_temps = remap_ints_by_filament(use_fast_flush ? m_config.filament_flush_temp_fast
|
||||||
: m_config.filament_flush_temp);
|
: m_config.filament_flush_temp);
|
||||||
for (size_t i = 0; i < num_filaments; ++i) {
|
for (size_t i = 0; i < num_filaments; ++i) {
|
||||||
if (flush_v_speed[i] == 0)
|
if (flush_v_speed[i] == 0)
|
||||||
flush_v_speed[i] = filament_max_v[i];
|
flush_v_speed[i] = filament_max_v[i];
|
||||||
@@ -9494,7 +9513,12 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
|||||||
gcode += this->placeholder_parser_process("filament_start_gcode", filament_start_gcode, new_filament_id, &config);
|
gcode += this->placeholder_parser_process("filament_start_gcode", filament_start_gcode, new_filament_id, &config);
|
||||||
check_add_eol(gcode);
|
check_add_eol(gcode);
|
||||||
}
|
}
|
||||||
gcode += set_filament_pressure_advance(new_filament_id);
|
if (m_config.enable_pressure_advance.get_at(new_filament_id)) {
|
||||||
|
gcode += m_writer.set_pressure_advance(m_config.pressure_advance.get_at(new_filament_id));
|
||||||
|
// Orca: Adaptive PA
|
||||||
|
// Reset Adaptive PA processor last PA value
|
||||||
|
m_pa_processor->resetPreviousPA(m_config.pressure_advance.get_at(new_filament_id));
|
||||||
|
}
|
||||||
|
|
||||||
gcode += m_writer.toolchange(new_filament_id, new_extruder_id);
|
gcode += m_writer.toolchange(new_filament_id, new_extruder_id);
|
||||||
if (Extruder *fil = m_writer.filament())
|
if (Extruder *fil = m_writer.filament())
|
||||||
@@ -9885,24 +9909,18 @@ std::string GCode::set_extruder(unsigned int new_filament_id, double print_z, bo
|
|||||||
if (m_ooze_prevention.enable && !defer_temp_wait)
|
if (m_ooze_prevention.enable && !defer_temp_wait)
|
||||||
gcode += m_ooze_prevention.post_toolchange(*this);
|
gcode += m_ooze_prevention.post_toolchange(*this);
|
||||||
|
|
||||||
gcode += set_filament_pressure_advance(new_filament_id);
|
if (m_config.enable_pressure_advance.get_at(new_filament_id)) {
|
||||||
|
gcode += m_writer.set_pressure_advance(m_config.pressure_advance.get_at(new_filament_id));
|
||||||
|
// Orca: Adaptive PA
|
||||||
|
// Reset Adaptive PA processor last PA value
|
||||||
|
m_pa_processor->resetPreviousPA(m_config.pressure_advance.get_at(new_filament_id));
|
||||||
|
}
|
||||||
//Orca: tool changer or IDEX's firmware may change Z position, so we set it to unknown/undefined
|
//Orca: tool changer or IDEX's firmware may change Z position, so we set it to unknown/undefined
|
||||||
m_last_pos_defined = false;
|
m_last_pos_defined = false;
|
||||||
|
|
||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GCode::set_filament_pressure_advance(unsigned int filament_id)
|
|
||||||
{
|
|
||||||
const size_t fi = get_filament_config_index(filament_id);
|
|
||||||
if (!m_config.enable_pressure_advance.get_at(fi))
|
|
||||||
return {};
|
|
||||||
// Orca: Adaptive PA
|
|
||||||
// Reset Adaptive PA processor last PA value
|
|
||||||
m_pa_processor->resetPreviousPA(m_config.pressure_advance.get_at(fi));
|
|
||||||
return m_writer.set_pressure_advance(m_config.pressure_advance.get_at(fi));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string polygon_to_string(const Polygon &polygon, Print *print, bool is_print_space = false) {
|
inline std::string polygon_to_string(const Polygon &polygon, Print *print, bool is_print_space = false) {
|
||||||
std::ostringstream gcode;
|
std::ostringstream gcode;
|
||||||
gcode << "[";
|
gcode << "[";
|
||||||
|
|||||||
@@ -281,8 +281,6 @@ public:
|
|||||||
// extra_retract forwards a PETG pre-extrusion over-extrusion; default 0 -> identical to the plain deretract.
|
// extra_retract forwards a PETG pre-extrusion over-extrusion; default 0 -> identical to the plain deretract.
|
||||||
std::string unretract(float extra_retract = 0.f) { return m_writer.unlift() + m_writer.unretract(extra_retract); }
|
std::string unretract(float extra_retract = 0.f) { return m_writer.unlift() + m_writer.unretract(extra_retract); }
|
||||||
std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false, int toolchange_temp_override = -1, bool defer_temp_wait = false);
|
std::string set_extruder(unsigned int extruder_id, double print_z, bool by_object=false, int toolchange_temp_override = -1, bool defer_temp_wait = false);
|
||||||
// Sets the pressure advance of the filament's extruder variant, if enabled for it.
|
|
||||||
std::string set_filament_pressure_advance(unsigned int filament_id);
|
|
||||||
bool is_BBL_Printer();
|
bool is_BBL_Printer();
|
||||||
WipeTowerType wipe_tower_type();
|
WipeTowerType wipe_tower_type();
|
||||||
|
|
||||||
|
|||||||
@@ -21,30 +21,38 @@ namespace Slic3r {
|
|||||||
*
|
*
|
||||||
* @param gcodegen A reference to the GCode object that generates the G-code.
|
* @param gcodegen A reference to the GCode object that generates the G-code.
|
||||||
*/
|
*/
|
||||||
AdaptivePAProcessor::AdaptivePAProcessor(GCode &gcodegen)
|
AdaptivePAProcessor::AdaptivePAProcessor(GCode &gcodegen, const std::vector<unsigned int> &tools_used)
|
||||||
: m_gcodegen(gcodegen),
|
: m_gcodegen(gcodegen),
|
||||||
m_config(gcodegen.config()),
|
m_config(gcodegen.config()),
|
||||||
m_last_predicted_pa(0.0),
|
m_last_predicted_pa(0.0),
|
||||||
m_max_next_feedrate(0.0),
|
m_max_next_feedrate(0.0),
|
||||||
m_next_feedrate(0.0),
|
m_next_feedrate(0.0),
|
||||||
m_current_feedrate(0.0),
|
m_current_feedrate(0.0),
|
||||||
m_last_config_index(-1),
|
m_last_extruder_id(-1),
|
||||||
m_pa_change_pattern(R"(; PA_CHANGE:T(\d+) MM3MM:([0-9]*\.[0-9]+) ACCEL:(\d+) BR:(\d+) RC:(\d+) OV:(\d+))"),
|
m_pa_change_pattern(R"(; PA_CHANGE:T(\d+) MM3MM:([0-9]*\.[0-9]+) ACCEL:(\d+) BR:(\d+) RC:(\d+) OV:(\d+))"),
|
||||||
m_g1_f_pattern(R"(G1 F([0-9]+))")
|
m_g1_f_pattern(R"(G1 F([0-9]+))")
|
||||||
{
|
{
|
||||||
|
// Constructor body can be used for further initialization if necessary
|
||||||
|
for (unsigned int tool : tools_used) {
|
||||||
|
// Only enable model for the tool if both PA and adaptive PA options are enabled
|
||||||
|
if(m_config.adaptive_pressure_advance.get_at(tool) && m_config.enable_pressure_advance.get_at(tool)){
|
||||||
|
auto interpolator = std::make_unique<AdaptivePAInterpolator>();
|
||||||
|
// Get calibration values from extruder
|
||||||
|
std::string pa_calibration_values = m_config.adaptive_pressure_advance_model.get_at(tool);
|
||||||
|
// Setup the model and store it in the tool-interpolation model map
|
||||||
|
interpolator->parseAndSetData(pa_calibration_values);
|
||||||
|
m_AdaptivePAInterpolators[tool] = std::move(interpolator);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to get the interpolator for a specific filament config index.
|
// Method to get the interpolator for a specific tool ID
|
||||||
// The model is built the first time an index is requested, as the indices in use depend on
|
AdaptivePAInterpolator* AdaptivePAProcessor::getInterpolator(unsigned int tool_id) {
|
||||||
// the extruder variant each filament prints with.
|
auto it = m_AdaptivePAInterpolators.find(tool_id);
|
||||||
AdaptivePAInterpolator* AdaptivePAProcessor::getInterpolator(unsigned int config_index) {
|
if (it != m_AdaptivePAInterpolators.end()) {
|
||||||
auto [it, inserted] = m_AdaptivePAInterpolators.try_emplace(config_index);
|
return it->second.get();
|
||||||
// Only enable model for the index if both PA and adaptive PA options are enabled
|
|
||||||
if (inserted && m_config.adaptive_pressure_advance.get_at(config_index) && m_config.enable_pressure_advance.get_at(config_index)) {
|
|
||||||
it->second = std::make_unique<AdaptivePAInterpolator>();
|
|
||||||
it->second->parseAndSetData(m_config.adaptive_pressure_advance_model.get_at(config_index));
|
|
||||||
}
|
}
|
||||||
return it->second.get();
|
return nullptr; // Handle the case where the tool_id was not found
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,17 +108,16 @@ std::string AdaptivePAProcessor::process_layer(std::string &&gcode) {
|
|||||||
// the PA for that material is set. As no tag below will be found for this extruder, the original PA is retained.
|
// the PA for that material is set. As no tag below will be found for this extruder, the original PA is retained.
|
||||||
if (line.find("; PA_CHANGE") == 0) { // prune lines quickly before running regex check as regex is more expensive to run
|
if (line.find("; PA_CHANGE") == 0) { // prune lines quickly before running regex check as regex is more expensive to run
|
||||||
if (std::regex_search(line, m_match, m_pa_change_pattern)) {
|
if (std::regex_search(line, m_match, m_pa_change_pattern)) {
|
||||||
// The tag carries the filament config index, which selects the PA settings of the filament's extruder variant
|
int extruder_id = std::stoi(m_match[1].str());
|
||||||
int config_index = std::stoi(m_match[1].str());
|
|
||||||
mm3mm_value = std::stod(m_match[2].str());
|
mm3mm_value = std::stod(m_match[2].str());
|
||||||
accel_value = std::stod(m_match[3].str());
|
accel_value = std::stod(m_match[3].str());
|
||||||
int isBridge = std::stoi(m_match[4].str());
|
int isBridge = std::stoi(m_match[4].str());
|
||||||
int roleChange = std::stoi(m_match[5].str());
|
int roleChange = std::stoi(m_match[5].str());
|
||||||
int isOverhang = std::stoi(m_match[6].str());
|
int isOverhang = std::stoi(m_match[6].str());
|
||||||
|
|
||||||
// Check if the filament config index has changed
|
// Check if the extruder ID has changed
|
||||||
bool config_index_changed = (config_index != m_last_config_index);
|
bool extruder_changed = (extruder_id != m_last_extruder_id);
|
||||||
m_last_config_index = config_index;
|
m_last_extruder_id = extruder_id;
|
||||||
|
|
||||||
// Save the PA_CHANGE line to output later after finding feedrate
|
// Save the PA_CHANGE line to output later after finding feedrate
|
||||||
pa_change_line = line;
|
pa_change_line = line;
|
||||||
@@ -205,23 +212,23 @@ std::string AdaptivePAProcessor::process_layer(std::string &&gcode) {
|
|||||||
|
|
||||||
// Calculate the predicted PA using the upcomming feature maximum feedrate
|
// Calculate the predicted PA using the upcomming feature maximum feedrate
|
||||||
// Get the interpolator for the active tool
|
// Get the interpolator for the active tool
|
||||||
AdaptivePAInterpolator* interpolator = getInterpolator(m_last_config_index);
|
AdaptivePAInterpolator* interpolator = getInterpolator(m_last_extruder_id);
|
||||||
|
|
||||||
double predicted_pa = 0;
|
double predicted_pa = 0;
|
||||||
double adaptive_PA_speed = 0;
|
double adaptive_PA_speed = 0;
|
||||||
|
|
||||||
if(!interpolator){ // Tool not found in the interpolator map
|
if(!interpolator){ // Tool not found in the interpolator map
|
||||||
// Tool not found in the PA interpolator to tool map
|
// Tool not found in the PA interpolator to tool map
|
||||||
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_config_index) ? m_config.pressure_advance.get_at(m_last_config_index) : 0;
|
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_extruder_id) ? m_config.pressure_advance.get_at(m_last_extruder_id) : 0;
|
||||||
if(m_config.gcode_comments) output << "; APA: Tool doesnt have APA enabled\n";
|
if(m_config.gcode_comments) output << "; APA: Tool doesnt have APA enabled\n";
|
||||||
} else if (!interpolator->isInitialised() || (!m_config.adaptive_pressure_advance.get_at(m_last_config_index)) )
|
} else if (!interpolator->isInitialised() || (!m_config.adaptive_pressure_advance.get_at(m_last_extruder_id)) )
|
||||||
// Check if the model is not initialised by the constructor for the active extruder
|
// Check if the model is not initialised by the constructor for the active extruder
|
||||||
// Also check that adaptive PA is enabled for that extruder. This should not be needed
|
// Also check that adaptive PA is enabled for that extruder. This should not be needed
|
||||||
// as the PA change flag should not be set upstream (in the GCode.cpp file) if adaptive PA is disabled
|
// as the PA change flag should not be set upstream (in the GCode.cpp file) if adaptive PA is disabled
|
||||||
// however check for robustness sake.
|
// however check for robustness sake.
|
||||||
{
|
{
|
||||||
// Model failed or adaptive pressure advance not enabled - use default value from m_config
|
// Model failed or adaptive pressure advance not enabled - use default value from m_config
|
||||||
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_config_index) ? m_config.pressure_advance.get_at(m_last_config_index) : 0;
|
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_extruder_id) ? m_config.pressure_advance.get_at(m_last_extruder_id) : 0;
|
||||||
if(m_config.gcode_comments) output << "; APA: Interpolator setup failed, using default pressure advance\n";
|
if(m_config.gcode_comments) output << "; APA: Interpolator setup failed, using default pressure advance\n";
|
||||||
} else { // Model setup succeeded
|
} else { // Model setup succeeded
|
||||||
// Proceed to identify the print speed to use to calculate the adaptive PA value
|
// Proceed to identify the print speed to use to calculate the adaptive PA value
|
||||||
@@ -242,18 +249,18 @@ std::string AdaptivePAProcessor::process_layer(std::string &&gcode) {
|
|||||||
predicted_pa = (*interpolator)(mm3mm_value * adaptive_PA_speed, accel_value);
|
predicted_pa = (*interpolator)(mm3mm_value * adaptive_PA_speed, accel_value);
|
||||||
|
|
||||||
// This is a bridge, use the dedicated PA setting.
|
// This is a bridge, use the dedicated PA setting.
|
||||||
if(isBridge && m_config.adaptive_pressure_advance_bridges.get_at(m_last_config_index) > EPSILON)
|
if(isBridge && m_config.adaptive_pressure_advance_bridges.get_at(m_last_extruder_id) > EPSILON)
|
||||||
predicted_pa = m_config.adaptive_pressure_advance_bridges.get_at(m_last_config_index);
|
predicted_pa = m_config.adaptive_pressure_advance_bridges.get_at(m_last_extruder_id);
|
||||||
|
|
||||||
if (predicted_pa < 0) { // If extrapolation fails, fall back to the default PA for the extruder.
|
if (predicted_pa < 0) { // If extrapolation fails, fall back to the default PA for the extruder.
|
||||||
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_config_index) ? m_config.pressure_advance.get_at(m_last_config_index) : 0;
|
predicted_pa = m_config.enable_pressure_advance.get_at(m_last_extruder_id) ? m_config.pressure_advance.get_at(m_last_extruder_id) : 0;
|
||||||
if(m_config.gcode_comments) output << "; APA: Interpolation failed, using fallback pressure advance value\n";
|
if(m_config.gcode_comments) output << "; APA: Interpolation failed, using fallback pressure advance value\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(m_config.gcode_comments) {
|
if(m_config.gcode_comments) {
|
||||||
// Output debug GCode comments
|
// Output debug GCode comments
|
||||||
output << pa_change_line << '\n'; // Output PA change command tag
|
output << pa_change_line << '\n'; // Output PA change command tag
|
||||||
if(isBridge && m_config.adaptive_pressure_advance_bridges.get_at(m_last_config_index) > EPSILON)
|
if(isBridge && m_config.adaptive_pressure_advance_bridges.get_at(m_last_extruder_id) > EPSILON)
|
||||||
output << "; APA Model Override (bridge)\n";
|
output << "; APA Model Override (bridge)\n";
|
||||||
output << "; APA Current Speed: " << std::to_string(m_current_feedrate) << "\n";
|
output << "; APA Current Speed: " << std::to_string(m_current_feedrate) << "\n";
|
||||||
output << "; APA Next Speed: " << std::to_string(m_next_feedrate) << "\n";
|
output << "; APA Next Speed: " << std::to_string(m_next_feedrate) << "\n";
|
||||||
@@ -262,7 +269,7 @@ std::string AdaptivePAProcessor::process_layer(std::string &&gcode) {
|
|||||||
output << "; APA Flow rate: " << std::to_string(mm3mm_value * m_max_next_feedrate) << "\n";
|
output << "; APA Flow rate: " << std::to_string(mm3mm_value * m_max_next_feedrate) << "\n";
|
||||||
output << "; APA Prev PA: " << std::to_string(m_last_predicted_pa) << " New PA: " << std::to_string(predicted_pa) << "\n";
|
output << "; APA Prev PA: " << std::to_string(m_last_predicted_pa) << " New PA: " << std::to_string(predicted_pa) << "\n";
|
||||||
}
|
}
|
||||||
if (config_index_changed || std::fabs(predicted_pa - m_last_predicted_pa) > EPSILON) {
|
if (extruder_changed || std::fabs(predicted_pa - m_last_predicted_pa) > EPSILON) {
|
||||||
output << m_gcodegen.writer().set_pressure_advance(predicted_pa); // Use m_writer to set pressure advance
|
output << m_gcodegen.writer().set_pressure_advance(predicted_pa); // Use m_writer to set pressure advance
|
||||||
m_last_predicted_pa = predicted_pa; // Update the last predicted PA value
|
m_last_predicted_pa = predicted_pa; // Update the last predicted PA value
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <regex>
|
#include <regex>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
#include "AdaptivePAInterpolator.hpp"
|
#include "AdaptivePAInterpolator.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
@@ -32,7 +33,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @param gcodegen A reference to the GCode object that generates the G-code.
|
* @param gcodegen A reference to the GCode object that generates the G-code.
|
||||||
*/
|
*/
|
||||||
AdaptivePAProcessor(GCode &gcodegen);
|
AdaptivePAProcessor(GCode &gcodegen, const std::vector<unsigned int> &tools_used);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Processes a layer of G-code and applies adaptive pressure advance.
|
* @brief Processes a layer of G-code and applies adaptive pressure advance.
|
||||||
@@ -69,25 +70,28 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
GCode &m_gcodegen; ///< Reference to the GCode object.
|
GCode &m_gcodegen; ///< Reference to the GCode object.
|
||||||
std::unordered_map<unsigned int, std::unique_ptr<AdaptivePAInterpolator>> m_AdaptivePAInterpolators; ///< Map between Interpolator objects and filament config indices (null when adaptive PA is off)
|
std::unordered_map<unsigned int, std::unique_ptr<AdaptivePAInterpolator>> m_AdaptivePAInterpolators; ///< Map between Interpolator objects and tool ID's
|
||||||
const PrintConfig &m_config; ///< Reference to the print configuration.
|
const PrintConfig &m_config; ///< Reference to the print configuration.
|
||||||
double m_last_predicted_pa; ///< Last predicted pressure advance value.
|
double m_last_predicted_pa; ///< Last predicted pressure advance value.
|
||||||
double m_max_next_feedrate; ///< Maximum feed rate (speed) for the upcomming island. If no speed is found, the previous island speed is used.
|
double m_max_next_feedrate; ///< Maximum feed rate (speed) for the upcomming island. If no speed is found, the previous island speed is used.
|
||||||
double m_next_feedrate; ///< First feed rate (speed) for the upcomming island.
|
double m_next_feedrate; ///< First feed rate (speed) for the upcomming island.
|
||||||
double m_current_feedrate; ///< Current, latest feedrate.
|
double m_current_feedrate; ///< Current, latest feedrate.
|
||||||
int m_last_config_index; ///< Filament config index of the last PA_CHANGE tag.
|
int m_last_extruder_id; ///< Last used extruder ID.
|
||||||
|
|
||||||
std::regex m_pa_change_pattern; ///< Regular expression to detect PA_CHANGE pattern.
|
std::regex m_pa_change_pattern; ///< Regular expression to detect PA_CHANGE pattern.
|
||||||
std::regex m_g1_f_pattern; ///< Regular expression to detect G1 F pattern.
|
std::regex m_g1_f_pattern; ///< Regular expression to detect G1 F pattern.
|
||||||
std::smatch m_match; ///< Match results for regular expressions.
|
std::smatch m_match; ///< Match results for regular expressions.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the PA interpolator attached to the specified filament config index.
|
* @brief Get the PA interpolator attached to the specified tool ID.
|
||||||
*
|
*
|
||||||
* @param config_index The filament config index (one per filament and extruder variant) for which the PA interpolation model is to be returned.
|
* This method manually sets the adaptive PA internally held value.
|
||||||
* @return The Adaptive PA Interpolator object corresponding to that index, or nullptr when adaptive PA is off for it.
|
* Call this when changing tools or in any other case where the internally assumed last PA value may be incorrect
|
||||||
|
*
|
||||||
|
* @param An integer with the tool ID for which the PA interpolation model is to be returned.
|
||||||
|
* @return The Adaptive PA Interpolator object corresponding to that tool.
|
||||||
*/
|
*/
|
||||||
AdaptivePAInterpolator* getInterpolator(unsigned int config_index);
|
AdaptivePAInterpolator* getInterpolator(unsigned int tool_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|||||||
@@ -13,19 +13,8 @@
|
|||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
|
||||||
// How many setters this thread holds, so the ones nested in another can skip
|
|
||||||
// setlocale, which takes a lock the whole process shares on Windows.
|
|
||||||
static thread_local int s_numeric_locale_depth = 0;
|
|
||||||
|
|
||||||
CNumericLocalesSetter::CNumericLocalesSetter()
|
CNumericLocalesSetter::CNumericLocalesSetter()
|
||||||
{
|
{
|
||||||
// Nested in another setter on this thread, whose "C" the separator check
|
|
||||||
// confirms is still set.
|
|
||||||
if (s_numeric_locale_depth > 0 && is_decimal_separator_point()) {
|
|
||||||
m_nested = true;
|
|
||||||
++ s_numeric_locale_depth;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
||||||
m_orig_numeric_locale = std::setlocale(LC_NUMERIC, nullptr);
|
m_orig_numeric_locale = std::setlocale(LC_NUMERIC, nullptr);
|
||||||
@@ -40,17 +29,12 @@ CNumericLocalesSetter::CNumericLocalesSetter()
|
|||||||
m_new_locale = newlocale(LC_NUMERIC_MASK, "C", m_new_locale);
|
m_new_locale = newlocale(LC_NUMERIC_MASK, "C", m_new_locale);
|
||||||
uselocale(m_new_locale);
|
uselocale(m_new_locale);
|
||||||
#endif
|
#endif
|
||||||
// Counted last, since the destructor does not run for a constructor that throws.
|
|
||||||
++ s_numeric_locale_depth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CNumericLocalesSetter::~CNumericLocalesSetter()
|
CNumericLocalesSetter::~CNumericLocalesSetter()
|
||||||
{
|
{
|
||||||
-- s_numeric_locale_depth;
|
|
||||||
if (m_nested)
|
|
||||||
return;
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::setlocale(LC_NUMERIC, m_orig_numeric_locale.data());
|
std::setlocale(LC_NUMERIC, m_orig_numeric_locale.data());
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -19,13 +19,8 @@ class CNumericLocalesSetter {
|
|||||||
public:
|
public:
|
||||||
CNumericLocalesSetter();
|
CNumericLocalesSetter();
|
||||||
~CNumericLocalesSetter();
|
~CNumericLocalesSetter();
|
||||||
// A copy would restore the locale twice, and count down once more than up.
|
|
||||||
CNumericLocalesSetter(const CNumericLocalesSetter&) = delete;
|
|
||||||
CNumericLocalesSetter& operator=(const CNumericLocalesSetter&) = delete;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Inside another setter on this thread, which does the setting and restoring.
|
|
||||||
bool m_nested { false };
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::string m_orig_numeric_locale;
|
std::string m_orig_numeric_locale;
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
#include <variant>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <tbb/blocked_range.h>
|
|
||||||
#include <tbb/parallel_for.h>
|
|
||||||
#include <tbb/task_arena.h>
|
|
||||||
#include <tbb/task_group.h>
|
|
||||||
|
|
||||||
#include "Exception.hpp"
|
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
|
|
||||||
// A batch of resolved presets, each a whole config, is what resolve_then_commit adds
|
|
||||||
// to peak memory, so it stays far below a vendor's preset count and above any core count.
|
|
||||||
inline constexpr size_t resolve_batch_size = 64;
|
|
||||||
|
|
||||||
// Resolve `count` items that do not depend on each other and install them one at
|
|
||||||
// a time.
|
|
||||||
//
|
|
||||||
// `resolve(i)` runs on any thread and must read only, since the items are
|
|
||||||
// resolved side by side. `commit(i, resolved)` is called for every item in index
|
|
||||||
// order, on the calling thread, and is where shared state is written.
|
|
||||||
//
|
|
||||||
// The items are worked through in batches, so what is resolved and held at once
|
|
||||||
// does not grow with `count`. An exception from either callable propagates after
|
|
||||||
// the batches before it have been committed. A cancellation of the caller's task
|
|
||||||
// group, which stops a batch partway without an exception, throws RuntimeError
|
|
||||||
// before that batch commits.
|
|
||||||
//
|
|
||||||
// `ChunkSetup`, when given, is constructed once for each piece of a batch TBB hands
|
|
||||||
// out, for per-thread state a resolve would otherwise set up per item, such as the
|
|
||||||
// C numeric locale, whose setting takes a lock the whole process shares.
|
|
||||||
template<class ChunkSetup = std::monostate, class Resolve, class Commit>
|
|
||||||
void resolve_then_commit(size_t count, Resolve resolve, Commit commit)
|
|
||||||
{
|
|
||||||
using Resolved = std::invoke_result_t<Resolve&, size_t>;
|
|
||||||
|
|
||||||
std::vector<Resolved> resolved(std::min(count, resolve_batch_size));
|
|
||||||
for (size_t first = 0; first < count; first += resolve_batch_size) {
|
|
||||||
const size_t last = std::min(first + resolve_batch_size, count);
|
|
||||||
// Isolated, so a thread waiting on the batch runs none of the caller's other
|
|
||||||
// tasks before finishing it.
|
|
||||||
tbb::this_task_arena::isolate([&] {
|
|
||||||
tbb::parallel_for(tbb::blocked_range<size_t>(first, last),
|
|
||||||
[&](const tbb::blocked_range<size_t>& range) {
|
|
||||||
ChunkSetup setup;
|
|
||||||
(void) setup;
|
|
||||||
for (size_t i = range.begin(); i < range.end(); ++ i)
|
|
||||||
resolved[i - first] = resolve(i);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if (tbb::is_current_task_group_canceling())
|
|
||||||
throw RuntimeError("resolve_then_commit: canceled before the batch was resolved");
|
|
||||||
for (size_t i = first; i < last; ++ i)
|
|
||||||
commit(i, std::move(resolved[i - first]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
|
||||||
+187
-286
@@ -5,8 +5,6 @@
|
|||||||
#include "Preset.hpp"
|
#include "Preset.hpp"
|
||||||
#include "PresetBundle.hpp"
|
#include "PresetBundle.hpp"
|
||||||
#include "AppConfig.hpp"
|
#include "AppConfig.hpp"
|
||||||
#include "LocalesUtils.hpp"
|
|
||||||
#include "ParallelResolve.hpp"
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
@@ -508,11 +506,10 @@ void Preset::normalize(DynamicPrintConfig &config)
|
|||||||
handle_legacy_sla(config);
|
handle_legacy_sla(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Preset::remove_invalid_keys(DynamicPrintConfig &config, const DynamicPrintConfig &default_config,
|
std::string Preset::remove_invalid_keys(DynamicPrintConfig &config, const DynamicPrintConfig &default_config)
|
||||||
const DynamicPrintConfig *added)
|
|
||||||
{
|
{
|
||||||
std::string incorrect_keys;
|
std::string incorrect_keys;
|
||||||
for (const std::string &key : (added != nullptr ? *added : config).keys())
|
for (const std::string &key : config.keys())
|
||||||
if (! default_config.has(key)) {
|
if (! default_config.has(key)) {
|
||||||
if (incorrect_keys.empty())
|
if (incorrect_keys.empty())
|
||||||
incorrect_keys = key;
|
incorrect_keys = key;
|
||||||
@@ -624,6 +621,7 @@ void Preset::load_info(const std::string& file)
|
|||||||
}
|
}
|
||||||
else if (v.first.compare("base_id") == 0) {
|
else if (v.first.compare("base_id") == 0) {
|
||||||
this->base_id = v.second.get_value<std::string>();
|
this->base_id = v.second.get_value<std::string>();
|
||||||
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " load info from: " << file << " and base_id: " << this->base_id;
|
||||||
if (this->base_id.compare("null") == 0)
|
if (this->base_id.compare("null") == 0)
|
||||||
this->base_id.clear();
|
this->base_id.clear();
|
||||||
}
|
}
|
||||||
@@ -976,37 +974,6 @@ void Preset::get_extruder_names_and_keysets(Type type, std::string& extruder_id_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicPrintConfig Preset::load_external_config(Type type, const DynamicPrintConfig &default_config, const DynamicPrintConfig &project_config,
|
|
||||||
const std::set<std::string> &different_settings_list,
|
|
||||||
const std::function<DynamicPrintConfig *(const std::string &inherits)> &find_base,
|
|
||||||
t_config_option_keys *keys)
|
|
||||||
{
|
|
||||||
// Load the preset over a default preset, so that the missing fields are filled in from the default preset.
|
|
||||||
DynamicPrintConfig cfg(default_config);
|
|
||||||
// SoftFever: ignore print connection info from project
|
|
||||||
auto cfg_keys = cfg.keys();
|
|
||||||
cfg_keys.erase(std::remove_if(cfg_keys.begin(), cfg_keys.end(),
|
|
||||||
[](std::string &val) {
|
|
||||||
return val == "print_host" || val == "print_host_webui" || val == "printhost_apikey" ||
|
|
||||||
val == "printhost_cafile" || val == "printhost_user" || val == "printhost_password" || val == "printhost_port";
|
|
||||||
}),
|
|
||||||
cfg_keys.end());
|
|
||||||
cfg.apply_only(project_config, cfg_keys, true);
|
|
||||||
|
|
||||||
//add different settings check logic, replace the old system preset's default value with new system preset's default values
|
|
||||||
if (!different_settings_list.empty()) {
|
|
||||||
if (DynamicPrintConfig *base_config = find_base(Preset::inherits(cfg))) {
|
|
||||||
std::string extruder_id_name, extruder_variant_name;
|
|
||||||
std::set<std::string> *key_set1 = nullptr, *key_set2 = nullptr;
|
|
||||||
Preset::get_extruder_names_and_keysets(type, extruder_id_name, extruder_variant_name, &key_set1, &key_set2);
|
|
||||||
cfg.update_non_diff_values_to_base_config(*base_config, cfg_keys, different_settings_list, extruder_id_name, extruder_variant_name, *key_set1, *key_set2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (keys)
|
|
||||||
*keys = std::move(cfg_keys);
|
|
||||||
return cfg;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Preset::has_lidar(PresetBundle *preset_bundle)
|
bool Preset::has_lidar(PresetBundle *preset_bundle)
|
||||||
{
|
{
|
||||||
bool has_lidar = false;
|
bool has_lidar = false;
|
||||||
@@ -1702,169 +1669,6 @@ std::string PresetCollection::canonical_preset_name(const std::string &name, con
|
|||||||
return get_preset_canonical_name(parsed.bare, origin);
|
return get_preset_canonical_name(parsed.bare, origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
PresetCollection::UserPresetLoad PresetCollection::resolve_user_preset(
|
|
||||||
const boost::filesystem::path &file, const std::string &canonical_name,
|
|
||||||
const PresetOrigin &load_origin, ForwardCompatibilitySubstitutionRule substitution_rule,
|
|
||||||
const std::string &extruder_id_name, const std::string &extruder_variant_name,
|
|
||||||
std::set<std::string> *key_set1, std::set<std::string> *key_set2) const
|
|
||||||
{
|
|
||||||
UserPresetLoad out;
|
|
||||||
out.preset = Preset(m_type, canonical_name, false);
|
|
||||||
Preset &preset = out.preset;
|
|
||||||
preset.bundle_id = load_origin.bundle_id;
|
|
||||||
preset.file = file.string();
|
|
||||||
// Load the preset file, apply preset values on top of defaults.
|
|
||||||
try {
|
|
||||||
fs::path idx_path(preset.file);
|
|
||||||
idx_path.replace_extension(".info");
|
|
||||||
if (fs::exists(idx_path)) {
|
|
||||||
out.info_file = idx_path.string();
|
|
||||||
preset.load_info(out.info_file);
|
|
||||||
}
|
|
||||||
DynamicPrintConfig config;
|
|
||||||
//BBS: change to json format
|
|
||||||
//ConfigSubstitutions config_substitutions = config.load_from_ini(preset.file, substitution_rule);
|
|
||||||
std::map<std::string, std::string> key_values;
|
|
||||||
std::string reason;
|
|
||||||
ConfigSubstitutions config_substitutions = config.load_from_json(preset.file, substitution_rule, key_values, reason);
|
|
||||||
if (! config_substitutions.empty())
|
|
||||||
out.substitutions.push_back({ preset.name, m_type, PresetConfigSubstitutions::Source::UserFile, preset.file, std::move(config_substitutions) });
|
|
||||||
if (!reason.empty()) {
|
|
||||||
out.discard_file = true;
|
|
||||||
out.errors.push_back((boost::format("parse config %1% failed") % preset.file).str());
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string version_str = key_values[BBL_JSON_KEY_VERSION];
|
|
||||||
boost::optional<Semver> version = Semver::parse(version_str);
|
|
||||||
if (!version) return out;
|
|
||||||
preset.version = *version;
|
|
||||||
|
|
||||||
if (key_values.find(BBL_JSON_KEY_FILAMENT_ID) != key_values.end())
|
|
||||||
preset.filament_id = key_values[BBL_JSON_KEY_FILAMENT_ID];
|
|
||||||
if (key_values.find(BBL_JSON_KEY_DESCRIPTION) != key_values.end())
|
|
||||||
preset.description = key_values[BBL_JSON_KEY_DESCRIPTION];
|
|
||||||
if (key_values.find(BBL_JSON_KEY_INSTANTIATION) != key_values.end())
|
|
||||||
preset.is_visible = key_values[BBL_JSON_KEY_INSTANTIATION] != "false";
|
|
||||||
|
|
||||||
//Orca: find and use the inherit config as the base
|
|
||||||
const Preset* inherit_preset = nullptr;
|
|
||||||
ConfigOption* inherits_config = config.option(BBL_JSON_KEY_INHERITS);
|
|
||||||
|
|
||||||
// check inherits_config
|
|
||||||
if (inherits_config) {
|
|
||||||
ConfigOptionString * option_str = dynamic_cast<ConfigOptionString *> (inherits_config);
|
|
||||||
std::string inherits_value = option_str->value;
|
|
||||||
// Orca: try to find if the parent preset has been renamed
|
|
||||||
inherit_preset = this->find_preset2(inherits_value);
|
|
||||||
Preset::normalize_inherits(config, inherit_preset);
|
|
||||||
}
|
|
||||||
const Preset& default_preset = this->default_preset_for(config);
|
|
||||||
if (inherit_preset) {
|
|
||||||
preset.config = inherit_preset->config;
|
|
||||||
preset.filament_id = inherit_preset->filament_id;
|
|
||||||
extend_default_config_length(config, false, {});
|
|
||||||
preset.config.update_diff_values_to_child_config(config, extruder_id_name, extruder_variant_name, *key_set1, *key_set2);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
auto inherits_config2 = dynamic_cast<ConfigOptionString *>(inherits_config);
|
|
||||||
if ((inherits_config2 && !inherits_config2->value.empty())) {
|
|
||||||
out.errors.push_back((boost::format("can not find parent %1% for config %2%!") % inherits_config2->value % preset.file).str());
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
// We support custom root preset now
|
|
||||||
// Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field.
|
|
||||||
preset.config = default_preset.config;
|
|
||||||
preset.config.apply(std::move(config));
|
|
||||||
extend_default_config_length(preset.config, true, default_preset.config);
|
|
||||||
}
|
|
||||||
|
|
||||||
Preset::normalize(preset.config);
|
|
||||||
// Report configuration fields, which are misplaced into a wrong group.
|
|
||||||
std::string incorrect_keys = Preset::remove_invalid_keys(preset.config, default_preset.config);
|
|
||||||
if (!incorrect_keys.empty())
|
|
||||||
out.errors.push_back("Error in a preset file: The preset \"" + preset.file +
|
|
||||||
"\" contains the following incorrect keys: " + incorrect_keys + ", which were removed");
|
|
||||||
|
|
||||||
if (preset.type == Preset::TYPE_FILAMENT && preset.is_user() && preset.inherits().empty()) {
|
|
||||||
auto compatible_printers = dynamic_cast<ConfigOptionStrings *>(preset.config.option("compatible_printers", true));
|
|
||||||
if (compatible_printers && compatible_printers->values.empty()) {
|
|
||||||
size_t at_pos = canonical_name.find('@');
|
|
||||||
if (at_pos != std::string::npos && at_pos + 1 < canonical_name.length()) {
|
|
||||||
compatible_printers->values.push_back(canonical_name.substr(at_pos + 1));
|
|
||||||
out.save_compatible_printers = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
preset.loaded = true;
|
|
||||||
out.complete = true;
|
|
||||||
} catch (const std::ifstream::failure &err) {
|
|
||||||
out.discard_file = true;
|
|
||||||
out.errors.push_back((boost::format("The user-config cannot be loaded: %1%. Reason: %2%") % preset.file % err.what()).str());
|
|
||||||
//throw Slic3r::RuntimeError(std::string("The selected preset cannot be loaded: ") + preset.file + "\n\tReason: " + err.what());
|
|
||||||
} catch (const std::runtime_error &err) {
|
|
||||||
out.discard_file = true;
|
|
||||||
out.errors.push_back((boost::format("Failed loading the user-config file: %1%. Reason: %2%") % preset.file % err.what()).str());
|
|
||||||
//throw Slic3r::RuntimeError(std::string("Failed loading the preset file: ") + preset.file + "\n\tReason: " + err.what());
|
|
||||||
}
|
|
||||||
out.install = true;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PresetCollection::commit_user_preset(UserPresetLoad &&loaded, std::deque<Preset> &presets_loaded,
|
|
||||||
PresetsConfigSubstitutions &substitutions,
|
|
||||||
const std::function<void(Preset&)> &preset_loaded_fn,
|
|
||||||
bool read_only)
|
|
||||||
{
|
|
||||||
Preset &preset = loaded.preset;
|
|
||||||
if (! loaded.info_file.empty())
|
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " load info from: " << loaded.info_file << " and base_id: " << preset.base_id;
|
|
||||||
append(substitutions, std::move(loaded.substitutions));
|
|
||||||
for (const std::string &error : loaded.errors) {
|
|
||||||
++m_errors;
|
|
||||||
BOOST_LOG_TRIVIAL(error) << error;
|
|
||||||
}
|
|
||||||
if (loaded.discard_file && !read_only) {
|
|
||||||
fs::path file_path(loaded.preset.file);
|
|
||||||
if (fs::exists(file_path))
|
|
||||||
fs::remove(file_path);
|
|
||||||
file_path.replace_extension(".info");
|
|
||||||
if (fs::exists(file_path))
|
|
||||||
fs::remove(file_path);
|
|
||||||
}
|
|
||||||
if (!loaded.install)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (loaded.complete) {
|
|
||||||
if (loaded.save_compatible_printers) {
|
|
||||||
// A filesystem error from the rewrite is counted, and the preset still loads.
|
|
||||||
try {
|
|
||||||
if (!read_only)
|
|
||||||
preset.save(nullptr);
|
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " added compatible_printers for preset: " << preset.name;
|
|
||||||
} catch (const std::runtime_error &err) {
|
|
||||||
++m_errors;
|
|
||||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " can not write compatible_printers back to " << preset.file << ": " << err.what();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//BBS: add some workaround for previous incorrect settings
|
|
||||||
if ((!preset.setting_id.empty())&&(preset.setting_id == preset.base_id))
|
|
||||||
preset.setting_id.clear();
|
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " load preset: " << preset.name << " and filament_id: " << preset.filament_id << " and base_id: " << preset.base_id;
|
|
||||||
//BBS: add config related logs
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(", preset type %1%, name %2%, path %3%, is_system %4%, is_default %5% is_visible %6%")%Preset::get_type_string(m_type) %preset.name %preset.file %preset.is_system %preset.is_default %preset.is_visible;
|
|
||||||
// add alias for custom filament preset
|
|
||||||
set_custom_preset_alias(preset);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preset_loaded_fn != nullptr)
|
|
||||||
preset_loaded_fn(preset);
|
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " load config successful and preset name is:" << preset.name;
|
|
||||||
presets_loaded.emplace_back(std::move(preset));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load all presets found in dir_path.
|
// Load all presets found in dir_path.
|
||||||
// Throws an exception on error.
|
// Throws an exception on error.
|
||||||
void PresetCollection::load_presets(
|
void PresetCollection::load_presets(
|
||||||
@@ -1902,8 +1706,6 @@ void PresetCollection::load_presets(
|
|||||||
std::set<std::string> *key_set1 = nullptr, *key_set2 = nullptr;
|
std::set<std::string> *key_set1 = nullptr, *key_set2 = nullptr;
|
||||||
Preset::get_extruder_names_and_keysets(m_type, extruder_id_name, extruder_variant_name, &key_set1, &key_set2);
|
Preset::get_extruder_names_and_keysets(m_type, extruder_id_name, extruder_variant_name, &key_set1, &key_set2);
|
||||||
|
|
||||||
struct UserPresetFile { fs::path path; std::string canonical_name; };
|
|
||||||
std::vector<UserPresetFile> files;
|
|
||||||
//BBS: change to json format
|
//BBS: change to json format
|
||||||
for (auto &dir_entry : boost::filesystem::directory_iterator(dir))
|
for (auto &dir_entry : boost::filesystem::directory_iterator(dir))
|
||||||
{
|
{
|
||||||
@@ -1919,26 +1721,149 @@ void PresetCollection::load_presets(
|
|||||||
BOOST_LOG_TRIVIAL(warning) << "Preset already present, not loading: " << canonical_name;
|
BOOST_LOG_TRIVIAL(warning) << "Preset already present, not loading: " << canonical_name;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
files.push_back({ dir_entry.path(), std::move(canonical_name) });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve_then_commit<CNumericLocalesSetter>(files.size(),
|
|
||||||
[&](size_t i) {
|
|
||||||
return this->resolve_user_preset(files[i].path, files[i].canonical_name, resolved_origin, substitution_rule,
|
|
||||||
extruder_id_name, extruder_variant_name, key_set1, key_set2);
|
|
||||||
},
|
|
||||||
[&](size_t, UserPresetLoad &&loaded) {
|
|
||||||
// Committing can remove an unreadable preset's file, and a filesystem error
|
|
||||||
// there is reported without stopping the rest of the directory.
|
|
||||||
try {
|
try {
|
||||||
this->commit_user_preset(std::move(loaded), presets_loaded, substitutions, preset_loaded_fn, read_only);
|
Preset preset(m_type, canonical_name, false);
|
||||||
|
preset.bundle_id = resolved_origin.bundle_id;
|
||||||
|
preset.file = dir_entry.path().string();
|
||||||
|
// Load the preset file, apply preset values on top of defaults.
|
||||||
|
try {
|
||||||
|
fs::path idx_path(preset.file);
|
||||||
|
idx_path.replace_extension(".info");
|
||||||
|
if (fs::exists(idx_path)) {
|
||||||
|
preset.load_info(idx_path.string());
|
||||||
|
}
|
||||||
|
DynamicPrintConfig config;
|
||||||
|
//BBS: change to json format
|
||||||
|
//ConfigSubstitutions config_substitutions = config.load_from_ini(preset.file, substitution_rule);
|
||||||
|
std::map<std::string, std::string> key_values;
|
||||||
|
std::string reason;
|
||||||
|
ConfigSubstitutions config_substitutions = config.load_from_json(preset.file, substitution_rule, key_values, reason);
|
||||||
|
if (! config_substitutions.empty())
|
||||||
|
substitutions.push_back({ preset.name, m_type, PresetConfigSubstitutions::Source::UserFile, preset.file, std::move(config_substitutions) });
|
||||||
|
if (!reason.empty()) {
|
||||||
|
fs::path file_path(preset.file);
|
||||||
|
if (!read_only && fs::exists(file_path))
|
||||||
|
fs::remove(file_path);
|
||||||
|
file_path.replace_extension(".info");
|
||||||
|
if (!read_only && fs::exists(file_path))
|
||||||
|
fs::remove(file_path);
|
||||||
|
BOOST_LOG_TRIVIAL(error) << boost::format("parse config %1% failed")%preset.file;
|
||||||
|
++m_errors;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string version_str = key_values[BBL_JSON_KEY_VERSION];
|
||||||
|
boost::optional<Semver> version = Semver::parse(version_str);
|
||||||
|
if (!version) continue;
|
||||||
|
preset.version = *version;
|
||||||
|
|
||||||
|
if (key_values.find(BBL_JSON_KEY_FILAMENT_ID) != key_values.end())
|
||||||
|
preset.filament_id = key_values[BBL_JSON_KEY_FILAMENT_ID];
|
||||||
|
if (key_values.find(BBL_JSON_KEY_DESCRIPTION) != key_values.end())
|
||||||
|
preset.description = key_values[BBL_JSON_KEY_DESCRIPTION];
|
||||||
|
if (key_values.find(BBL_JSON_KEY_INSTANTIATION) != key_values.end())
|
||||||
|
preset.is_visible = key_values[BBL_JSON_KEY_INSTANTIATION] != "false";
|
||||||
|
|
||||||
|
//Orca: find and use the inherit config as the base
|
||||||
|
Preset* inherit_preset = nullptr;
|
||||||
|
ConfigOption* inherits_config = config.option(BBL_JSON_KEY_INHERITS);
|
||||||
|
|
||||||
|
// check inherits_config
|
||||||
|
if (inherits_config) {
|
||||||
|
ConfigOptionString * option_str = dynamic_cast<ConfigOptionString *> (inherits_config);
|
||||||
|
std::string inherits_value = option_str->value;
|
||||||
|
// Orca: try to find if the parent preset has been renamed
|
||||||
|
inherit_preset = this->find_preset2(inherits_value);
|
||||||
|
Preset::normalize_inherits(config, inherit_preset);
|
||||||
|
} else {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
const Preset& default_preset = this->default_preset_for(config);
|
||||||
|
if (inherit_preset) {
|
||||||
|
preset.config = inherit_preset->config;
|
||||||
|
preset.filament_id = inherit_preset->filament_id;
|
||||||
|
extend_default_config_length(config, false, {});
|
||||||
|
preset.config.update_diff_values_to_child_config(config, extruder_id_name, extruder_variant_name, *key_set1, *key_set2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto inherits_config2 = dynamic_cast<ConfigOptionString *>(inherits_config);
|
||||||
|
if ((inherits_config2 && !inherits_config2->value.empty())) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << boost::format("can not find parent %1% for config %2%!")%inherits_config2->value %preset.file;
|
||||||
|
++m_errors;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// We support custom root preset now
|
||||||
|
// Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field.
|
||||||
|
preset.config = default_preset.config;
|
||||||
|
preset.config.apply(std::move(config));
|
||||||
|
extend_default_config_length(preset.config, true, default_preset.config);
|
||||||
|
}
|
||||||
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " load preset: " << name << " and filament_id: " << preset.filament_id << " and base_id: " << preset.base_id;
|
||||||
|
|
||||||
|
Preset::normalize(preset.config);
|
||||||
|
// Report configuration fields, which are misplaced into a wrong group.
|
||||||
|
std::string incorrect_keys = Preset::remove_invalid_keys(preset.config, default_preset.config);
|
||||||
|
if (!incorrect_keys.empty()) {
|
||||||
|
++m_errors;
|
||||||
|
BOOST_LOG_TRIVIAL(error)
|
||||||
|
<< "Error in a preset file: The preset \"" << preset.file
|
||||||
|
<< "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preset.type == Preset::TYPE_FILAMENT && preset.is_user() && preset.inherits().empty()) {
|
||||||
|
auto compatible_printers = dynamic_cast<ConfigOptionStrings *>(preset.config.option("compatible_printers", true));
|
||||||
|
if (compatible_printers && compatible_printers->values.empty()) {
|
||||||
|
size_t at_pos = name.find('@');
|
||||||
|
if (at_pos != std::string::npos && at_pos + 1 < name.length()) {
|
||||||
|
compatible_printers->values.push_back(name.substr(at_pos + 1));
|
||||||
|
if (!read_only)
|
||||||
|
preset.save(nullptr);
|
||||||
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " added compatible_printers for preset: " << name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
preset.loaded = true;
|
||||||
|
//BBS: add some workaround for previous incorrect settings
|
||||||
|
if ((!preset.setting_id.empty())&&(preset.setting_id == preset.base_id))
|
||||||
|
preset.setting_id.clear();
|
||||||
|
//BBS: add config related logs
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(", preset type %1%, name %2%, path %3%, is_system %4%, is_default %5% is_visible %6%")%Preset::get_type_string(m_type) %preset.name %preset.file %preset.is_system %preset.is_default %preset.is_visible;
|
||||||
|
// add alias for custom filament preset
|
||||||
|
set_custom_preset_alias(preset);
|
||||||
|
} catch (const std::ifstream::failure &err) {
|
||||||
|
++m_errors;
|
||||||
|
BOOST_LOG_TRIVIAL(error) << boost::format("The user-config cannot be loaded: %1%. Reason: %2%")%preset.file %err.what();
|
||||||
|
fs::path file_path(preset.file);
|
||||||
|
if (!read_only && fs::exists(file_path))
|
||||||
|
fs::remove(file_path);
|
||||||
|
file_path.replace_extension(".info");
|
||||||
|
if (!read_only && fs::exists(file_path))
|
||||||
|
fs::remove(file_path);
|
||||||
|
//throw Slic3r::RuntimeError(std::string("The selected preset cannot be loaded: ") + preset.file + "\n\tReason: " + err.what());
|
||||||
|
} catch (const std::runtime_error &err) {
|
||||||
|
++m_errors;
|
||||||
|
BOOST_LOG_TRIVIAL(error) << boost::format("Failed loading the user-config file: %1%. Reason: %2%")%preset.file %err.what();
|
||||||
|
//throw Slic3r::RuntimeError(std::string("Failed loading the preset file: ") + preset.file + "\n\tReason: " + err.what());
|
||||||
|
fs::path file_path(preset.file);
|
||||||
|
if (!read_only && fs::exists(file_path))
|
||||||
|
fs::remove(file_path);
|
||||||
|
file_path.replace_extension(".info");
|
||||||
|
if (!read_only && fs::exists(file_path))
|
||||||
|
fs::remove(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preset_loaded_fn != nullptr)
|
||||||
|
preset_loaded_fn(preset);
|
||||||
|
|
||||||
|
presets_loaded.emplace_back(preset);
|
||||||
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " load config successful and preset name is:" << preset.name;
|
||||||
} catch (const std::runtime_error &err) {
|
} catch (const std::runtime_error &err) {
|
||||||
errors_cummulative += err.what();
|
errors_cummulative += err.what();
|
||||||
errors_cummulative += "\n";
|
errors_cummulative += "\n";
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
}
|
||||||
if (presets_loaded.size() > 0)
|
if (presets_loaded.size() > 0)
|
||||||
m_presets.insert(m_presets.end(), std::make_move_iterator(presets_loaded.begin()), std::make_move_iterator(presets_loaded.end()));
|
m_presets.insert(m_presets.end(), std::make_move_iterator(presets_loaded.begin()), std::make_move_iterator(presets_loaded.end()));
|
||||||
sort_presets();
|
sort_presets();
|
||||||
@@ -2671,6 +2596,20 @@ std::pair<Preset*, bool> PresetCollection::load_external_preset(
|
|||||||
const Semver file_version,
|
const Semver file_version,
|
||||||
const std::string filament_id)
|
const std::string filament_id)
|
||||||
{
|
{
|
||||||
|
// Load the preset over a default preset, so that the missing fields are filled in from the default preset.
|
||||||
|
DynamicPrintConfig cfg(this->default_preset_for(combined_config).config);
|
||||||
|
// SoftFever: ignore print connection info from project
|
||||||
|
auto keys = cfg.keys();
|
||||||
|
keys.erase(std::remove_if(keys.begin(), keys.end(),
|
||||||
|
[](std::string &val) {
|
||||||
|
return val == "print_host" || val == "print_host_webui" || val == "printhost_apikey" ||
|
||||||
|
val == "printhost_cafile" || val == "printhost_user" || val == "printhost_password" || val == "printhost_port";
|
||||||
|
}),
|
||||||
|
keys.end());
|
||||||
|
cfg.apply_only(combined_config, keys, true);
|
||||||
|
std::string &inherits = Preset::inherits(cfg);
|
||||||
|
|
||||||
|
//add different settings check logic, replace the old system preset's default value with new system preset's default values
|
||||||
std::deque<Preset>::iterator it = this->find_preset_internal(original_name);
|
std::deque<Preset>::iterator it = this->find_preset_internal(original_name);
|
||||||
bool found = it != m_presets.end() && it->name == original_name;
|
bool found = it != m_presets.end() && it->name == original_name;
|
||||||
if (! found) {
|
if (! found) {
|
||||||
@@ -2679,25 +2618,24 @@ std::pair<Preset*, bool> PresetCollection::load_external_preset(
|
|||||||
found = it != m_presets.end();
|
found = it != m_presets.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
t_config_option_keys keys;
|
std::string extruder_id_name, extruder_variant_name;
|
||||||
DynamicPrintConfig cfg = Preset::load_external_config(m_type, this->default_preset_for(combined_config).config, combined_config, different_settings_list,
|
std::set<std::string> *key_set1 = nullptr, *key_set2 = nullptr;
|
||||||
[this, &original_name, &path, found, it](const std::string &inherits) -> DynamicPrintConfig * {
|
Preset::get_extruder_names_and_keysets(m_type, extruder_id_name, extruder_variant_name, &key_set1, &key_set2);
|
||||||
if (!inherits.empty()) {
|
|
||||||
auto iter = this->find_preset_internal(inherits);
|
if (!inherits.empty() && (different_settings_list.size() > 0)) {
|
||||||
if (iter == m_presets.end() || iter->name != inherits)
|
auto iter = this->find_preset_internal(inherits);
|
||||||
iter = this->find_preset_renamed(inherits);
|
if (iter == m_presets.end() || iter->name != inherits)
|
||||||
if (iter == m_presets.end())
|
iter = this->find_preset_renamed(inherits);
|
||||||
return nullptr;
|
if (iter != m_presets.end()) {
|
||||||
BOOST_LOG_TRIVIAL(info) << "load_external_preset" << boost::format(": change preset %1% inherit %2% 's value to %3% 's values")%original_name %inherits %path;
|
//std::vector<std::string> dirty_options = cfg.diff(iter->config);
|
||||||
return &iter->config;
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": change preset %1% inherit %2% 's value to %3% 's values")%original_name %inherits %path;
|
||||||
}
|
cfg.update_non_diff_values_to_base_config(iter->config, keys, different_settings_list, extruder_id_name, extruder_variant_name, *key_set1, *key_set2);
|
||||||
if (found && it->is_system) {
|
}
|
||||||
BOOST_LOG_TRIVIAL(info) << "load_external_preset" << boost::format(": change preset %1% 's value to %2% 's values")%original_name %path;
|
}
|
||||||
return &it->config;
|
else if (found && it->is_system && (different_settings_list.size() > 0)) {
|
||||||
}
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": change preset %1% 's value to %2% 's values")%original_name %path;
|
||||||
return nullptr;
|
cfg.update_non_diff_values_to_base_config(it->config, keys, different_settings_list, extruder_id_name, extruder_variant_name, *key_set1, *key_set2);
|
||||||
}, &keys);
|
}
|
||||||
std::string &inherits = Preset::inherits(cfg);
|
|
||||||
|
|
||||||
//BBS: add config related logs
|
//BBS: add config related logs
|
||||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, type %1% , path %2%, name %3%, original_name %4%, inherits %5%")%Preset::get_type_string(m_type) %path %name %original_name %inherits;
|
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, type %1% , path %2%, name %3%, original_name %4%, inherits %5%")%Preset::get_type_string(m_type) %path %name %original_name %inherits;
|
||||||
@@ -2889,18 +2827,6 @@ std::pair<Preset*, bool> PresetCollection::load_external_preset(
|
|||||||
return std::make_pair(&preset, false);
|
return std::make_pair(&preset, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Preset& PresetCollection::append_preset(std::string &&path, const std::string &name, DynamicPrintConfig &&config)
|
|
||||||
{
|
|
||||||
lock();
|
|
||||||
Preset &preset = m_presets.emplace_back(m_type, name, false);
|
|
||||||
preset.file = std::move(path);
|
|
||||||
preset.config = std::move(config);
|
|
||||||
preset.loaded = true;
|
|
||||||
preset.is_dirty = false;
|
|
||||||
unlock();
|
|
||||||
return preset;
|
|
||||||
}
|
|
||||||
|
|
||||||
Preset& PresetCollection::load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select, Semver file_version)
|
Preset& PresetCollection::load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select, Semver file_version)
|
||||||
{
|
{
|
||||||
lock();
|
lock();
|
||||||
@@ -3920,53 +3846,28 @@ bool PresetCollection::select_preset_by_name_strict(const std::string &name)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::vector<std::string>> PresetCollection::merge_presets(const std::vector<PresetCollection*> &others, const VendorMap &new_vendors)
|
// Merge one vendor's presets with the other vendor's presets, report duplicates.
|
||||||
|
std::vector<std::string> PresetCollection::merge_presets(PresetCollection &&other, const VendorMap &new_vendors)
|
||||||
{
|
{
|
||||||
auto less = [this](const Preset &a, const Preset &b) {
|
std::vector<std::string> duplicates;
|
||||||
return m_type == Preset::TYPE_FILAMENT ? filament_preset_less(a, b) : a < b;
|
for (Preset &preset : other.m_presets) {
|
||||||
};
|
if (preset.is_default || preset.is_external)
|
||||||
struct Incoming { Preset *preset; size_t source; };
|
continue;
|
||||||
auto incoming_less = [&less](const Incoming &a, const Incoming &b) { return less(*a.preset, *b.preset); };
|
Preset key(m_type, preset.name);
|
||||||
// Each of `others` is sorted, so its presets form one sorted run.
|
auto it = (m_type == Preset::TYPE_FILAMENT)
|
||||||
std::vector<Incoming> incoming;
|
? std::lower_bound(m_presets.begin() + m_num_default_presets, m_presets.end(), key, filament_preset_less)
|
||||||
std::vector<size_t> run_ends { 0 };
|
: std::lower_bound(m_presets.begin() + m_num_default_presets, m_presets.end(), key);
|
||||||
for (size_t source = 0; source < others.size(); ++ source) {
|
if (it == m_presets.end() || it->name != preset.name) {
|
||||||
for (Preset &preset : others[source]->m_presets)
|
|
||||||
if (! preset.is_default && ! preset.is_external)
|
|
||||||
incoming.push_back({ &preset, source });
|
|
||||||
assert(std::is_sorted(incoming.begin() + run_ends.back(), incoming.end(), incoming_less));
|
|
||||||
run_ends.push_back(incoming.size());
|
|
||||||
}
|
|
||||||
// Merged pairwise and stably, so equal names stay in the order of `others`.
|
|
||||||
const size_t runs = others.size();
|
|
||||||
for (size_t width = 1; width < runs; width *= 2)
|
|
||||||
for (size_t i = 0; i + width < runs; i += 2 * width)
|
|
||||||
std::inplace_merge(incoming.begin() + run_ends[i], incoming.begin() + run_ends[i + width],
|
|
||||||
incoming.begin() + run_ends[std::min(i + 2 * width, runs)], incoming_less);
|
|
||||||
|
|
||||||
std::vector<std::vector<std::string>> duplicates(others.size());
|
|
||||||
std::deque<Preset> merged;
|
|
||||||
auto own = m_presets.begin() + m_num_default_presets;
|
|
||||||
std::move(m_presets.begin(), own, std::back_inserter(merged));
|
|
||||||
// On equal names this collection's preset is kept, else the earliest of `others`,
|
|
||||||
// and each repeat is listed under the collection it came from.
|
|
||||||
for (auto next = incoming.begin(); own != m_presets.end() || next != incoming.end();) {
|
|
||||||
if (next == incoming.end() || (own != m_presets.end() && ! less(*next->preset, *own)))
|
|
||||||
merged.emplace_back(std::move(*own ++));
|
|
||||||
else {
|
|
||||||
Preset &preset = *(next ++)->preset;
|
|
||||||
if (preset.vendor != nullptr) {
|
if (preset.vendor != nullptr) {
|
||||||
// Re-assign a pointer to the vendor structure in the new PresetBundle.
|
// Re-assign a pointer to the vendor structure in the new PresetBundle.
|
||||||
auto it = new_vendors.find(preset.vendor->id);
|
auto it = new_vendors.find(preset.vendor->id);
|
||||||
assert(it != new_vendors.end());
|
assert(it != new_vendors.end());
|
||||||
preset.vendor = &it->second;
|
preset.vendor = &it->second;
|
||||||
}
|
}
|
||||||
merged.emplace_back(std::move(preset));
|
m_presets.emplace(it, std::move(preset));
|
||||||
}
|
} else
|
||||||
for (; next != incoming.end() && next->preset->name == merged.back().name; ++ next)
|
duplicates.emplace_back(std::move(preset.name));
|
||||||
duplicates[next->source].emplace_back(next->preset->name);
|
|
||||||
}
|
}
|
||||||
m_presets = std::move(merged);
|
|
||||||
return duplicates;
|
return duplicates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -403,15 +403,6 @@ public:
|
|||||||
std::string get_current_printer_type(PresetBundle *preset_bundle); // get current preset type
|
std::string get_current_printer_type(PresetBundle *preset_bundle); // get current preset type
|
||||||
|
|
||||||
static void get_extruder_names_and_keysets(Type type, std::string& extruder_id_name, std::string& extruder_variant_name, std::set<std::string>** p_key_set1, std::set<std::string>** p_key_set2);
|
static void get_extruder_names_and_keysets(Type type, std::string& extruder_id_name, std::string& extruder_variant_name, std::set<std::string>** p_key_set1, std::set<std::string>** p_key_set2);
|
||||||
// Config of a preset loaded from a project or config file: the project's values over the type's
|
|
||||||
// default preset config, without the print-host keys. When different_settings_list is not empty,
|
|
||||||
// every key not listed in it is then refreshed from the base system preset, which find_base returns
|
|
||||||
// for the project's "inherits" (nullptr when there is none), with the listed per-variant values
|
|
||||||
// mapped onto the base's extruder variants. keys, if given, receives the keys taken from the project.
|
|
||||||
static DynamicPrintConfig load_external_config(Type type, const DynamicPrintConfig &default_config, const DynamicPrintConfig &project_config,
|
|
||||||
const std::set<std::string> &different_settings_list,
|
|
||||||
const std::function<DynamicPrintConfig *(const std::string &inherits)> &find_base,
|
|
||||||
t_config_option_keys *keys = nullptr);
|
|
||||||
std::string get_printer_id() const { return vendor ? vendor->id : ""; }
|
std::string get_printer_id() const { return vendor ? vendor->id : ""; }
|
||||||
|
|
||||||
bool has_lidar(PresetBundle *preset_bundle);
|
bool has_lidar(PresetBundle *preset_bundle);
|
||||||
@@ -454,10 +445,7 @@ public:
|
|||||||
static std::string remove_suffix_modified(const std::string& name);
|
static std::string remove_suffix_modified(const std::string& name);
|
||||||
static void normalize(DynamicPrintConfig &config);
|
static void normalize(DynamicPrintConfig &config);
|
||||||
// Report configuration fields, which are misplaced into a wrong group, remove them from the config.
|
// Report configuration fields, which are misplaced into a wrong group, remove them from the config.
|
||||||
// `added`, when given, is the diff applied over a copy of default_config, and only
|
static std::string remove_invalid_keys(DynamicPrintConfig &config, const DynamicPrintConfig &default_config);
|
||||||
// its keys are checked, since no other key can be missing from default_config.
|
|
||||||
static std::string remove_invalid_keys(DynamicPrintConfig &config, const DynamicPrintConfig &default_config,
|
|
||||||
const DynamicPrintConfig *added = nullptr);
|
|
||||||
|
|
||||||
// BBS: move constructor to public
|
// BBS: move constructor to public
|
||||||
Preset(Type type, const std::string &name, bool is_default = false) : type(type), is_default(is_default), name(name) {}
|
Preset(Type type, const std::string &name, bool is_default = false) : type(type), is_default(is_default), name(name) {}
|
||||||
@@ -813,8 +801,6 @@ public:
|
|||||||
// Return number of presets including the "- default -" preset.
|
// Return number of presets including the "- default -" preset.
|
||||||
size_t size() const { return m_presets.size(); }
|
size_t size() const { return m_presets.size(); }
|
||||||
bool has_defaults_only() const { return m_presets.size() <= m_num_default_presets; }
|
bool has_defaults_only() const { return m_presets.size() <= m_num_default_presets; }
|
||||||
// How many presets this collection refused or repaired while loading.
|
|
||||||
int error_count() const { return m_errors; }
|
|
||||||
|
|
||||||
// For Print / Filament presets, disable those, which are not compatible with the printer.
|
// For Print / Filament presets, disable those, which are not compatible with the printer.
|
||||||
template<typename PreferedCondition>
|
template<typename PreferedCondition>
|
||||||
@@ -888,10 +874,8 @@ protected:
|
|||||||
// This is a temporary state, which shall be fixed immediately by the following step.
|
// This is a temporary state, which shall be fixed immediately by the following step.
|
||||||
bool select_preset_by_name_strict(const std::string &name);
|
bool select_preset_by_name_strict(const std::string &name);
|
||||||
|
|
||||||
// Move the presets of `others` into this collection in one pass. A name this
|
// Merge one vendor's presets with the other vendor's presets, report duplicates.
|
||||||
// collection or an earlier one of `others` already has is left out, and reported
|
std::vector<std::string> merge_presets(PresetCollection &&other, const VendorMap &new_vendors);
|
||||||
// in the list of the collection that repeats it.
|
|
||||||
std::vector<std::vector<std::string>> merge_presets(const std::vector<PresetCollection*> &others, const VendorMap &new_vendors);
|
|
||||||
|
|
||||||
// Update m_map_alias_to_profile_name from loaded system profiles.
|
// Update m_map_alias_to_profile_name from loaded system profiles.
|
||||||
void update_map_alias_to_profile_name();
|
void update_map_alias_to_profile_name();
|
||||||
@@ -906,43 +890,6 @@ protected:
|
|||||||
void set_custom_preset_alias(Preset &preset);
|
void set_custom_preset_alias(Preset &preset);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// One preset file read and flattened against the presets already in this
|
|
||||||
// collection, before anything the collection shares has been touched.
|
|
||||||
struct UserPresetLoad
|
|
||||||
{
|
|
||||||
Preset preset;
|
|
||||||
// Joins the collection. A file that threw partway still joins it, without
|
|
||||||
// the steps that did not run.
|
|
||||||
bool install { false };
|
|
||||||
// The whole of the load ran, so the preset is ready to be aliased.
|
|
||||||
bool complete { false };
|
|
||||||
// A filament preset that named no compatible printer and was given one from
|
|
||||||
// its name, which commit writes back to its file.
|
|
||||||
bool save_compatible_printers { false };
|
|
||||||
// Unreadable, so commit removes it and its .info file.
|
|
||||||
bool discard_file { false };
|
|
||||||
// The .info file read beside the preset, which commit logs.
|
|
||||||
std::string info_file;
|
|
||||||
// Counted and logged by commit, in the order the directory listed the files.
|
|
||||||
std::vector<std::string> errors;
|
|
||||||
PresetsConfigSubstitutions substitutions;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Read and flatten one preset file. It reads only, and resolves against the presets
|
|
||||||
// loaded before this pass, never another file of the same pass, so the files of a
|
|
||||||
// pass are independent of each other.
|
|
||||||
UserPresetLoad resolve_user_preset(const boost::filesystem::path &file, const std::string &canonical_name,
|
|
||||||
const PresetOrigin &load_origin, ForwardCompatibilitySubstitutionRule substitution_rule,
|
|
||||||
const std::string &extruder_id_name, const std::string &extruder_variant_name,
|
|
||||||
std::set<std::string> *key_set1, std::set<std::string> *key_set2) const;
|
|
||||||
|
|
||||||
// Install one resolved preset. The collection, its alias maps, the error count
|
|
||||||
// and the preset files on disk are touched here and only here.
|
|
||||||
void commit_user_preset(UserPresetLoad &&loaded, std::deque<Preset> &presets_loaded,
|
|
||||||
PresetsConfigSubstitutions &substitutions,
|
|
||||||
const std::function<void(Preset&)> &preset_loaded_fn,
|
|
||||||
bool read_only);
|
|
||||||
|
|
||||||
std::string canonical_preset_name(const std::string &name, const PresetOrigin &load_origin = PresetOrigin()) const;
|
std::string canonical_preset_name(const std::string &name, const PresetOrigin &load_origin = PresetOrigin()) const;
|
||||||
|
|
||||||
// Comparator that sorts "Generic " prefixed presets before others, then alphabetically within each group.
|
// Comparator that sorts "Generic " prefixed presets before others, then alphabetically within each group.
|
||||||
@@ -954,10 +901,6 @@ private:
|
|||||||
return a.name < b.name;
|
return a.name < b.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append a preset without keeping the collection sorted, for a caller installing
|
|
||||||
// many at once; find_preset() is unusable until sort_presets() runs.
|
|
||||||
Preset& append_preset(std::string &&path, const std::string &name, DynamicPrintConfig &&config);
|
|
||||||
|
|
||||||
// Sort presets: filament presets use generic-first ordering, others sort alphabetically.
|
// Sort presets: filament presets use generic-first ordering, others sort alphabetically.
|
||||||
void sort_presets() {
|
void sort_presets() {
|
||||||
if (m_type == Preset::TYPE_FILAMENT)
|
if (m_type == Preset::TYPE_FILAMENT)
|
||||||
|
|||||||
+432
-616
File diff suppressed because it is too large
Load Diff
+29
-182
@@ -15,7 +15,6 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
@@ -235,9 +234,6 @@ public:
|
|||||||
|
|
||||||
// ORCA: utility function to find the vendor for a given preset name
|
// ORCA: utility function to find the vendor for a given preset name
|
||||||
static std::string find_preset_vendor(const std::string& preset_name, Preset::Type type);
|
static std::string find_preset_vendor(const std::string& preset_name, Preset::Type type);
|
||||||
// Keys a project keeps when its presets are loaded: those listed in its escaped
|
|
||||||
// "different_settings_to_system" entry for the preset, plus the preset bookkeeping keys.
|
|
||||||
static std::set<std::string> project_different_keys(const std::string &different_settings);
|
|
||||||
|
|
||||||
PresetBundle();
|
PresetBundle();
|
||||||
PresetBundle(const PresetBundle &rhs);
|
PresetBundle(const PresetBundle &rhs);
|
||||||
@@ -277,10 +273,6 @@ public:
|
|||||||
const std::string &source_file,
|
const std::string &source_file,
|
||||||
ForwardCompatibilitySubstitutionRule compatibility_rule,
|
ForwardCompatibilitySubstitutionRule compatibility_rule,
|
||||||
std::string &error, bool allow_source_manifest = true);
|
std::string &error, bool allow_source_manifest = true);
|
||||||
// Resolve a system preset by name. The vendor tree is read from data_dir()/system when installed
|
|
||||||
// there, as the GUI reads it, and from the bundled profiles otherwise.
|
|
||||||
bool resolve_system_preset(DynamicPrintConfig &config, Preset::Type type, const std::string &name,
|
|
||||||
ForwardCompatibilitySubstitutionRule compatibility_rule, std::string &error);
|
|
||||||
|
|
||||||
// Load selections (current print, current filaments, current printer) from config.ini
|
// Load selections (current print, current filaments, current printer) from config.ini
|
||||||
// This is done just once on application start up.
|
// This is done just once on application start up.
|
||||||
@@ -630,180 +622,36 @@ public:
|
|||||||
// default_filament_profile must resolve to a system filament.
|
// default_filament_profile must resolve to a system filament.
|
||||||
bool check_printer_default_materials() const;
|
bool check_printer_default_materials() const;
|
||||||
|
|
||||||
// One vendor to load, and the directory it is installed in.
|
// Merge one vendor's presets with the other vendor's presets, report duplicates.
|
||||||
struct VendorSource
|
// Public so per-vendor-cache consumers (e.g. the setup wizard) can assemble a
|
||||||
{
|
// bundle out of several per-vendor caches loaded into separate PresetBundle instances.
|
||||||
std::string name;
|
std::vector<std::string> merge_presets(PresetBundle &&other);
|
||||||
boost::filesystem::path dir;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Load `vendors` into this bundle, the Orca filament library directly and every
|
|
||||||
// other vendor in parallel into a bundle of its own that inherits from it, merged
|
|
||||||
// in the order given. A vendor that cannot be loaded has its error added to the
|
|
||||||
// returned text, or thrown in validation mode, and its name to `failed`; it is
|
|
||||||
// left out, except for the library, which keeps what it installed before the
|
|
||||||
// failure. Once `cancel` is set, no further vendor starts loading.
|
|
||||||
std::pair<PresetsConfigSubstitutions, std::string> load_vendors(const std::vector<VendorSource>& vendors,
|
|
||||||
ForwardCompatibilitySubstitutionRule compatibility_rule, bool allow_cache,
|
|
||||||
const std::atomic<bool>* cancel = nullptr, std::vector<std::string>* failed = nullptr);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Move the presets and vendor profiles of `others` into this bundle, in one pass
|
// Load one vendor from the preset cache installed in `dir`, judged against
|
||||||
// over each collection. A preset whose name this bundle or an earlier one of
|
// the vendor profile there. False, with this bundle left clean, when there
|
||||||
// `others` already has is left out and listed under the bundle that repeats it.
|
// is no usable cache and the vendor has to be parsed. This is how
|
||||||
std::vector<std::vector<std::string>> merge_presets(const std::vector<PresetBundle*> &others);
|
// load_vendor_configs_from_json reads a cache.
|
||||||
|
bool load_vendor_cache(const boost::filesystem::path& dir, const std::string& vendor_name, const PresetBundle* base_bundle);
|
||||||
|
|
||||||
// What parsing one entry's JSON sub-file reported. Its errors and warnings are
|
// Load one source-form preset entry into this bundle: resolve `inherits`
|
||||||
// logged when the entry installs, so they come out in listing order with the
|
// and `include`, flatten, validate and register the preset. Returns the
|
||||||
// entry's install errors, as parsing and installing one entry at a time leaves them.
|
// reason loading failed, empty on success. See the definition for the
|
||||||
struct EntryParse
|
// sharing contract between the JSON parse and the cache load.
|
||||||
{
|
// retain_configs / retain_includes, when non-null, name the only presets
|
||||||
ConfigSubstitutions substitutions;
|
// registered into config_maps / include_maps (a config copy each). The
|
||||||
// Counted in the bundle's error count.
|
// cache load passes the names its entries inherit / include — the only
|
||||||
std::vector<std::string> errors;
|
// ones ever looked up again; the JSON parse retains all, not knowing what
|
||||||
std::vector<std::string> warnings;
|
// later subfiles name.
|
||||||
};
|
std::string load_vendor_preset(const CachedPreset& entry,
|
||||||
|
const std::string& path, const std::string& vendor_name,
|
||||||
// An EntryParse for each entry of the VendorCacheData list of the same name.
|
const PresetBundle* base_bundle,
|
||||||
struct VendorParse
|
LoadConfigBundleAttributes flags,
|
||||||
{
|
ConfigSubstitutionContext& substitution_context, PresetsConfigSubstitutions& substitutions,
|
||||||
std::vector<EntryParse> process_entries;
|
std::map<std::string, DynamicPrintConfig>& config_maps, std::map<std::string, DynamicPrintConfig>& include_maps,
|
||||||
std::vector<EntryParse> filament_entries;
|
std::map<std::string, std::string>& filament_id_maps,
|
||||||
std::vector<EntryParse> machine_entries;
|
PresetCollection* presets_collection, size_t& count, bool is_from_lib,
|
||||||
};
|
const std::set<std::string>* retain_configs = nullptr, const std::set<std::string>* retain_includes = nullptr);
|
||||||
|
|
||||||
// One vendor read from its cache or its JSONs by read_vendor, for
|
|
||||||
// install_vendor_read to install.
|
|
||||||
struct VendorRead
|
|
||||||
{
|
|
||||||
std::string dir;
|
|
||||||
std::string vendor_name;
|
|
||||||
LoadConfigBundleAttributes flags;
|
|
||||||
ForwardCompatibilitySubstitutionRule compatibility_rule;
|
|
||||||
// The errors this bundle had counted before the read, which the cache stamp leaves out.
|
|
||||||
int errors_at_entry { 0 };
|
|
||||||
// A whole-vendor load, which can read a cache and write one.
|
|
||||||
bool cacheable { false };
|
|
||||||
// Read from the cache at cache_path, which install can still reject.
|
|
||||||
bool from_cache { false };
|
|
||||||
std::string cache_path;
|
|
||||||
// Only the vendor profile was asked for.
|
|
||||||
bool vendor_only { false };
|
|
||||||
VendorCacheData data;
|
|
||||||
// What each entry's JSON parse reported, and whether and with which version
|
|
||||||
// the cache is written once the entries install.
|
|
||||||
VendorParse parsed;
|
|
||||||
bool will_cache { false };
|
|
||||||
std::string version;
|
|
||||||
// The sub-file the parse stopped at, its kind, why, and the errors it reported.
|
|
||||||
std::string reason;
|
|
||||||
std::string failed_subfile;
|
|
||||||
const char* failed_kind { nullptr };
|
|
||||||
std::vector<std::string> failed_errors;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Read a vendor into this bundle's vendor profiles and `data`, from its cache
|
|
||||||
// when one covers it, else from its JSONs; nothing is installed. Throws
|
|
||||||
// ConfigurationError when the vendor's own JSON cannot be parsed.
|
|
||||||
VendorRead read_vendor(const std::string& dir, const std::string& vendor_name, LoadConfigBundleAttributes flags,
|
|
||||||
ForwardCompatibilitySubstitutionRule compatibility_rule, bool allow_cache);
|
|
||||||
|
|
||||||
// Parse the vendor's JSONs into `read`, up to the first sub-file that fails.
|
|
||||||
void parse_vendor_json(VendorRead& read);
|
|
||||||
|
|
||||||
// Install what read_vendor read, against base_bundle's filament library. A cache
|
|
||||||
// that cannot be installed is replaced by a parse of the JSONs. Throws
|
|
||||||
// ConfigurationError at the first entry that cannot be installed, or after
|
|
||||||
// installing the entries before a sub-file that could not be parsed.
|
|
||||||
std::pair<PresetsConfigSubstitutions, size_t> install_vendor_read(VendorRead&& read, const PresetBundle* base_bundle);
|
|
||||||
|
|
||||||
// Install a cache's entries. False, with this bundle left clean, when one of them
|
|
||||||
// cannot be installed.
|
|
||||||
bool install_vendor_cache(const std::string& cache_path, const std::string& vendor_name, VendorCacheData&& data,
|
|
||||||
const PresetBundle* base_bundle);
|
|
||||||
|
|
||||||
// Log and count errors reported by a resolve or a parse.
|
|
||||||
void log_errors(const std::vector<std::string>& errors);
|
|
||||||
|
|
||||||
// The state of installing one collection of one vendor, which
|
|
||||||
// resolve_vendor_preset reads through a const reference and only
|
|
||||||
// commit_vendor_preset writes.
|
|
||||||
struct VendorInstall
|
|
||||||
{
|
|
||||||
// The directory holding <vendor_name>/, whose sub-paths the entries name.
|
|
||||||
std::string path;
|
|
||||||
std::string vendor_name;
|
|
||||||
const VendorProfile* vendor_profile;
|
|
||||||
const PresetBundle* base_bundle;
|
|
||||||
LoadConfigBundleAttributes flags;
|
|
||||||
PresetCollection* presets;
|
|
||||||
// The Orca filament library, which keeps every config for other vendors to
|
|
||||||
// resolve against.
|
|
||||||
bool is_from_lib;
|
|
||||||
PresetsConfigSubstitutions* substitutions;
|
|
||||||
// The names some entry inherits / includes, the only ones whose configs /
|
|
||||||
// include diffs are looked up again.
|
|
||||||
std::set<std::string> inherited;
|
|
||||||
std::set<std::string> included;
|
|
||||||
std::map<std::string, DynamicPrintConfig> config_maps;
|
|
||||||
std::map<std::string, DynamicPrintConfig> include_maps;
|
|
||||||
std::map<std::string, std::string> filament_id_maps;
|
|
||||||
std::unordered_set<std::string> installed_names;
|
|
||||||
size_t count { 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
// Install a vendor's source-form entries, parsed from its JSON or read from its
|
|
||||||
// cache: processes, then filaments, then printers. Both loads go through here,
|
|
||||||
// so a cache-loaded bundle cannot come out different from a JSON-loaded one.
|
|
||||||
// `parsed` is given for entries parsed just now. `complete` says the entries
|
|
||||||
// are the vendor's whole lists; only then are the filament library's configs
|
|
||||||
// and filament ids left in m_config_maps and m_filament_id_maps. Returns the
|
|
||||||
// number of presets installed, and throws ConfigurationError at the first
|
|
||||||
// entry that cannot be installed.
|
|
||||||
size_t install_vendor(const std::string& path, const std::string& vendor_name, const PresetBundle* base_bundle,
|
|
||||||
LoadConfigBundleAttributes flags, const VendorCacheData& entries,
|
|
||||||
VendorParse* parsed, bool complete, PresetsConfigSubstitutions& substitutions);
|
|
||||||
|
|
||||||
// Install one collection's entries in the order they are listed.
|
|
||||||
void install_vendor_entries(VendorInstall& install, const std::vector<CachedPreset>& entries,
|
|
||||||
std::vector<EntryParse>* parsed);
|
|
||||||
|
|
||||||
// One entry flattened against the preset it inherits, before anything this
|
|
||||||
// bundle shares has been touched.
|
|
||||||
struct PresetInstall
|
|
||||||
{
|
|
||||||
DynamicPrintConfig config;
|
|
||||||
std::string file_path;
|
|
||||||
// Empty when the preset is its own alias.
|
|
||||||
std::string alias;
|
|
||||||
std::string filament_id;
|
|
||||||
std::vector<std::string> renamed_from;
|
|
||||||
// Reported by commit, so resolving entries together leaves the log and
|
|
||||||
// the error count as one entry at a time produces them.
|
|
||||||
std::vector<std::string> errors;
|
|
||||||
// What a base states for the presets that include it, when it is retained.
|
|
||||||
std::optional<DynamicPrintConfig> included;
|
|
||||||
// The config kept for the entries that inherit this one, or for other
|
|
||||||
// vendors when this is the filament library.
|
|
||||||
std::optional<DynamicPrintConfig> retained;
|
|
||||||
// Not instantiated, so it contributes a config and no preset.
|
|
||||||
bool config_only { false };
|
|
||||||
// Non-empty when the entry is rejected, and says why.
|
|
||||||
std::string reason;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Flatten one entry against the config it inherits, from this collection's
|
|
||||||
// config_maps or base_bundle's filament library, with the include diffs it
|
|
||||||
// names layered in. It looks up nothing but the names the entry inherits and
|
|
||||||
// includes, and writes nothing.
|
|
||||||
PresetInstall resolve_vendor_preset(const CachedPreset& entry, const VendorInstall& install) const;
|
|
||||||
|
|
||||||
// Install a resolved entry. The collections, the maps in `install` and the
|
|
||||||
// error count are touched here and only here, one entry at a time.
|
|
||||||
// Presets are appended, so a repeated name is caught with `installed_names`,
|
|
||||||
// and the collection is sorted once every entry is in.
|
|
||||||
std::string commit_vendor_preset(const CachedPreset& entry, PresetInstall&& resolved,
|
|
||||||
ConfigSubstitutions&& substitutions, VendorInstall& install);
|
|
||||||
|
|
||||||
// Clear every collection's m_printer_hold_alias, which reset() leaves alone.
|
// Clear every collection's m_printer_hold_alias, which reset() leaves alone.
|
||||||
void clear_printer_hold_aliases();
|
void clear_printer_hold_aliases();
|
||||||
@@ -815,14 +663,13 @@ private:
|
|||||||
// Vendor trees loaded by resolve_preset_config's manifest path, so every preset
|
// Vendor trees loaded by resolve_preset_config's manifest path, so every preset
|
||||||
// resolved through this bundle shares one load per source root and vendor. The
|
// resolved through this bundle shares one load per source root and vendor. The
|
||||||
// filament library is one such tree, shared by every vendor under its root.
|
// filament library is one such tree, shared by every vendor under its root.
|
||||||
// A tree read from its preset cache is kept apart: its presets carry no source file.
|
std::map<std::tuple<std::string, std::string, ForwardCompatibilitySubstitutionRule>, std::unique_ptr<PresetBundle>>
|
||||||
std::map<std::tuple<std::string, std::string, ForwardCompatibilitySubstitutionRule, bool>, std::unique_ptr<PresetBundle>>
|
|
||||||
m_source_vendor_bundles;
|
m_source_vendor_bundles;
|
||||||
|
|
||||||
const PresetBundle *load_source_vendor(const boost::filesystem::path &root_dir,
|
const PresetBundle *load_source_vendor(const boost::filesystem::path &root_dir,
|
||||||
const std::string &vendor_id,
|
const std::string &vendor_id,
|
||||||
ForwardCompatibilitySubstitutionRule compatibility_rule,
|
ForwardCompatibilitySubstitutionRule compatibility_rule,
|
||||||
std::string &error, bool allow_cache = false);
|
std::string &error);
|
||||||
|
|
||||||
// Orca: validation only - flag any printer with two or more compatible
|
// Orca: validation only - flag any printer with two or more compatible
|
||||||
// filament presets sharing one filament_id (ambiguous AMS subtype match).
|
// filament presets sharing one filament_id (ambiguous AMS subtype match).
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ void skip_config(cereal::BinaryInputArchive& ar, const CacheDictionary& dict);
|
|||||||
|
|
||||||
// One preset as its JSON subfile states it: the config diff, the names of the
|
// One preset as its JSON subfile states it: the config diff, the names of the
|
||||||
// preset it inherits and the presets it includes, and the parse metadata —
|
// preset it inherits and the presets it includes, and the parse metadata —
|
||||||
// everything PresetBundle::parse_vendor_json extracts and
|
// everything the parse phase of load_vendor_configs_from_json extracts and
|
||||||
// nothing it derives. Inheritance and includes are resolved when the entry is
|
// nothing it derives. Inheritance and includes are resolved when the entry is
|
||||||
// installed, against whatever filament library is loaded then, so a cache
|
// installed, against whatever filament library is loaded then, so a cache
|
||||||
// carries no other vendor's values and no other vendor's update can make it
|
// carries no other vendor's values and no other vendor's update can make it
|
||||||
|
|||||||
+6
-12
@@ -2439,18 +2439,12 @@ StringObjectException Print::validate(std::vector<StringObjectException> *warnin
|
|||||||
if (m_default_region_config.precise_outer_wall && m_default_region_config.wall_sequence != WallSequence::InnerOuter)
|
if (m_default_region_config.precise_outer_wall && m_default_region_config.wall_sequence != WallSequence::InnerOuter)
|
||||||
warn(L("The precise wall option will be ignored for outer-inner or inner-outer-inner wall sequences."), "precise_outer_wall");
|
warn(L("The precise wall option will be ignored for outer-inner or inner-outer-inner wall sequences."), "precise_outer_wall");
|
||||||
|
|
||||||
// check adaptive pressure advance model of every extruder variant column of the used filaments
|
// check adaptive pressure advance model
|
||||||
const std::vector<int> &self_index = m_config.filament_self_index.values;
|
for (unsigned int extruder_id : extruders) {
|
||||||
const size_t pa_columns = std::max(m_config.adaptive_pressure_advance_model.size(), size_t(extruders.back()) + 1);
|
if (m_config.adaptive_pressure_advance.get_at(extruder_id) &&
|
||||||
for (size_t column = 0; column < pa_columns; ++column) {
|
m_config.enable_pressure_advance.get_at(extruder_id)) {
|
||||||
// filament_self_index maps a column to its filament once the filament arrays hold one column per variant
|
|
||||||
const unsigned int filament_id = self_index.size() == pa_columns ? self_index[column] - 1 : column;
|
const std::string pa_model = m_config.adaptive_pressure_advance_model.get_at(extruder_id);
|
||||||
if (!std::binary_search(extruders.begin(), extruders.end(), filament_id))
|
|
||||||
continue;
|
|
||||||
if (m_config.adaptive_pressure_advance.get_at(column) &&
|
|
||||||
m_config.enable_pressure_advance.get_at(column)) {
|
|
||||||
|
|
||||||
const std::string pa_model = m_config.adaptive_pressure_advance_model.get_at(column);
|
|
||||||
if (!pa_model.empty()) {
|
if (!pa_model.empty()) {
|
||||||
std::string validation_error = AdaptivePAProcessor::validate_adaptive_pa_model(pa_model);
|
std::string validation_error = AdaptivePAProcessor::validate_adaptive_pa_model(pa_model);
|
||||||
if (!validation_error.empty()) {
|
if (!validation_error.empty()) {
|
||||||
|
|||||||
@@ -9403,10 +9403,6 @@ void PrintConfigDef::handle_legacy_composite(DynamicPrintConfig &config)
|
|||||||
}
|
}
|
||||||
config.set_key_value("wiping_volumes_use_custom_matrix", new ConfigOptionBool(custom));
|
config.set_key_value("wiping_volumes_use_custom_matrix", new ConfigOptionBool(custom));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Orca: a config saved before a key joined filament_options_with_variant stores it once per filament
|
|
||||||
// rather than once per filament variant, and one exported by an older CLI may store a single value.
|
|
||||||
normalize_filament_values_to_variants(config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const PrintConfigDef print_config_def;
|
const PrintConfigDef print_config_def;
|
||||||
@@ -9509,13 +9505,6 @@ std::set<std::string> filament_options_with_variant = {
|
|||||||
"filament_ironing_spacing",
|
"filament_ironing_spacing",
|
||||||
"filament_ironing_inset",
|
"filament_ironing_inset",
|
||||||
"filament_ironing_speed",
|
"filament_ironing_speed",
|
||||||
// Orca: pressure advance
|
|
||||||
"enable_pressure_advance",
|
|
||||||
"pressure_advance",
|
|
||||||
"adaptive_pressure_advance",
|
|
||||||
"adaptive_pressure_advance_model",
|
|
||||||
"adaptive_pressure_advance_overhangs",
|
|
||||||
"adaptive_pressure_advance_bridges",
|
|
||||||
"activate_air_filtration",
|
"activate_air_filtration",
|
||||||
"activate_air_filtration_during_print",
|
"activate_air_filtration_during_print",
|
||||||
"activate_air_filtration_on_completion",
|
"activate_air_filtration_on_completion",
|
||||||
@@ -10723,25 +10712,6 @@ void set_variant_override(ConfigOptionVectorBase &target, const ConfigOptionVect
|
|||||||
target.set_to_index(&source, indices, stride);
|
target.set_to_index(&source, indices, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
void normalize_filament_values_to_variants(DynamicPrintConfig &config)
|
|
||||||
{
|
|
||||||
const auto *self_index = config.option<ConfigOptionInts>("filament_self_index");
|
|
||||||
if (self_index == nullptr || self_index->empty())
|
|
||||||
return;
|
|
||||||
const int filament_count = *std::max_element(self_index->values.begin(), self_index->values.end());
|
|
||||||
if (filament_count <= 0 || size_t(filament_count) >= self_index->size())
|
|
||||||
return;
|
|
||||||
for (const std::string &key : filament_options_with_variant) {
|
|
||||||
auto *opt = dynamic_cast<ConfigOptionVectorBase *>(config.option(key));
|
|
||||||
if (opt == nullptr || (opt->size() != size_t(filament_count) && opt->size() != 1))
|
|
||||||
continue;
|
|
||||||
std::unique_ptr<ConfigOption> per_filament(opt->clone());
|
|
||||||
// set_at() takes the first value for a filament past the end of a single-value vector
|
|
||||||
for (size_t variant = 0; variant < self_index->size(); ++variant)
|
|
||||||
opt->set_at(per_filament.get(), variant, self_index->values[variant] - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//used for object/region config
|
//used for object/region config
|
||||||
//use the smallest of multiple to single
|
//use the smallest of multiple to single
|
||||||
@@ -12595,7 +12565,6 @@ OtherSlicingStatesConfigDef::OtherSlicingStatesConfigDef()
|
|||||||
|
|
||||||
new_def("initial_no_support_extruder", coInt, "Initial no support extruder", "Zero-based index of the first extruder used for printing without support. Same as initial_no_support_tool.");
|
new_def("initial_no_support_extruder", coInt, "Initial no support extruder", "Zero-based index of the first extruder used for printing without support. Same as initial_no_support_tool.");
|
||||||
new_def("in_head_wrap_detect_zone", coBool, "In head wrap detect zone", "Indicates if the first layer overlaps with the head wrap zone.");
|
new_def("in_head_wrap_detect_zone", coBool, "In head wrap detect zone", "Indicates if the first layer overlaps with the head wrap zone.");
|
||||||
new_def("curr_bed_type", coString, "Current bed type", "Name of the currently selected bed plate type (e.g. 'Textured PEI Plate', 'Smooth High Temp Plate').");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintStatisticsConfigDef::PrintStatisticsConfigDef()
|
PrintStatisticsConfigDef::PrintStatisticsConfigDef()
|
||||||
|
|||||||
@@ -884,11 +884,6 @@ extern std::set<std::string> empty_options;
|
|||||||
void set_variant_override(ConfigOptionVectorBase &target, const ConfigOptionVectorBase &source,
|
void set_variant_override(ConfigOptionVectorBase &target, const ConfigOptionVectorBase &source,
|
||||||
const std::vector<int> &variant_index, int stride = 1);
|
const std::vector<int> &variant_index, int stride = 1);
|
||||||
|
|
||||||
// Orca: lays every filament_options_with_variant option out one value per filament variant, as
|
|
||||||
// filament_self_index maps the variants to filaments. An option holding one value per filament, or a
|
|
||||||
// single value, gives every variant of a filament that filament's value; other lengths are left alone.
|
|
||||||
void normalize_filament_values_to_variants(DynamicPrintConfig &config);
|
|
||||||
|
|
||||||
extern std::set<std::string> filament_dev_options;
|
extern std::set<std::string> filament_dev_options;
|
||||||
|
|
||||||
extern void update_static_print_config_from_dynamic(ConfigBase& config, const DynamicPrintConfig& dest_config, std::vector<int> variant_index, std::set<std::string>& key_set1, int stride = 1);
|
extern void update_static_print_config_from_dynamic(ConfigBase& config, const DynamicPrintConfig& dest_config, std::vector<int> variant_index, std::set<std::string>& key_set1, int stride = 1);
|
||||||
|
|||||||
+1
-10
@@ -256,19 +256,10 @@ extern bool is_gallery_file(const std::string& path, char const* type);
|
|||||||
extern bool is_shapes_dir(const std::string& dir);
|
extern bool is_shapes_dir(const std::string& dir);
|
||||||
//BBS: add json support
|
//BBS: add json support
|
||||||
extern bool is_json_file(const std::string& path);
|
extern bool is_json_file(const std::string& path);
|
||||||
// True if rel_path is relative, has no ".." component or embedded NUL and, joined to root, still resolves inside it.
|
// True if rel_path is relative, has no ".." component and, joined to root, still resolves inside it.
|
||||||
// Both '/' and '\\' are treated as separators on every platform, so an archive rejected on one OS
|
// Both '/' and '\\' are treated as separators on every platform, so an archive rejected on one OS
|
||||||
// is rejected on all of them.
|
// is rejected on all of them.
|
||||||
extern bool is_path_within_root(const std::string &rel_path, const boost::filesystem::path &root);
|
extern bool is_path_within_root(const std::string &rel_path, const boost::filesystem::path &root);
|
||||||
// True if a symlink stored at link_rel_path (relative to root) with this target stays inside root: the target
|
|
||||||
// must be relative, and joined to the link's directory it must pass is_path_within_root.
|
|
||||||
extern bool is_symlink_target_within_root(const std::string &link_rel_path, const std::string &target, const boost::filesystem::path &root);
|
|
||||||
// True if path names an entry strictly inside root: it must be spelled with root as its prefix,
|
|
||||||
// and must still resolve inside root once symlinks are followed.
|
|
||||||
extern bool is_absolute_path_within_root(const boost::filesystem::path &path, const boost::filesystem::path &root);
|
|
||||||
// True if a file with this name is of a type that the desktop opens as plain content, so it cannot run code.
|
|
||||||
// Anything unknown is not safe.
|
|
||||||
extern bool is_safe_to_open_file_name(const std::string &file_name);
|
|
||||||
|
|
||||||
// Orca: custom protocal support utils
|
// Orca: custom protocal support utils
|
||||||
inline bool is_orca_open(const std::string& url) { return boost::starts_with(url, "orcaslicer://open"); }
|
inline bool is_orca_open(const std::string& url) { return boost::starts_with(url, "orcaslicer://open"); }
|
||||||
|
|||||||
@@ -4,9 +4,6 @@
|
|||||||
#include "miniz_extension.hpp"
|
#include "miniz_extension.hpp"
|
||||||
#include "Utils.hpp"
|
#include "Utils.hpp"
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
#include <boost/log/trivial.hpp>
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(__MINGW64__)
|
#if defined(_MSC_VER) || defined(__MINGW64__)
|
||||||
#include "boost/nowide/cstdio.hpp"
|
#include "boost/nowide/cstdio.hpp"
|
||||||
#endif
|
#endif
|
||||||
@@ -118,66 +115,6 @@ std::string decode_archive_entry_path(mz_zip_archive *zip, const mz_zip_archive_
|
|||||||
return decode_zip_unicode_path_extra_field(extra.substr(0, extra_size > 0 ? extra_size - 1 : 0), stat.m_filename);
|
return decode_zip_unicode_path_extra_field(extra.substr(0, extra_size > 0 ? extra_size - 1 : 0), stat.m_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool extract_archive_confined(const std::string &zip_path_utf8, const std::string &dest_dir)
|
|
||||||
{
|
|
||||||
mz_zip_archive archive;
|
|
||||||
mz_zip_zero_struct(&archive);
|
|
||||||
|
|
||||||
if (!open_zip_reader(&archive, zip_path_utf8)) {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "Unable to open zip reader for " << zip_path_utf8;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mz_uint num_entries = mz_zip_reader_get_num_files(&archive);
|
|
||||||
mz_zip_archive_file_stat stat;
|
|
||||||
|
|
||||||
// Validate every entry first so an archive with a single escaping entry leaves no partial output behind.
|
|
||||||
const boost::filesystem::path root(dest_dir);
|
|
||||||
for (mz_uint i = 0; i < num_entries; ++i) {
|
|
||||||
if (mz_zip_reader_file_stat(&archive, i, &stat) && !is_path_within_root(stat.m_filename, root)) {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "Unzip: rejecting " << zip_path_utf8 << ", entry " << stat.m_filename << " resolves outside " << dest_dir;
|
|
||||||
close_zip_reader(&archive);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (mz_uint i = 0; i < num_entries; ++i) {
|
|
||||||
if (!mz_zip_reader_file_stat(&archive, i, &stat)) {
|
|
||||||
BOOST_LOG_TRIVIAL(warning) << "Unzip: read file stat failed";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const std::string dest_file = dest_dir + "/" + stat.m_filename;
|
|
||||||
try {
|
|
||||||
if (stat.m_is_directory) {
|
|
||||||
const boost::filesystem::path dest_path(dest_file);
|
|
||||||
if (!boost::filesystem::exists(dest_path))
|
|
||||||
boost::filesystem::create_directories(dest_path);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (stat.m_uncomp_size == 0) {
|
|
||||||
BOOST_LOG_TRIVIAL(warning) << "Unzip: invalid size for file " << stat.m_filename;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Replace a symlink at the destination rather than writing through it.
|
|
||||||
const boost::filesystem::path dest_path(dest_file);
|
|
||||||
if (boost::filesystem::is_symlink(boost::filesystem::symlink_status(dest_path)))
|
|
||||||
boost::filesystem::remove(dest_path);
|
|
||||||
if (!mz_zip_reader_extract_to_file(&archive, stat.m_file_index, dest_file.c_str(), 0)) {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "Unzip: extract file " << stat.m_filename << " to dest " << dest_file << " failed";
|
|
||||||
close_zip_reader(&archive);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "Unzip: successfully extract file " << stat.m_file_index << " to " << dest_file;
|
|
||||||
} catch (const std::exception &e) {
|
|
||||||
close_zip_reader(&archive);
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "Unzip: archive read exception: " << e.what();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close_zip_reader(&archive);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
MZ_Archive::MZ_Archive()
|
MZ_Archive::MZ_Archive()
|
||||||
{
|
{
|
||||||
mz_zip_zero_struct(&arch);
|
mz_zip_zero_struct(&arch);
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ bool open_zip_writer(mz_zip_archive *zip, const std::string &fname_utf8);
|
|||||||
bool close_zip_reader(mz_zip_archive *zip);
|
bool close_zip_reader(mz_zip_archive *zip);
|
||||||
bool close_zip_writer(mz_zip_archive *zip);
|
bool close_zip_writer(mz_zip_archive *zip);
|
||||||
std::string decode_archive_entry_path(mz_zip_archive *zip, const mz_zip_archive_file_stat &stat);
|
std::string decode_archive_entry_path(mz_zip_archive *zip, const mz_zip_archive_file_stat &stat);
|
||||||
// Extracts every entry of the archive under dest_dir. Nothing is written if any entry would resolve outside dest_dir.
|
|
||||||
bool extract_archive_confined(const std::string &zip_path_utf8, const std::string &dest_dir);
|
|
||||||
|
|
||||||
class MZ_Archive {
|
class MZ_Archive {
|
||||||
public:
|
public:
|
||||||
|
|||||||
+1
-39
@@ -70,7 +70,6 @@
|
|||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/algorithm/string/case_conv.hpp>
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/filesystem/path.hpp>
|
#include <boost/filesystem/path.hpp>
|
||||||
#include <boost/nowide/fstream.hpp>
|
#include <boost/nowide/fstream.hpp>
|
||||||
@@ -1094,9 +1093,6 @@ bool is_path_within_root(const std::string &rel_path, const boost::filesystem::p
|
|||||||
auto is_separator = [](char c) { return c == '/' || c == '\\'; };
|
auto is_separator = [](char c) { return c == '/' || c == '\\'; };
|
||||||
if (rel_path.empty() || is_separator(rel_path.front()) || (rel_path.size() > 1 && rel_path[1] == ':'))
|
if (rel_path.empty() || is_separator(rel_path.front()) || (rel_path.size() > 1 && rel_path[1] == ':'))
|
||||||
return false;
|
return false;
|
||||||
// The filesystem calls stop at a NUL, so they would act on a shorter path than the one checked here.
|
|
||||||
if (rel_path.find('\0') != std::string::npos)
|
|
||||||
return false;
|
|
||||||
for (size_t start = 0; start <= rel_path.size();) {
|
for (size_t start = 0; start <= rel_path.size();) {
|
||||||
size_t end = start;
|
size_t end = start;
|
||||||
while (end < rel_path.size() && !is_separator(rel_path[end]))
|
while (end < rel_path.size() && !is_separator(rel_path[end]))
|
||||||
@@ -1107,10 +1103,7 @@ bool is_path_within_root(const std::string &rel_path, const boost::filesystem::p
|
|||||||
}
|
}
|
||||||
// Resolve against the canonical root so a symlink inside it cannot lead back out.
|
// Resolve against the canonical root so a symlink inside it cannot lead back out.
|
||||||
try {
|
try {
|
||||||
std::string root_str = boost::filesystem::weakly_canonical(root).string();
|
const std::string root_str = boost::filesystem::weakly_canonical(root).string();
|
||||||
// A trailing separator on root would otherwise fail the prefix match below for every path.
|
|
||||||
while (!root_str.empty() && (root_str.back() == '/' || root_str.back() == boost::filesystem::path::preferred_separator))
|
|
||||||
root_str.pop_back();
|
|
||||||
const std::string full_str = boost::filesystem::weakly_canonical(root / rel_path).string();
|
const std::string full_str = boost::filesystem::weakly_canonical(root / rel_path).string();
|
||||||
return full_str.compare(0, root_str.size(), root_str) == 0 &&
|
return full_str.compare(0, root_str.size(), root_str) == 0 &&
|
||||||
(full_str.size() == root_str.size() || full_str[root_str.size()] == boost::filesystem::path::preferred_separator);
|
(full_str.size() == root_str.size() || full_str[root_str.size()] == boost::filesystem::path::preferred_separator);
|
||||||
@@ -1119,37 +1112,6 @@ bool is_path_within_root(const std::string &rel_path, const boost::filesystem::p
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_symlink_target_within_root(const std::string &link_rel_path, const std::string &target, const boost::filesystem::path &root)
|
|
||||||
{
|
|
||||||
if (target.empty() || target.front() == '/' || target.front() == '\\' || (target.size() > 1 && target[1] == ':'))
|
|
||||||
return false;
|
|
||||||
// A relative target without ".." only descends from the link's directory, so no chain of such links can leave root.
|
|
||||||
const size_t sep = link_rel_path.find_last_of("/\\");
|
|
||||||
return is_path_within_root((sep == std::string::npos ? std::string() : link_rel_path.substr(0, sep + 1)) + target, root);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_absolute_path_within_root(const boost::filesystem::path &path, const boost::filesystem::path &root)
|
|
||||||
{
|
|
||||||
const boost::filesystem::path rel = path.lexically_relative(root);
|
|
||||||
return !rel.empty() && rel != "." && is_path_within_root(rel.string(), root);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_safe_to_open_file_name(const std::string &file_name)
|
|
||||||
{
|
|
||||||
// Formats that cannot carry macros or scripts. Legacy and OpenDocument office files, HTML and SVG are left out on purpose.
|
|
||||||
static const std::vector<std::string> safe_extensions = {
|
|
||||||
"jpg", "jpeg", "jfif", "pjpeg", "pjp", "png", "gif", "bmp", "webp", "tif", "tiff",
|
|
||||||
"pdf", "txt", "md", "csv", "docx", "xlsx", "pptx",
|
|
||||||
"stl", "obj", "3mf", "amf", "ply", "step", "stp", "iges", "igs", "dxf",
|
|
||||||
"mp4", "mov", "webm"};
|
|
||||||
// The name must end in the extension itself: Windows drops trailing dots and spaces and reads ':' as a stream separator.
|
|
||||||
const size_t dot = file_name.find_last_of('.');
|
|
||||||
if (dot == std::string::npos || file_name.find_first_of("/\\:") != std::string::npos)
|
|
||||||
return false;
|
|
||||||
const std::string extension = boost::algorithm::to_lower_copy(file_name.substr(dot + 1));
|
|
||||||
return std::find(safe_extensions.begin(), safe_extensions.end(), extension) != safe_extensions.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_img_file(const std::string &path)
|
bool is_img_file(const std::string &path)
|
||||||
{
|
{
|
||||||
return boost::iends_with(path, ".png") || boost::iends_with(path, ".svg");
|
return boost::iends_with(path, ".png") || boost::iends_with(path, ".svg");
|
||||||
|
|||||||
@@ -158,6 +158,21 @@ enum class EGCodeExtrusionRole : uint8_t
|
|||||||
|
|
||||||
static constexpr std::size_t GCODE_EXTRUSION_ROLES_COUNT = static_cast<std::size_t>(EGCodeExtrusionRole::COUNT);
|
static constexpr std::size_t GCODE_EXTRUSION_ROLES_COUNT = static_cast<std::size_t>(EGCodeExtrusionRole::COUNT);
|
||||||
|
|
||||||
|
//
|
||||||
|
// What the reduced set, drawn while the user is dragging, holds in place of the full toolpaths
|
||||||
|
//
|
||||||
|
enum class EReducedDetailMode : uint8_t
|
||||||
|
{
|
||||||
|
// nothing: no reduced set is built
|
||||||
|
Off,
|
||||||
|
// only the bottom and top layers of the visible range, for a caller that draws the print
|
||||||
|
// itself some other way
|
||||||
|
EndLayersOnly,
|
||||||
|
// every role but the infill under the skins and the gap fill: what can be seen from outside
|
||||||
|
ShellOnly,
|
||||||
|
COUNT
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Option types
|
// Option types
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -114,6 +114,19 @@ public:
|
|||||||
//
|
//
|
||||||
bool is_dim_previous_layers() const;
|
bool is_dim_previous_layers() const;
|
||||||
void set_dim_previous_layers(bool value);
|
void set_dim_previous_layers(bool value);
|
||||||
|
//
|
||||||
|
// The reduced set drawn while the user drags: what the mode keeps, and always the bottom and
|
||||||
|
// top layers of the visible range. While a mode is set it is built alongside the full set, so
|
||||||
|
// set_reduced_detail() rebuilds nothing. Ignored on the OpenGL ES path.
|
||||||
|
//
|
||||||
|
EReducedDetailMode get_reduced_detail_mode() const;
|
||||||
|
void set_reduced_detail_mode(EReducedDetailMode mode);
|
||||||
|
// Whether the shell mode hides the infill roles; off for a profile that leaves them on the
|
||||||
|
// surface, with no top or bottom shell or no walls.
|
||||||
|
bool get_reduced_detail_hide_infill() const;
|
||||||
|
void set_reduced_detail_hide_infill(bool value);
|
||||||
|
void set_reduced_detail(bool value);
|
||||||
|
bool is_reduced_detail() const;
|
||||||
float get_dim_previous_layers_brightness() const;
|
float get_dim_previous_layers_brightness() const;
|
||||||
void set_dim_previous_layers_brightness(float value);
|
void set_dim_previous_layers_brightness(float value);
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ struct Settings
|
|||||||
// ORCA: how bright those darkened layers are rendered, 1.0 = unchanged, 0.0 = black
|
// ORCA: how bright those darkened layers are rendered, 1.0 = unchanged, 0.0 = black
|
||||||
float dim_previous_layers_brightness{ 0.4f };
|
float dim_previous_layers_brightness{ 0.4f };
|
||||||
bool spiral_vase_mode{ false };
|
bool spiral_vase_mode{ false };
|
||||||
|
// what the reduced set holds and whether it is drawn. Ignored on the OpenGL ES path.
|
||||||
|
EReducedDetailMode reduced_detail_mode{ EReducedDetailMode::Off };
|
||||||
|
// whether the shell mode may hide the infill roles: false when the profile leaves them on the surface
|
||||||
|
bool reduced_detail_hide_infill{ true };
|
||||||
|
bool reduced_detail{ false };
|
||||||
//
|
//
|
||||||
// Required update flags
|
// Required update flags
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -92,6 +92,36 @@ bool Viewer::is_dim_previous_layers() const
|
|||||||
return m_impl->is_dim_previous_layers();
|
return m_impl->is_dim_previous_layers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Viewer::set_reduced_detail(bool value)
|
||||||
|
{
|
||||||
|
m_impl->set_reduced_detail(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Viewer::is_reduced_detail() const
|
||||||
|
{
|
||||||
|
return m_impl->is_reduced_detail();
|
||||||
|
}
|
||||||
|
|
||||||
|
EReducedDetailMode Viewer::get_reduced_detail_mode() const
|
||||||
|
{
|
||||||
|
return m_impl->get_reduced_detail_mode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Viewer::set_reduced_detail_mode(EReducedDetailMode mode)
|
||||||
|
{
|
||||||
|
m_impl->set_reduced_detail_mode(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Viewer::get_reduced_detail_hide_infill() const
|
||||||
|
{
|
||||||
|
return m_impl->get_reduced_detail_hide_infill();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Viewer::set_reduced_detail_hide_infill(bool value)
|
||||||
|
{
|
||||||
|
m_impl->set_reduced_detail_hide_infill(value);
|
||||||
|
}
|
||||||
|
|
||||||
void Viewer::set_dim_previous_layers(bool value)
|
void Viewer::set_dim_previous_layers(bool value)
|
||||||
{
|
{
|
||||||
m_impl->set_dim_previous_layers(value);
|
m_impl->set_dim_previous_layers(value);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <cfloat>
|
||||||
|
|
||||||
namespace libvgcode {
|
namespace libvgcode {
|
||||||
|
|
||||||
@@ -901,9 +902,17 @@ void ViewerImpl::reset()
|
|||||||
#else
|
#else
|
||||||
m_enabled_segments_count = 0;
|
m_enabled_segments_count = 0;
|
||||||
m_enabled_options_count = 0;
|
m_enabled_options_count = 0;
|
||||||
|
m_enabled_segments_reduced_count = 0;
|
||||||
|
m_enabled_options_reduced_count = 0;
|
||||||
|
m_enabled_segments_reduced_tex_size = 0;
|
||||||
|
m_enabled_options_reduced_tex_size = 0;
|
||||||
|
|
||||||
m_settings_used_for_ranges = std::nullopt;
|
m_settings_used_for_ranges = std::nullopt;
|
||||||
|
|
||||||
|
delete_textures(m_enabled_options_reduced_tex_id);
|
||||||
|
delete_buffers(m_enabled_options_reduced_buf_id);
|
||||||
|
delete_textures(m_enabled_segments_reduced_tex_id);
|
||||||
|
delete_buffers(m_enabled_segments_reduced_buf_id);
|
||||||
delete_textures(m_enabled_options_tex_id);
|
delete_textures(m_enabled_options_tex_id);
|
||||||
delete_buffers(m_enabled_options_buf_id);
|
delete_buffers(m_enabled_options_buf_id);
|
||||||
delete_textures(m_enabled_segments_tex_id);
|
delete_textures(m_enabled_segments_tex_id);
|
||||||
@@ -1163,6 +1172,17 @@ void ViewerImpl::load(GCodeInputData&& gcode_data)
|
|||||||
glsafe(glGenTextures(1, &m_enabled_options_tex_id));
|
glsafe(glGenTextures(1, &m_enabled_options_tex_id));
|
||||||
glsafe(glBindTexture(GL_TEXTURE_BUFFER, m_enabled_options_tex_id));
|
glsafe(glBindTexture(GL_TEXTURE_BUFFER, m_enabled_options_tex_id));
|
||||||
|
|
||||||
|
// create (but do not fill) the reduced counterparts of the two buffers above
|
||||||
|
glsafe(glGenBuffers(1, &m_enabled_segments_reduced_buf_id));
|
||||||
|
glsafe(glBindBuffer(GL_TEXTURE_BUFFER, m_enabled_segments_reduced_buf_id));
|
||||||
|
glsafe(glGenTextures(1, &m_enabled_segments_reduced_tex_id));
|
||||||
|
glsafe(glBindTexture(GL_TEXTURE_BUFFER, m_enabled_segments_reduced_tex_id));
|
||||||
|
|
||||||
|
glsafe(glGenBuffers(1, &m_enabled_options_reduced_buf_id));
|
||||||
|
glsafe(glBindBuffer(GL_TEXTURE_BUFFER, m_enabled_options_reduced_buf_id));
|
||||||
|
glsafe(glGenTextures(1, &m_enabled_options_reduced_tex_id));
|
||||||
|
glsafe(glBindTexture(GL_TEXTURE_BUFFER, m_enabled_options_reduced_tex_id));
|
||||||
|
|
||||||
glsafe(glBindBuffer(GL_TEXTURE_BUFFER, 0));
|
glsafe(glBindBuffer(GL_TEXTURE_BUFFER, 0));
|
||||||
glsafe(glBindTexture(GL_TEXTURE_BUFFER, old_bound_texture));
|
glsafe(glBindTexture(GL_TEXTURE_BUFFER, old_bound_texture));
|
||||||
#endif // ENABLE_OPENGL_ES
|
#endif // ENABLE_OPENGL_ES
|
||||||
@@ -1174,6 +1194,18 @@ void ViewerImpl::load(GCodeInputData&& gcode_data)
|
|||||||
update_colors();
|
update_colors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef ENABLE_OPENGL_ES
|
||||||
|
// the roles that lie under a skin or between walls, never seen from outside the print
|
||||||
|
static bool is_hidden_in_shell(EGCodeExtrusionRole role)
|
||||||
|
{
|
||||||
|
return role == EGCodeExtrusionRole::InternalInfill ||
|
||||||
|
role == EGCodeExtrusionRole::SolidInfill ||
|
||||||
|
role == EGCodeExtrusionRole::InternalBridgeInfill ||
|
||||||
|
role == EGCodeExtrusionRole::GapFill;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_OPENGL_ES
|
||||||
|
|
||||||
|
|
||||||
void ViewerImpl::update_enabled_entities()
|
void ViewerImpl::update_enabled_entities()
|
||||||
{
|
{
|
||||||
if (m_vertices.empty())
|
if (m_vertices.empty())
|
||||||
@@ -1181,6 +1213,17 @@ void ViewerImpl::update_enabled_entities()
|
|||||||
|
|
||||||
std::vector<uint32_t> enabled_segments;
|
std::vector<uint32_t> enabled_segments;
|
||||||
std::vector<uint32_t> enabled_options;
|
std::vector<uint32_t> enabled_options;
|
||||||
|
#ifndef ENABLE_OPENGL_ES
|
||||||
|
// the reduced set is filled by the same walk, so switching to it costs no rebuild. Whatever the
|
||||||
|
// mode leaves out, the bottom and top layers of the visible range are kept whole: they are the
|
||||||
|
// surfaces the range cuts open
|
||||||
|
const EReducedDetailMode reduced_mode = m_settings.reduced_detail_mode;
|
||||||
|
const bool build_reduced = reduced_mode != EReducedDetailMode::Off;
|
||||||
|
const bool hide_infill = m_settings.reduced_detail_hide_infill;
|
||||||
|
std::vector<uint32_t> enabled_segments_reduced;
|
||||||
|
std::vector<uint32_t> enabled_options_reduced;
|
||||||
|
const Interval& layers_range = m_layers.get_view_range();
|
||||||
|
#endif // ENABLE_OPENGL_ES
|
||||||
Interval range = m_view_range.get_visible();
|
Interval range = m_view_range.get_visible();
|
||||||
|
|
||||||
// when top layer only visualization is enabled, we need to render
|
// when top layer only visualization is enabled, we need to render
|
||||||
@@ -1228,6 +1271,20 @@ void ViewerImpl::update_enabled_entities()
|
|||||||
enabled_options.push_back(static_cast<uint32_t>(i));
|
enabled_options.push_back(static_cast<uint32_t>(i));
|
||||||
else
|
else
|
||||||
enabled_segments.push_back(static_cast<uint32_t>(i));
|
enabled_segments.push_back(static_cast<uint32_t>(i));
|
||||||
|
|
||||||
|
#ifndef ENABLE_OPENGL_ES
|
||||||
|
if (build_reduced) {
|
||||||
|
const bool end_layer = v.layer_id == layers_range[0] || v.layer_id == layers_range[1];
|
||||||
|
if (end_layer)
|
||||||
|
(v.is_option() ? enabled_options_reduced : enabled_segments_reduced).push_back(static_cast<uint32_t>(i));
|
||||||
|
else if (reduced_mode == EReducedDetailMode::ShellOnly) {
|
||||||
|
if (v.is_option())
|
||||||
|
enabled_options_reduced.push_back(static_cast<uint32_t>(i));
|
||||||
|
else if (!v.is_extrusion() || !hide_infill || !is_hidden_in_shell(v.role))
|
||||||
|
enabled_segments_reduced.push_back(static_cast<uint32_t>(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ENABLE_OPENGL_ES
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_OPENGL_ES
|
#ifdef ENABLE_OPENGL_ES
|
||||||
@@ -1256,6 +1313,23 @@ void ViewerImpl::update_enabled_entities()
|
|||||||
else
|
else
|
||||||
glsafe(glBufferData(GL_TEXTURE_BUFFER, 0, nullptr, GL_STATIC_DRAW));
|
glsafe(glBufferData(GL_TEXTURE_BUFFER, 0, nullptr, GL_STATIC_DRAW));
|
||||||
|
|
||||||
|
m_enabled_segments_reduced_count = enabled_segments_reduced.size();
|
||||||
|
m_enabled_options_reduced_count = enabled_options_reduced.size();
|
||||||
|
m_enabled_segments_reduced_tex_size = enabled_segments_reduced.size() * sizeof(uint32_t);
|
||||||
|
m_enabled_options_reduced_tex_size = enabled_options_reduced.size() * sizeof(uint32_t);
|
||||||
|
|
||||||
|
// uploaded even when nothing was built, so that the last reduced set is released as soon as
|
||||||
|
// the preference is switched off
|
||||||
|
assert(m_enabled_segments_reduced_buf_id > 0);
|
||||||
|
glsafe(glBindBuffer(GL_TEXTURE_BUFFER, m_enabled_segments_reduced_buf_id));
|
||||||
|
glsafe(glBufferData(GL_TEXTURE_BUFFER, m_enabled_segments_reduced_tex_size,
|
||||||
|
enabled_segments_reduced.empty() ? nullptr : enabled_segments_reduced.data(), GL_STATIC_DRAW));
|
||||||
|
|
||||||
|
assert(m_enabled_options_reduced_buf_id > 0);
|
||||||
|
glsafe(glBindBuffer(GL_TEXTURE_BUFFER, m_enabled_options_reduced_buf_id));
|
||||||
|
glsafe(glBufferData(GL_TEXTURE_BUFFER, m_enabled_options_reduced_tex_size,
|
||||||
|
enabled_options_reduced.empty() ? nullptr : enabled_options_reduced.data(), GL_STATIC_DRAW));
|
||||||
|
|
||||||
glsafe(glBindBuffer(GL_TEXTURE_BUFFER, 0));
|
glsafe(glBindBuffer(GL_TEXTURE_BUFFER, 0));
|
||||||
#endif // ENABLE_OPENGL_ES
|
#endif // ENABLE_OPENGL_ES
|
||||||
|
|
||||||
@@ -1463,6 +1537,23 @@ void ViewerImpl::toggle_top_layer_only_view_range()
|
|||||||
update_colors_texture();
|
update_colors_texture();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Both decide which vertices land in the reduced set, so the sets are rebuilt.
|
||||||
|
void ViewerImpl::set_reduced_detail_mode(EReducedDetailMode mode)
|
||||||
|
{
|
||||||
|
if (m_settings.reduced_detail_mode == mode)
|
||||||
|
return;
|
||||||
|
m_settings.reduced_detail_mode = mode;
|
||||||
|
m_settings.update_enabled_entities = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ViewerImpl::set_reduced_detail_hide_infill(bool value)
|
||||||
|
{
|
||||||
|
if (m_settings.reduced_detail_hide_infill == value)
|
||||||
|
return;
|
||||||
|
m_settings.reduced_detail_hide_infill = value;
|
||||||
|
m_settings.update_enabled_entities = true;
|
||||||
|
}
|
||||||
|
|
||||||
// ORCA: enable/disable darkening of the layers the layer slider is not scrubbed to
|
// ORCA: enable/disable darkening of the layers the layer slider is not scrubbed to
|
||||||
void ViewerImpl::set_dim_previous_layers(bool value)
|
void ViewerImpl::set_dim_previous_layers(bool value)
|
||||||
{
|
{
|
||||||
@@ -1856,6 +1947,8 @@ size_t ViewerImpl::get_used_gpu_memory() const
|
|||||||
ret += m_colors_tex_size;
|
ret += m_colors_tex_size;
|
||||||
ret += m_enabled_segments_tex_size;
|
ret += m_enabled_segments_tex_size;
|
||||||
ret += m_enabled_options_tex_size;
|
ret += m_enabled_options_tex_size;
|
||||||
|
ret += m_enabled_segments_reduced_tex_size;
|
||||||
|
ret += m_enabled_options_reduced_tex_size;
|
||||||
#endif // ENABLE_OPENGL_ES
|
#endif // ENABLE_OPENGL_ES
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -2072,7 +2165,8 @@ void ViewerImpl::render_segments(const Mat4x4& view_matrix, const Mat4x4& projec
|
|||||||
#ifdef ENABLE_OPENGL_ES
|
#ifdef ENABLE_OPENGL_ES
|
||||||
if (m_texture_data.get_enabled_segments_count() == 0)
|
if (m_texture_data.get_enabled_segments_count() == 0)
|
||||||
#else
|
#else
|
||||||
if (m_enabled_segments_count == 0)
|
const ActiveSet segments = active_segments();
|
||||||
|
if (segments.count == 0)
|
||||||
#endif // ENABLE_OPENGL_ES
|
#endif // ENABLE_OPENGL_ES
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -2099,7 +2193,7 @@ void ViewerImpl::render_segments(const Mat4x4& view_matrix, const Mat4x4& projec
|
|||||||
const bool top_down = !m_rendering_shadow_casters && view_matrix[10] > 0.0f;
|
const bool top_down = !m_rendering_shadow_casters && view_matrix[10] > 0.0f;
|
||||||
glsafe(glUniform1i(m_uni_segments_reverse_order_id, top_down ? 1 : 0));
|
glsafe(glUniform1i(m_uni_segments_reverse_order_id, top_down ? 1 : 0));
|
||||||
#ifndef ENABLE_OPENGL_ES
|
#ifndef ENABLE_OPENGL_ES
|
||||||
glsafe(glUniform1i(m_uni_segments_instance_count_id, static_cast<int>(m_enabled_segments_count)));
|
glsafe(glUniform1i(m_uni_segments_instance_count_id, static_cast<int>(segments.count)));
|
||||||
#endif // ENABLE_OPENGL_ES
|
#endif // ENABLE_OPENGL_ES
|
||||||
// ORCA: realistic view. The depth pass writes the map it would otherwise read, so it shades
|
// ORCA: realistic view. The depth pass writes the map it would otherwise read, so it shades
|
||||||
// with the lookup off.
|
// with the lookup off.
|
||||||
@@ -2149,10 +2243,10 @@ void ViewerImpl::render_segments(const Mat4x4& view_matrix, const Mat4x4& projec
|
|||||||
glsafe(glBindTexture(GL_TEXTURE_BUFFER, m_colors_tex_id));
|
glsafe(glBindTexture(GL_TEXTURE_BUFFER, m_colors_tex_id));
|
||||||
glsafe(glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, m_colors_buf_id));
|
glsafe(glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, m_colors_buf_id));
|
||||||
glsafe(glActiveTexture(GL_TEXTURE3));
|
glsafe(glActiveTexture(GL_TEXTURE3));
|
||||||
glsafe(glBindTexture(GL_TEXTURE_BUFFER, m_enabled_segments_tex_id));
|
glsafe(glBindTexture(GL_TEXTURE_BUFFER, segments.tex_id));
|
||||||
glsafe(glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, m_enabled_segments_buf_id));
|
glsafe(glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, segments.buf_id));
|
||||||
|
|
||||||
m_segment_template.render(m_enabled_segments_count);
|
m_segment_template.render(segments.count);
|
||||||
#endif // ENABLE_OPENGL_ES
|
#endif // ENABLE_OPENGL_ES
|
||||||
|
|
||||||
if (curr_cull_face)
|
if (curr_cull_face)
|
||||||
@@ -2178,7 +2272,8 @@ void ViewerImpl::render_options(const Mat4x4& view_matrix, const Mat4x4& project
|
|||||||
#ifdef ENABLE_OPENGL_ES
|
#ifdef ENABLE_OPENGL_ES
|
||||||
if (m_texture_data.get_enabled_options_count() == 0)
|
if (m_texture_data.get_enabled_options_count() == 0)
|
||||||
#else
|
#else
|
||||||
if (m_enabled_options_count == 0)
|
const ActiveSet options = active_options();
|
||||||
|
if (options.count == 0)
|
||||||
#endif // ENABLE_OPENGL_ES
|
#endif // ENABLE_OPENGL_ES
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -2236,10 +2331,10 @@ void ViewerImpl::render_options(const Mat4x4& view_matrix, const Mat4x4& project
|
|||||||
glsafe(glBindTexture(GL_TEXTURE_BUFFER, m_colors_tex_id));
|
glsafe(glBindTexture(GL_TEXTURE_BUFFER, m_colors_tex_id));
|
||||||
glsafe(glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, m_colors_buf_id));
|
glsafe(glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, m_colors_buf_id));
|
||||||
glsafe(glActiveTexture(GL_TEXTURE3));
|
glsafe(glActiveTexture(GL_TEXTURE3));
|
||||||
glsafe(glBindTexture(GL_TEXTURE_BUFFER, m_enabled_options_tex_id));
|
glsafe(glBindTexture(GL_TEXTURE_BUFFER, options.tex_id));
|
||||||
glsafe(glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, m_enabled_options_buf_id));
|
glsafe(glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, options.buf_id));
|
||||||
|
|
||||||
m_option_template.render(m_enabled_options_count);
|
m_option_template.render(options.count);
|
||||||
#endif // ENABLE_OPENGL_ES
|
#endif // ENABLE_OPENGL_ES
|
||||||
|
|
||||||
if (!curr_cull_face)
|
if (!curr_cull_face)
|
||||||
|
|||||||
@@ -109,6 +109,21 @@ public:
|
|||||||
// 0.0 = black
|
// 0.0 = black
|
||||||
bool is_dim_previous_layers() const { return m_settings.dim_previous_layers; }
|
bool is_dim_previous_layers() const { return m_settings.dim_previous_layers; }
|
||||||
void set_dim_previous_layers(bool value);
|
void set_dim_previous_layers(bool value);
|
||||||
|
//
|
||||||
|
// Draw from the reduced set; it is already built, so this is just a buffer binding.
|
||||||
|
//
|
||||||
|
void set_reduced_detail(bool value) {
|
||||||
|
#ifdef ENABLE_OPENGL_ES
|
||||||
|
// no reduced set is built on OpenGL ES
|
||||||
|
value = false;
|
||||||
|
#endif // ENABLE_OPENGL_ES
|
||||||
|
m_settings.reduced_detail = value;
|
||||||
|
}
|
||||||
|
bool is_reduced_detail() const { return m_settings.reduced_detail; }
|
||||||
|
EReducedDetailMode get_reduced_detail_mode() const { return m_settings.reduced_detail_mode; }
|
||||||
|
void set_reduced_detail_mode(EReducedDetailMode mode);
|
||||||
|
bool get_reduced_detail_hide_infill() const { return m_settings.reduced_detail_hide_infill; }
|
||||||
|
void set_reduced_detail_hide_infill(bool value);
|
||||||
float get_dim_previous_layers_brightness() const { return m_settings.dim_previous_layers_brightness; }
|
float get_dim_previous_layers_brightness() const { return m_settings.dim_previous_layers_brightness; }
|
||||||
void set_dim_previous_layers_brightness(float value);
|
void set_dim_previous_layers_brightness(float value);
|
||||||
|
|
||||||
@@ -501,6 +516,15 @@ private:
|
|||||||
unsigned int m_enabled_options_tex_id{ 0 };
|
unsigned int m_enabled_options_tex_id{ 0 };
|
||||||
size_t m_enabled_options_count{ 0 };
|
size_t m_enabled_options_count{ 0 };
|
||||||
//
|
//
|
||||||
|
// OpenGL buffers to store the reduced set drawn while Settings::reduced_detail is set
|
||||||
|
//
|
||||||
|
unsigned int m_enabled_segments_reduced_buf_id{ 0 };
|
||||||
|
unsigned int m_enabled_segments_reduced_tex_id{ 0 };
|
||||||
|
size_t m_enabled_segments_reduced_count{ 0 };
|
||||||
|
unsigned int m_enabled_options_reduced_buf_id{ 0 };
|
||||||
|
unsigned int m_enabled_options_reduced_tex_id{ 0 };
|
||||||
|
size_t m_enabled_options_reduced_count{ 0 };
|
||||||
|
//
|
||||||
// Caches for size of data sent to gpu, in bytes
|
// Caches for size of data sent to gpu, in bytes
|
||||||
//
|
//
|
||||||
size_t m_positions_tex_size{ 0 };
|
size_t m_positions_tex_size{ 0 };
|
||||||
@@ -508,6 +532,27 @@ private:
|
|||||||
size_t m_colors_tex_size{ 0 };
|
size_t m_colors_tex_size{ 0 };
|
||||||
size_t m_enabled_segments_tex_size{ 0 };
|
size_t m_enabled_segments_tex_size{ 0 };
|
||||||
size_t m_enabled_options_tex_size{ 0 };
|
size_t m_enabled_options_tex_size{ 0 };
|
||||||
|
size_t m_enabled_segments_reduced_tex_size{ 0 };
|
||||||
|
size_t m_enabled_options_reduced_tex_size{ 0 };
|
||||||
|
|
||||||
|
// The set the next draw reads from: the reduced one while dragging, if one is built.
|
||||||
|
bool use_reduced_set() const { return m_settings.reduced_detail && m_settings.reduced_detail_mode != EReducedDetailMode::Off; }
|
||||||
|
struct ActiveSet
|
||||||
|
{
|
||||||
|
size_t count{ 0 };
|
||||||
|
unsigned int buf_id{ 0 };
|
||||||
|
unsigned int tex_id{ 0 };
|
||||||
|
};
|
||||||
|
ActiveSet active_segments() const {
|
||||||
|
if (use_reduced_set())
|
||||||
|
return { m_enabled_segments_reduced_count, m_enabled_segments_reduced_buf_id, m_enabled_segments_reduced_tex_id };
|
||||||
|
return { m_enabled_segments_count, m_enabled_segments_buf_id, m_enabled_segments_tex_id };
|
||||||
|
}
|
||||||
|
ActiveSet active_options() const {
|
||||||
|
if (use_reduced_set())
|
||||||
|
return { m_enabled_options_reduced_count, m_enabled_options_reduced_buf_id, m_enabled_options_reduced_tex_id };
|
||||||
|
return { m_enabled_options_count, m_enabled_options_buf_id, m_enabled_options_tex_id };
|
||||||
|
}
|
||||||
#endif // ENABLE_OPENGL_ES
|
#endif // ENABLE_OPENGL_ES
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
+15
-19
@@ -236,7 +236,6 @@ set(SLIC3R_GUI_SOURCES
|
|||||||
GUI/GLToolbar.hpp
|
GUI/GLToolbar.hpp
|
||||||
GUI/ImageDPIFrame.cpp
|
GUI/ImageDPIFrame.cpp
|
||||||
GUI/ImageDPIFrame.hpp
|
GUI/ImageDPIFrame.hpp
|
||||||
GUI/IMediaController.hpp
|
|
||||||
GUI/GUI_App.cpp
|
GUI/GUI_App.cpp
|
||||||
GUI/GUI_App.hpp
|
GUI/GUI_App.hpp
|
||||||
GUI/GUI_AuxiliaryList.cpp
|
GUI/GUI_AuxiliaryList.cpp
|
||||||
@@ -366,8 +365,6 @@ set(SLIC3R_GUI_SOURCES
|
|||||||
GUI/MediaFilePanel.h
|
GUI/MediaFilePanel.h
|
||||||
GUI/MediaPlayCtrl.cpp
|
GUI/MediaPlayCtrl.cpp
|
||||||
GUI/MediaPlayCtrl.h
|
GUI/MediaPlayCtrl.h
|
||||||
GUI/WebRtcMediaController.cpp
|
|
||||||
GUI/WebRtcMediaController.hpp
|
|
||||||
GUI/MeshUtils.cpp
|
GUI/MeshUtils.cpp
|
||||||
GUI/MeshUtils.hpp
|
GUI/MeshUtils.hpp
|
||||||
GUI/ModelMall.cpp
|
GUI/ModelMall.cpp
|
||||||
@@ -563,8 +560,6 @@ set(SLIC3R_GUI_SOURCES
|
|||||||
GUI/WebUserLoginDialog.hpp
|
GUI/WebUserLoginDialog.hpp
|
||||||
GUI/WebViewDialog.cpp
|
GUI/WebViewDialog.cpp
|
||||||
GUI/WebViewDialog.hpp
|
GUI/WebViewDialog.hpp
|
||||||
GUI/WebMediaController.hpp
|
|
||||||
GUI/WebMediaController.cpp
|
|
||||||
GUI/Widgets/AMSControl.cpp
|
GUI/Widgets/AMSControl.cpp
|
||||||
GUI/Widgets/AMSControl.hpp
|
GUI/Widgets/AMSControl.hpp
|
||||||
GUI/Widgets/AMSItem.cpp
|
GUI/Widgets/AMSItem.cpp
|
||||||
@@ -759,7 +754,6 @@ set(SLIC3R_GUI_SOURCES
|
|||||||
Utils/NetworkAgentFactory.cpp
|
Utils/NetworkAgentFactory.cpp
|
||||||
Utils/ICloudServiceAgent.hpp
|
Utils/ICloudServiceAgent.hpp
|
||||||
Utils/IPrinterAgent.hpp
|
Utils/IPrinterAgent.hpp
|
||||||
Utils/ICameraSignalingChannel.hpp
|
|
||||||
Utils/OrcaCloudServiceAgent.cpp
|
Utils/OrcaCloudServiceAgent.cpp
|
||||||
Utils/OrcaCloudServiceAgent.hpp
|
Utils/OrcaCloudServiceAgent.hpp
|
||||||
Utils/OrcaPrinterAgent.cpp
|
Utils/OrcaPrinterAgent.cpp
|
||||||
@@ -930,7 +924,7 @@ else()
|
|||||||
set(_opengl_link_lib OpenGL::GL)
|
set(_opengl_link_lib OpenGL::GL)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo libvgcode md4c-html glad ${_opengl_link_lib} hidapi mdns ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto LibDataChannel::LibDataChannel noise::noise pybind11::embed)
|
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo libvgcode md4c-html glad ${_opengl_link_lib} hidapi mdns ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto noise::noise pybind11::embed)
|
||||||
|
|
||||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
# Linux finds wxWidgets in module mode, whose include dirs and definitions
|
# Linux finds wxWidgets in module mode, whose include dirs and definitions
|
||||||
@@ -987,32 +981,29 @@ endif ()
|
|||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
# Static FFmpeg from the deps install: nothing to bundle into the .app,
|
# Static FFmpeg from the deps install: nothing to bundle into the .app,
|
||||||
# no rpath/install_name handling. Order matters: avformat -> avcodec -> swscale -> avutil.
|
# no rpath/install_name handling. Order matters: avcodec -> swscale -> avutil.
|
||||||
find_library(LIBAVFORMAT_LIBRARY NAMES libavformat.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
|
||||||
find_library(LIBAVCODEC_LIBRARY NAMES libavcodec.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
find_library(LIBAVCODEC_LIBRARY NAMES libavcodec.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||||
find_library(LIBSWSCALE_LIBRARY NAMES libswscale.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
find_library(LIBSWSCALE_LIBRARY NAMES libswscale.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||||
find_library(LIBAVUTIL_LIBRARY NAMES libavutil.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
find_library(LIBAVUTIL_LIBRARY NAMES libavutil.a PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||||
if (NOT LIBAVFORMAT_LIBRARY OR NOT LIBAVCODEC_LIBRARY OR NOT LIBSWSCALE_LIBRARY OR NOT LIBAVUTIL_LIBRARY)
|
if (NOT LIBAVCODEC_LIBRARY OR NOT LIBSWSCALE_LIBRARY OR NOT LIBAVUTIL_LIBRARY)
|
||||||
message(FATAL_ERROR "Static FFmpeg (libavformat.a/libavcodec.a/libswscale.a/libavutil.a) not found under ${CMAKE_PREFIX_PATH}/lib. Rebuild the deps — FFMPEG builds static-only on macOS.")
|
message(FATAL_ERROR "Static FFmpeg (libavcodec.a/libswscale.a/libavutil.a) not found under ${CMAKE_PREFIX_PATH}/lib. Rebuild the deps — FFMPEG builds static-only on macOS.")
|
||||||
endif ()
|
endif ()
|
||||||
target_link_libraries(libslic3r_gui ${LIBAVFORMAT_LIBRARY} ${LIBAVCODEC_LIBRARY} ${LIBSWSCALE_LIBRARY} ${LIBAVUTIL_LIBRARY})
|
target_link_libraries(libslic3r_gui ${LIBAVCODEC_LIBRARY} ${LIBSWSCALE_LIBRARY} ${LIBAVUTIL_LIBRARY})
|
||||||
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${CMAKE_PREFIX_PATH}/include)
|
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${CMAKE_PREFIX_PATH}/include)
|
||||||
elseif (WIN32)
|
elseif (WIN32)
|
||||||
# Prebuilt shared FFmpeg from the deps install. Windows has no pkg-config,
|
# Prebuilt shared FFmpeg from the deps install. Windows has no pkg-config,
|
||||||
# so resolve the import libraries out of the deps prefix directly; the DLLs
|
# so resolve the import libraries out of the deps prefix directly; the DLLs
|
||||||
# are copied next to the executable by the top level CMakeLists.
|
# are copied next to the executable by the top level CMakeLists.
|
||||||
find_library(LIBAVFORMAT_LIBRARY NAMES avformat PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
|
||||||
find_library(LIBAVCODEC_LIBRARY NAMES avcodec PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
find_library(LIBAVCODEC_LIBRARY NAMES avcodec PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||||
find_library(LIBSWSCALE_LIBRARY NAMES swscale PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
find_library(LIBSWSCALE_LIBRARY NAMES swscale PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||||
find_library(LIBAVUTIL_LIBRARY NAMES avutil PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
find_library(LIBAVUTIL_LIBRARY NAMES avutil PATHS ${CMAKE_PREFIX_PATH}/lib NO_DEFAULT_PATH)
|
||||||
if (NOT LIBAVFORMAT_LIBRARY OR NOT LIBAVCODEC_LIBRARY OR NOT LIBSWSCALE_LIBRARY OR NOT LIBAVUTIL_LIBRARY)
|
if (NOT LIBAVCODEC_LIBRARY OR NOT LIBSWSCALE_LIBRARY OR NOT LIBAVUTIL_LIBRARY)
|
||||||
message(FATAL_ERROR "FFmpeg (avformat/avcodec/swscale/avutil) not found under ${CMAKE_PREFIX_PATH}/lib. Rebuild the deps.")
|
message(FATAL_ERROR "FFmpeg (avcodec/swscale/avutil) not found under ${CMAKE_PREFIX_PATH}/lib. Rebuild the deps.")
|
||||||
endif ()
|
endif ()
|
||||||
target_link_libraries(libslic3r_gui ${LIBAVFORMAT_LIBRARY} ${LIBAVCODEC_LIBRARY} ${LIBSWSCALE_LIBRARY} ${LIBAVUTIL_LIBRARY})
|
target_link_libraries(libslic3r_gui ${LIBAVCODEC_LIBRARY} ${LIBSWSCALE_LIBRARY} ${LIBAVUTIL_LIBRARY})
|
||||||
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${CMAKE_PREFIX_PATH}/include)
|
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${CMAKE_PREFIX_PATH}/include)
|
||||||
else ()
|
else ()
|
||||||
pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
|
pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
|
||||||
libavformat
|
|
||||||
libavcodec
|
libavcodec
|
||||||
libswscale
|
libswscale
|
||||||
libavutil
|
libavutil
|
||||||
@@ -1028,9 +1019,14 @@ if (UNIX AND NOT APPLE)
|
|||||||
find_package(GTK${SLIC3R_GTK} REQUIRED)
|
find_package(GTK${SLIC3R_GTK} REQUIRED)
|
||||||
pkg_check_modules(LIBSECRET REQUIRED libsecret-1)
|
pkg_check_modules(LIBSECRET REQUIRED libsecret-1)
|
||||||
pkg_check_modules(webkit2gtk REQUIRED webkit2gtk-4.1)
|
pkg_check_modules(webkit2gtk REQUIRED webkit2gtk-4.1)
|
||||||
find_package(X11 REQUIRED)
|
if (FLATPAK)
|
||||||
|
# I don't know why this is needed, but for whatever reason slic3r isn't
|
||||||
|
# linking to X11 and webkit2gtk. force it.
|
||||||
|
find_package(X11 REQUIRED)
|
||||||
|
target_link_libraries(libslic3r_gui ${X11_LIBRARIES} ${webkit2gtk_LIBRARIES})
|
||||||
|
endif()
|
||||||
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${GTK${SLIC3R_GTK}_INCLUDE_DIRS} ${LIBSECRET_INCLUDE_DIRS} ${webkit2gtk_INCLUDE_DIRS})
|
target_include_directories(libslic3r_gui SYSTEM PRIVATE ${GTK${SLIC3R_GTK}_INCLUDE_DIRS} ${LIBSECRET_INCLUDE_DIRS} ${webkit2gtk_INCLUDE_DIRS})
|
||||||
target_link_libraries(libslic3r_gui ${GTK${SLIC3R_GTK}_LIBRARIES} fontconfig ${LIBSECRET_LIBRARIES} ${webkit2gtk_LIBRARIES} ${X11_LIBRARIES})
|
target_link_libraries(libslic3r_gui ${GTK${SLIC3R_GTK}_LIBRARIES} fontconfig ${LIBSECRET_LIBRARIES})
|
||||||
|
|
||||||
# Propagate GDK backend detection results as compile definitions so that
|
# Propagate GDK backend detection results as compile definitions so that
|
||||||
# LinuxDisplayBackend.cpp can include the right GDK headers.
|
# LinuxDisplayBackend.cpp can include the right GDK headers.
|
||||||
|
|||||||
@@ -45,25 +45,6 @@ int AVVideoDecoder::open(Bambu_StreamInfo const &info)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AVVideoDecoder::open(AVCodecParameters const ¶meters)
|
|
||||||
{
|
|
||||||
if (avcodec_parameters_to_context(codec_ctx_, ¶meters) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
auto codec = avcodec_find_decoder(codec_ctx_->codec_id);
|
|
||||||
if (codec == nullptr) {
|
|
||||||
fprintf(stderr, "AVVideoDecoder: unsupported codec!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (avcodec_open2(codec_ctx_, codec, nullptr) < 0) {
|
|
||||||
fprintf(stderr, "AVVideoDecoder: could not open codec\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
frame_ = av_frame_alloc();
|
|
||||||
return frame_ == nullptr ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AVVideoDecoder::decode(const Bambu_Sample &sample)
|
int AVVideoDecoder::decode(const Bambu_Sample &sample)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
@@ -90,14 +71,6 @@ int AVVideoDecoder::decode(const Bambu_Sample &sample)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AVVideoDecoder::decode(const AVPacket &packet)
|
|
||||||
{
|
|
||||||
int ret = avcodec_send_packet(codec_ctx_, &packet);
|
|
||||||
if (ret == 0)
|
|
||||||
got_frame_ = avcodec_receive_frame(codec_ctx_, frame_) == 0;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AVVideoDecoder::flush()
|
int AVVideoDecoder::flush()
|
||||||
{
|
{
|
||||||
int ret = avcodec_send_packet(codec_ctx_, nullptr);
|
int ret = avcodec_send_packet(codec_ctx_, nullptr);
|
||||||
|
|||||||
@@ -23,10 +23,8 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
int open(Bambu_StreamInfo const &info);
|
int open(Bambu_StreamInfo const &info);
|
||||||
int open(AVCodecParameters const ¶meters);
|
|
||||||
|
|
||||||
int decode(Bambu_Sample const &sample);
|
int decode(Bambu_Sample const &sample);
|
||||||
int decode(AVPacket const &packet);
|
|
||||||
|
|
||||||
int flush();
|
int flush();
|
||||||
|
|
||||||
@@ -36,14 +34,6 @@ public:
|
|||||||
|
|
||||||
bool toWxBitmap(wxBitmap &bitmap, wxSize const & size);
|
bool toWxBitmap(wxBitmap &bitmap, wxSize const & size);
|
||||||
|
|
||||||
// Native size of the most recently decoded frame, or an unspecified size if
|
|
||||||
// nothing has decoded yet. Lets a caller learn the video dimensions when the
|
|
||||||
// container/probe could not report them up front.
|
|
||||||
wxSize decoded_frame_size() const
|
|
||||||
{
|
|
||||||
return got_frame_ && frame_ ? wxSize{frame_->width, frame_->height} : wxSize{};
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AVCodecContext *codec_ctx_ = nullptr;
|
AVCodecContext *codec_ctx_ = nullptr;
|
||||||
AVFrame * frame_ = nullptr;
|
AVFrame * frame_ = nullptr;
|
||||||
|
|||||||
@@ -428,7 +428,7 @@ void AuFile::on_dclick(wxMouseEvent &evt)
|
|||||||
if (m_type == AddFileButton)
|
if (m_type == AddFileButton)
|
||||||
return;
|
return;
|
||||||
else
|
else
|
||||||
desktop_open_project_attachment(this, m_file_path);
|
wxLaunchDefaultApplication(m_file_path.wstring(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuFile::on_mouse_left_up(wxMouseEvent &evt)
|
void AuFile::on_mouse_left_up(wxMouseEvent &evt)
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ void SelectMObjectPopup::update_user_devices()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_bind_machine_list.clear();
|
m_bind_machine_list.clear();
|
||||||
m_bind_machine_list = dev->get_my_machine_list(dev->get_current_printer_agent_id());
|
m_bind_machine_list = dev->get_my_machine_list();
|
||||||
|
|
||||||
//sort list
|
//sort list
|
||||||
std::vector<std::pair<std::string, MachineObject*>> user_machine_list;
|
std::vector<std::pair<std::string, MachineObject*>> user_machine_list;
|
||||||
|
|||||||
@@ -6,10 +6,8 @@
|
|||||||
#include "Widgets/Label.hpp"
|
#include "Widgets/Label.hpp"
|
||||||
#include "MsgDialog.hpp"
|
#include "MsgDialog.hpp"
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
#include "PrePrintChecker.hpp"
|
|
||||||
|
|
||||||
#include "DeviceCore/DevConfig.h"
|
#include "DeviceCore/DevConfig.h"
|
||||||
#include "DeviceCore/DevConfigUtil.h"
|
|
||||||
#include "DeviceCore/DevExtruderSystem.h"
|
#include "DeviceCore/DevExtruderSystem.h"
|
||||||
#include "DeviceCore/DevFilaBlackList.h"
|
#include "DeviceCore/DevFilaBlackList.h"
|
||||||
#include "DeviceCore/DevFilaSystem.h"
|
#include "DeviceCore/DevFilaSystem.h"
|
||||||
@@ -1639,6 +1637,29 @@ void CalibrationPresetPage::update_combobox_filaments(MachineObject* obj)
|
|||||||
select_default_compatible_filament();
|
select_default_compatible_filament();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CalibrationPresetPage::is_blocking_printing()
|
||||||
|
{
|
||||||
|
DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
|
||||||
|
if (!dev) return true;
|
||||||
|
|
||||||
|
MachineObject* obj_ = dev->get_selected_machine();
|
||||||
|
if (obj_ == nullptr) return true;
|
||||||
|
|
||||||
|
PresetBundle* preset_bundle = wxGetApp().preset_bundle;
|
||||||
|
auto source_model = preset_bundle->printers.get_edited_preset().get_printer_type(preset_bundle);
|
||||||
|
auto target_model = obj_->printer_type;
|
||||||
|
|
||||||
|
if (source_model != target_model) {
|
||||||
|
std::vector<std::string> compatible_machine = obj_->get_compatible_machine();
|
||||||
|
vector<std::string>::iterator it = find(compatible_machine.begin(), compatible_machine.end(), source_model);
|
||||||
|
if (it == compatible_machine.end()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool CalibrationPresetPage::is_nozzle_info_synced() const
|
bool CalibrationPresetPage::is_nozzle_info_synced() const
|
||||||
{
|
{
|
||||||
if (!curr_obj || !curr_obj->is_info_ready())
|
if (!curr_obj || !curr_obj->is_info_ready())
|
||||||
@@ -1720,13 +1741,11 @@ void CalibrationPresetPage::update_show_status()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_optional_printer_model = DevPrinterConfigUtil::is_optional_printer_model_id(obj_->printer_type);
|
//if (is_blocking_printing()) {
|
||||||
if (PresetBundle *preset_bundle = wxGetApp().preset_bundle) {
|
// show_status(CaliPresetPageStatus::CaliPresetStatusUnsupportedPrinter);
|
||||||
has_optional_printer_model = has_optional_printer_model ||
|
// return;
|
||||||
DevPrinterConfigUtil::is_optional_printer_model_id(
|
//}
|
||||||
preset_bundle->printers.get_edited_preset().get_printer_type(preset_bundle));
|
//else
|
||||||
}
|
|
||||||
|
|
||||||
if (obj_->is_connecting() || !obj_->is_connected()) {
|
if (obj_->is_connecting() || !obj_->is_connected()) {
|
||||||
show_status(CaliPresetPageStatus::CaliPresetStatusInConnecting);
|
show_status(CaliPresetPageStatus::CaliPresetStatusInConnecting);
|
||||||
return;
|
return;
|
||||||
@@ -1778,9 +1797,7 @@ void CalibrationPresetPage::update_show_status()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
show_status(has_optional_printer_model ?
|
show_status(CaliPresetPageStatus::CaliPresetStatusNormal);
|
||||||
CaliPresetPageStatus::CaliPresetStatusOptionalPrinterModel :
|
|
||||||
CaliPresetPageStatus::CaliPresetStatusNormal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1834,10 +1851,6 @@ void CalibrationPresetPage::show_status(CaliPresetPageStatus status)
|
|||||||
Layout();
|
Layout();
|
||||||
Fit();
|
Fit();
|
||||||
}
|
}
|
||||||
else if (status == CaliPresetPageStatus::CaliPresetStatusOptionalPrinterModel) {
|
|
||||||
update_print_status_msg(PrePrintChecker::get_pre_state_msg(PrintDialogStatus::PrintStatusOptionalPrinterModel), true);
|
|
||||||
Enable_Send_Button(true);
|
|
||||||
}
|
|
||||||
else if (status == CaliPresetPageStatus::CaliPresetStatusNoUserLogin) {
|
else if (status == CaliPresetPageStatus::CaliPresetStatusNoUserLogin) {
|
||||||
wxString msg_text = _L("No login account, only printers in LAN mode are displayed.");
|
wxString msg_text = _L("No login account, only printers in LAN mode are displayed.");
|
||||||
update_print_status_msg(msg_text, false);
|
update_print_status_msg(msg_text, false);
|
||||||
|
|||||||
@@ -152,8 +152,7 @@ enum CaliPresetPageStatus
|
|||||||
CaliPresetStatusInConnecting,
|
CaliPresetStatusInConnecting,
|
||||||
CaliPresetStatusFilamentIncompatible,
|
CaliPresetStatusFilamentIncompatible,
|
||||||
CaliPresetStatusLanModeSDcardNotAvailable,
|
CaliPresetStatusLanModeSDcardNotAvailable,
|
||||||
CaliPresetStatusDifferentNozzleDiameters,
|
CaliPresetStatusDifferentNozzleDiameters
|
||||||
CaliPresetStatusOptionalPrinterModel
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CalibrationPresetPage : public CalibrationWizardPage
|
class CalibrationPresetPage : public CalibrationWizardPage
|
||||||
@@ -269,6 +268,7 @@ protected:
|
|||||||
bool is_nozzle_info_synced() const;
|
bool is_nozzle_info_synced() const;
|
||||||
void show_status(CaliPresetPageStatus status);
|
void show_status(CaliPresetPageStatus status);
|
||||||
void Enable_Send_Button(bool enable);
|
void Enable_Send_Button(bool enable);
|
||||||
|
bool is_blocking_printing();
|
||||||
bool need_check_sdcard(MachineObject* obj);
|
bool need_check_sdcard(MachineObject* obj);
|
||||||
|
|
||||||
CaliPresetPageStatus get_status() { return m_page_status; }
|
CaliPresetPageStatus get_status() { return m_page_status; }
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ wxEND_EVENT_TABLE()
|
|||||||
|
|
||||||
wxDEFINE_EVENT(EVT_VCAMERA_SWITCH, wxMouseEvent);
|
wxDEFINE_EVENT(EVT_VCAMERA_SWITCH, wxMouseEvent);
|
||||||
wxDEFINE_EVENT(EVT_SDCARD_ABSENT_HINT, wxCommandEvent);
|
wxDEFINE_EVENT(EVT_SDCARD_ABSENT_HINT, wxCommandEvent);
|
||||||
|
wxDEFINE_EVENT(EVT_CAM_SOURCE_CHANGE, wxCommandEvent);
|
||||||
|
|
||||||
#define CAMERAPOPUP_CLICK_INTERVAL 20
|
#define CAMERAPOPUP_CLICK_INTERVAL 20
|
||||||
|
|
||||||
@@ -101,6 +102,34 @@ CameraPopup::CameraPopup(wxWindow *parent)
|
|||||||
top_sizer->Add(0, 0, wxALL, 0);
|
top_sizer->Add(0, 0, wxALL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Orca: custom IP camera source — lets the user point Live Video at any camera URL (Orca feature; not in the reference)
|
||||||
|
m_custom_camera_input_confirm = new Button(m_panel, _L("Enable"));
|
||||||
|
m_custom_camera_input_confirm->SetBackgroundColor(wxColour(38, 166, 154));
|
||||||
|
m_custom_camera_input_confirm->SetBorderColor(wxColour(38, 166, 154));
|
||||||
|
m_custom_camera_input_confirm->SetTextColor(wxColour(0xFFFFFE));
|
||||||
|
m_custom_camera_input_confirm->SetFont(Label::Body_14);
|
||||||
|
m_custom_camera_input_confirm->SetMinSize(wxSize(FromDIP(90), FromDIP(30)));
|
||||||
|
m_custom_camera_input_confirm->SetPosition(wxDefaultPosition);
|
||||||
|
m_custom_camera_input_confirm->SetCornerRadius(FromDIP(12));
|
||||||
|
m_custom_camera_input = new TextInput(m_panel, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, wxDefaultSize);
|
||||||
|
m_custom_camera_input->GetTextCtrl()->SetHint(_L("Hostname or IP"));
|
||||||
|
m_custom_camera_input->GetTextCtrl()->SetFont(Label::Body_14);
|
||||||
|
m_custom_camera_hint = new wxStaticText(m_panel, wxID_ANY, _L("Custom camera source"));
|
||||||
|
m_custom_camera_hint->Wrap(-1);
|
||||||
|
m_custom_camera_hint->SetFont(Label::Head_14);
|
||||||
|
m_custom_camera_hint->SetForegroundColour(TEXT_COL);
|
||||||
|
|
||||||
|
m_custom_camera_input_confirm->Bind(wxEVT_BUTTON, &CameraPopup::on_camera_source_changed, this);
|
||||||
|
|
||||||
|
if (!wxGetApp().app_config->get("camera", "custom_source").empty()) {
|
||||||
|
m_custom_camera_input->GetTextCtrl()->SetValue(wxGetApp().app_config->get("camera", "custom_source"));
|
||||||
|
set_custom_cam_button_state(wxGetApp().app_config->get("camera", "enable_custom_source") == "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
top_sizer->Add(m_custom_camera_hint, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT | wxALL, FromDIP(5));
|
||||||
|
top_sizer->Add(0, 0, wxALL, 0);
|
||||||
|
top_sizer->Add(m_custom_camera_input, 2, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, FromDIP(5));
|
||||||
|
top_sizer->Add(m_custom_camera_input_confirm, 1, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT | wxALL, FromDIP(5));
|
||||||
main_sizer->Add(top_sizer, 0, wxALL, FromDIP(10));
|
main_sizer->Add(top_sizer, 0, wxALL, FromDIP(10));
|
||||||
|
|
||||||
auto url = wxString(L"https://www.orcaslicer.com/wiki/"); // Orca: neutral wiki link (vendor URL removed)
|
auto url = wxString(L"https://www.orcaslicer.com/wiki/"); // Orca: neutral wiki link (vendor URL removed)
|
||||||
@@ -155,6 +184,37 @@ void CameraPopup::sdcard_absent_hint()
|
|||||||
GetEventHandler()->ProcessEvent(evt);
|
GetEventHandler()->ProcessEvent(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CameraPopup::on_camera_source_changed(wxCommandEvent &event)
|
||||||
|
{
|
||||||
|
if (m_obj && !m_custom_camera_input->GetTextCtrl()->IsEmpty()) {
|
||||||
|
handle_camera_source_change();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraPopup::handle_camera_source_change()
|
||||||
|
{
|
||||||
|
m_custom_camera_enabled = !m_custom_camera_enabled;
|
||||||
|
|
||||||
|
set_custom_cam_button_state(m_custom_camera_enabled);
|
||||||
|
|
||||||
|
wxGetApp().app_config->set("camera", "custom_source", m_custom_camera_input->GetTextCtrl()->GetValue().ToStdString());
|
||||||
|
wxGetApp().app_config->set("camera", "enable_custom_source", m_custom_camera_enabled);
|
||||||
|
|
||||||
|
wxCommandEvent evt(EVT_CAM_SOURCE_CHANGE);
|
||||||
|
evt.SetEventObject(this);
|
||||||
|
GetEventHandler()->ProcessEvent(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraPopup::set_custom_cam_button_state(bool state)
|
||||||
|
{
|
||||||
|
m_custom_camera_enabled = state;
|
||||||
|
auto stateColour = state ? wxColour(170, 0, 0) : wxColour(38, 166, 154);
|
||||||
|
auto stateText = state ? "Disable" : "Enable";
|
||||||
|
m_custom_camera_input_confirm->SetBackgroundColor(stateColour);
|
||||||
|
m_custom_camera_input_confirm->SetBorderColor(stateColour);
|
||||||
|
m_custom_camera_input_confirm->SetLabel(_L(stateText));
|
||||||
|
}
|
||||||
|
|
||||||
void CameraPopup::on_switch_recording(wxCommandEvent& event)
|
void CameraPopup::on_switch_recording(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
if (!m_obj) return;
|
if (!m_obj) return;
|
||||||
|
|||||||
@@ -15,12 +15,14 @@
|
|||||||
#include "Widgets/SwitchButton.hpp"
|
#include "Widgets/SwitchButton.hpp"
|
||||||
#include "Widgets/RadioBox.hpp"
|
#include "Widgets/RadioBox.hpp"
|
||||||
#include "Widgets/PopupWindow.hpp"
|
#include "Widgets/PopupWindow.hpp"
|
||||||
|
#include "Widgets/TextInput.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
wxDECLARE_EVENT(EVT_VCAMERA_SWITCH, wxMouseEvent);
|
wxDECLARE_EVENT(EVT_VCAMERA_SWITCH, wxMouseEvent);
|
||||||
wxDECLARE_EVENT(EVT_SDCARD_ABSENT_HINT, wxCommandEvent);
|
wxDECLARE_EVENT(EVT_SDCARD_ABSENT_HINT, wxCommandEvent);
|
||||||
|
wxDECLARE_EVENT(EVT_CAM_SOURCE_CHANGE, wxCommandEvent);
|
||||||
|
|
||||||
class CameraPopup : public PopupWindow
|
class CameraPopup : public PopupWindow
|
||||||
{
|
{
|
||||||
@@ -51,6 +53,9 @@ protected:
|
|||||||
void on_switch_recording(wxCommandEvent& event);
|
void on_switch_recording(wxCommandEvent& event);
|
||||||
void on_set_resolution();
|
void on_set_resolution();
|
||||||
void sdcard_absent_hint();
|
void sdcard_absent_hint();
|
||||||
|
void on_camera_source_changed(wxCommandEvent& event);
|
||||||
|
void handle_camera_source_change();
|
||||||
|
void set_custom_cam_button_state(bool state);
|
||||||
|
|
||||||
wxWindow * create_item_radiobox(wxString title, wxWindow *parent, wxString tooltip, int padding_left);
|
wxWindow * create_item_radiobox(wxString title, wxWindow *parent, wxString tooltip, int padding_left);
|
||||||
void select_curr_radiobox(int btn_idx);
|
void select_curr_radiobox(int btn_idx);
|
||||||
@@ -71,10 +76,10 @@ private:
|
|||||||
wxStaticText* m_text_liveview_retry;
|
wxStaticText* m_text_liveview_retry;
|
||||||
SwitchButton* m_switch_liveview_retry;
|
SwitchButton* m_switch_liveview_retry;
|
||||||
#endif //BBL_RELEASE_TO_PUBLIC
|
#endif //BBL_RELEASE_TO_PUBLIC
|
||||||
// wxStaticText* m_custom_camera_hint;
|
wxStaticText* m_custom_camera_hint;
|
||||||
// TextInput* m_custom_camera_input;
|
TextInput* m_custom_camera_input;
|
||||||
// Button* m_custom_camera_input_confirm;
|
Button* m_custom_camera_input_confirm;
|
||||||
// bool m_custom_camera_enabled{ false };
|
bool m_custom_camera_enabled{ false };
|
||||||
wxStaticText* m_text_resolution;
|
wxStaticText* m_text_resolution;
|
||||||
wxWindow* m_resolution_options[RESOLUTION_OPTIONS_NUM];
|
wxWindow* m_resolution_options[RESOLUTION_OPTIONS_NUM];
|
||||||
wxScrolledWindow *m_panel;
|
wxScrolledWindow *m_panel;
|
||||||
|
|||||||
@@ -171,16 +171,14 @@ void ConfigManipulation::check_adaptive_pressure_advance_model(DynamicPrintConfi
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
const auto* model = config->option<ConfigOptionStrings>("adaptive_pressure_advance_model");
|
const auto* model = config->option<ConfigOptionStrings>("adaptive_pressure_advance_model");
|
||||||
if (model == nullptr)
|
if (model == nullptr || model->values.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Each extruder variant holds its own model.
|
std::string raw_model;
|
||||||
std::string error;
|
for (const std::string& chunk : model->values)
|
||||||
for (const std::string& variant_model : model->values) {
|
raw_model += chunk;
|
||||||
error = AdaptivePAProcessor::validate_adaptive_pa_model(variant_model);
|
|
||||||
if (!error.empty())
|
std::string error = AdaptivePAProcessor::validate_adaptive_pa_model(raw_model);
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!error.empty()) {
|
if (!error.empty()) {
|
||||||
wxString msg_text = _L("Adaptive Pressure Advance model validation failed:\n");
|
wxString msg_text = _L("Adaptive Pressure Advance model validation failed:\n");
|
||||||
msg_text += from_u8(error);
|
msg_text += from_u8(error);
|
||||||
|
|||||||
@@ -35,9 +35,7 @@ ConnectPrinterDialog::ConnectPrinterDialog(wxWindow *parent, wxWindowID id, cons
|
|||||||
sizer_connect = new wxBoxSizer(wxHORIZONTAL);
|
sizer_connect = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
|
||||||
m_textCtrl_code = new TextInput(this, wxEmptyString);
|
m_textCtrl_code = new TextInput(this, wxEmptyString);
|
||||||
// OrcaSonar uses a 12-character base32 access code. Keep this field long
|
m_textCtrl_code->GetTextCtrl()->SetMaxLength(10);
|
||||||
// enough for it while retaining the existing validation for LAN codes.
|
|
||||||
m_textCtrl_code->GetTextCtrl()->SetMaxLength(12);
|
|
||||||
m_textCtrl_code->SetFont(Label::Body_14);
|
m_textCtrl_code->SetFont(Label::Body_14);
|
||||||
m_textCtrl_code->SetCornerRadius(FromDIP(5));
|
m_textCtrl_code->SetCornerRadius(FromDIP(5));
|
||||||
m_textCtrl_code->SetSize(wxSize(FromDIP(330), FromDIP(40)));
|
m_textCtrl_code->SetSize(wxSize(FromDIP(330), FromDIP(40)));
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#include "DevConfigUtil.h"
|
#include "DevConfigUtil.h"
|
||||||
|
|
||||||
#include "slic3r/GUI/DeviceManager.hpp"
|
|
||||||
|
|
||||||
#include <wx/dir.h>
|
#include <wx/dir.h>
|
||||||
#include <boost/filesystem/operations.hpp>
|
#include <boost/filesystem/operations.hpp>
|
||||||
#include "../I18N.hpp"
|
#include "../I18N.hpp"
|
||||||
@@ -43,19 +41,6 @@ static void _toolhead_translation_markers()
|
|||||||
|
|
||||||
std::string DevPrinterConfigUtil::m_resource_file_path = "";
|
std::string DevPrinterConfigUtil::m_resource_file_path = "";
|
||||||
|
|
||||||
bool DevPrinterConfigUtil::is_printer_model_compatible(const std::string& source_model, MachineObject& machine)
|
|
||||||
{
|
|
||||||
const std::string& target_model = machine.printer_type;
|
|
||||||
if (is_optional_printer_model_id(source_model) || is_optional_printer_model_id(target_model))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (source_model == target_model)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
const auto compatible_machine = machine.get_compatible_machine();
|
|
||||||
return std::find(compatible_machine.begin(), compatible_machine.end(), source_model) != compatible_machine.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::map<std::string, std::string> DevPrinterConfigUtil::get_all_model_id_with_name()
|
std::map<std::string, std::string> DevPrinterConfigUtil::get_all_model_id_with_name()
|
||||||
{
|
{
|
||||||
@@ -420,4 +405,4 @@ std::string DevPrinterConfigUtil::get_toolhead_display_name(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -25,8 +25,6 @@
|
|||||||
namespace Slic3r
|
namespace Slic3r
|
||||||
{
|
{
|
||||||
|
|
||||||
class MachineObject;
|
|
||||||
|
|
||||||
/// Toolhead component type (extruder / nozzle / hotend)
|
/// Toolhead component type (extruder / nozzle / hotend)
|
||||||
enum class ToolHeadComponent {
|
enum class ToolHeadComponent {
|
||||||
Extruder,
|
Extruder,
|
||||||
@@ -61,10 +59,6 @@ public:
|
|||||||
/*printer*/
|
/*printer*/
|
||||||
// info
|
// info
|
||||||
static std::map<std::string, std::string> get_all_model_id_with_name();
|
static std::map<std::string, std::string> get_all_model_id_with_name();
|
||||||
// A printer agent may not know the physical model. Keep that case optional so
|
|
||||||
// model compatibility checks do not turn missing identity into a hard error.
|
|
||||||
static bool is_printer_model_compatible(const std::string& source_model, MachineObject& machine);
|
|
||||||
static bool is_optional_printer_model_id(const std::string& model_id) { return model_id.empty(); }
|
|
||||||
static std::string get_printer_type(const std::string& type_str) { return get_value_from_config<std::string>(type_str, "printer_type"); }
|
static std::string get_printer_type(const std::string& type_str) { return get_value_from_config<std::string>(type_str, "printer_type"); }
|
||||||
static std::string get_printer_display_name(const std::string& type_str) { return get_value_from_config<std::string>(type_str, "display_name"); }
|
static std::string get_printer_display_name(const std::string& type_str) { return get_value_from_config<std::string>(type_str, "display_name"); }
|
||||||
static std::string get_printer_series_str(std::string type_str) { return get_value_from_config<std::string>(type_str, "printer_series"); }
|
static std::string get_printer_series_str(std::string type_str) { return get_value_from_config<std::string>(type_str, "printer_series"); }
|
||||||
@@ -233,4 +227,4 @@ static std::string _parse_printer_type(const std::string &type_str)
|
|||||||
return type_str;
|
return type_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
};// namespace Slic3r
|
};// namespace Slic3r
|
||||||
@@ -762,9 +762,9 @@ void DevFilaSystemParser::ParseV1_0(const json& jj, MachineObject* obj, DevFilaS
|
|||||||
{
|
{
|
||||||
curr_tray->remain = -1;
|
curr_tray->remain = -1;
|
||||||
}
|
}
|
||||||
// The tray objects are reused across status updates. Reset this
|
if (tray_it->contains("tray_slot_placeholder")) {
|
||||||
// state when a previously empty slot receives a filament again.
|
curr_tray->is_slot_placeholder = true;
|
||||||
curr_tray->is_slot_placeholder = tray_it->contains("tray_slot_placeholder");
|
}
|
||||||
int ams_id_int = 0;
|
int ams_id_int = 0;
|
||||||
int tray_id_int = 0;
|
int tray_id_int = 0;
|
||||||
try
|
try
|
||||||
@@ -999,4 +999,4 @@ void DevFilaSystemParser::ParseAgentFilament(const json& data, MachineObject* ob
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
#include "DevManager.h"
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
|
||||||
#include <libslic3r/AppConfig.hpp>
|
#include "DevManager.h"
|
||||||
#include "CloudProvider.hpp"
|
|
||||||
#include "DevUtil.h"
|
#include "DevUtil.h"
|
||||||
|
|
||||||
// TODO: remove this include
|
// TODO: remove this include
|
||||||
@@ -17,8 +15,6 @@
|
|||||||
|
|
||||||
#include "libslic3r/Time.hpp"
|
#include "libslic3r/Time.hpp"
|
||||||
|
|
||||||
#include "IPrinterAgent.hpp"
|
|
||||||
|
|
||||||
using namespace nlohmann;
|
using namespace nlohmann;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -50,12 +46,10 @@ namespace {
|
|||||||
|
|
||||||
namespace Slic3r
|
namespace Slic3r
|
||||||
{
|
{
|
||||||
DeviceManager::DeviceManager(NetworkAgent* agent, bool enable_refresher, AppConfig* app_config)
|
DeviceManager::DeviceManager(NetworkAgent* agent)
|
||||||
{
|
{
|
||||||
m_agent = agent;
|
m_agent = agent;
|
||||||
m_app_config = app_config;
|
m_refresher = new DeviceManagerRefresher(this);
|
||||||
if (enable_refresher)
|
|
||||||
m_refresher = new DeviceManagerRefresher(this);
|
|
||||||
|
|
||||||
DevPrinterConfigUtil::InitFilePath(resources_dir());
|
DevPrinterConfigUtil::InitFilePath(resources_dir());
|
||||||
|
|
||||||
@@ -66,14 +60,9 @@ namespace Slic3r
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AppConfig* DeviceManager::get_app_config() const
|
|
||||||
{
|
|
||||||
return m_app_config ? m_app_config : GUI::wxGetApp().app_config;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceManager::load_local_machines_from_config()
|
void DeviceManager::load_local_machines_from_config()
|
||||||
{
|
{
|
||||||
AppConfig* config = get_app_config();
|
AppConfig* config = GUI::wxGetApp().app_config;
|
||||||
if (!config)
|
if (!config)
|
||||||
return;
|
return;
|
||||||
const auto local_machines = config->get_local_machines();
|
const auto local_machines = config->get_local_machines();
|
||||||
@@ -99,8 +88,9 @@ namespace Slic3r
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceManager::update_local_machine(const MachineObject& m, AppConfig* config)
|
void DeviceManager::update_local_machine(const MachineObject& m)
|
||||||
{
|
{
|
||||||
|
AppConfig* config = GUI::wxGetApp().app_config;
|
||||||
if (config) {
|
if (config) {
|
||||||
if (m.is_lan_mode_printer()) {
|
if (m.is_lan_mode_printer()) {
|
||||||
if (m.has_access_right()) {
|
if (m.has_access_right()) {
|
||||||
@@ -121,8 +111,7 @@ namespace Slic3r
|
|||||||
|
|
||||||
DeviceManager::~DeviceManager()
|
DeviceManager::~DeviceManager()
|
||||||
{
|
{
|
||||||
if (m_refresher)
|
delete m_refresher;
|
||||||
delete m_refresher;
|
|
||||||
|
|
||||||
for (auto it = localMachineList.begin(); it != localMachineList.end(); it++)
|
for (auto it = localMachineList.begin(); it != localMachineList.end(); it++)
|
||||||
{
|
{
|
||||||
@@ -182,22 +171,14 @@ namespace Slic3r
|
|||||||
return printer_agent ? printer_agent->get_agent_info().id : "";
|
return printer_agent ? printer_agent->get_agent_info().id : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DeviceManager::get_current_cloud_provider() const
|
|
||||||
{
|
|
||||||
const std::string agent_id = get_current_printer_agent_id();
|
|
||||||
if (!agent_id.empty())
|
|
||||||
return agent_id == BBL_PRINTER_AGENT_ID ? BBL_CLOUD_PROVIDER : ORCA_CLOUD_PROVIDER;
|
|
||||||
return GUI::wxGetApp().get_printer_cloud_provider();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceManager::EnableMultiMachine(bool enable)
|
void DeviceManager::EnableMultiMachine(bool enable)
|
||||||
{
|
{
|
||||||
m_agent->enable_multi_machine(enable);
|
m_agent->enable_multi_machine(enable);
|
||||||
m_enable_mutil_machine = enable;
|
m_enable_mutil_machine = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceManager::start_refresher() { if (m_refresher) m_refresher->Start(); }
|
void DeviceManager::start_refresher() { m_refresher->Start(); }
|
||||||
void DeviceManager::stop_refresher() { if (m_refresher) m_refresher->Stop(); }
|
void DeviceManager::stop_refresher() { m_refresher->Stop(); }
|
||||||
|
|
||||||
|
|
||||||
void DeviceManager::keep_alive()
|
void DeviceManager::keep_alive()
|
||||||
@@ -284,10 +265,6 @@ namespace Slic3r
|
|||||||
/* update userMachineList info */
|
/* update userMachineList info */
|
||||||
auto it = userMachineList.find(dev_id);
|
auto it = userMachineList.find(dev_id);
|
||||||
if (it != userMachineList.end()) {
|
if (it != userMachineList.end()) {
|
||||||
// A reused entry may have been created while another printer agent was active.
|
|
||||||
// The response was obtained through the current agent, so move ownership with
|
|
||||||
// the entry; otherwise agent-scoped lists hide it after a preset switch.
|
|
||||||
it->second->printer_agent_id = get_current_printer_agent_id();
|
|
||||||
if (it->second->get_dev_ip() != dev_ip ||
|
if (it->second->get_dev_ip() != dev_ip ||
|
||||||
it->second->bind_state != bind_state ||
|
it->second->bind_state != bind_state ||
|
||||||
it->second->bind_sec_link != sec_link ||
|
it->second->bind_sec_link != sec_link ||
|
||||||
@@ -314,15 +291,10 @@ namespace Slic3r
|
|||||||
|
|
||||||
/* update localMachineList */
|
/* update localMachineList */
|
||||||
it = localMachineList.find(dev_id);
|
it = localMachineList.find(dev_id);
|
||||||
AppConfig* config = get_app_config();
|
|
||||||
|
|
||||||
if (it != localMachineList.end()) {
|
if (it != localMachineList.end()) {
|
||||||
// update properties
|
// update properties
|
||||||
/* ip changed */
|
/* ip changed */
|
||||||
obj = it->second;
|
obj = it->second;
|
||||||
// A reused LAN entry may have been discovered while another printer agent was
|
|
||||||
// active. The current discovery message establishes ownership for this agent.
|
|
||||||
obj->printer_agent_id = get_current_printer_agent_id();
|
|
||||||
|
|
||||||
if (obj->get_dev_ip().compare(dev_ip) != 0) {
|
if (obj->get_dev_ip().compare(dev_ip) != 0) {
|
||||||
if ( connection_name.empty() ) {
|
if ( connection_name.empty() ) {
|
||||||
@@ -412,6 +384,7 @@ namespace Slic3r
|
|||||||
obj->m_is_online = true;
|
obj->m_is_online = true;
|
||||||
|
|
||||||
//load access code
|
//load access code
|
||||||
|
AppConfig* config = Slic3r::GUI::wxGetApp().app_config;
|
||||||
if (config) {
|
if (config) {
|
||||||
obj->set_access_code(get_access_code_with_legacy_fallback(config, dev_id, obj->printer_agent_id), false);
|
obj->set_access_code(get_access_code_with_legacy_fallback(config, dev_id, obj->printer_agent_id), false);
|
||||||
}
|
}
|
||||||
@@ -434,7 +407,7 @@ namespace Slic3r
|
|||||||
fire_lifecycle_event(LifecycleEvent::DeviceDiscovered, ctx);
|
fire_lifecycle_event(LifecycleEvent::DeviceDiscovered, ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
update_local_machine(*obj, config);
|
update_local_machine(*obj);
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
;
|
;
|
||||||
@@ -449,9 +422,6 @@ namespace Slic3r
|
|||||||
auto it = localMachineList.find(machine.dev_id);
|
auto it = localMachineList.find(machine.dev_id);
|
||||||
if (it != localMachineList.end()) {
|
if (it != localMachineList.end()) {
|
||||||
obj = it->second;
|
obj = it->second;
|
||||||
// insert_local_device is called by the active agent, so a reused entry must follow
|
|
||||||
// that agent as well; otherwise the agent-scoped printer list hides it.
|
|
||||||
obj->printer_agent_id = get_current_printer_agent_id();
|
|
||||||
} else {
|
} else {
|
||||||
obj = new MachineObject(this, m_agent, machine.dev_name, machine.dev_id, machine.dev_ip);
|
obj = new MachineObject(this, m_agent, machine.dev_name, machine.dev_id, machine.dev_ip);
|
||||||
obj->printer_agent_id = get_current_printer_agent_id();
|
obj->printer_agent_id = get_current_printer_agent_id();
|
||||||
@@ -469,16 +439,11 @@ namespace Slic3r
|
|||||||
obj->last_alive = Slic3r::Utils::get_current_time_utc();
|
obj->last_alive = Slic3r::Utils::get_current_time_utc();
|
||||||
obj->set_access_code(access_code, false);
|
obj->set_access_code(access_code, false);
|
||||||
|
|
||||||
update_local_machine(*obj, get_app_config());
|
update_local_machine(*obj);
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceManager::update_local_machine(const MachineObject& m)
|
|
||||||
{
|
|
||||||
update_local_machine(m, GUI::wxGetApp().app_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
int DeviceManager::query_bind_status(std::string& msg, const std::string& provider)
|
int DeviceManager::query_bind_status(std::string& msg, const std::string& provider)
|
||||||
{
|
{
|
||||||
if (!m_agent)
|
if (!m_agent)
|
||||||
@@ -549,7 +514,7 @@ namespace Slic3r
|
|||||||
|
|
||||||
MachineObject* DeviceManager::get_my_machine(std::string dev_id)
|
MachineObject* DeviceManager::get_my_machine(std::string dev_id)
|
||||||
{
|
{
|
||||||
auto list = get_my_machine_list(get_current_printer_agent_id());
|
auto list = get_my_machine_list();
|
||||||
auto it = list.find(dev_id);
|
auto it = list.find(dev_id);
|
||||||
if (it != list.end())
|
if (it != list.end())
|
||||||
{
|
{
|
||||||
@@ -586,15 +551,25 @@ namespace Slic3r
|
|||||||
OnSelectedMachineChanged(previous_selected_machine, selected_machine);
|
OnSelectedMachineChanged(previous_selected_machine, selected_machine);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceManager::clear_other_devices()
|
void DeviceManager::clear_other_devices(const std::string& target_agent_id)
|
||||||
{
|
{
|
||||||
// Device entries are now scoped by printer_agent_id when they are presented. Keep
|
// why: on agent swap, keep "My Devices" but drop the transient "Other Devices"
|
||||||
// agent-owned discoveries across a switch so agents without automatic discovery (and
|
// Those belong to the previous agent's network scan; the new agent's start_discovery re-populates its own.
|
||||||
// plugins whose devices have not received an access code yet) do not lose their list.
|
//
|
||||||
// Entries without an owner are legacy/unscoped and cannot safely be shown.
|
// Also drop "My Devices" stamped by a different agent than the one we're swapping to
|
||||||
|
// (target_agent_id, passed by the caller since the live agent hasn't been repointed yet
|
||||||
|
// at this point): otherwise a device first discovered under agent A survives every swap
|
||||||
|
// with a stale printer_agent_id, stays hidden from every agent's filtered list, and only
|
||||||
|
// gets re-tagged if something happens to delete and re-create it (e.g. account logout).
|
||||||
|
// Dropping it here instead lets the new agent's start_discovery re-insert and re-stamp it
|
||||||
|
// like any other fresh device.
|
||||||
|
const auto my = get_my_machine_list();
|
||||||
for (auto it = localMachineList.begin(); it != localMachineList.end();)
|
for (auto it = localMachineList.begin(); it != localMachineList.end();)
|
||||||
{
|
{
|
||||||
if (!it->second || it->second->printer_agent_id.empty())
|
const bool is_my_device = my.find(it->first) != my.end();
|
||||||
|
const bool agent_mismatch = !target_agent_id.empty() && it->second &&
|
||||||
|
it->second->printer_agent_id != target_agent_id;
|
||||||
|
if (!is_my_device || agent_mismatch)
|
||||||
{
|
{
|
||||||
delete it->second;
|
delete it->second;
|
||||||
it = localMachineList.erase(it);
|
it = localMachineList.erase(it);
|
||||||
@@ -610,22 +585,8 @@ namespace Slic3r
|
|||||||
{
|
{
|
||||||
BOOST_LOG_TRIVIAL(info) << "set_selected_machine=" << dev_id
|
BOOST_LOG_TRIVIAL(info) << "set_selected_machine=" << dev_id
|
||||||
<< " cur_selected=" << selected_machine;
|
<< " cur_selected=" << selected_machine;
|
||||||
auto my_machine_list = get_my_machine_list(get_current_printer_agent_id());
|
auto my_machine_list = get_my_machine_list();
|
||||||
auto it = my_machine_list.find(dev_id);
|
auto it = my_machine_list.find(dev_id);
|
||||||
BOOST_LOG_TRIVIAL(trace) << "Orca diagnostic: set_selected_machine lookup dev_id=" << dev_id
|
|
||||||
<< " found=" << (it != my_machine_list.end())
|
|
||||||
<< " my_machine_count=" << my_machine_list.size()
|
|
||||||
<< " current_agent=" << get_current_printer_agent_id()
|
|
||||||
<< " provider=" << GUI::wxGetApp().get_printer_cloud_provider();
|
|
||||||
if (it != my_machine_list.end() && it->second) {
|
|
||||||
BOOST_LOG_TRIVIAL(trace) << "Orca diagnostic: target machine dev_id=" << it->second->get_dev_id()
|
|
||||||
<< " printer_agent_id=" << it->second->printer_agent_id
|
|
||||||
<< " connection_type=" << it->second->connection_type()
|
|
||||||
<< " dev_connection_type=" << it->second->dev_connection_type;
|
|
||||||
} else if (!dev_id.empty()) {
|
|
||||||
BOOST_LOG_TRIVIAL(warning) << "Orca diagnostic: target machine was not found in the current agent's machine list";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// disconnect last if dev_id difference from previous one
|
// disconnect last if dev_id difference from previous one
|
||||||
auto last_selected = my_machine_list.find(selected_machine);
|
auto last_selected = my_machine_list.find(selected_machine);
|
||||||
@@ -636,9 +597,7 @@ namespace Slic3r
|
|||||||
m_agent->disconnect_printer();
|
m_agent->disconnect_printer();
|
||||||
}
|
}
|
||||||
else if (last_selected->second->connection_type() == "cloud") {
|
else if (last_selected->second->connection_type() == "cloud") {
|
||||||
const int result = m_agent->set_user_selected_machine("");
|
m_agent->set_user_selected_machine("");
|
||||||
BOOST_LOG_TRIVIAL(trace) << "Orca diagnostic: cleared previous cloud selection dev_id="
|
|
||||||
<< selected_machine << " result=" << result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -673,7 +632,11 @@ namespace Slic3r
|
|||||||
m_agent->disconnect_printer();
|
m_agent->disconnect_printer();
|
||||||
it->second->reset();
|
it->second->reset();
|
||||||
|
|
||||||
it->second->connect();
|
#if !BBL_RELEASE_TO_PUBLIC
|
||||||
|
it->second->connect(Slic3r::GUI::wxGetApp().app_config->get("enable_ssl_for_mqtt") == "true" ? true : false);
|
||||||
|
#else
|
||||||
|
it->second->connect(it->second->local_use_ssl);
|
||||||
|
#endif
|
||||||
it->second->set_lan_mode_connection_state(true);
|
it->second->set_lan_mode_connection_state(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -686,16 +649,18 @@ namespace Slic3r
|
|||||||
{
|
{
|
||||||
// diff dev_id, cloud => set_user_selected_machine(new)
|
// diff dev_id, cloud => set_user_selected_machine(new)
|
||||||
BOOST_LOG_TRIVIAL(info) << "set_selected_machine: select new cloud machine, dev_id =" << dev_id;
|
BOOST_LOG_TRIVIAL(info) << "set_selected_machine: select new cloud machine, dev_id =" << dev_id;
|
||||||
const int result = m_agent->set_user_selected_machine(dev_id);
|
m_agent->set_user_selected_machine(dev_id);
|
||||||
BOOST_LOG_TRIVIAL(trace) << "Orca diagnostic: set new cloud selection dev_id="
|
|
||||||
<< dev_id << " result=" << result;
|
|
||||||
it->second->reset();
|
it->second->reset();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BOOST_LOG_TRIVIAL(info) << "set_selected_machine: select new lan machine, dev_id =" << dev_id;
|
BOOST_LOG_TRIVIAL(info) << "set_selected_machine: select new lan machine, dev_id =" << dev_id;
|
||||||
it->second->reset();
|
it->second->reset();
|
||||||
it->second->connect();
|
#if !BBL_RELEASE_TO_PUBLIC
|
||||||
|
it->second->connect(Slic3r::GUI::wxGetApp().app_config->get("enable_ssl_for_mqtt") == "true" ? true : false);
|
||||||
|
#else
|
||||||
|
it->second->connect(it->second->local_use_ssl);
|
||||||
|
#endif
|
||||||
it->second->set_lan_mode_connection_state(true);
|
it->second->set_lan_mode_connection_state(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -712,8 +677,6 @@ namespace Slic3r
|
|||||||
|
|
||||||
selected_machine = dev_id;
|
selected_machine = dev_id;
|
||||||
record_user_last_machine(selected_machine);
|
record_user_last_machine(selected_machine);
|
||||||
BOOST_LOG_TRIVIAL(trace) << "Orca diagnostic: DeviceManager selection complete selected_machine="
|
|
||||||
<< selected_machine;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -744,9 +707,7 @@ namespace Slic3r
|
|||||||
dev_list.push_back(it->first);
|
dev_list.push_back(it->first);
|
||||||
BOOST_LOG_TRIVIAL(trace) << "add_user_subscribe: " << it->first;
|
BOOST_LOG_TRIVIAL(trace) << "add_user_subscribe: " << it->first;
|
||||||
}
|
}
|
||||||
const int result = m_agent->add_subscribe(dev_list);
|
m_agent->add_subscribe(dev_list);
|
||||||
BOOST_LOG_TRIVIAL(trace) << "Orca diagnostic: add_user_subscribe count=" << dev_list.size()
|
|
||||||
<< " result=" << result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -759,9 +720,7 @@ namespace Slic3r
|
|||||||
dev_list.push_back(it->first);
|
dev_list.push_back(it->first);
|
||||||
BOOST_LOG_TRIVIAL(trace) << "del_user_subscribe: " << it->first;
|
BOOST_LOG_TRIVIAL(trace) << "del_user_subscribe: " << it->first;
|
||||||
}
|
}
|
||||||
const int result = m_agent->del_subscribe(dev_list);
|
m_agent->del_subscribe(dev_list);
|
||||||
BOOST_LOG_TRIVIAL(trace) << "Orca diagnostic: del_user_subscribe count=" << dev_list.size()
|
|
||||||
<< " result=" << result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceManager::subscribe_device_list(std::vector<std::string> dev_list)
|
void DeviceManager::subscribe_device_list(std::vector<std::string> dev_list)
|
||||||
@@ -880,24 +839,7 @@ namespace Slic3r
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
json j = json::parse(body);
|
json j = json::parse(body);
|
||||||
|
const std::string provider = GUI::wxGetApp().get_printer_cloud_provider();
|
||||||
const bool has_request_context = j.contains("provider") && j.contains("agent_id") && j.contains("generation");
|
|
||||||
const std::string current_provider = get_current_cloud_provider();
|
|
||||||
const std::string provider = j.contains("provider") ? j["provider"].get<std::string>()
|
|
||||||
: current_provider;
|
|
||||||
const std::string agent_id = j.contains("agent_id") ? j["agent_id"].get<std::string>()
|
|
||||||
: get_current_printer_agent_id();
|
|
||||||
const std::uint64_t generation = j.value("generation", std::uint64_t(0));
|
|
||||||
|
|
||||||
if (has_request_context &&
|
|
||||||
(provider != current_provider ||
|
|
||||||
agent_id != get_current_printer_agent_id() ||
|
|
||||||
generation != (m_agent ? m_agent->get_user_machine_list_generation() : 0))) {
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": ignoring stale response provider="
|
|
||||||
<< provider << " agent_id=" << agent_id
|
|
||||||
<< " generation=" << generation;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !BBL_RELEASE_TO_PUBLIC
|
#if !BBL_RELEASE_TO_PUBLIC
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": " << j;
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": " << j;
|
||||||
@@ -920,14 +862,11 @@ namespace Slic3r
|
|||||||
/* update field */
|
/* update field */
|
||||||
obj = iter->second;
|
obj = iter->second;
|
||||||
obj->set_dev_id(dev_id);
|
obj->set_dev_id(dev_id);
|
||||||
// A device can be rediscovered by a different agent after a preset
|
|
||||||
// switch while retaining the same MachineObject instance.
|
|
||||||
obj->printer_agent_id = agent_id;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
obj = new MachineObject(this, m_agent, "", "", "");
|
obj = new MachineObject(this, m_agent, "", "", "");
|
||||||
obj->printer_agent_id = agent_id;
|
obj->printer_agent_id = get_current_printer_agent_id();
|
||||||
if (m_agent)
|
if (m_agent)
|
||||||
{
|
{
|
||||||
obj->set_bind_status(m_agent->get_user_name(provider));
|
obj->set_bind_status(m_agent->get_user_name(provider));
|
||||||
@@ -935,20 +874,13 @@ namespace Slic3r
|
|||||||
|
|
||||||
if (obj->get_dev_ip().empty())
|
if (obj->get_dev_ip().empty())
|
||||||
{
|
{
|
||||||
if (AppConfig* config = get_app_config())
|
obj->get_dev_ip() = Slic3r::GUI::wxGetApp().app_config->get("ip_address", dev_id);
|
||||||
obj->get_dev_ip() = config->get("ip_address", dev_id);
|
|
||||||
}
|
}
|
||||||
userMachineList.insert(std::make_pair(dev_id, obj));
|
userMachineList.insert(std::make_pair(dev_id, obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!obj) continue;
|
if (!obj) continue;
|
||||||
|
|
||||||
// Orca cloud printers are only ever delivered through this REST
|
|
||||||
// account list; tag them so DeviceManager's cloud/lan branches
|
|
||||||
// (subscribe + deselect in set_selected_machine) treat them right.
|
|
||||||
if (provider == ORCA_CLOUD_PROVIDER)
|
|
||||||
obj->dev_connection_type = "cloud";
|
|
||||||
|
|
||||||
if (!elem["dev_id"].is_null())
|
if (!elem["dev_id"].is_null())
|
||||||
obj->set_dev_id(elem["dev_id"].get<std::string>());
|
obj->set_dev_id(elem["dev_id"].get<std::string>());
|
||||||
if (!elem["dev_name"].is_null())
|
if (!elem["dev_name"].is_null())
|
||||||
@@ -980,12 +912,6 @@ namespace Slic3r
|
|||||||
acc_code.erase(std::remove(acc_code.begin(), acc_code.end(), '\n'), acc_code.end());
|
acc_code.erase(std::remove(acc_code.begin(), acc_code.end(), '\n'), acc_code.end());
|
||||||
obj->set_access_code(acc_code);
|
obj->set_access_code(acc_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(trace) << "Orca diagnostic: parsed cloud machine dev_id=" << dev_id
|
|
||||||
<< " name=" << obj->get_dev_name()
|
|
||||||
<< " agent_id=" << obj->printer_agent_id
|
|
||||||
<< " connection_type=" << obj->connection_type()
|
|
||||||
<< " online=" << obj->m_is_online;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//remove MachineObject from userMachineList
|
//remove MachineObject from userMachineList
|
||||||
@@ -1001,9 +927,6 @@ namespace Slic3r
|
|||||||
iterat++;
|
iterat++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BOOST_LOG_TRIVIAL(trace) << "Orca diagnostic: parse_user_print_info complete provider=" << provider
|
|
||||||
<< " parsed_count=" << new_list.size()
|
|
||||||
<< " stored_count=" << userMachineList.size();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
@@ -1020,29 +943,25 @@ namespace Slic3r
|
|||||||
unsigned int http_code;
|
unsigned int http_code;
|
||||||
std::string body;
|
std::string body;
|
||||||
int result = m_agent->get_user_print_info(&http_code, &body, provider);
|
int result = m_agent->get_user_print_info(&http_code, &body, provider);
|
||||||
BOOST_LOG_TRIVIAL(trace) << "Orca diagnostic: get_user_print_info provider=" << provider
|
|
||||||
<< " result=" << result << " http_code=" << http_code
|
|
||||||
<< " body_bytes=" << body.size();
|
|
||||||
if (result == 0)
|
if (result == 0)
|
||||||
{
|
{
|
||||||
// parse_user_print_info and on_machine_alive (SSDP for discovery) both mutate the same userMachineList map.
|
// parse_user_print_info and on_machine_alive (SSDP for discovery) both mutate the same userMachineList map.
|
||||||
// on_machine_alive mutates the map on the UI thread, do the same for parse_user_print_info.
|
// on_machine_alive mutates the map on the UI thread, do the same for parse_user_print_info.
|
||||||
BOOST_LOG_TRIVIAL(trace) << "Orca diagnostic: queueing parse_user_print_info on UI thread";
|
|
||||||
Slic3r::GUI::wxGetApp().CallAfter([this, body]() { parse_user_print_info(body); });
|
Slic3r::GUI::wxGetApp().CallAfter([this, body]() { parse_user_print_info(body); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceManager::record_user_last_machine(const std::string& dev_id)
|
void DeviceManager::record_user_last_machine(const std::string& dev_id)
|
||||||
{
|
{
|
||||||
if (AppConfig* config = get_app_config()) {
|
if (Slic3r::GUI::wxGetApp().app_config) {
|
||||||
config->set("user_last_selected_machine", dev_id);
|
Slic3r::GUI::wxGetApp().app_config->set("user_last_selected_machine", dev_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DeviceManager::get_user_last_machine() const
|
std::string DeviceManager::get_user_last_machine() const
|
||||||
{
|
{
|
||||||
if (AppConfig* config = get_app_config()) {
|
if (Slic3r::GUI::wxGetApp().app_config) {
|
||||||
const auto& user_last_machine = config->get("user_last_selected_machine");
|
const auto& user_last_machine = Slic3r::GUI::wxGetApp().app_config->get("user_last_selected_machine");
|
||||||
if (!user_last_machine.empty()) {
|
if (!user_last_machine.empty()) {
|
||||||
return user_last_machine;
|
return user_last_machine;
|
||||||
} else if (m_agent) {
|
} else if (m_agent) {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ namespace Slic3r
|
|||||||
struct BBLocalMachine;
|
struct BBLocalMachine;
|
||||||
class MachineObject;
|
class MachineObject;
|
||||||
class NetworkAgent;
|
class NetworkAgent;
|
||||||
class AppConfig;
|
|
||||||
|
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
class GUI_App;
|
class GUI_App;
|
||||||
@@ -25,7 +24,6 @@ class DeviceManager
|
|||||||
friend class DeviceManagerRefresher;
|
friend class DeviceManagerRefresher;
|
||||||
private:
|
private:
|
||||||
NetworkAgent* m_agent{ nullptr };
|
NetworkAgent* m_agent{ nullptr };
|
||||||
AppConfig* m_app_config{ nullptr };
|
|
||||||
DeviceManagerRefresher* m_refresher{ nullptr };
|
DeviceManagerRefresher* m_refresher{ nullptr };
|
||||||
|
|
||||||
bool m_enable_mutil_machine = false;
|
bool m_enable_mutil_machine = false;
|
||||||
@@ -37,13 +35,11 @@ private:
|
|||||||
std::map<std::string, MachineObject*> userMachineList; /* dev_id -> MachineObject* cloudMachine of User */
|
std::map<std::string, MachineObject*> userMachineList; /* dev_id -> MachineObject* cloudMachine of User */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DeviceManager(NetworkAgent* agent = nullptr, bool enable_refresher = true,
|
DeviceManager(NetworkAgent* agent = nullptr);
|
||||||
AppConfig* app_config = nullptr);
|
|
||||||
~DeviceManager();
|
~DeviceManager();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NetworkAgent* get_agent() const { return m_agent; }
|
NetworkAgent* get_agent() const { return m_agent; }
|
||||||
AppConfig* get_app_config() const;
|
|
||||||
void set_agent(NetworkAgent* agent);
|
void set_agent(NetworkAgent* agent);
|
||||||
|
|
||||||
void start_refresher();
|
void start_refresher();
|
||||||
@@ -78,9 +74,10 @@ public:
|
|||||||
void erase_user_machine(std::string dev_id) { userMachineList.erase(dev_id); }
|
void erase_user_machine(std::string dev_id) { userMachineList.erase(dev_id); }
|
||||||
void clean_user_info(bool keep_local_selection = false);
|
void clean_user_info(bool keep_local_selection = false);
|
||||||
|
|
||||||
// Retain agent-owned LAN discoveries across a switch; the active-agent list filter keeps
|
// target_agent_id: id of the agent being swapped to (empty = no agent-mismatch check,
|
||||||
// entries from other agents hidden while allowing them to reappear when switched back.
|
// just the original "drop Other Devices" behavior). Pass the incoming agent's id, not the
|
||||||
void clear_other_devices();
|
// live one - this runs before the live agent is repointed.
|
||||||
|
void clear_other_devices(const std::string& target_agent_id = "");
|
||||||
|
|
||||||
void load_last_machine();
|
void load_last_machine();
|
||||||
void update_user_machine_list_info(const std::string& provider);
|
void update_user_machine_list_info(const std::string& provider);
|
||||||
@@ -125,7 +122,6 @@ private:
|
|||||||
|
|
||||||
void keep_alive();
|
void keep_alive();
|
||||||
void check_pushing();
|
void check_pushing();
|
||||||
std::string get_current_cloud_provider() const;
|
|
||||||
|
|
||||||
void OnMachineBindStateChanged(MachineObject* obj, const std::string& new_state);
|
void OnMachineBindStateChanged(MachineObject* obj, const std::string& new_state);
|
||||||
void OnSelectedMachineChanged(const std::string& pre_dev_id, const std::string& new_dev_id);
|
void OnSelectedMachineChanged(const std::string& pre_dev_id, const std::string& new_dev_id);
|
||||||
@@ -138,15 +134,14 @@ public:
|
|||||||
std::string connection_type, std::string bind_state, std::string version,
|
std::string connection_type, std::string bind_state, std::string version,
|
||||||
std::string access_code);
|
std::string access_code);
|
||||||
static void update_local_machine(const MachineObject& m);
|
static void update_local_machine(const MachineObject& m);
|
||||||
static void update_local_machine(const MachineObject& m, AppConfig* config);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DeviceManagerRefresher : public wxObject
|
class DeviceManagerRefresher : public wxObject
|
||||||
{
|
{
|
||||||
wxTimer* m_timer{nullptr};
|
wxTimer* m_timer{ nullptr };
|
||||||
int m_timer_interval_msec = 5000;
|
int m_timer_interval_msec = 5000;
|
||||||
|
|
||||||
DeviceManager* m_manager{nullptr};
|
DeviceManager* m_manager{ nullptr };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DeviceManagerRefresher(DeviceManager* manger);
|
DeviceManagerRefresher(DeviceManager* manger);
|
||||||
@@ -159,4 +154,4 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
virtual void on_timer(wxTimerEvent& event);
|
virtual void on_timer(wxTimerEvent& event);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
#include "libslic3r/Time.hpp"
|
#include "libslic3r/Time.hpp"
|
||||||
#include "libslic3r/Thread.hpp"
|
#include "libslic3r/Thread.hpp"
|
||||||
#include "slic3r/Utils/Http.hpp"
|
|
||||||
#include "slic3r/Utils/NetworkAgent.hpp"
|
#include "slic3r/Utils/NetworkAgent.hpp"
|
||||||
#include "slic3r/plugin/PluginManager.hpp"
|
#include "slic3r/plugin/PluginManager.hpp"
|
||||||
#include "slic3r/Utils/NetworkAgentFactory.hpp"
|
#include "slic3r/Utils/NetworkAgentFactory.hpp"
|
||||||
@@ -18,7 +17,6 @@
|
|||||||
#include "ReleaseNote.hpp"
|
#include "ReleaseNote.hpp"
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <charconv>
|
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
#include <boost/typeof/typeof.hpp>
|
#include <boost/typeof/typeof.hpp>
|
||||||
@@ -56,7 +54,6 @@
|
|||||||
#include "DeviceCore/DevStatus.h"
|
#include "DeviceCore/DevStatus.h"
|
||||||
#include "DeviceCore/DevUpgrade.h"
|
#include "DeviceCore/DevUpgrade.h"
|
||||||
|
|
||||||
#include "IPrinterAgent.hpp"
|
|
||||||
|
|
||||||
#define CALI_DEBUG
|
#define CALI_DEBUG
|
||||||
#define MINUTE_30 1800000 //ms
|
#define MINUTE_30 1800000 //ms
|
||||||
@@ -383,22 +380,8 @@ NozzleVolumeType convert_to_nozzle_type(const std::string &str)
|
|||||||
wxString MachineObject::get_printer_type_display_str() const
|
wxString MachineObject::get_printer_type_display_str() const
|
||||||
{
|
{
|
||||||
std::string display_name = DevPrinterConfigUtil::get_printer_display_name(printer_type);
|
std::string display_name = DevPrinterConfigUtil::get_printer_display_name(printer_type);
|
||||||
|
|
||||||
// Bambu printers use m_resource_file_path + "/printers/" + type_str + ".json", which is a semantic that only works for their profiles.
|
|
||||||
// For any other profile, we can simply consult preset bundle if the model_id exists.
|
|
||||||
if (display_name.empty()) {
|
|
||||||
for (const auto& [vendor_id, vendor] : GUI::wxGetApp().preset_bundle->vendors) {
|
|
||||||
for (const auto& model : vendor.models) {
|
|
||||||
if (printer_type == model.model_id)
|
|
||||||
display_name = model.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!display_name.empty())
|
if (!display_name.empty())
|
||||||
return display_name;
|
return display_name;
|
||||||
else if (printer_type == "orcasonar")
|
|
||||||
return "OrcaSonar Printer";
|
|
||||||
else
|
else
|
||||||
return _L("Unknown");
|
return _L("Unknown");
|
||||||
}
|
}
|
||||||
@@ -485,7 +468,7 @@ void MachineObject::set_access_code(std::string code, bool only_refresh)
|
|||||||
{
|
{
|
||||||
this->access_code = code;
|
this->access_code = code;
|
||||||
if (only_refresh) {
|
if (only_refresh) {
|
||||||
AppConfig* config = m_manager ? m_manager->get_app_config() : GUI::wxGetApp().app_config;
|
AppConfig* config = GUI::wxGetApp().app_config;
|
||||||
if (config) {
|
if (config) {
|
||||||
if (is_lan_mode_printer()) {
|
if (is_lan_mode_printer()) {
|
||||||
// why: LAN codes are scoped via BBLocalMachine::access_code, keyed by dev_id and
|
// why: LAN codes are scoped via BBLocalMachine::access_code, keyed by dev_id and
|
||||||
@@ -498,7 +481,7 @@ void MachineObject::set_access_code(std::string code, bool only_refresh)
|
|||||||
// fresh from the cloud API's current response, so there's no cross-agent leakage
|
// fresh from the cloud API's current response, so there's no cross-agent leakage
|
||||||
// risk to guard against there.
|
// risk to guard against there.
|
||||||
if (!code.empty()) {
|
if (!code.empty()) {
|
||||||
DeviceManager::update_local_machine(*this, config);
|
DeviceManager::update_local_machine(*this);
|
||||||
} else {
|
} else {
|
||||||
// Only patch an existing record's code - don't persist a brand-new
|
// Only patch an existing record's code - don't persist a brand-new
|
||||||
// never-bound entry just because set_access_code("") was called on it.
|
// never-bound entry just because set_access_code("") was called on it.
|
||||||
@@ -1365,6 +1348,7 @@ int MachineObject::command_get_access_code() {
|
|||||||
return this->publish_json(j);
|
return this->publish_json(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int MachineObject::command_request_push_all(bool request_now)
|
int MachineObject::command_request_push_all(bool request_now)
|
||||||
{
|
{
|
||||||
auto curr_time = std::chrono::system_clock::now();
|
auto curr_time = std::chrono::system_clock::now();
|
||||||
@@ -1496,20 +1480,26 @@ int MachineObject::command_upgrade_module(std::string url, std::string module_ty
|
|||||||
|
|
||||||
int MachineObject::command_xyz_abs()
|
int MachineObject::command_xyz_abs()
|
||||||
{
|
{
|
||||||
if (!m_agent) return -1;
|
return this->publish_gcode("G90 \n");
|
||||||
return command_with_dialog(m_agent->command_xyz_abs(get_dev_id(), MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int MachineObject::command_auto_leveling()
|
int MachineObject::command_auto_leveling()
|
||||||
{
|
{
|
||||||
if (!m_agent) return -1;
|
return this->publish_gcode("G29 \n");
|
||||||
return command_with_dialog(m_agent->command_auto_leveling(get_dev_id(), MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int MachineObject::command_go_home()
|
int MachineObject::command_go_home()
|
||||||
{
|
{
|
||||||
if (!m_agent) return -1;
|
if (m_support_mqtt_homing)
|
||||||
return command_with_dialog(m_agent->command_go_home(get_dev_id(), this->is_in_printing(), m_support_mqtt_homing, MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
{
|
||||||
|
json j;
|
||||||
|
j["print"]["command"] = "back_to_center";
|
||||||
|
j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
|
||||||
|
return this->publish_json(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// gcode command
|
||||||
|
return this->is_in_printing() ? this->publish_gcode("G28 X\n") : this->publish_gcode("G28 \n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int MachineObject::command_task_partskip(std::vector<int> part_ids)
|
int MachineObject::command_task_partskip(std::vector<int> part_ids)
|
||||||
@@ -1631,14 +1621,23 @@ int MachineObject::command_stop_buzzer()
|
|||||||
|
|
||||||
int MachineObject::command_set_bed(int temp)
|
int MachineObject::command_set_bed(int temp)
|
||||||
{
|
{
|
||||||
if (!m_agent) return -1;
|
if (m_support_mqtt_bet_ctrl)
|
||||||
return command_with_dialog(m_agent->command_set_bed(get_dev_id(), temp, m_support_mqtt_bet_ctrl, MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
{
|
||||||
|
json j;
|
||||||
|
j["print"]["command"] = "set_bed_temp";
|
||||||
|
j["print"]["temp"] = temp;
|
||||||
|
j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
|
||||||
|
return this->publish_json(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gcode_str = (boost::format("M140 S%1%\n") % temp).str();
|
||||||
|
return this->publish_gcode(gcode_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MachineObject::command_set_nozzle(int temp)
|
int MachineObject::command_set_nozzle(int temp)
|
||||||
{
|
{
|
||||||
if (!m_agent) return -1;
|
std::string gcode_str = (boost::format("M104 S%1%\n") % temp).str();
|
||||||
return command_with_dialog(m_agent->command_set_nozzle(get_dev_id(), temp, MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
return this->publish_gcode(gcode_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MachineObject::command_set_nozzle_new(int nozzle_id, int temp)
|
int MachineObject::command_set_nozzle_new(int nozzle_id, int temp)
|
||||||
@@ -1743,8 +1742,9 @@ int MachineObject::command_ams_user_settings(bool start_read_opt, bool tray_read
|
|||||||
|
|
||||||
int MachineObject::command_ams_calibrate(int ams_id)
|
int MachineObject::command_ams_calibrate(int ams_id)
|
||||||
{
|
{
|
||||||
if (!m_agent) return -1;
|
std::string gcode_cmd = (boost::format("M620 C%1% \n") % ams_id).str();
|
||||||
return command_with_dialog(m_agent->command_ams_calibrate(get_dev_id(), ams_id, MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode_cmd;
|
||||||
|
return this->publish_gcode(gcode_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MachineObject::command_ams_filament_settings(int ams_id, int slot_id, std::string filament_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max)
|
int MachineObject::command_ams_filament_settings(int ams_id, int slot_id, std::string filament_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max)
|
||||||
@@ -1780,23 +1780,29 @@ int MachineObject::command_ams_filament_settings(int ams_id, int slot_id, std::s
|
|||||||
return this->publish_json(j);
|
return this->publish_json(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MachineObject::command_ams_refresh_rfid(int ams_id, int slot_id)
|
int MachineObject::command_ams_refresh_rfid(std::string tray_id)
|
||||||
{
|
{
|
||||||
if (!m_agent) return -1;
|
std::string gcode_cmd = (boost::format("M620 R%1% \n") % tray_id).str();
|
||||||
return command_with_dialog(m_agent->command_ams_refresh_rfid(get_dev_id(), ams_id, slot_id, MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode_cmd;
|
||||||
|
return this->publish_gcode(gcode_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MachineObject::command_start_camera()
|
int MachineObject::command_ams_refresh_rfid2(int ams_id, int slot_id)
|
||||||
{
|
{
|
||||||
if (!m_agent) return -1;
|
json j;
|
||||||
return m_agent->command_start_camera(get_dev_id());
|
j["print"]["command"] = "ams_get_rfid";
|
||||||
|
j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
|
||||||
|
j["print"]["ams_id"] = ams_id;
|
||||||
|
j["print"]["slot_id"] = slot_id;
|
||||||
|
return this->publish_json(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int MachineObject::command_ams_select_tray(std::string tray_id)
|
int MachineObject::command_ams_select_tray(std::string tray_id)
|
||||||
{
|
{
|
||||||
if (!m_agent) return -1;
|
std::string gcode_cmd = (boost::format("M620 P%1% \n") % tray_id).str();
|
||||||
return command_with_dialog(m_agent->command_ams_select_tray(get_dev_id(), tray_id, MachineObject::m_sequence_id++, is_lan_mode_printer()));
|
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode_cmd;
|
||||||
|
return this->publish_gcode(gcode_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MachineObject::command_ams_control(std::string action)
|
int MachineObject::command_ams_control(std::string action)
|
||||||
@@ -1955,10 +1961,47 @@ int MachineObject::command_ams_air_print_detect(bool air_print_detect)
|
|||||||
|
|
||||||
int MachineObject::command_axis_control(std::string axis, double unit, double input_val, int speed)
|
int MachineObject::command_axis_control(std::string axis, double unit, double input_val, int speed)
|
||||||
{
|
{
|
||||||
if (!m_agent) return -1;
|
if (m_support_mqtt_axis_control)
|
||||||
return command_with_dialog(m_agent->command_axis_control(get_dev_id(), axis, unit, input_val, speed, is_core_xy(),
|
{
|
||||||
m_support_mqtt_axis_control, MachineObject::m_sequence_id++,
|
int dir = input_val > 0 ? 1 : -1;
|
||||||
is_lan_mode_printer()));
|
// i3-arch printers move the bed for Y/Z, so the on-screen direction is
|
||||||
|
// reversed — same negation the g-code fallback below applies.
|
||||||
|
if (!is_core_xy() && (axis.compare("Y") == 0 || axis.compare("Z") == 0)) {
|
||||||
|
dir = -dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
json j;
|
||||||
|
j["print"]["command"] = "xyz_ctrl";
|
||||||
|
j["print"]["axis"] = axis;
|
||||||
|
j["print"]["dir"] = dir;
|
||||||
|
j["print"]["mode"] = (std::abs(input_val) >= 10) ? 1 : 0;
|
||||||
|
j["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
|
||||||
|
return this->publish_json(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
double value = input_val;
|
||||||
|
if (!is_core_xy()) {
|
||||||
|
if ( axis.compare("Y") == 0
|
||||||
|
|| axis.compare("Z") == 0) {
|
||||||
|
value = -1.0 * input_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char cmd[256];
|
||||||
|
if (axis.compare("X") == 0
|
||||||
|
|| axis.compare("Y") == 0
|
||||||
|
|| axis.compare("Z") == 0) {
|
||||||
|
sprintf(cmd, "M211 S \nM211 X1 Y1 Z1\nM1002 push_ref_mode\nG91 \nG1 %s%0.1f F%d\nM1002 pop_ref_mode\nM211 R\n", axis.c_str(), value * unit, speed);
|
||||||
|
}
|
||||||
|
else if (axis.compare("E") == 0) {
|
||||||
|
sprintf(cmd, "M83 \nG0 %s%0.1f F%d\n", axis.c_str(), value * unit, speed);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return this->publish_gcode(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MachineObject::command_extruder_control(int nozzle_id, double val)
|
int MachineObject::command_extruder_control(int nozzle_id, double val)
|
||||||
@@ -2583,12 +2626,7 @@ void MachineObject::reset()
|
|||||||
vt_slot.erase(vt_slot.begin() + 1);
|
vt_slot.erase(vt_slot.begin() + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// why: reset reuses MachineObject, so release its lazy subtask
|
subtask_ = nullptr;
|
||||||
// before dropping the pointer to prevent reconnect leaks.
|
|
||||||
if (subtask_) {
|
|
||||||
delete subtask_;
|
|
||||||
subtask_ = nullptr;
|
|
||||||
}
|
|
||||||
has_extra_flow_type = false;
|
has_extra_flow_type = false;
|
||||||
m_partskip_ids.clear();
|
m_partskip_ids.clear();
|
||||||
}
|
}
|
||||||
@@ -2606,63 +2644,15 @@ void MachineObject::set_print_state(std::string status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// why: printer agents can report progress without BBL cloud task identity.
|
int MachineObject::connect(bool use_openssl)
|
||||||
void MachineObject::update_print_progress(const json& value)
|
|
||||||
{
|
|
||||||
if (value.is_string()) {
|
|
||||||
const std::string progress = value.get<std::string>();
|
|
||||||
int parsed_progress;
|
|
||||||
const auto result = std::from_chars(progress.data(), progress.data() + progress.size(), parsed_progress);
|
|
||||||
if (result.ec != std::errc{} || result.ptr != progress.data() + progress.size())
|
|
||||||
return;
|
|
||||||
mc_print_percent = parsed_progress;
|
|
||||||
} else if (value.is_number_integer())
|
|
||||||
mc_print_percent = value.get<int>();
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (BBLSubTask* curr_task = get_subtask())
|
|
||||||
curr_task->task_progress = mc_print_percent;
|
|
||||||
}
|
|
||||||
|
|
||||||
int MachineObject::connect()
|
|
||||||
{
|
{
|
||||||
if (get_dev_ip().empty()) return -1;
|
if (get_dev_ip().empty()) return -1;
|
||||||
std::string username = m_agent ? m_agent->default_lan_username() : std::string();
|
std::string username = "bblp";
|
||||||
std::string password = get_access_code();
|
std::string password = get_access_code();
|
||||||
|
|
||||||
std::string port;
|
|
||||||
std::string input = get_dev_ip();
|
|
||||||
|
|
||||||
const bool use_ssl = input.rfind("https", 0) == 0;
|
|
||||||
|
|
||||||
// This strips out the http/https prefix
|
|
||||||
std::string host = Http::get_host_from_url(input, &port);
|
|
||||||
std::string ca_file;
|
|
||||||
|
|
||||||
if (GUI::wxGetApp().preset_bundle) {
|
|
||||||
const auto& config = GUI::wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
|
||||||
if (port.empty())
|
|
||||||
port = config.opt_string("printhost_port");
|
|
||||||
ca_file = config.opt_string("printhost_cafile");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (host.empty())
|
|
||||||
host = get_dev_ip();
|
|
||||||
|
|
||||||
|
|
||||||
if (m_agent) {
|
if (m_agent) {
|
||||||
try {
|
try {
|
||||||
PrinterConnectionParams params{
|
return m_agent->connect_printer(get_dev_id(), get_dev_ip(), username, password, use_openssl);
|
||||||
get_dev_id(),
|
|
||||||
host,
|
|
||||||
port,
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
use_ssl,
|
|
||||||
ca_file
|
|
||||||
};
|
|
||||||
return m_agent->connect_printer(params);
|
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@@ -2778,14 +2768,6 @@ int MachineObject::publish_json(const json& json_item, int qos, int flag)
|
|||||||
BOOST_LOG_TRIVIAL(error) << "publish_json: " << json_item.dump() << " code: " << rtn;
|
BOOST_LOG_TRIVIAL(error) << "publish_json: " << json_item.dump() << " code: " << rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
// why: the agent is the only thing that knows what it can translate, so it reports
|
|
||||||
// not-supported in its return value and this - the single funnel every command_* builder
|
|
||||||
// passes through - is the one place that turns it into something the user sees. No list of
|
|
||||||
// unsupported commands is needed anywhere: an agent that has no case for a command says so.
|
|
||||||
if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE) {
|
|
||||||
show_unsupported_dlg(rtn);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3104,13 +3086,6 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
|
|||||||
}
|
}
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
|
|
||||||
try {
|
|
||||||
if (j.contains("info"))
|
|
||||||
parse_new_info2(j["info"]);
|
|
||||||
} catch (...) {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "parse_json: failed to parse OrcaSonar capability info";
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (auto ptr = m_fila_system->GetAmsFirmwareSwitch().lock()) {
|
if (auto ptr = m_fila_system->GetAmsFirmwareSwitch().lock()) {
|
||||||
ptr->ParseFirmwareSwitch(j);
|
ptr->ParseFirmwareSwitch(j);
|
||||||
@@ -3363,7 +3338,10 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
|
|||||||
print_type = jj["print_type"].get<std::string>();
|
print_type = jj["print_type"].get<std::string>();
|
||||||
}
|
}
|
||||||
if (jj.contains("mc_percent")) {
|
if (jj.contains("mc_percent")) {
|
||||||
update_print_progress(jj["mc_percent"]);
|
if (jj["mc_percent"].is_string())
|
||||||
|
mc_print_percent = stoi(j["print"]["mc_percent"].get<std::string>());
|
||||||
|
else if (jj["mc_percent"].is_number_integer())
|
||||||
|
mc_print_percent = j["print"]["mc_percent"].get<int>();
|
||||||
}
|
}
|
||||||
if (jj.contains("mc_print_sub_stage")) {
|
if (jj.contains("mc_print_sub_stage")) {
|
||||||
if (jj["mc_print_sub_stage"].is_number_integer())
|
if (jj["mc_print_sub_stage"].is_number_integer())
|
||||||
@@ -3533,9 +3511,6 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
|
|||||||
this->task_id_ = jj["task_id"].get<std::string>();
|
this->task_id_ = jj["task_id"].get<std::string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jj.contains("thumbnail_url") && jj["thumbnail_url"].is_string())
|
|
||||||
m_agent_thumbnail_url = jj["thumbnail_url"].get<std::string>();
|
|
||||||
|
|
||||||
if (jj.contains("job_attr")) {
|
if (jj.contains("job_attr")) {
|
||||||
int jobAttr = jj["job_attr"].get<int>();
|
int jobAttr = jj["job_attr"].get<int>();
|
||||||
jobState_ = get_flag_bits(jobAttr, 4, 4);
|
jobState_ = get_flag_bits(jobAttr, 4, 4);
|
||||||
@@ -3581,6 +3556,7 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
|
|||||||
update_slice_info(jj["project_id"].get<std::string>(), jj["profile_id"].get<std::string>(), jj["subtask_id"].get<std::string>(), plate_index);
|
update_slice_info(jj["project_id"].get<std::string>(), jj["profile_id"].get<std::string>(), jj["subtask_id"].get<std::string>(), plate_index);
|
||||||
BBLSubTask* curr_task = get_subtask();
|
BBLSubTask* curr_task = get_subtask();
|
||||||
if (curr_task) {
|
if (curr_task) {
|
||||||
|
curr_task->task_progress = mc_print_percent;
|
||||||
curr_task->printing_status = print_status;
|
curr_task->printing_status = print_status;
|
||||||
curr_task->task_id = jj["subtask_id"].get<std::string>();
|
curr_task->task_id = jj["subtask_id"].get<std::string>();
|
||||||
}
|
}
|
||||||
@@ -3883,7 +3859,6 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
|
|||||||
has_ipcam = true;
|
has_ipcam = true;
|
||||||
} else {
|
} else {
|
||||||
has_ipcam = false;
|
has_ipcam = false;
|
||||||
webcam_stream_url.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ipcam.contains("resolution")) {
|
if (ipcam.contains("resolution")) {
|
||||||
@@ -3918,9 +3893,6 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
|
|||||||
liveview_local = local_rtsp_url.empty() ? LVL_None : local_rtsp_url == "disable"
|
liveview_local = local_rtsp_url.empty() ? LVL_None : local_rtsp_url == "disable"
|
||||||
? LVL_Disable : boost::algorithm::starts_with(local_rtsp_url, "rtsps") ? LVL_Rtsps : LVL_Rtsp;
|
? LVL_Disable : boost::algorithm::starts_with(local_rtsp_url, "rtsps") ? LVL_Rtsps : LVL_Rtsp;
|
||||||
}
|
}
|
||||||
if (ipcam.contains("stream_url") && ipcam["stream_url"].is_string()) {
|
|
||||||
webcam_stream_url = ipcam["stream_url"].get<std::string>();
|
|
||||||
}
|
|
||||||
if (ipcam.contains("tutk_server")) {
|
if (ipcam.contains("tutk_server")) {
|
||||||
tutk_state = ipcam["tutk_server"].get<std::string>();
|
tutk_state = ipcam["tutk_server"].get<std::string>();
|
||||||
}
|
}
|
||||||
@@ -4679,7 +4651,7 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
|
|||||||
if (diff.count() > 10.0f) {
|
if (diff.count() > 10.0f) {
|
||||||
BOOST_LOG_TRIVIAL(trace) << "parse_json timeout = " << diff.count();
|
BOOST_LOG_TRIVIAL(trace) << "parse_json timeout = " << diff.count();
|
||||||
}
|
}
|
||||||
DeviceManager::update_local_machine(*this, m_manager ? m_manager->get_app_config() : GUI::wxGetApp().app_config);
|
DeviceManager::update_local_machine(*this);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -5488,86 +5460,6 @@ void MachineObject::parse_new_info(json print)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MachineObject::parse_new_info2(const json& info)
|
|
||||||
{
|
|
||||||
if (!info.is_object() || info.value("command", "") != "get_capabilities")
|
|
||||||
return;
|
|
||||||
|
|
||||||
const auto capabilities_it = info.find("capabilities");
|
|
||||||
if (capabilities_it == info.end() || !capabilities_it->is_object())
|
|
||||||
return;
|
|
||||||
const auto flags_it = capabilities_it->find("flags");
|
|
||||||
if (flags_it == capabilities_it->end() || !flags_it->is_object())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const json& flags = *flags_it;
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "parse_new_info2: OrcaSonar capability flags=" << flags.dump();
|
|
||||||
|
|
||||||
auto parse_bool = [&flags](const char* name, bool& target) {
|
|
||||||
const auto it = flags.find(name);
|
|
||||||
if (it != flags.end() && it->is_boolean())
|
|
||||||
target = it->get<bool>();
|
|
||||||
};
|
|
||||||
|
|
||||||
parse_bool("support_send_to_sd", is_support_send_to_sdcard);
|
|
||||||
parse_bool("support_filament_backup", is_support_filament_backup);
|
|
||||||
parse_bool("support_update_remain", is_support_update_remain);
|
|
||||||
parse_bool("support_auto_recovery_step_loss", is_support_auto_recovery_step_loss);
|
|
||||||
parse_bool("support_ams_humidity", is_support_ams_humidity);
|
|
||||||
parse_bool("support_prompt_sound", is_support_prompt_sound);
|
|
||||||
parse_bool("support_filament_tangle_detect", is_support_filament_tangle_detect);
|
|
||||||
parse_bool("support_1080dpi", is_support_1080dpi);
|
|
||||||
parse_bool("support_cloud_print_only", is_support_cloud_print_only);
|
|
||||||
parse_bool("support_command_ams_switch", is_support_command_ams_switch);
|
|
||||||
parse_bool("support_mqtt_alive", is_support_mqtt_alive);
|
|
||||||
parse_bool("support_motor_noise_cali", is_support_motor_noise_cali);
|
|
||||||
parse_bool("support_timelapse", is_support_timelapse);
|
|
||||||
parse_bool("support_user_preset", is_support_user_preset);
|
|
||||||
parse_bool("support_refresh_nozzle", is_support_refresh_nozzle);
|
|
||||||
parse_bool("support_flow_calibration", is_support_flow_calibration);
|
|
||||||
parse_bool("support_build_plate_marker_detect", is_support_build_plate_marker_detect);
|
|
||||||
parse_bool("support_nozzle_blob_detect", is_support_nozzle_blob_detection);
|
|
||||||
|
|
||||||
if (!m_manager->IsMultiMachineEnabled() && !is_support_agora)
|
|
||||||
parse_bool("support_tunnel_mqtt", is_support_tunnel_mqtt);
|
|
||||||
|
|
||||||
const auto bed_leveling_it = flags.find("support_bed_leveling");
|
|
||||||
if (bed_leveling_it != flags.end() && bed_leveling_it->is_number_integer())
|
|
||||||
is_support_bed_leveling = bed_leveling_it->get<int>();
|
|
||||||
|
|
||||||
auto copy_bool = [&flags](json& target, const char* name) {
|
|
||||||
const auto it = flags.find(name);
|
|
||||||
if (it != flags.end() && it->is_boolean())
|
|
||||||
target[name] = *it;
|
|
||||||
};
|
|
||||||
|
|
||||||
// The capability manifest uses an object for this range, while the legacy
|
|
||||||
// DeviceCore parser consumes a boolean plus a two-element range array.
|
|
||||||
json device_config;
|
|
||||||
copy_bool(device_config, "support_chamber");
|
|
||||||
copy_bool(device_config, "support_first_layer_inspect");
|
|
||||||
copy_bool(device_config, "support_ai_monitoring");
|
|
||||||
copy_bool(device_config, "support_lidar_calibration");
|
|
||||||
const auto chamber_edit_it = flags.find("support_chamber_temp_edit");
|
|
||||||
if (chamber_edit_it != flags.end() && chamber_edit_it->is_boolean()) {
|
|
||||||
device_config["support_chamber_temp_edit"] = *chamber_edit_it;
|
|
||||||
} else if (chamber_edit_it != flags.end() && chamber_edit_it->is_object()) {
|
|
||||||
const auto min_it = chamber_edit_it->find("min");
|
|
||||||
const auto max_it = chamber_edit_it->find("max");
|
|
||||||
if (min_it != chamber_edit_it->end() && max_it != chamber_edit_it->end() && min_it->is_number() && max_it->is_number()) {
|
|
||||||
device_config["support_chamber_temp_edit"] = true;
|
|
||||||
device_config["support_chamber_temp_edit_range"] = {*min_it, *max_it};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
json fan_config;
|
|
||||||
copy_bool(fan_config, "support_aux_fan");
|
|
||||||
copy_bool(fan_config, "support_chamber_fan");
|
|
||||||
|
|
||||||
m_config->ParseConfig(device_config);
|
|
||||||
m_fan->ParseV2_0(fan_config);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_hex_digit(char c) {
|
static bool is_hex_digit(char c) {
|
||||||
return std::isxdigit(static_cast<unsigned char>(c)) != 0;
|
return std::isxdigit(static_cast<unsigned char>(c)) != 0;
|
||||||
}
|
}
|
||||||
@@ -6073,15 +5965,6 @@ bool MachineObject::HasAms() const
|
|||||||
return m_fila_system->HasAms();
|
return m_fila_system->HasAms();
|
||||||
}
|
}
|
||||||
|
|
||||||
int MachineObject::command_with_dialog(int cmd_result)
|
|
||||||
{
|
|
||||||
if (!m_agent)
|
|
||||||
return -1;
|
|
||||||
if (cmd_result == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || cmd_result == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
|
|
||||||
show_unsupported_dlg(cmd_result);
|
|
||||||
return cmd_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void change_the_opacity(wxColour& colour)
|
void change_the_opacity(wxColour& colour)
|
||||||
{
|
{
|
||||||
if (colour.Alpha() == 255) {
|
if (colour.Alpha() == 255) {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
#include "boost/bimap/bimap.hpp"
|
#include "boost/bimap/bimap.hpp"
|
||||||
#include "libslic3r/calib.hpp"
|
#include "libslic3r/calib.hpp"
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
#include "slic3r/Utils/PrinterNetworkTypes.hpp"
|
|
||||||
|
|
||||||
#include "DeviceCore/DevDefs.h"
|
#include "DeviceCore/DevDefs.h"
|
||||||
#include "DeviceCore/DevConfigUtil.h"
|
#include "DeviceCore/DevConfigUtil.h"
|
||||||
@@ -101,6 +100,7 @@ struct DevPrintTaskRatingInfo;
|
|||||||
// given nozzle diameter (mm), bucketed per nozzle size to mirror the printer firmware.
|
// given nozzle diameter (mm), bucketed per nozzle size to mirror the printer firmware.
|
||||||
bool is_stringing_prone_filament(const std::string& filament_id, float nozzle_diameter);
|
bool is_stringing_prone_filament(const std::string& filament_id, float nozzle_diameter);
|
||||||
|
|
||||||
|
|
||||||
class MachineObject
|
class MachineObject
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -307,7 +307,7 @@ public:
|
|||||||
bool ams_support_virtual_tray { true };
|
bool ams_support_virtual_tray { true };
|
||||||
time_t ams_user_setting_start = 0;
|
time_t ams_user_setting_start = 0;
|
||||||
time_t ams_switch_filament_start = 0;
|
time_t ams_switch_filament_start = 0;
|
||||||
AmsStatusMain ams_status_main = AmsStatusMain::AMS_STATUS_MAIN_IDLE;
|
AmsStatusMain ams_status_main;
|
||||||
int ams_status_sub;
|
int ams_status_sub;
|
||||||
int ams_version = 0;
|
int ams_version = 0;
|
||||||
|
|
||||||
@@ -547,12 +547,30 @@ public:
|
|||||||
bool xcam_first_layer_inspector { false };
|
bool xcam_first_layer_inspector { false };
|
||||||
time_t xcam_first_layer_hold_start = 0;
|
time_t xcam_first_layer_hold_start = 0;
|
||||||
std::string local_rtsp_url;
|
std::string local_rtsp_url;
|
||||||
std::string webcam_stream_url;
|
|
||||||
std::string tutk_state;
|
std::string tutk_state;
|
||||||
LiveviewLocal liveview_local{ LiveviewLocal::LVL_None };
|
enum LiveviewLocal {
|
||||||
LiveviewRemote liveview_remote{ LiveviewRemote::LVR_None};
|
LVL_None,
|
||||||
FileLocal file_local{ FileLocal::FL_None };
|
LVL_Disable,
|
||||||
FileRemote file_remote{ FileRemote::FR_None };
|
LVL_Local,
|
||||||
|
LVL_Rtsps,
|
||||||
|
LVL_Rtsp
|
||||||
|
} liveview_local{ LVL_None };
|
||||||
|
enum LiveviewRemote {
|
||||||
|
LVR_None,
|
||||||
|
LVR_Tutk,
|
||||||
|
LVR_Agora,
|
||||||
|
LVR_TutkAgora
|
||||||
|
} liveview_remote{ LVR_None };
|
||||||
|
enum FileLocal {
|
||||||
|
FL_None,
|
||||||
|
FL_Local
|
||||||
|
} file_local{ FL_None };
|
||||||
|
enum FileRemote {
|
||||||
|
FR_None,
|
||||||
|
FR_Tutk,
|
||||||
|
FR_Agora,
|
||||||
|
FR_TutkAgora
|
||||||
|
} file_remote{ FR_None };
|
||||||
|
|
||||||
enum PlateMakerDectect : int
|
enum PlateMakerDectect : int
|
||||||
{
|
{
|
||||||
@@ -678,7 +696,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
/* machine mqtt apis */
|
/* machine mqtt apis */
|
||||||
int connect();
|
int connect(bool use_openssl = true);
|
||||||
int disconnect();
|
int disconnect();
|
||||||
|
|
||||||
json_diff print_json;
|
json_diff print_json;
|
||||||
@@ -690,8 +708,6 @@ public:
|
|||||||
std::string subtask_id_;
|
std::string subtask_id_;
|
||||||
std::string job_id_;
|
std::string job_id_;
|
||||||
std::string last_subtask_id_;
|
std::string last_subtask_id_;
|
||||||
// note: printer-agent-supplied thumbnail url, empty when the agent supplies none.
|
|
||||||
std::string m_agent_thumbnail_url;
|
|
||||||
BBLSliceInfo* slice_info {nullptr};
|
BBLSliceInfo* slice_info {nullptr};
|
||||||
boost::thread* get_slice_info_thread { nullptr };
|
boost::thread* get_slice_info_thread { nullptr };
|
||||||
boost::thread* get_model_task_thread { nullptr };
|
boost::thread* get_model_task_thread { nullptr };
|
||||||
@@ -749,7 +765,6 @@ public:
|
|||||||
int command_set_printer_nozzle(std::string nozzle_type, float diameter);
|
int command_set_printer_nozzle(std::string nozzle_type, float diameter);
|
||||||
int command_set_printer_nozzle2(int id, std::string nozzle_type, float diameter);
|
int command_set_printer_nozzle2(int id, std::string nozzle_type, float diameter);
|
||||||
int command_get_access_code();
|
int command_get_access_code();
|
||||||
int command_start_camera();
|
|
||||||
int command_ack_proceed(json& proceed);
|
int command_ack_proceed(json& proceed);
|
||||||
int command_purification_disable();
|
int command_purification_disable();
|
||||||
int command_dont_remind_next_time(json& mqtt_guard_json);
|
int command_dont_remind_next_time(json& mqtt_guard_json);
|
||||||
@@ -796,7 +811,8 @@ public:
|
|||||||
int command_ams_calibrate(int ams_id);
|
int command_ams_calibrate(int ams_id);
|
||||||
int command_ams_filament_settings(int ams_id, int slot_id, std::string filament_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max);
|
int command_ams_filament_settings(int ams_id, int slot_id, std::string filament_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max);
|
||||||
int command_ams_select_tray(std::string tray_id);
|
int command_ams_select_tray(std::string tray_id);
|
||||||
int command_ams_refresh_rfid(int ams_id, int slot_id);
|
int command_ams_refresh_rfid(std::string tray_id);
|
||||||
|
int command_ams_refresh_rfid2(int ams_id, int slot_id);
|
||||||
int command_ams_control(std::string action);
|
int command_ams_control(std::string action);
|
||||||
int command_ams_drying_stop();
|
int command_ams_drying_stop();
|
||||||
int command_start_extrusion_cali(int tray_index, int nozzle_temp, int bed_temp, float max_volumetric_speed, std::string setting_id = "");
|
int command_start_extrusion_cali(int tray_index, int nozzle_temp, int bed_temp, float max_volumetric_speed, std::string setting_id = "");
|
||||||
@@ -878,7 +894,6 @@ public:
|
|||||||
static bool is_in_printing_status(std::string status);
|
static bool is_in_printing_status(std::string status);
|
||||||
|
|
||||||
void set_print_state(std::string status);
|
void set_print_state(std::string status);
|
||||||
void update_print_progress(const json& value);
|
|
||||||
|
|
||||||
bool is_connected();
|
bool is_connected();
|
||||||
bool is_connecting();
|
bool is_connecting();
|
||||||
@@ -947,7 +962,6 @@ public:
|
|||||||
/*for parse new info*/
|
/*for parse new info*/
|
||||||
bool check_enable_np(const json& print) const;
|
bool check_enable_np(const json& print) const;
|
||||||
void parse_new_info(json print);
|
void parse_new_info(json print);
|
||||||
void parse_new_info2(const json& info);
|
|
||||||
int get_flag_bits(std::string str, int start, int count = 1) const;
|
int get_flag_bits(std::string str, int start, int count = 1) const;
|
||||||
uint32_t get_flag_bits_no_border(std::string str, int start_idx, int count = 1) const;
|
uint32_t get_flag_bits_no_border(std::string str, int start_idx, int count = 1) const;
|
||||||
int get_flag_bits(int num, int start, int count = 1, int base = 10) const;
|
int get_flag_bits(int num, int start, int count = 1, int base = 10) const;
|
||||||
@@ -976,7 +990,7 @@ public:
|
|||||||
void command_set_save_remote_print_file_to_storage(bool save);
|
void command_set_save_remote_print_file_to_storage(bool save);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int command_with_dialog(int cmd_result);
|
|
||||||
/* xcam door open check*/
|
/* xcam door open check*/
|
||||||
bool is_support_door_open_check = false;
|
bool is_support_door_open_check = false;
|
||||||
DoorOpenCheckState xcam_door_open_check = DoorOpenCheckState::DOOR_OPEN_CHECK_DISABLE;
|
DoorOpenCheckState xcam_door_open_check = DoorOpenCheckState::DOOR_OPEN_CHECK_DISABLE;
|
||||||
|
|||||||
@@ -1267,6 +1267,8 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
|
|||||||
if (current_top_layer_only != required_top_layer_only)
|
if (current_top_layer_only != required_top_layer_only)
|
||||||
m_viewer.toggle_top_layer_only_view_range();
|
m_viewer.toggle_top_layer_only_view_range();
|
||||||
|
|
||||||
|
read_reduced_detail_preferences();
|
||||||
|
|
||||||
// ORCA: darken the layers the preview layer slider is not scrubbed to
|
// ORCA: darken the layers the preview layer slider is not scrubbed to
|
||||||
m_viewer.set_dim_previous_layers(get_app_config()->get_bool("preview_dim_previous_layers"));
|
m_viewer.set_dim_previous_layers(get_app_config()->get_bool("preview_dim_previous_layers"));
|
||||||
m_viewer.set_dim_previous_layers_brightness(0.01f * std::stoi(get_app_config()->get("preview_dim_previous_layers_brightness")));
|
m_viewer.set_dim_previous_layers_brightness(0.01f * std::stoi(get_app_config()->get("preview_dim_previous_layers_brightness")));
|
||||||
@@ -1491,6 +1493,10 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
|
|||||||
|
|
||||||
// BBS: data for rendering color arrangement recommendation
|
// BBS: data for rendering color arrangement recommendation
|
||||||
m_nozzle_nums = print.config().option<ConfigOptionFloats>("nozzle_diameter")->values.size();
|
m_nozzle_nums = print.config().option<ConfigOptionFloats>("nozzle_diameter")->values.size();
|
||||||
|
// the shell drag mode hides the infill only where the profile covers it: with no top or bottom
|
||||||
|
// shell, or no walls, the infill is the surface. Per-object settings are not consulted.
|
||||||
|
const PrintRegionConfig& region = print.default_region_config();
|
||||||
|
m_viewer.set_reduced_detail_hide_infill(region.top_shell_layers.value > 0 && region.bottom_shell_layers.value > 0 && region.wall_loops.value > 0);
|
||||||
// Orca hack: Hide filament group for non-bbl printers
|
// Orca hack: Hide filament group for non-bbl printers
|
||||||
if (!print.is_BBL_printer()) m_nozzle_nums = 1;
|
if (!print.is_BBL_printer()) m_nozzle_nums = 1;
|
||||||
std::vector<int> filament_maps = print.get_filament_maps();
|
std::vector<int> filament_maps = print.get_filament_maps();
|
||||||
@@ -1661,6 +1667,7 @@ void GCodeViewer::reset_shell()
|
|||||||
{
|
{
|
||||||
m_shells.volumes.clear();
|
m_shells.volumes.clear();
|
||||||
m_shells.print_id = -1;
|
m_shells.print_id = -1;
|
||||||
|
m_shells.with_wipe_tower = false;
|
||||||
m_shell_bounding_box = BoundingBoxf3();
|
m_shell_bounding_box = BoundingBoxf3();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1697,7 +1704,12 @@ void GCodeViewer::reset()
|
|||||||
void GCodeViewer::render_scene(int canvas_width, int canvas_height)
|
void GCodeViewer::render_scene(int canvas_width, int canvas_height)
|
||||||
{
|
{
|
||||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||||
render_shells(canvas_width, canvas_height);
|
// while dragging in the solid model mode, the objects stand in for their toolpaths, cut to the
|
||||||
|
// visible layer range; the toolpath set then holds only the range's bottom and top layers
|
||||||
|
if (m_viewer.is_reduced_detail() && solid_model_enabled())
|
||||||
|
render_solid_model(canvas_width, canvas_height);
|
||||||
|
else
|
||||||
|
render_shells(canvas_width, canvas_height);
|
||||||
|
|
||||||
if (m_viewer.get_extrusion_roles_count() == 0)
|
if (m_viewer.get_extrusion_roles_count() == 0)
|
||||||
return;
|
return;
|
||||||
@@ -2020,6 +2032,56 @@ void GCodeViewer::update_layers_slider_mode()
|
|||||||
// TODO m_layers_slider->SetModeAndOnlyExtruder(one_extruder_printed_model, only_extruder);
|
// TODO m_layers_slider->SetModeAndOnlyExtruder(one_extruder_printed_model, only_extruder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GCodeViewer::set_interacting(bool interacting)
|
||||||
|
{
|
||||||
|
// with no shells to stand in for the toolpaths, the solid model would leave only the end layers
|
||||||
|
const bool usable = !solid_model_enabled() || !m_shells.volumes.empty();
|
||||||
|
m_viewer.set_reduced_detail(interacting && usable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCodeViewer::read_reduced_detail_preferences()
|
||||||
|
{
|
||||||
|
m_reduced_detail_mode = reduced_detail_mode_from_string(get_app_config()->get("preview_reduced_detail_mode"));
|
||||||
|
apply_reduced_detail_settings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCodeViewer::apply_reduced_detail_settings()
|
||||||
|
{
|
||||||
|
m_viewer.set_reduced_detail_mode(m_reduced_detail_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCodeViewer::set_reduced_detail_mode(const std::string& mode)
|
||||||
|
{
|
||||||
|
const bool was_solid = solid_model_enabled();
|
||||||
|
m_reduced_detail_mode = reduced_detail_mode_from_string(mode);
|
||||||
|
apply_reduced_detail_settings();
|
||||||
|
reload_shells_if_solid_model_changed(was_solid);
|
||||||
|
}
|
||||||
|
|
||||||
|
libvgcode::EReducedDetailMode GCodeViewer::reduced_detail_mode_from_string(const std::string& mode)
|
||||||
|
{
|
||||||
|
if (mode == "solid")
|
||||||
|
return libvgcode::EReducedDetailMode::EndLayersOnly;
|
||||||
|
if (mode == "shell")
|
||||||
|
return libvgcode::EReducedDetailMode::ShellOnly;
|
||||||
|
return libvgcode::EReducedDetailMode::Off;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCodeViewer::reload_shells_if_solid_model_changed(bool was_enabled)
|
||||||
|
{
|
||||||
|
if (was_enabled == solid_model_enabled() || m_shells.print_id == -1)
|
||||||
|
return;
|
||||||
|
// only the prime tower comes and goes with the mode: a full reload would drop the shells
|
||||||
|
// whenever the print has moved on since they were loaded, leaving the solid model nothing to draw
|
||||||
|
if (wxGetApp().plater() == nullptr)
|
||||||
|
return;
|
||||||
|
// the shells are loaded from the current plate's print, which is not the plater's own
|
||||||
|
const Print& print = wxGetApp().plater()->get_partplate_list().get_current_fff_print();
|
||||||
|
if (static_cast<int>(print.id().id) != m_shells.print_id)
|
||||||
|
return;
|
||||||
|
update_shell_wipe_tower(print, m_gl_data_initialized);
|
||||||
|
}
|
||||||
|
|
||||||
void GCodeViewer::set_layers_z_range(const std::array<unsigned int, 2>& layers_z_range)
|
void GCodeViewer::set_layers_z_range(const std::array<unsigned int, 2>& layers_z_range)
|
||||||
{
|
{
|
||||||
m_viewer.set_layers_view_range(static_cast<uint32_t>(layers_z_range[0]), static_cast<uint32_t>(layers_z_range[1]));
|
m_viewer.set_layers_view_range(static_cast<uint32_t>(layers_z_range[0]), static_cast<uint32_t>(layers_z_range[1]));
|
||||||
@@ -2344,7 +2406,11 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const
|
|||||||
void GCodeViewer::load_shells(const Print& print, bool initialized, bool force_previewing)
|
void GCodeViewer::load_shells(const Print& print, bool initialized, bool force_previewing)
|
||||||
{
|
{
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": initialized=%1%, force_previewing=%2%")%initialized %force_previewing;
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": initialized=%1%, force_previewing=%2%")%initialized %force_previewing;
|
||||||
|
// the shells can load before the first G-code does, so the preferences are read here as well
|
||||||
|
read_reduced_detail_preferences();
|
||||||
if ((print.id().id == m_shells.print_id)&&(print.get_modified_count() == m_shells.print_modify_count)) {
|
if ((print.id().id == m_shells.print_id)&&(print.get_modified_count() == m_shells.print_modify_count)) {
|
||||||
|
// the prime tower comes and goes on its own, without reloading the objects
|
||||||
|
update_shell_wipe_tower(print, initialized);
|
||||||
//BBS: update force previewing logic
|
//BBS: update force previewing logic
|
||||||
if (force_previewing)
|
if (force_previewing)
|
||||||
m_shells.previewing = force_previewing;
|
m_shells.previewing = force_previewing;
|
||||||
@@ -2453,10 +2519,45 @@ void GCodeViewer::load_shells(const Print& print, bool initialized, bool force_p
|
|||||||
m_shells.print_id = print.id().id;
|
m_shells.print_id = print.id().id;
|
||||||
m_shells.print_modify_count = print.get_modified_count();
|
m_shells.print_modify_count = print.get_modified_count();
|
||||||
m_shells.previewing = true;
|
m_shells.previewing = true;
|
||||||
|
update_shell_wipe_tower(print, initialized);
|
||||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": shell loaded, id change to %1%, modify_count %2%, object count %3%, glvolume count %4%")
|
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": shell loaded, id change to %1%, modify_count %2%, object count %3%, glvolume count %4%")
|
||||||
% m_shells.print_id % m_shells.print_modify_count % object_count %m_shells.volumes.volumes.size();
|
% m_shells.print_id % m_shells.print_modify_count % object_count %m_shells.volumes.volumes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The prime tower as it was sliced, so that the solid model shows what the print shows. It keeps its
|
||||||
|
// opaque colour, so it never appears among the translucent shells, and stays out of their bounding box.
|
||||||
|
void GCodeViewer::update_shell_wipe_tower(const Print& print, bool initialized)
|
||||||
|
{
|
||||||
|
const bool with_wipe_tower = solid_model_enabled() && print.is_step_done(psWipeTower) && print.wipe_tower_data().wipe_tower_mesh_data;
|
||||||
|
if (with_wipe_tower == m_shells.with_wipe_tower)
|
||||||
|
return;
|
||||||
|
m_shells.with_wipe_tower = with_wipe_tower;
|
||||||
|
GLVolumePtrs& volumes = m_shells.volumes.volumes;
|
||||||
|
if (!with_wipe_tower) {
|
||||||
|
volumes.erase(std::remove_if(volumes.begin(), volumes.end(), [](GLVolume* volume) {
|
||||||
|
if (!volume->is_wipe_tower)
|
||||||
|
return false;
|
||||||
|
delete volume;
|
||||||
|
return true;
|
||||||
|
}), volumes.end());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const PrintConfig& config = print.config();
|
||||||
|
const int plate_idx = print.get_plate_index();
|
||||||
|
const Vec3d plate_origin = print.get_plate_origin();
|
||||||
|
const float x = static_cast<float>(config.wipe_tower_x.get_at(plate_idx) + plate_origin.x());
|
||||||
|
const float y = static_cast<float>(config.wipe_tower_y.get_at(plate_idx) + plate_origin.y());
|
||||||
|
const size_t first_new = volumes.size();
|
||||||
|
m_shells.volumes.load_real_wipe_tower_preview(1000 + plate_idx, x, y, print.wipe_tower_data().wipe_tower_mesh_data->real_wipe_tower_mesh,
|
||||||
|
print.wipe_tower_data().wipe_tower_mesh_data->real_brim_mesh, true,
|
||||||
|
static_cast<float>(config.wipe_tower_rotation_angle), false, initialized);
|
||||||
|
for (size_t i = first_new; i < volumes.size(); ++i) {
|
||||||
|
volumes[i]->zoom_to_volumes = false;
|
||||||
|
volumes[i]->force_native_color = true;
|
||||||
|
volumes[i]->set_render_color();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GCodeViewer::render_toolpaths()
|
void GCodeViewer::render_toolpaths()
|
||||||
{
|
{
|
||||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||||
@@ -2657,6 +2758,50 @@ void GCodeViewer::render_shells(int canvas_width, int canvas_height)
|
|||||||
glsafe(::glDepthMask(GL_TRUE));
|
glsafe(::glDepthMask(GL_TRUE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The sliced objects and the prime tower drawn opaque, in their filament colours, cut to the
|
||||||
|
// visible layer range by the shader's z range. The toolpaths of the range's bottom and top layers
|
||||||
|
// are drawn afterwards and cap the cut.
|
||||||
|
void GCodeViewer::render_solid_model(int canvas_width, int canvas_height)
|
||||||
|
{
|
||||||
|
if (m_shells.volumes.empty())
|
||||||
|
return;
|
||||||
|
// gouraud_light has no z range, so it could not cut the model
|
||||||
|
GLShaderProgram* shader = wxGetApp().get_shader("gouraud");
|
||||||
|
if (shader == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const libvgcode::Interval& layers = m_viewer.get_layers_view_range();
|
||||||
|
const float z_top = m_viewer.get_layer_z(layers[1]) - m_z_offset + 0.001f;
|
||||||
|
const float z_bottom = (layers[0] > 0) ? m_viewer.get_layer_z(layers[0] - 1) - m_z_offset - 0.001f : -FLT_MAX;
|
||||||
|
|
||||||
|
std::vector<float> alphas;
|
||||||
|
alphas.reserve(m_shells.volumes.volumes.size());
|
||||||
|
for (GLVolume* volume : m_shells.volumes.volumes) {
|
||||||
|
alphas.push_back(volume->color.a());
|
||||||
|
volume->color.a(1.0f);
|
||||||
|
volume->set_render_color();
|
||||||
|
}
|
||||||
|
m_shells.volumes.set_z_range(z_bottom, z_top);
|
||||||
|
// gouraud also clips by this plane, which nothing else sets on the shells
|
||||||
|
m_shells.volumes.set_clipping_plane(ClippingPlane::ClipsNothing().get_data());
|
||||||
|
|
||||||
|
shader->start_using();
|
||||||
|
// the 3D view leaves its shadow settings on the shared program
|
||||||
|
shader->set_uniform("shadow_intensity", 0.0f);
|
||||||
|
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||||
|
shader->set_uniform("z_far", camera.get_far_z());
|
||||||
|
shader->set_uniform("z_near", camera.get_near_z());
|
||||||
|
m_shells.volumes.render(GLVolumeCollection::ERenderType::Opaque, false, camera.get_view_matrix(), camera.get_projection_matrix(), {canvas_width, canvas_height});
|
||||||
|
shader->stop_using();
|
||||||
|
|
||||||
|
m_shells.volumes.set_z_range(-FLT_MAX, FLT_MAX);
|
||||||
|
size_t k = 0;
|
||||||
|
for (GLVolume* volume : m_shells.volumes.volumes) {
|
||||||
|
volume->color.a(alphas[k++]);
|
||||||
|
volume->set_render_color();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//BBS
|
//BBS
|
||||||
void GCodeViewer::render_all_plates_stats(const std::vector<const GCodeProcessorResult*>& gcode_result_list, bool show /*= true*/) const {
|
void GCodeViewer::render_all_plates_stats(const std::vector<const GCodeProcessorResult*>& gcode_result_list, bool show /*= true*/) const {
|
||||||
if (!show)
|
if (!show)
|
||||||
|
|||||||
@@ -174,6 +174,8 @@ public:
|
|||||||
int print_id{-1};
|
int print_id{-1};
|
||||||
int print_modify_count{-1};
|
int print_modify_count{-1};
|
||||||
bool previewing{false};
|
bool previewing{false};
|
||||||
|
// the prime tower was loaded with the objects, for the solid model
|
||||||
|
bool with_wipe_tower{false};
|
||||||
};
|
};
|
||||||
//BBS
|
//BBS
|
||||||
ConflictResultOpt m_conflict_result;
|
ConflictResultOpt m_conflict_result;
|
||||||
@@ -234,6 +236,17 @@ private:
|
|||||||
|
|
||||||
bool m_legend_visible{ true };
|
bool m_legend_visible{ true };
|
||||||
bool m_legend_enabled{ true };
|
bool m_legend_enabled{ true };
|
||||||
|
// the reduced-detail preferences, pushed to libvgcode by apply_reduced_detail_settings()
|
||||||
|
libvgcode::EReducedDetailMode m_reduced_detail_mode{ libvgcode::EReducedDetailMode::Off };
|
||||||
|
void read_reduced_detail_preferences();
|
||||||
|
void apply_reduced_detail_settings();
|
||||||
|
static libvgcode::EReducedDetailMode reduced_detail_mode_from_string(const std::string& mode);
|
||||||
|
// in the solid model mode, the sliced objects are drawn as solid shapes instead of toolpaths
|
||||||
|
bool solid_model_enabled() const { return m_reduced_detail_mode == libvgcode::EReducedDetailMode::EndLayersOnly; }
|
||||||
|
void render_solid_model(int canvas_width, int canvas_height);
|
||||||
|
// the prime tower is only among the shells for the solid model, so it is added or removed when that changes
|
||||||
|
void reload_shells_if_solid_model_changed(bool was_enabled);
|
||||||
|
void update_shell_wipe_tower(const Print& print, bool initialized);
|
||||||
|
|
||||||
float m_legend_height;
|
float m_legend_height;
|
||||||
PrintEstimatedStatistics m_print_statistics;
|
PrintEstimatedStatistics m_print_statistics;
|
||||||
@@ -291,7 +304,7 @@ public:
|
|||||||
// void _render_calibration_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
|
// void _render_calibration_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
|
||||||
// void _render_calibration_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
|
// void _render_calibration_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
|
||||||
// void render_calibration_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
|
// void render_calibration_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
|
||||||
bool has_data() const { return !m_viewer.get_extrusion_roles().empty(); }
|
bool has_data() const { return m_viewer.get_extrusion_roles_count() != 0; }
|
||||||
|
|
||||||
bool can_export_toolpaths() const;
|
bool can_export_toolpaths() const;
|
||||||
std::vector<int> get_plater_extruder();
|
std::vector<int> get_plater_extruder();
|
||||||
@@ -363,6 +376,14 @@ public:
|
|||||||
void set_dim_previous_layers_brightness(float value) { m_viewer.set_dim_previous_layers_brightness(value); }
|
void set_dim_previous_layers_brightness(float value) { m_viewer.set_dim_previous_layers_brightness(value); }
|
||||||
float get_dim_previous_layers_brightness() const { return m_viewer.get_dim_previous_layers_brightness(); }
|
float get_dim_previous_layers_brightness() const { return m_viewer.get_dim_previous_layers_brightness(); }
|
||||||
|
|
||||||
|
// whether the mouse is holding either slider's handle
|
||||||
|
bool is_slider_dragging() const { return m_layers_slider->is_dragging() || m_moves_slider->is_dragging(); }
|
||||||
|
// while the user drags the camera or a slider, draw the reduced set, if the preference asks for one
|
||||||
|
void set_interacting(bool interacting);
|
||||||
|
bool is_reduced_detail() const { return m_viewer.is_reduced_detail(); }
|
||||||
|
// the preference's string value: "off", "solid" or "shell"
|
||||||
|
void set_reduced_detail_mode(const std::string& mode);
|
||||||
|
|
||||||
void set_layers_z_range(const std::array<unsigned int, 2>& layers_z_range);
|
void set_layers_z_range(const std::array<unsigned int, 2>& layers_z_range);
|
||||||
|
|
||||||
bool is_legend_shown() const { return m_legend_visible && m_legend_enabled; }
|
bool is_legend_shown() const { return m_legend_visible && m_legend_enabled; }
|
||||||
|
|||||||
@@ -2084,6 +2084,11 @@ void GLCanvas3D::_render_frame(bool scene_dirty, bool only_init)
|
|||||||
const bool overlay_tick = m_fps_overlay_tick;
|
const bool overlay_tick = m_fps_overlay_tick;
|
||||||
m_fps_overlay_tick = false;
|
m_fps_overlay_tick = false;
|
||||||
|
|
||||||
|
// Whether the preview draws its reduced set is decided before the cached scene is consulted,
|
||||||
|
// since switching changes what the scene pass draws.
|
||||||
|
if (m_canvas_type == ECanvasType::CanvasPreview && m_render_preview && m_gcode_viewer.has_data() && _update_preview_interaction())
|
||||||
|
scene_dirty = true;
|
||||||
|
|
||||||
// An overlay-only frame reuses the last scene pass. The overlay is rebuilt either way, and drawn
|
// An overlay-only frame reuses the last scene pass. The overlay is rebuilt either way, and drawn
|
||||||
// below once it is known whether the frame differs from the one on screen.
|
// below once it is known whether the frame differs from the one on screen.
|
||||||
const bool reuse_scene = !scene_dirty && _can_reuse_cached_scene(camera);
|
const bool reuse_scene = !scene_dirty && _can_reuse_cached_scene(camera);
|
||||||
@@ -3277,9 +3282,16 @@ void GLCanvas3D::bind_event_handlers()
|
|||||||
if (m_selection_edit.kind != SelectionEdit::None)
|
if (m_selection_edit.kind != SelectionEdit::None)
|
||||||
finish_selection_edit();
|
finish_selection_edit();
|
||||||
ImGui::SetWindowFocus(nullptr);
|
ImGui::SetWindowFocus(nullptr);
|
||||||
|
// a drag cut short never sees its button release, which would leave the reduced set drawn
|
||||||
|
if (m_canvas_type == CanvasPreview && m_mouse.dragging && m_gcode_viewer.is_reduced_detail())
|
||||||
|
mouse_up_cleanup();
|
||||||
render();
|
render();
|
||||||
evt.Skip();
|
evt.Skip();
|
||||||
});
|
});
|
||||||
|
m_canvas->Bind(wxEVT_MOUSE_CAPTURE_LOST, [this](wxMouseCaptureLostEvent&) {
|
||||||
|
if (m_canvas_type == CanvasPreview && m_mouse.dragging && m_gcode_viewer.is_reduced_detail())
|
||||||
|
mouse_up_cleanup();
|
||||||
|
});
|
||||||
m_event_handlers_bound = true;
|
m_event_handlers_bound = true;
|
||||||
|
|
||||||
m_canvas->Bind(wxEVT_GESTURE_PAN, &GLCanvas3D::on_gesture, this);
|
m_canvas->Bind(wxEVT_GESTURE_PAN, &GLCanvas3D::on_gesture, this);
|
||||||
@@ -3355,6 +3367,17 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
|
|||||||
m_overlay_dirty |= imgui_requires_extra_frame;
|
m_overlay_dirty |= imgui_requires_extra_frame;
|
||||||
#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
|
#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
|
||||||
m_dirty |= GLTexture::Compressor::has_compressed_texture_to_refresh();
|
m_dirty |= GLTexture::Compressor::has_compressed_texture_to_refresh();
|
||||||
|
// the render timer only wakes the idle loop; the frame that puts the preview's toolpaths back
|
||||||
|
// after a wheel burst has to be asked for here, once the settle time is really up
|
||||||
|
if (m_preview_settle_pending) {
|
||||||
|
const auto now = std::chrono::steady_clock::now();
|
||||||
|
if (now >= m_preview_interaction_until) {
|
||||||
|
m_preview_settle_pending = false;
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
else // the timer fired early
|
||||||
|
schedule_extra_frame(static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(m_preview_interaction_until - now).count()) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_dirty && !m_overlay_dirty)
|
if (!m_dirty && !m_overlay_dirty)
|
||||||
return;
|
return;
|
||||||
@@ -3885,6 +3908,10 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only a wheel the panels did not take moves the camera
|
||||||
|
if (m_canvas_type == CanvasPreview)
|
||||||
|
note_preview_interaction();
|
||||||
|
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
// For some reason the Idle event is not being generated after the mouse scroll event in case of scrolling with the two fingers on the touch pad,
|
// For some reason the Idle event is not being generated after the mouse scroll event in case of scrolling with the two fingers on the touch pad,
|
||||||
// if the event is not allowed to be passed further.
|
// if the event is not allowed to be passed further.
|
||||||
@@ -3985,6 +4012,11 @@ void GLCanvas3D::on_fps_overlay_timer(wxTimerEvent& evt)
|
|||||||
wxWakeUpIdle();
|
wxWakeUpIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLCanvas3D::note_preview_interaction()
|
||||||
|
{
|
||||||
|
m_preview_interaction_until = std::chrono::steady_clock::now() + std::chrono::milliseconds(150);
|
||||||
|
}
|
||||||
|
|
||||||
void GLCanvas3D::schedule_extra_frame(int milliseconds)
|
void GLCanvas3D::schedule_extra_frame(int milliseconds)
|
||||||
{
|
{
|
||||||
// Schedule idle event right now
|
// Schedule idle event right now
|
||||||
@@ -5631,6 +5663,9 @@ void GLCanvas3D::mouse_up_cleanup()
|
|||||||
m_mouse.ignore_left_up = false;
|
m_mouse.ignore_left_up = false;
|
||||||
m_mouse.ignore_right_up = false;
|
m_mouse.ignore_right_up = false;
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
|
// the frame that follows a release puts the preview's toolpaths back, and on some platforms
|
||||||
|
// no idle event follows a button release until the next input
|
||||||
|
wxWakeUpIdle();
|
||||||
|
|
||||||
if (m_canvas->HasCapture())
|
if (m_canvas->HasCapture())
|
||||||
m_canvas->ReleaseMouse();
|
m_canvas->ReleaseMouse();
|
||||||
@@ -6546,11 +6581,8 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const
|
|||||||
// glsafe(::glClearColor(1.0f, 1.0f, 1.0f, 1.0f));
|
// glsafe(::glClearColor(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
BOOST_LOG_TRIVIAL(info) << boost::format("render_thumbnail: finished");
|
BOOST_LOG_TRIVIAL(info) << boost::format("render_thumbnail: finished");
|
||||||
|
|
||||||
// Puts the canvas viewport back in place of the thumbnail one set above. The CLI renders
|
// Puts the canvas viewport back in place of the thumbnail one set above.
|
||||||
// thumbnails with no application and no plater, so there is no canvas viewport to restore.
|
wxGetApp().plater()->get_camera().apply_viewport();
|
||||||
if (wxTheApp != nullptr)
|
|
||||||
if (Plater *plater = wxGetApp().plater(); plater != nullptr)
|
|
||||||
plater->get_camera().apply_viewport();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
void GLCanvas3D::render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
||||||
@@ -7782,13 +7814,20 @@ bool GLCanvas3D::_is_scene_cacheable() const
|
|||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The scene follows the cursor during a drag, under a gizmo that draws at the cursor, and while
|
// The scene follows the cursor while the user drags, under a gizmo that draws at the cursor, and
|
||||||
// the cursor is on the layer height bar, where the object shader draws a band at its height.
|
// while the cursor is on the layer height bar, where the object shader draws a band at its height.
|
||||||
const GLGizmoBase* gizmo = m_gizmos.get_current();
|
const GLGizmoBase* gizmo = m_gizmos.get_current();
|
||||||
const bool cursor_on_layers_bar = is_layers_editing_enabled() &&
|
const bool cursor_on_layers_bar = is_layers_editing_enabled() &&
|
||||||
m_layers_editing.bar_rect_contains(*this, (float)m_mouse.position.x(), (float)m_mouse.position.y());
|
m_layers_editing.bar_rect_contains(*this, (float)m_mouse.position.x(), (float)m_mouse.position.y());
|
||||||
return !m_mouse.dragging && !m_gizmos.is_dragging() && !m_rectangle_selection.is_dragging() &&
|
return !is_user_interacting() && (gizmo == nullptr || !gizmo->render_follows_cursor()) && !cursor_on_layers_bar;
|
||||||
(gizmo == nullptr || !gizmo->render_follows_cursor()) && !cursor_on_layers_bar;
|
}
|
||||||
|
|
||||||
|
// Whether the user is holding something that moves the scene: the camera, the navigator, a gizmo,
|
||||||
|
// the rectangle selection or a preview slider.
|
||||||
|
bool GLCanvas3D::is_user_interacting() const
|
||||||
|
{
|
||||||
|
return m_mouse.dragging || m_navigator_dragging || m_gizmos.is_dragging() || m_rectangle_selection.is_dragging() ||
|
||||||
|
m_gcode_viewer.is_slider_dragging();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GLCanvas3D::_is_frame_skipping_enabled() const
|
bool GLCanvas3D::_is_frame_skipping_enabled() const
|
||||||
@@ -8779,6 +8818,24 @@ void GLCanvas3D::_render_wireframe_overlay()
|
|||||||
shader->stop_using();
|
shader->stop_using();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The reduced set is drawn while the camera, the navigator or either slider is dragged. A wheel
|
||||||
|
// step has no duration, so it holds the reduced set for a settle time instead, and the frame that
|
||||||
|
// restores the full toolpaths is scheduled for when that time runs out. Returns whether what the scene
|
||||||
|
// pass draws changed, since a frame that reuses the cached scene would hide the change.
|
||||||
|
bool GLCanvas3D::_update_preview_interaction()
|
||||||
|
{
|
||||||
|
const auto now = std::chrono::steady_clock::now();
|
||||||
|
const bool settling = now < m_preview_interaction_until;
|
||||||
|
const bool dragging = is_user_interacting();
|
||||||
|
const bool was_reduced = m_gcode_viewer.is_reduced_detail();
|
||||||
|
m_gcode_viewer.set_interacting(dragging || settling);
|
||||||
|
if (settling && !dragging && m_gcode_viewer.is_reduced_detail()) {
|
||||||
|
m_preview_settle_pending = true;
|
||||||
|
schedule_extra_frame(static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(m_preview_interaction_until - now).count()) + 1);
|
||||||
|
}
|
||||||
|
return m_gcode_viewer.is_reduced_detail() != was_reduced;
|
||||||
|
}
|
||||||
|
|
||||||
//BBS: GUI refactor: add canvas size as parameters
|
//BBS: GUI refactor: add canvas size as parameters
|
||||||
void GLCanvas3D::_render_gcode(int canvas_width, int canvas_height)
|
void GLCanvas3D::_render_gcode(int canvas_width, int canvas_height)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -656,6 +656,10 @@ private:
|
|||||||
ECursorType m_cursor_type;
|
ECursorType m_cursor_type;
|
||||||
GLSelectionRectangle m_rectangle_selection;
|
GLSelectionRectangle m_rectangle_selection;
|
||||||
bool m_navigator_dragging{ false };
|
bool m_navigator_dragging{ false };
|
||||||
|
// until when a wheel step keeps the preview's reduced set drawn
|
||||||
|
std::chrono::time_point<std::chrono::steady_clock> m_preview_interaction_until{};
|
||||||
|
// whether the frame that restores the toolpaths once that time is up is still owed
|
||||||
|
bool m_preview_settle_pending{ false };
|
||||||
|
|
||||||
//BBS:add plate related logic
|
//BBS:add plate related logic
|
||||||
mutable std::vector<int> m_hover_volume_idxs;
|
mutable std::vector<int> m_hover_volume_idxs;
|
||||||
@@ -1222,6 +1226,10 @@ public:
|
|||||||
void msw_rescale() { m_gcode_viewer.invalidate_legend(); }
|
void msw_rescale() { m_gcode_viewer.invalidate_legend(); }
|
||||||
|
|
||||||
void request_extra_frame() { m_extra_frame_requested = true; }
|
void request_extra_frame() { m_extra_frame_requested = true; }
|
||||||
|
// whether the user is holding the camera, the navigator, a gizmo, the rectangle selection or a preview slider
|
||||||
|
bool is_user_interacting() const;
|
||||||
|
// a wheel step is over before the next frame, so it holds the preview's reduced set for a settle time
|
||||||
|
void note_preview_interaction();
|
||||||
|
|
||||||
void schedule_extra_frame(int milliseconds);
|
void schedule_extra_frame(int milliseconds);
|
||||||
|
|
||||||
@@ -1372,6 +1380,9 @@ private:
|
|||||||
//BBS: GUI refactor: add canvas size as parameters
|
//BBS: GUI refactor: add canvas size as parameters
|
||||||
void _render_gcode(int canvas_width, int canvas_height);
|
void _render_gcode(int canvas_width, int canvas_height);
|
||||||
void _render_gcode_overlay(int canvas_width, int canvas_height);
|
void _render_gcode_overlay(int canvas_width, int canvas_height);
|
||||||
|
// decides whether the preview draws its reduced set this frame and returns whether what the scene
|
||||||
|
// pass draws changed; runs before the cached scene is consulted
|
||||||
|
bool _update_preview_interaction();
|
||||||
//BBS: render a plane for assemble
|
//BBS: render a plane for assemble
|
||||||
void _render_plane() const;
|
void _render_plane() const;
|
||||||
void _render_selection();
|
void _render_selection();
|
||||||
|
|||||||
@@ -14,9 +14,6 @@
|
|||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/any.hpp>
|
#include <boost/any.hpp>
|
||||||
|
|
||||||
#include <wx/filename.h>
|
|
||||||
#include <wx/filesys.h>
|
|
||||||
|
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
#import <IOKit/pwr_mgt/IOPMLib.h>
|
#import <IOKit/pwr_mgt/IOPMLib.h>
|
||||||
#elif _WIN32
|
#elif _WIN32
|
||||||
@@ -30,13 +27,11 @@
|
|||||||
|
|
||||||
#include "AboutDialog.hpp"
|
#include "AboutDialog.hpp"
|
||||||
#include "MsgDialog.hpp"
|
#include "MsgDialog.hpp"
|
||||||
#include "Plater.hpp"
|
|
||||||
#include "format.hpp"
|
#include "format.hpp"
|
||||||
|
|
||||||
#include "WebUserLoginDialog.hpp"
|
#include "WebUserLoginDialog.hpp"
|
||||||
|
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
#include "libslic3r/Utils.hpp"
|
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
@@ -536,11 +531,6 @@ boost::filesystem::path into_path(const wxString &str)
|
|||||||
return boost::filesystem::path(str.wx_str());
|
return boost::filesystem::path(str.wx_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString file_url_from_path(const boost::filesystem::path &path)
|
|
||||||
{
|
|
||||||
return wxFileSystem::FileNameToURL(wxFileName(from_path(path)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void about()
|
void about()
|
||||||
{
|
{
|
||||||
AboutDialog dlg;
|
AboutDialog dlg;
|
||||||
@@ -645,26 +635,4 @@ void desktop_open_any_folder( const std::string& path )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool desktop_open_project_attachment(wxWindow *parent, const boost::filesystem::path &path)
|
|
||||||
{
|
|
||||||
// The auxiliary path is UTF-8, which is what boost::filesystem reads a narrow string as.
|
|
||||||
const boost::filesystem::path aux_root(wxGetApp().plater()->model().get_auxiliary_file_temp_path());
|
|
||||||
boost::system::error_code ec;
|
|
||||||
if (!is_absolute_path_within_root(path, aux_root) || !boost::filesystem::is_regular_file(path, ec))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Attachments come with the project and carry no download mark, so the desktop would open them without a warning.
|
|
||||||
if (!is_safe_to_open_file_name(path.filename().string())) {
|
|
||||||
MessageDialog dlg(parent,
|
|
||||||
wxString::Format(_L("\"%s\" is not a plain document, image or model file. Opening it may run it as a "
|
|
||||||
"program or script on this computer.\n\n"
|
|
||||||
"Only open attachments from projects you trust. Open it anyway?"),
|
|
||||||
from_path(path.filename())),
|
|
||||||
_L("Open attachment"), wxICON_WARNING | wxYES_NO);
|
|
||||||
if (dlg.ShowModal() != wxID_YES)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return wxLaunchDefaultApplication(from_path(path), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
|||||||
@@ -76,9 +76,6 @@ std::string into_u8(const wxString &str);
|
|||||||
wxString from_path(const boost::filesystem::path &path);
|
wxString from_path(const boost::filesystem::path &path);
|
||||||
// boost path from wxString
|
// boost path from wxString
|
||||||
boost::filesystem::path into_path(const wxString &str);
|
boost::filesystem::path into_path(const wxString &str);
|
||||||
// file:// URL of a local path, percent-encoded so characters such as '#', '%' and '?' stay part of the path.
|
|
||||||
// Append any query or fragment to the result.
|
|
||||||
wxString file_url_from_path(const boost::filesystem::path &path);
|
|
||||||
|
|
||||||
// Display an About dialog
|
// Display an About dialog
|
||||||
extern void about();
|
extern void about();
|
||||||
@@ -86,9 +83,6 @@ extern void about();
|
|||||||
extern void desktop_open_datadir_folder();
|
extern void desktop_open_datadir_folder();
|
||||||
// Ask the destop to open one folder
|
// Ask the destop to open one folder
|
||||||
extern void desktop_open_any_folder(const std::string& path);
|
extern void desktop_open_any_folder(const std::string& path);
|
||||||
// Ask the desktop to open a file from the project's auxiliary directory, after a confirmation
|
|
||||||
// unless its type is known to be plain content. Returns false if the file was not opened.
|
|
||||||
extern bool desktop_open_project_attachment(wxWindow *parent, const boost::filesystem::path &path);
|
|
||||||
} // namespace GUI
|
} // namespace GUI
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
|||||||
+51
-59
@@ -4,7 +4,6 @@
|
|||||||
#include "libslic3r/Platform.hpp"
|
#include "libslic3r/Platform.hpp"
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
#include "Shortcuts.hpp"
|
#include "Shortcuts.hpp"
|
||||||
#include "DeviceCore/DevConfigUtil.h"
|
|
||||||
#include "BindDialog.hpp"
|
#include "BindDialog.hpp"
|
||||||
#include "DeviceManager.hpp"
|
#include "DeviceManager.hpp"
|
||||||
#include "HMS.hpp"
|
#include "HMS.hpp"
|
||||||
@@ -25,6 +24,7 @@
|
|||||||
#include <boost/locale/encoding_utf.hpp>
|
#include <boost/locale/encoding_utf.hpp>
|
||||||
#include <boost/log/detail/native_typeof.hpp>
|
#include <boost/log/detail/native_typeof.hpp>
|
||||||
#include <libslic3r/Config.hpp>
|
#include <libslic3r/Config.hpp>
|
||||||
|
#include <mutex>
|
||||||
#include <slic3r/plugin/PythonPluginInterface.hpp>
|
#include <slic3r/plugin/PythonPluginInterface.hpp>
|
||||||
#include <wx/event.h>
|
#include <wx/event.h>
|
||||||
|
|
||||||
@@ -41,11 +41,9 @@
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <mutex>
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
@@ -90,6 +88,7 @@
|
|||||||
#include "libslic3r/Thread.hpp"
|
#include "libslic3r/Thread.hpp"
|
||||||
#include "libslic3r/miniz_extension.hpp"
|
#include "libslic3r/miniz_extension.hpp"
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
|
#include "libslic3r/Color.hpp"
|
||||||
#include "slic3r/plugin/PluginManager.hpp"
|
#include "slic3r/plugin/PluginManager.hpp"
|
||||||
#include "slic3r/plugin/host/PluginHostUi.hpp"
|
#include "slic3r/plugin/host/PluginHostUi.hpp"
|
||||||
#include "slic3r/plugin/PythonInterpreter.hpp"
|
#include "slic3r/plugin/PythonInterpreter.hpp"
|
||||||
@@ -109,18 +108,19 @@
|
|||||||
#include "../Utils/PrintHost.hpp"
|
#include "../Utils/PrintHost.hpp"
|
||||||
#include "../Utils/Process.hpp"
|
#include "../Utils/Process.hpp"
|
||||||
#include "../Utils/wxInspectorPlugins/Registration.hpp"
|
#include "../Utils/wxInspectorPlugins/Registration.hpp"
|
||||||
|
#include "../Utils/MacDarkMode.hpp"
|
||||||
#include "../Utils/Http.hpp"
|
#include "../Utils/Http.hpp"
|
||||||
#include "../Utils/InstanceID.hpp"
|
#include "../Utils/InstanceID.hpp"
|
||||||
#include "../Utils/UndoRedo.hpp"
|
#include "../Utils/UndoRedo.hpp"
|
||||||
#include "slic3r/Config/Snapshot.hpp"
|
#include "slic3r/Config/Snapshot.hpp"
|
||||||
#include "Preferences.hpp"
|
#include "Preferences.hpp"
|
||||||
#include "Tab.hpp"
|
#include "Tab.hpp"
|
||||||
|
#include "SysInfoDialog.hpp"
|
||||||
#include "UpdateDialogs.hpp"
|
#include "UpdateDialogs.hpp"
|
||||||
#include "Mouse3DController.hpp"
|
#include "Mouse3DController.hpp"
|
||||||
#include "RemovableDriveManager.hpp"
|
#include "RemovableDriveManager.hpp"
|
||||||
#include "InstanceCheck.hpp"
|
#include "InstanceCheck.hpp"
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include "../Utils/MacDarkMode.hpp"
|
|
||||||
#include "DeepLinkHandlerMac.h"
|
#include "DeepLinkHandlerMac.h"
|
||||||
#endif
|
#endif
|
||||||
#include "NotificationManager.hpp"
|
#include "NotificationManager.hpp"
|
||||||
@@ -129,6 +129,8 @@
|
|||||||
#include "PrintHostDialogs.hpp"
|
#include "PrintHostDialogs.hpp"
|
||||||
#include "NetworkPluginDialog.hpp"
|
#include "NetworkPluginDialog.hpp"
|
||||||
#include "DesktopIntegrationDialog.hpp"
|
#include "DesktopIntegrationDialog.hpp"
|
||||||
|
#include "SendSystemInfoDialog.hpp"
|
||||||
|
#include "ParamsDialog.hpp"
|
||||||
#include "KBShortcutsDialog.hpp"
|
#include "KBShortcutsDialog.hpp"
|
||||||
#include "DownloadProgressDialog.hpp"
|
#include "DownloadProgressDialog.hpp"
|
||||||
#include "TroubleshootDialog.hpp"
|
#include "TroubleshootDialog.hpp"
|
||||||
@@ -139,6 +141,7 @@
|
|||||||
#include "Widgets/ProgressDialog.hpp"
|
#include "Widgets/ProgressDialog.hpp"
|
||||||
|
|
||||||
//BBS: DailyTip and UserGuide Dialog
|
//BBS: DailyTip and UserGuide Dialog
|
||||||
|
#include "WebDownPluginDlg.hpp"
|
||||||
#include "WebGuideDialog.hpp"
|
#include "WebGuideDialog.hpp"
|
||||||
#include "ReleaseNote.hpp"
|
#include "ReleaseNote.hpp"
|
||||||
#include "PrivacyUpdateDialog.hpp"
|
#include "PrivacyUpdateDialog.hpp"
|
||||||
@@ -1509,33 +1512,11 @@ int GUI_App::install_plugin(std::string name, std::string package_name, InstallP
|
|||||||
size_t n = mz_zip_reader_get_extra(&archive, stat.m_file_index, extra.data(), extra.size());
|
size_t n = mz_zip_reader_get_extra(&archive, stat.m_file_index, extra.data(), extra.size());
|
||||||
dest_file = decode(extra.substr(0, n), stat.m_filename);
|
dest_file = decode(extra.substr(0, n), stat.m_filename);
|
||||||
}
|
}
|
||||||
if (!is_path_within_root(dest_file, plugin_folder)) {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "[install_plugin] entry " << dest_file << " resolves outside " << plugin_folder.string();
|
|
||||||
close_zip_reader(&archive);
|
|
||||||
if (pro_fn) { pro_fn(InstallStatusUnzipFailed, 0, cancel); }
|
|
||||||
return InstallStatusUnzipFailed;
|
|
||||||
}
|
|
||||||
auto dest_path = plugin_folder / dest_file;
|
auto dest_path = plugin_folder / dest_file;
|
||||||
|
boost::filesystem::create_directories(dest_path.parent_path());
|
||||||
std::string dest_zip_file = encode_path(dest_path.string().c_str());
|
std::string dest_zip_file = encode_path(dest_path.string().c_str());
|
||||||
#ifndef WIN32
|
|
||||||
// Validate a symlink's target before anything at the destination is replaced.
|
|
||||||
const bool is_link = S_ISLNK(stat.m_external_attr >> 16);
|
|
||||||
std::string link;
|
|
||||||
if (is_link) {
|
|
||||||
link.assign(stat.m_uncomp_size, 0);
|
|
||||||
if (!mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, link.data(), stat.m_uncomp_size, 0) ||
|
|
||||||
!is_symlink_target_within_root(dest_file, link, plugin_folder)) {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "[install_plugin] link " << dest_file << " -> " << link << " is unreadable or resolves outside " << plugin_folder.string();
|
|
||||||
close_zip_reader(&archive);
|
|
||||||
if (pro_fn) { pro_fn(InstallStatusUnzipFailed, 0, cancel); }
|
|
||||||
return InstallStatusUnzipFailed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
try {
|
try {
|
||||||
boost::filesystem::create_directories(dest_path.parent_path());
|
if (fs::exists(dest_path)) {
|
||||||
// symlink_status so that an existing symlink, dangling or not, is replaced rather than written through.
|
|
||||||
if (fs::exists(fs::symlink_status(dest_path))) {
|
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
fs::remove(dest_path, ec);
|
fs::remove(dest_path, ec);
|
||||||
if (ec) {
|
if (ec) {
|
||||||
@@ -1563,8 +1544,9 @@ int GUI_App::install_plugin(std::string name, std::string package_name, InstallP
|
|||||||
}
|
}
|
||||||
mz_bool res = 0;
|
mz_bool res = 0;
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
if (is_link) {
|
if (S_ISLNK(stat.m_external_attr >> 16)) {
|
||||||
res = 1;
|
std::string link(stat.m_uncomp_size + 1, 0);
|
||||||
|
res = mz_zip_reader_extract_to_mem(&archive, stat.m_file_index, link.data(), stat.m_uncomp_size, 0);
|
||||||
try {
|
try {
|
||||||
boost::filesystem::create_symlink(link, dest_path);
|
boost::filesystem::create_symlink(link, dest_path);
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
@@ -2416,23 +2398,34 @@ GUI_App::~GUI_App()
|
|||||||
|
|
||||||
bool GUI_App::is_blocking_printing(MachineObject *obj_)
|
bool GUI_App::is_blocking_printing(MachineObject *obj_)
|
||||||
{
|
{
|
||||||
PresetBundle *preset_bundle = wxGetApp().preset_bundle;
|
DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager();
|
||||||
const std::string source_model = preset_bundle
|
|
||||||
? preset_bundle->printers.get_edited_preset().get_printer_type(preset_bundle)
|
|
||||||
: std::string();
|
|
||||||
return is_blocking_printing(obj_, source_model);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GUI_App::is_blocking_printing(MachineObject *obj_, const std::string& source_model)
|
|
||||||
{
|
|
||||||
DeviceManager *dev = getDeviceManager();
|
|
||||||
if (!dev) return true;
|
if (!dev) return true;
|
||||||
if (obj_ == nullptr)
|
std::string target_model;
|
||||||
|
if (obj_ == nullptr) {
|
||||||
obj_ = dev->get_selected_machine();
|
obj_ = dev->get_selected_machine();
|
||||||
if (!obj_)
|
if (obj_) {
|
||||||
return false;
|
target_model = obj_->printer_type;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target_model = obj_->printer_type;
|
||||||
|
}
|
||||||
|
|
||||||
return !DevPrinterConfigUtil::is_printer_model_compatible(source_model, *obj_);
|
if (!obj_)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PresetBundle *preset_bundle = wxGetApp().preset_bundle;
|
||||||
|
std::string source_model = preset_bundle->printers.get_edited_preset().get_printer_type(preset_bundle);
|
||||||
|
|
||||||
|
if (source_model != target_model) {
|
||||||
|
std::vector<std::string> compatible_machine = obj_->get_compatible_machine();
|
||||||
|
vector<std::string>::iterator it = find(compatible_machine.begin(), compatible_machine.end(), source_model);
|
||||||
|
if (it == compatible_machine.end()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If formatted for github, plaintext with OpenGL extensions enclosed into <details>.
|
// If formatted for github, plaintext with OpenGL extensions enclosed into <details>.
|
||||||
@@ -3993,16 +3986,20 @@ void GUI_App::set_live_printer_agent(std::shared_ptr<IPrinterAgent> agent)
|
|||||||
m_agent->set_user_selected_machine("");
|
m_agent->set_user_selected_machine("");
|
||||||
// note: belt-and-suspenders (precedent: DeviceManagerRefresher::on_timer)
|
// note: belt-and-suspenders (precedent: DeviceManagerRefresher::on_timer)
|
||||||
dev->OnSelectedMachineLost(); // why: clear stale sidebar sync-status / AMS
|
dev->OnSelectedMachineLost(); // why: clear stale sidebar sync-status / AMS
|
||||||
// why: retain agent-owned LAN discoveries so agents without automatic discovery (for
|
// why: drop stale LAN discoveries; keep My Devices, but only those belonging to the
|
||||||
// example the Moonraker-based Qidi/Snapmaker agents) can reuse them after a switch.
|
// agent we're about to swap to, so a device stamped by the outgoing agent doesn't
|
||||||
dev->clear_other_devices();
|
// linger hidden - the new agent's start_discovery re-inserts and re-stamps it fresh.
|
||||||
|
// agent is null when clearing the live agent entirely (e.g. plugin unload); there's no
|
||||||
|
// target to filter against then, so fall back to the original "keep all My Devices"
|
||||||
|
// behavior rather than guessing.
|
||||||
|
dev->clear_other_devices(agent ? agent->get_agent_info().id : std::string());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_agent->set_printer_agent(agent);
|
m_agent->set_printer_agent(agent);
|
||||||
sidebar().update_all_preset_comboboxes();
|
sidebar().update_all_preset_comboboxes();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GUI_App::resolve_printer_agent_id(const std::string& stored_id) const
|
std::string GUI_App::resolve_printer_agent_id(const std::string& stored_id)
|
||||||
{
|
{
|
||||||
if (!stored_id.empty())
|
if (!stored_id.empty())
|
||||||
return stored_id;
|
return stored_id;
|
||||||
@@ -4038,7 +4035,6 @@ void GUI_App::switch_printer_agent()
|
|||||||
|
|
||||||
std::string log_dir = data_dir();
|
std::string log_dir = data_dir();
|
||||||
std::string cloud_agent_id = agent_info.id == BBL_PRINTER_AGENT_ID ? BBL_CLOUD_PROVIDER : ORCA_CLOUD_PROVIDER;
|
std::string cloud_agent_id = agent_info.id == BBL_PRINTER_AGENT_ID ? BBL_CLOUD_PROVIDER : ORCA_CLOUD_PROVIDER;
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << agent_info.id;
|
|
||||||
std::shared_ptr<ICloudServiceAgent> cloud_agent = m_agent->get_cloud_agent(cloud_agent_id);
|
std::shared_ptr<ICloudServiceAgent> cloud_agent = m_agent->get_cloud_agent(cloud_agent_id);
|
||||||
|
|
||||||
// Create new printer agent via registry
|
// Create new printer agent via registry
|
||||||
@@ -4052,10 +4048,8 @@ void GUI_App::switch_printer_agent()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare the registered IDs, not only the implementation pointer. Different registry IDs
|
// The factory caches agents per ID, so an identical pointer means the agent type is unchanged.
|
||||||
// may intentionally be backed by the same implementation object (especially for plugins).
|
if (m_agent->get_printer_agent() == new_printer_agent) {
|
||||||
const auto current_printer_agent = m_agent->get_printer_agent();
|
|
||||||
if (current_printer_agent && current_printer_agent->get_agent_info().id == effective_agent_id) {
|
|
||||||
// Orca: the agent type is unchanged (e.g. switching between two Moonraker/Klipper
|
// Orca: the agent type is unchanged (e.g. switching between two Moonraker/Klipper
|
||||||
// printer presets), so the selected machine and the agent's cached device_info still
|
// printer presets), so the selected machine and the agent's cached device_info still
|
||||||
// point at the previously active printer preset. Re-select the machine when the new
|
// point at the previously active printer preset. Re-select the machine when the new
|
||||||
@@ -5038,16 +5032,14 @@ bool GUI_App::is_user_login(const std::string& provider/* = ORCA_CLOUD_PROVIDER*
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GUI_App::get_printer_cloud_provider() const
|
const std::string& GUI_App::get_printer_cloud_provider() const
|
||||||
{
|
{
|
||||||
const std::string agent_id = resolve_printer_agent_id(
|
// Orca todo: this need to be revisted. currently it is mainly used for device manager and related clausses and only bambu machines use them.
|
||||||
preset_bundle ? preset_bundle->printers.get_edited_preset().config.opt_string("printer_agent")
|
//
|
||||||
: std::string());
|
return BBL_CLOUD_PROVIDER;
|
||||||
return agent_id == BBL_PRINTER_AGENT_ID ? BBL_CLOUD_PROVIDER : ORCA_CLOUD_PROVIDER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool GUI_App::check_login(const std::string& provider/* = ORCA_CLOUD_PROVIDER*/)
|
bool GUI_App::check_login(const std::string& provider/* = ORCA_CLOUD_PROVIDER*/)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|||||||
@@ -24,6 +24,9 @@
|
|||||||
#include <wx/snglinst.h>
|
#include <wx/snglinst.h>
|
||||||
#include <wx/msgdlg.h>
|
#include <wx/msgdlg.h>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
//#define BBL_HAS_FIRST_PAGE 1
|
//#define BBL_HAS_FIRST_PAGE 1
|
||||||
#define STUDIO_INACTIVE_TIMEOUT 15*60*1000
|
#define STUDIO_INACTIVE_TIMEOUT 15*60*1000
|
||||||
#define LOG_FILES_MAX_NUM 30
|
#define LOG_FILES_MAX_NUM 30
|
||||||
@@ -370,7 +373,6 @@ public:
|
|||||||
EAppMode get_app_mode() const { return m_app_mode; }
|
EAppMode get_app_mode() const { return m_app_mode; }
|
||||||
Slic3r::DeviceManager* getDeviceManager() { return m_device_manager; }
|
Slic3r::DeviceManager* getDeviceManager() { return m_device_manager; }
|
||||||
bool is_blocking_printing(MachineObject *obj_ = nullptr);
|
bool is_blocking_printing(MachineObject *obj_ = nullptr);
|
||||||
bool is_blocking_printing(MachineObject *obj_, const std::string& source_model);
|
|
||||||
Slic3r::TaskManager* getTaskManager() { return m_task_manager; }
|
Slic3r::TaskManager* getTaskManager() { return m_task_manager; }
|
||||||
HMSQuery* get_hms_query() { return hms_query; }
|
HMSQuery* get_hms_query() { return hms_query; }
|
||||||
NetworkAgent* getAgent() { return m_agent; }
|
NetworkAgent* getAgent() { return m_agent; }
|
||||||
@@ -378,7 +380,7 @@ public:
|
|||||||
// Reconcile the live printer agent with the stored preset selection.
|
// Reconcile the live printer agent with the stored preset selection.
|
||||||
void switch_printer_agent();
|
void switch_printer_agent();
|
||||||
|
|
||||||
std::string resolve_printer_agent_id(const std::string& stored_id) const;
|
std::string resolve_printer_agent_id(const std::string& stored_id);
|
||||||
// ORCA TODO: in the future, bbl presets should specify "bbl" printer agent id
|
// ORCA TODO: in the future, bbl presets should specify "bbl" printer agent id
|
||||||
// then, all resolve and canonical would just be ORCA<->""
|
// then, all resolve and canonical would just be ORCA<->""
|
||||||
std::string canonical_printer_agent_id(const std::string& picked_id);
|
std::string canonical_printer_agent_id(const std::string& picked_id);
|
||||||
@@ -509,7 +511,7 @@ public:
|
|||||||
bool check_login(const std::string& provider = ORCA_CLOUD_PROVIDER);
|
bool check_login(const std::string& provider = ORCA_CLOUD_PROVIDER);
|
||||||
void get_login_info(const std::string& provider = ORCA_CLOUD_PROVIDER);
|
void get_login_info(const std::string& provider = ORCA_CLOUD_PROVIDER);
|
||||||
bool is_user_login(const std::string& provider = ORCA_CLOUD_PROVIDER);
|
bool is_user_login(const std::string& provider = ORCA_CLOUD_PROVIDER);
|
||||||
std::string get_printer_cloud_provider() const;
|
const std::string& get_printer_cloud_provider() const;
|
||||||
|
|
||||||
void request_user_login(int online_login = 0, const std::string& provider = ORCA_CLOUD_PROVIDER);
|
void request_user_login(int online_login = 0, const std::string& provider = ORCA_CLOUD_PROVIDER);
|
||||||
void request_user_handle(int online_login = 0, const std::string& provider = ORCA_CLOUD_PROVIDER);
|
void request_user_handle(int online_login = 0, const std::string& provider = ORCA_CLOUD_PROVIDER);
|
||||||
|
|||||||
@@ -483,6 +483,11 @@ void IMSlider::draw_background_and_groove(const ImRect& bg_rect, const ImRect& g
|
|||||||
ImGui::RenderFrame(groove.Min, groove.Max, groove_col, false, 0.5 * groove.GetWidth());
|
ImGui::RenderFrame(groove.Min, groove.Max, groove_col, false, 0.5 * groove.GetWidth());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IMSlider::is_dragging() const
|
||||||
|
{
|
||||||
|
return GImGui != nullptr && m_imgui_id != 0 && GImGui->ActiveId == m_imgui_id && GImGui->IO.MouseDown[0];
|
||||||
|
}
|
||||||
|
|
||||||
bool IMSlider::horizontal_slider(const char* str_id, int* value, int v_min, int v_max, const ImVec2& size, float scale)
|
bool IMSlider::horizontal_slider(const char* str_id, int* value, int v_min, int v_max, const ImVec2& size, float scale)
|
||||||
{
|
{
|
||||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||||
@@ -491,6 +496,7 @@ bool IMSlider::horizontal_slider(const char* str_id, int* value, int v_min, int
|
|||||||
|
|
||||||
ImGuiContext& context = *GImGui;
|
ImGuiContext& context = *GImGui;
|
||||||
const ImGuiID id = window->GetID(str_id);
|
const ImGuiID id = window->GetID(str_id);
|
||||||
|
m_imgui_id = id;
|
||||||
|
|
||||||
const ImVec2 pos = window->DC.CursorPos;
|
const ImVec2 pos = window->DC.CursorPos;
|
||||||
const ImRect draw_region(pos, pos + size);
|
const ImRect draw_region(pos, pos + size);
|
||||||
@@ -883,6 +889,7 @@ bool IMSlider::vertical_slider(const char* str_id, int* higher_value, int* lower
|
|||||||
|
|
||||||
ImGuiContext& context = *GImGui;
|
ImGuiContext& context = *GImGui;
|
||||||
const ImGuiID id = window->GetID(str_id);
|
const ImGuiID id = window->GetID(str_id);
|
||||||
|
m_imgui_id = id;
|
||||||
|
|
||||||
const ImVec2 pos = window->DC.CursorPos;
|
const ImVec2 pos = window->DC.CursorPos;
|
||||||
const ImRect draw_region(pos, pos + size);
|
const ImRect draw_region(pos, pos + size);
|
||||||
|
|||||||
@@ -118,6 +118,9 @@ public:
|
|||||||
|
|
||||||
//BBS update scroll value changed
|
//BBS update scroll value changed
|
||||||
bool is_dirty() { return m_dirty; }
|
bool is_dirty() { return m_dirty; }
|
||||||
|
// whether the mouse is holding this slider's handle, read from ImGui's active id rather than
|
||||||
|
// from the dirty flag, which is raised and consumed inside a single frame
|
||||||
|
bool is_dragging() const;
|
||||||
void set_as_dirty(bool dirty = true) { m_dirty = dirty; }
|
void set_as_dirty(bool dirty = true) { m_dirty = dirty; }
|
||||||
bool is_need_post_tick_event() { return m_is_need_post_tick_changed_event; }
|
bool is_need_post_tick_event() { return m_is_need_post_tick_changed_event; }
|
||||||
void reset_post_tick_event(bool val = false) {
|
void reset_post_tick_event(bool val = false) {
|
||||||
@@ -182,6 +185,8 @@ private:
|
|||||||
int m_higher_value;
|
int m_higher_value;
|
||||||
int m_one_layer_value; // ORCA
|
int m_one_layer_value; // ORCA
|
||||||
bool m_dirty = false;
|
bool m_dirty = false;
|
||||||
|
// the ImGui id of the slider widget, as of its last render
|
||||||
|
unsigned int m_imgui_id = 0;
|
||||||
|
|
||||||
bool m_render_as_disabled{ false };
|
bool m_render_as_disabled{ false };
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user