Merge remote-tracking branch 'upstream/main' into feedback

This commit is contained in:
Clifford Garwood
2026-04-21 14:56:08 -04:00
10271 changed files with 1877977 additions and 1865978 deletions
+13
View File
@@ -14,6 +14,7 @@ find_package(libnoise REQUIRED)
add_subdirectory(libslic3r)
if (SLIC3R_GUI)
add_subdirectory(glad)
# imgui, imguizmo, and hidapi are now included from deps_src
add_subdirectory(libvgcode)
@@ -43,6 +44,18 @@ if (SLIC3R_GUI)
include(${wxWidgets_USE_FILE})
endif()
if(APPLE AND TARGET wx::wxgl)
# Newer wxWidgets CMake exports may inject the macOS OpenGL framework
# as a quoted file path inside wx::wxgl, which Ninja then treats as a
# missing input file. Orca links OpenGL explicitly elsewhere, so strip
# these broken pseudo-paths from the imported target.
get_target_property(_wx_gl_libs wx::wxgl INTERFACE_LINK_LIBRARIES)
if(_wx_gl_libs)
list(FILTER _wx_gl_libs EXCLUDE REGEX "framework OpenGL")
set_target_properties(wx::wxgl PROPERTIES INTERFACE_LINK_LIBRARIES "${_wx_gl_libs}")
endif()
endif()
find_package(JPEG QUIET)
string(REGEX MATCH "wxpng" WX_PNG_BUILTIN ${wxWidgets_LIBRARIES})
+42 -30
View File
@@ -88,7 +88,9 @@ using namespace nlohmann;
#include <GLFW/glfw3.h>
#ifdef __WXGTK__
#if __has_include(<X11/Xlib.h>)
#include <X11/Xlib.h>
#endif
#include <unistd.h>
#endif
@@ -444,7 +446,7 @@ void record_exit_reson(std::string outputdir, int code, int plate_id, std::strin
boost::nowide::ofstream c;
c.open(result_file, std::ios::out | std::ios::trunc);
c << std::setw(4) << j << std::endl;
c << j.dump(1, '\t') << std::endl;
c.close();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", saved config to %1%\n")%result_file;
@@ -1183,30 +1185,42 @@ int CLI::run(int argc, char **argv)
save_main_thread_id();
#ifdef __WXGTK__
// On Linux, wxGTK has no support for Wayland, and the app crashes on
// startup if gtk3 is used. This env var has to be set explicitly to
// instruct the window manager to fall back to X server mode.
::setenv("GDK_BACKEND", "x11", /* replace */ true);
// Safety fallback: if wxWidgets was not built with EGL support, native
// Wayland will crash in wxGLCanvas::IsDisplaySupported() because the GLX
// backend cannot access an X11 display. Force X11 mode in that case.
// NOTE: Do NOT remove this block even after enabling wxHAS_EGL
// in the build — it protects against builds where deps were not rebuilt.
#if !defined(wxHAS_EGL) || !wxHAS_EGL
{
const char* wayland_env = ::getenv("WAYLAND_DISPLAY");
if (wayland_env && *wayland_env) {
BOOST_LOG_TRIVIAL(warning) << "Wayland detected but wxWidgets has no EGL support (wxHAS_EGL is OFF). Forcing X11 backend.";
::setenv("GDK_BACKEND", "x11", true);
}
}
#endif
// WebKit2GTK's compositing mode can fail under XWayland, causing WebViews
// (like the Setup Wizard) to render blank or freeze. Disabling compositing
// mode forces software rendering, which works reliably on all backends.
::setenv("WEBKIT_DISABLE_COMPOSITING_MODE", "1", /* replace */ false);
// On Linux dual-GPU systems, request the high-performance discrete GPU.
// DRI_PRIME=1 handles AMD and nouveau (open-source NVIDIA) PRIME setups.
::setenv("DRI_PRIME", "1", /* replace */ false);
// For NVIDIA proprietary driver PRIME render offload, set additional variables.
// Only set if the NVIDIA kernel module is loaded to avoid breaking systems without NVIDIA.
if (::access("/proc/driver/nvidia/version", F_OK) == 0) {
::setenv("__NV_PRIME_RENDER_OFFLOAD", "1", /* replace */ false);
::setenv("__GLX_VENDOR_LIBRARY_NAME", "nvidia", /* replace */ false);
// WebKit2GTK compositing can fail under XWayland. Only disable it when
// both DISPLAY and WAYLAND_DISPLAY are set (i.e., XWayland is in use).
// On pure X11 or native Wayland, compositing is left enabled.
{
const char* display_env_wk = ::getenv("DISPLAY");
const char* wayland_env_wk = ::getenv("WAYLAND_DISPLAY");
if (display_env_wk && *display_env_wk && wayland_env_wk && *wayland_env_wk) {
::setenv("WEBKIT_DISABLE_COMPOSITING_MODE", "1", /* replace */ false);
}
}
// Also on Linux, we need to tell Xlib that we will be using threads,
// lest we crash when we fire up GStreamer.
XInitThreads();
// XInitThreads is needed before GStreamer may use Xlib. On native
// Wayland without DISPLAY, GStreamer uses waylandsink (no Xlib).
#if __has_include(<X11/Xlib.h>)
{
const char* display_env = ::getenv("DISPLAY");
if (display_env && *display_env) {
XInitThreads();
}
}
#endif
#endif
// Switch boost::filesystem to utf8.
@@ -1280,19 +1294,17 @@ int CLI::run(int argc, char **argv)
if (start_gui) {
BOOST_LOG_TRIVIAL(info) << "no action, start gui directly" << std::endl;
#ifdef SLIC3R_GUI
/*#if !defined(_WIN32) && !defined(__APPLE__)
#if !defined(_WIN32) && !defined(__APPLE__)
// likely some linux / unix system
const char *display = boost::nowide::getenv("DISPLAY");
// const char *wayland_display = boost::nowide::getenv("WAYLAND_DISPLAY");
//if (! ((display && *display) || (wayland_display && *wayland_display))) {
if (! (display && *display)) {
// DISPLAY not set.
boost::nowide::cerr << "DISPLAY not set, GUI mode not available." << std::endl << std::endl;
const char *wayland_display = boost::nowide::getenv("WAYLAND_DISPLAY");
if (! ((display && *display) || (wayland_display && *wayland_display))) {
boost::nowide::cerr << "Neither DISPLAY nor WAYLAND_DISPLAY set, GUI mode not available." << std::endl << std::endl;
this->print_help(false);
// Indicate an error.
return 1;
}
#endif // some linux / unix system*/
#endif // some linux / unix system
Slic3r::GUI::GUI_InitParams params;
params.argc = argc;
params.argv = argv;
@@ -6453,7 +6465,7 @@ int CLI::run(int argc, char **argv)
BOOST_LOG_TRIVIAL(error) << "init opengl failed! skip thumbnail generating" << std::endl;
}
else {
BOOST_LOG_TRIVIAL(info) << "glewInit Success." << std::endl;
BOOST_LOG_TRIVIAL(info) << "gladLoadGL Success." << std::endl;
GLVolumeCollection glvolume_collection;
Model &model = m_models[0];
int obj_extruder_id = 1, volume_extruder_id = 1;
@@ -1,9 +0,0 @@
[Desktop Entry]
Name=Bambu GCode viewer
Exec=orca-slicer --gcodeviewer %F
Icon=OrcaSlicer-gcodeviewer
Terminal=false
Type=Application
MimeType=text/x.gcode;
Categories=Graphics;3DGraphics;
Keywords=3D;Printing;Slicer;
@@ -1,5 +1,7 @@
#!/bin/sh
#!/usr/bin/env bash
APPIMAGETOOLURL="https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-$(uname -m).AppImage"
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../../.." && pwd)"
APP_IMAGE="@SLIC3R_APP_KEY@_Linux_V@SoftFever_VERSION@.AppImage"
@@ -11,30 +13,40 @@ if [ -f /.dockerenv ] ; then # Only run if inside of a Docker Container
sed '0,/AI\x02/{s|AI\x02|\x00\x00\x00|}' -i ../appimagetool.AppImage
fi
sed -i -e 's#/usr#././#g' bin/@SLIC3R_APP_CMD@
mv @SLIC3R_APP_CMD@ AppRun
chmod +x AppRun
cp resources/images/@SLIC3R_APP_KEY@_192px.png @SLIC3R_APP_KEY@.png
mkdir -p usr/share/icons/hicolor/192x192/apps
cp resources/images/@SLIC3R_APP_KEY@_192px.png usr/share/icons/hicolor/192x192/apps/@SLIC3R_APP_KEY@.png
cat <<EOF > @SLIC3R_APP_KEY@.desktop
cat <<EOF > com.orcaslicer.@SLIC3R_APP_KEY@.desktop
[Desktop Entry]
Name=@SLIC3R_APP_KEY@
Exec=AppRun %F
Icon=@SLIC3R_APP_KEY@
Type=Application
PrefersNonDefaultGPU=true
X-KDE-RunOnDiscreteGpu=true
Categories=Utility;
MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;
EOF
mkdir -p usr/share/applications
cp com.orcaslicer.@SLIC3R_APP_KEY@.desktop usr/share/applications/
mkdir -p usr/share/metainfo
cp "${REPO_ROOT}/scripts/flatpak/com.orcaslicer.@SLIC3R_APP_KEY@.metainfo.xml" \
"usr/share/metainfo/com.orcaslicer.@SLIC3R_APP_KEY@.metainfo.xml"
cp "${REPO_ROOT}/scripts/flatpak/com.orcaslicer.@SLIC3R_APP_KEY@.metainfo.xml" \
"usr/share/metainfo/com.orcaslicer.@SLIC3R_APP_KEY@.appdata.xml"
export ARCH=$(uname -m)
if [ -f /.dockerenv ] ; then # Only run if inside of a Docker Container
../appimagetool.AppImage --appimage-extract-and-run . $([ ! -z "${container}" ] && echo '--appimage-extract-and-run')
../appimagetool.AppImage --appimage-extract-and-run . $([ -n "${container}" ] && echo '--appimage-extract-and-run')
else
../appimagetool.AppImage . $([ ! -z "${container}" ] && echo '--appimage-extract-and-run')
../appimagetool.AppImage . $([ -n "${container}" ] && echo '--appimage-extract-and-run')
fi
mv @SLIC3R_APP_KEY@-$(uname -m).AppImage ${APP_IMAGE}
@@ -3,10 +3,25 @@
# Despite the script name, this doesn't necessarily create an "image";
# it sets up a compatibility script wrapper for the binary and arranges some resources.
set -e
export ROOT=$(echo $ROOT | grep . || pwd)
export NCORES=`nproc --all`
export NCORES=$(nproc --all)
CONFIG=Release
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)"
POLICY_FILE="${REPO_ROOT}/scripts/appimage_lib_policy.sh"
CHECK_SCRIPT="${REPO_ROOT}/scripts/check_appimage_libs.sh"
if [ ! -f "${POLICY_FILE}" ]; then
echo "Error: missing AppImage helper ${POLICY_FILE}"
exit 1
fi
# shellcheck source=/dev/null
source "${POLICY_FILE}"
while getopts ":ihR:" opt; do
case ${opt} in
i )
@@ -23,35 +38,324 @@ while getopts ":ihR:" opt; do
esac
done
copy_directory_if_present() {
local src_dir="$1"
local dst_dir="$2"
if [ -n "$src_dir" ] && [ -d "$src_dir" ]; then
mkdir -p "$dst_dir"
cp -a "$src_dir"/. "$dst_dir"/
fi
}
find_pkg_config_dir() {
local variable="$1"
shift
local module
for module in "$@"; do
if pkg-config --exists "$module" 2>/dev/null; then
pkg-config --variable="$variable" "$module" 2>/dev/null || true
return 0
fi
done
return 1
}
find_first_existing_file() {
local path
for path in "$@"; do
if [ -f "$path" ]; then
printf '%s\n' "$path"
return 0
fi
done
return 1
}
copy_shared_object_to_dir() {
local src="$1"
local dst_dir="$2"
local src_real dst_name soname
src_real="$(readlink -f "$src")"
dst_name="$(basename "$src_real")"
mkdir -p "$dst_dir"
cp -fL "$src_real" "$dst_dir/$dst_name"
if [ -L "$src" ]; then
ln -snf "$dst_name" "$dst_dir/$(basename "$src")"
fi
soname="$(objdump -p "$src_real" 2>/dev/null | awk '$1 == "SONAME" { print $2; exit }')"
if [ -n "$soname" ] && [ "$soname" != "$dst_name" ]; then
ln -snf "$dst_name" "$dst_dir/$soname"
fi
}
bundle_dependency_closure() {
local dst_dir="$1"
shift
local -a queue=("$@")
local target dep dep_real copied_path
declare -A seen=()
while [ ${#queue[@]} -gt 0 ]; do
target="${queue[0]}"
queue=("${queue[@]:1}")
if [ ! -e "$target" ] || ! appimage_is_elf_file "$target"; then
continue
fi
while IFS= read -r dep; do
if [[ "$dep" == MISSING:* ]]; then
echo "Error: missing runtime dependency ${dep#MISSING:} while bundling $target"
exit 1
fi
dep_real="$(readlink -f "$dep" 2>/dev/null || printf '%s' "$dep")"
if appimage_is_host_library "$dep_real"; then
continue
fi
if [ -n "${seen[$dep_real]}" ]; then
continue
fi
seen[$dep_real]=1
copy_shared_object_to_dir "$dep" "$dst_dir"
copied_path="$dst_dir/$(basename "$dep_real")"
if [ -e "$copied_path" ]; then
queue+=("$copied_path")
fi
done < <(appimage_list_direct_dependencies "$target")
done
}
echo -n "[9/9] Generating Linux app..."
#{
# create directory and copy into it
# {
if [ -d "package" ]; then
rm -rf package
rm -rf package
fi
APPDIR="package"
BIN_DIR="$APPDIR/bin"
LIB_DIR="$APPDIR/lib"
PRIVATE_LIB_DIR="$LIB_DIR/orca-runtime"
SHARE_DIR="$APPDIR/share"
LIBEXEC_DIR="$APPDIR/libexec"
BUNDLE_DESKTOP_STACK="${ORCA_BUNDLE_DESKTOP_STACK:-0}"
GST_PLUGIN_DIR="$LIB_DIR/gstreamer-1.0"
GIO_MODULE_DIR="$LIB_DIR/gio/modules"
GDK_PIXBUF_DIR="$LIB_DIR/gdk-pixbuf-2.0/2.10.0/loaders"
mkdir -p "$BIN_DIR" "$LIB_DIR" "$PRIVATE_LIB_DIR" "$SHARE_DIR" "$LIBEXEC_DIR"
if [ "$BUNDLE_DESKTOP_STACK" = "1" ]; then
mkdir -p "$GST_PLUGIN_DIR" "$GIO_MODULE_DIR" "$GDK_PIXBUF_DIR"
fi
mkdir -p package/bin
cp -Rf ../resources "$APPDIR/resources"
# Copy Resources
cp -Rf ../resources package/resources
# Find and hard link the @SLIC3R_APP_CMD@ binary from Multi-Config build
ORIGINAL_BINARY_LOCATION=""
if [ -f "src/${CONFIG}/@SLIC3R_APP_CMD@" ]; then
ORIGINAL_BINARY_LOCATION="$(realpath "src/${CONFIG}/@SLIC3R_APP_CMD@")"
ORIGINAL_BINARY_LOCATION="$(realpath "src/${CONFIG}/@SLIC3R_APP_CMD@")"
elif [ -f "src/@SLIC3R_APP_CMD@" ]; then
# Fallback for single-config builds
ORIGINAL_BINARY_LOCATION="$(realpath "src/@SLIC3R_APP_CMD@")"
else
echo "Error: @SLIC3R_APP_CMD@ binary not found in any configuration directory"
exit 1
fi
cp -fl "${ORIGINAL_BINARY_LOCATION}" package/bin/@SLIC3R_APP_CMD@
cp -fl "${ORIGINAL_BINARY_LOCATION}" "$BIN_DIR/@SLIC3R_APP_CMD@"
if [ "$BUNDLE_DESKTOP_STACK" = "1" ]; then
GSTREAMER_PLUGIN_SOURCE_DIR="$(find_pkg_config_dir pluginsdir gstreamer-1.0 || true)"
if [ -z "$GSTREAMER_PLUGIN_SOURCE_DIR" ]; then
GSTREAMER_PLUGIN_SOURCE_DIR="$(find /usr/lib /usr/lib64 -maxdepth 4 -type d -name gstreamer-1.0 2>/dev/null | head -n1)"
fi
copy_directory_if_present "$GSTREAMER_PLUGIN_SOURCE_DIR" "$GST_PLUGIN_DIR"
GIO_MODULE_SOURCE_DIR="$(find_pkg_config_dir giomoduledir gio-2.0 || true)"
if [ -z "$GIO_MODULE_SOURCE_DIR" ]; then
GIO_MODULE_SOURCE_DIR="$(find /usr/lib /usr/lib64 -maxdepth 5 -type d -path '*/gio/modules' 2>/dev/null | head -n1)"
fi
copy_directory_if_present "$GIO_MODULE_SOURCE_DIR" "$GIO_MODULE_DIR"
GDK_PIXBUF_SOURCE_DIR="$(find_pkg_config_dir gdk_pixbuf_moduledir gdk-pixbuf-2.0 || true)"
if [ -z "$GDK_PIXBUF_SOURCE_DIR" ]; then
GDK_PIXBUF_SOURCE_DIR="$(find /usr/lib /usr/lib64 -maxdepth 6 -type d -path '*/gdk-pixbuf-2.0/*/loaders' 2>/dev/null | head -n1)"
fi
copy_directory_if_present "$GDK_PIXBUF_SOURCE_DIR" "$GDK_PIXBUF_DIR"
GLIB_SCHEMAS_SOURCE_DIR="$(find_pkg_config_dir schemasdir gio-2.0 || true)"
if [ -z "$GLIB_SCHEMAS_SOURCE_DIR" ]; then
GLIB_SCHEMAS_SOURCE_DIR="/usr/share/glib-2.0/schemas"
fi
copy_directory_if_present "$GLIB_SCHEMAS_SOURCE_DIR" "$SHARE_DIR/glib-2.0/schemas"
if [ -d "$SHARE_DIR/glib-2.0/schemas" ] && command -v glib-compile-schemas >/dev/null 2>&1; then
glib-compile-schemas "$SHARE_DIR/glib-2.0/schemas"
fi
# Distros disagree on where helper executables live: pkg-config may point to libexec,
# Debian/Ubuntu often ship the scanner under a multiarch libdir, and RPM distros may use lib64.
GST_PLUGIN_SCANNER_SOURCE="$(find_first_existing_file \
"$(find_pkg_config_dir pluginscannerdir gstreamer-1.0 || true)/gst-plugin-scanner" \
/usr/libexec/gstreamer-1.0/gst-plugin-scanner \
/usr/lib/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner \
/usr/lib/*/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner \
/usr/lib64/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner)" || true
if [ -n "$GST_PLUGIN_SCANNER_SOURCE" ]; then
mkdir -p "$LIBEXEC_DIR/gstreamer-1.0"
cp -fL "$GST_PLUGIN_SCANNER_SOURCE" "$LIBEXEC_DIR/gstreamer-1.0/gst-plugin-scanner"
fi
# Prefer the canonical pkg-config-reported helper path, but keep PATH-based fallbacks
# for distros exposing gdk-pixbuf-query-loaders or gdk-pixbuf-query-loaders-64 directly.
GDK_PIXBUF_QUERY_LOADERS_SOURCE="$(find_first_existing_file \
"$(pkg-config --variable=gdk_pixbuf_query_loaders gdk-pixbuf-2.0 2>/dev/null || true)" \
"$(command -v gdk-pixbuf-query-loaders 2>/dev/null || true)" \
"$(command -v gdk-pixbuf-query-loaders-64 2>/dev/null || true)")" || true
if [ -n "$GDK_PIXBUF_QUERY_LOADERS_SOURCE" ]; then
cp -fL "$GDK_PIXBUF_QUERY_LOADERS_SOURCE" "$LIBEXEC_DIR/gdk-pixbuf-query-loaders"
fi
fi
# WebKitGTK helper binaries are resolved from distro-specific absolute paths
# baked into libwebkit2gtk. Bundling Ubuntu's WebKitGTK inside an AppImage
# built with -g makes those helper paths unusable on Fedora and vice versa,
# so rely on the host WebKitGTK runtime instead of copying the helper stack.
mapfile -d '' BUNDLE_TARGETS < <(find "$BIN_DIR" "$LIB_DIR" "$LIBEXEC_DIR" -type f -print0 2>/dev/null)
bundle_dependency_closure "$PRIVATE_LIB_DIR" "${BUNDLE_TARGETS[@]}"
cat << EOF >"$LIBEXEC_DIR/@SLIC3R_APP_CMD@-env"
#!/bin/sh
set -e
SELF_DIR=\$(CDPATH= cd -- "\$(dirname -- "\$0")" && pwd)
APPDIR="\${APPDIR:-\$(CDPATH= cd -- "\$SELF_DIR/.." && pwd)}"
USE_BUNDLED_WEBKITGTK_STACK=0
if [ -e "\$APPDIR/lib/libwebkit2gtk-4.1.so.0" ] || [ -e "\$APPDIR/lib/libwebkit2gtk-4.0.so.0" ]; then
USE_BUNDLED_WEBKITGTK_STACK=1
fi
export APPDIR
PRIVATE_LIB_DIR="\$APPDIR/lib/orca-runtime"
if [ -d "\$PRIVATE_LIB_DIR" ]; then
export LD_LIBRARY_PATH="\$PRIVATE_LIB_DIR:\$APPDIR/bin\${LD_LIBRARY_PATH:+:\$LD_LIBRARY_PATH}"
else
export LD_LIBRARY_PATH="\$APPDIR/bin\${LD_LIBRARY_PATH:+:\$LD_LIBRARY_PATH}"
fi
has_host_runtime_library() {
local lib_name path
if command -v ldconfig >/dev/null 2>&1; then
if ldconfig -p 2>/dev/null | grep -Fq " \$lib_name"; then
return 0
fi
fi
for path in \
/lib /lib64 /usr/lib /usr/lib64 \
/usr/lib/* /usr/lib64/* /lib/* /lib64/*; do
if [ -e "\$path/\$lib_name" ]; then
return 0
fi
done
return 1
}
target_missing_runtime_library() {
local target_bin="\$1"
local lib_name="\$2"
if [ -z "\$target_bin" ] || [ ! -e "\$target_bin" ]; then
return 1
fi
if command -v ldd >/dev/null 2>&1; then
if ldd "\$target_bin" 2>/dev/null | grep -Fq "\$lib_name => not found"; then
return 0
fi
fi
return 1
}
TARGET_BIN="\$1"
if target_missing_runtime_library "\$TARGET_BIN" "libOpenGL.so.0" || ! has_host_runtime_library "libOpenGL.so.0"; then
echo "Error: missing host OpenGL runtime library libOpenGL.so.0." >&2
echo "On Ubuntu/Pop!_OS/Debian, install: libopengl0 and libglu1-mesa" >&2
echo "On Arch/CachyOS, install: libglvnd" >&2
exit 1
fi
if [ "\$USE_BUNDLED_WEBKITGTK_STACK" = "1" ]; then
export LD_LIBRARY_PATH="\$APPDIR/lib\${LD_LIBRARY_PATH:+:\$LD_LIBRARY_PATH}"
export GST_PLUGIN_SYSTEM_PATH=""
export GST_PLUGIN_PATH="\$APPDIR/lib/gstreamer-1.0\${GST_PLUGIN_PATH:+:\$GST_PLUGIN_PATH}"
export GIO_EXTRA_MODULES="\$APPDIR/lib/gio/modules\${GIO_EXTRA_MODULES:+:\$GIO_EXTRA_MODULES}"
export XDG_DATA_DIRS="\$APPDIR/share\${XDG_DATA_DIRS:+:\$XDG_DATA_DIRS}"
if [ -d "\$APPDIR/share/glib-2.0/schemas" ]; then
export GSETTINGS_SCHEMA_DIR="\$APPDIR/share/glib-2.0/schemas"
fi
if [ -x "\$APPDIR/libexec/gstreamer-1.0/gst-plugin-scanner" ]; then
export GST_PLUGIN_SCANNER="\$APPDIR/libexec/gstreamer-1.0/gst-plugin-scanner"
fi
if [ -d "\$APPDIR/lib/gdk-pixbuf-2.0/2.10.0/loaders" ]; then
export GDK_PIXBUF_MODULEDIR="\$APPDIR/lib/gdk-pixbuf-2.0/2.10.0/loaders"
if [ -x "\$APPDIR/libexec/gdk-pixbuf-query-loaders" ]; then
PIXBUF_CACHE_DIR="\${XDG_CACHE_HOME:-\$HOME/.cache}/@SLIC3R_APP_KEY@"
PIXBUF_CACHE_FILE="\$PIXBUF_CACHE_DIR/gdk-pixbuf-loaders.cache"
mkdir -p "\$PIXBUF_CACHE_DIR"
if [ ! -s "\$PIXBUF_CACHE_FILE" ] || find "\$APPDIR/lib/gdk-pixbuf-2.0/2.10.0/loaders" -type f -newer "\$PIXBUF_CACHE_FILE" | grep -q .; then
"\$APPDIR/libexec/gdk-pixbuf-query-loaders" "\$APPDIR/lib/gdk-pixbuf-2.0/2.10.0/loaders"/*.so > "\$PIXBUF_CACHE_FILE" 2>/dev/null || true
fi
if [ -s "\$PIXBUF_CACHE_FILE" ]; then
export GDK_PIXBUF_MODULE_FILE="\$PIXBUF_CACHE_FILE"
fi
fi
fi
if [ -d "\$APPDIR/lib/webkit2gtk-4.1" ]; then
export WEBKIT_EXEC_PATH="\$APPDIR/lib/webkit2gtk-4.1"
elif [ -d "\$APPDIR/lib/webkit2gtk-4.0" ]; then
export WEBKIT_EXEC_PATH="\$APPDIR/lib/webkit2gtk-4.0"
fi
if [ -d "\$APPDIR/lib/webkit2gtk-4.1/injected-bundle" ]; then
export WEBKIT_INJECTED_BUNDLE_PATH="\$APPDIR/lib/webkit2gtk-4.1/injected-bundle"
elif [ -d "\$APPDIR/lib/webkit2gtk-4.0/injected-bundle" ]; then
export WEBKIT_INJECTED_BUNDLE_PATH="\$APPDIR/lib/webkit2gtk-4.0/injected-bundle"
fi
else
if target_missing_runtime_library "\$TARGET_BIN" "libwebkit2gtk-4.1.so.0" || \
target_missing_runtime_library "\$TARGET_BIN" "libjavascriptcoregtk-4.1.so.0" || \
! has_host_runtime_library "libwebkit2gtk-4.1.so.0" || \
! has_host_runtime_library "libjavascriptcoregtk-4.1.so.0"; then
echo "Error: missing host WebKitGTK 4.1 runtime libraries." >&2
echo "Install the distro package providing libwebkit2gtk-4.1.so.0 and libjavascriptcoregtk-4.1.so.0." >&2
echo "On Arch/CachyOS, install: webkit2gtk-4.1" >&2
exit 1
fi
fi
exec "\$@"
EOF
chmod ug+x "$LIBEXEC_DIR/@SLIC3R_APP_CMD@-env"
# create bin
cat << EOF >@SLIC3R_APP_CMD@
#!/bin/bash
DIR=\$(readlink -f "\$0" | xargs dirname)
export LD_LIBRARY_PATH="\$DIR/bin:\$LD_LIBRARY_PATH"
DIR=\$(dirname "\$(readlink -f "\$0")")
export APPDIR="\${APPDIR:-\$DIR}"
# FIXME: OrcaSlicer segfault workarounds
# 1) OrcaSlicer will segfault on systems where locale info is not as expected (i.e. Holo-ISO arch-based distro)
@@ -76,38 +380,33 @@ if [ "\$XDG_SESSION_TYPE" = "wayland" ] && [ "\$ZINK_DISABLE_OVERRIDE" != "1" ];
fi
fi
fi
exec "\$DIR/bin/@SLIC3R_APP_CMD@" "\$@"
exec "\$DIR/libexec/@SLIC3R_APP_CMD@-env" "\$DIR/bin/@SLIC3R_APP_CMD@" "\$@"
EOF
chmod ug+x @SLIC3R_APP_CMD@
cp -fl @SLIC3R_APP_CMD@ package/@SLIC3R_APP_CMD@
# Nothing uses this tar? Remove if nobody has complained and it's been a while since this comment added.
# Original commit was https://github.com/OrcaSlicer/OrcaSlicer/commit/f5a4862da52fc68f77b5201ddf330a9800d83228
# and it doesn't appear to have been used there either.
#pushd package > /dev/null
#tar -cvf ../@SLIC3R_APP_KEY@.tar . &>/dev/null
#popd > /dev/null
#} &> $ROOT/Build.log # Capture all command output
cp -fl @SLIC3R_APP_CMD@ "$APPDIR/@SLIC3R_APP_CMD@"
if [ -x "${CHECK_SCRIPT}" ] && [ -z "${ORCA_SKIP_APPIMAGE_AUDIT}" ]; then
"${CHECK_SCRIPT}" "$APPDIR" "$BIN_DIR/@SLIC3R_APP_CMD@"
fi
# } &> $ROOT/Build.log # Capture all command output
echo "done"
if [[ -n "$BUILD_IMAGE" ]]
then
echo -n "Creating Appimage for distribution..."
#{
# AppImage script modifies files in place, so make a copy and clean up after.
# {
rm -rf package_appimage
cp -Rf package package_appimage
pushd package_appimage > /dev/null
chmod +x ../build_appimage.sh
if ../build_appimage.sh; then
# Clean up on success.
popd > /dev/null
mv package_appimage/"@SLIC3R_APP_KEY@_Linux_V@SoftFever_VERSION@.AppImage" "@SLIC3R_APP_KEY@_Linux_V@SoftFever_VERSION@.AppImage"
rm -fR package_appimage
popd > /dev/null
mv package_appimage/"@SLIC3R_APP_KEY@_Linux_V@SoftFever_VERSION@.AppImage" "@SLIC3R_APP_KEY@_Linux_V@SoftFever_VERSION@.AppImage"
rm -fR package_appimage
else
# Leave files on failure so you can debug.
popd > /dev/null
popd > /dev/null
fi
#} &> $ROOT/Build.log # Capture all command output
# } &> $ROOT/Build.log # Capture all command output
echo "done"
fi
@@ -5,6 +5,8 @@ Icon=OrcaSlicer
Exec=orca-slicer %U
Terminal=false
Type=Application
PrefersNonDefaultGPU=true
X-KDE-RunOnDiscreteGpu=true
MimeType=model/stl;model/3mf;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;x-scheme-handler/orcaslicer;model/step;
Categories=Graphics;3DGraphics;Engineering;
Keywords=3D;Printing;Slicer;slice;3D;printer;convert;gcode;stl;obj;amf;SLA
+3
View File
@@ -0,0 +1,3 @@
add_library(glad STATIC src/gl.c)
target_include_directories(glad PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(glad PRIVATE ${CMAKE_DL_LIBS})
+311
View File
@@ -0,0 +1,311 @@
#ifndef __khrplatform_h_
#define __khrplatform_h_
/*
** Copyright (c) 2008-2018 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and/or associated documentation files (the
** "Materials"), to deal in the Materials without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Materials, and to
** permit persons to whom the Materials are furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be included
** in all copies or substantial portions of the Materials.
**
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
*/
/* Khronos platform-specific types and definitions.
*
* The master copy of khrplatform.h is maintained in the Khronos EGL
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
* The last semantic modification to khrplatform.h was at commit ID:
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
*
* Adopters may modify this file to suit their platform. Adopters are
* encouraged to submit platform specific modifications to the Khronos
* group so that they can be included in future versions of this file.
* Please submit changes by filing pull requests or issues on
* the EGL Registry repository linked above.
*
*
* See the Implementer's Guidelines for information about where this file
* should be located on your system and for more details of its use:
* http://www.khronos.org/registry/implementers_guide.pdf
*
* This file should be included as
* #include <KHR/khrplatform.h>
* by Khronos client API header files that use its types and defines.
*
* The types in khrplatform.h should only be used to define API-specific types.
*
* Types defined in khrplatform.h:
* khronos_int8_t signed 8 bit
* khronos_uint8_t unsigned 8 bit
* khronos_int16_t signed 16 bit
* khronos_uint16_t unsigned 16 bit
* khronos_int32_t signed 32 bit
* khronos_uint32_t unsigned 32 bit
* khronos_int64_t signed 64 bit
* khronos_uint64_t unsigned 64 bit
* khronos_intptr_t signed same number of bits as a pointer
* khronos_uintptr_t unsigned same number of bits as a pointer
* khronos_ssize_t signed size
* khronos_usize_t unsigned size
* khronos_float_t signed 32 bit floating point
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
* nanoseconds
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
* khronos_boolean_enum_t enumerated boolean type. This should
* only be used as a base type when a client API's boolean type is
* an enum. Client APIs which use an integer or other type for
* booleans cannot use this as the base type for their boolean.
*
* Tokens defined in khrplatform.h:
*
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
*
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
*
* Calling convention macros defined in this file:
* KHRONOS_APICALL
* KHRONOS_APIENTRY
* KHRONOS_APIATTRIBUTES
*
* These may be used in function prototypes as:
*
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
* int arg1,
* int arg2) KHRONOS_APIATTRIBUTES;
*/
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
# define KHRONOS_STATIC 1
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APICALL
*-------------------------------------------------------------------------
* This precedes the return type of the function in the function prototype.
*/
#if defined(KHRONOS_STATIC)
/* If the preprocessor constant KHRONOS_STATIC is defined, make the
* header compatible with static linking. */
# define KHRONOS_APICALL
#elif defined(_WIN32)
# define KHRONOS_APICALL __declspec(dllimport)
#elif defined (__SYMBIAN32__)
# define KHRONOS_APICALL IMPORT_C
#elif defined(__ANDROID__)
# define KHRONOS_APICALL __attribute__((visibility("default")))
#else
# define KHRONOS_APICALL
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIENTRY
*-------------------------------------------------------------------------
* This follows the return type of the function and precedes the function
* name in the function prototype.
*/
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
/* Win32 but not WinCE */
# define KHRONOS_APIENTRY __stdcall
#else
# define KHRONOS_APIENTRY
#endif
/*-------------------------------------------------------------------------
* Definition of KHRONOS_APIATTRIBUTES
*-------------------------------------------------------------------------
* This follows the closing parenthesis of the function prototype arguments.
*/
#if defined (__ARMCC_2__)
#define KHRONOS_APIATTRIBUTES __softfp
#else
#define KHRONOS_APIATTRIBUTES
#endif
/*-------------------------------------------------------------------------
* basic type definitions
*-----------------------------------------------------------------------*/
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
/*
* Using <stdint.h>
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
/*
* To support platform where unsigned long cannot be used interchangeably with
* inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
* Ideally, we could just use (u)intptr_t everywhere, but this could result in
* ABI breakage if khronos_uintptr_t is changed from unsigned long to
* unsigned long long or similar (this results in different C++ name mangling).
* To avoid changes for existing platforms, we restrict usage of intptr_t to
* platforms where the size of a pointer is larger than the size of long.
*/
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
#define KHRONOS_USE_INTPTR_T
#endif
#endif
#elif defined(__VMS ) || defined(__sgi)
/*
* Using <inttypes.h>
*/
#include <inttypes.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
/*
* Win32
*/
typedef __int32 khronos_int32_t;
typedef unsigned __int32 khronos_uint32_t;
typedef __int64 khronos_int64_t;
typedef unsigned __int64 khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif defined(__sun__) || defined(__digital__)
/*
* Sun or Digital
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#if defined(__arch64__) || defined(_LP64)
typedef long int khronos_int64_t;
typedef unsigned long int khronos_uint64_t;
#else
typedef long long int khronos_int64_t;
typedef unsigned long long int khronos_uint64_t;
#endif /* __arch64__ */
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#elif 0
/*
* Hypothetical platform with no float or int64 support
*/
typedef int khronos_int32_t;
typedef unsigned int khronos_uint32_t;
#define KHRONOS_SUPPORT_INT64 0
#define KHRONOS_SUPPORT_FLOAT 0
#else
/*
* Generic fallback
*/
#include <stdint.h>
typedef int32_t khronos_int32_t;
typedef uint32_t khronos_uint32_t;
typedef int64_t khronos_int64_t;
typedef uint64_t khronos_uint64_t;
#define KHRONOS_SUPPORT_INT64 1
#define KHRONOS_SUPPORT_FLOAT 1
#endif
/*
* Types that are (so far) the same on all platforms
*/
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
typedef signed short int khronos_int16_t;
typedef unsigned short int khronos_uint16_t;
/*
* Types that differ between LLP64 and LP64 architectures - in LLP64,
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
* to be the only LLP64 architecture in current use.
*/
#ifdef KHRONOS_USE_INTPTR_T
typedef intptr_t khronos_intptr_t;
typedef uintptr_t khronos_uintptr_t;
#elif defined(_WIN64)
typedef signed long long int khronos_intptr_t;
typedef unsigned long long int khronos_uintptr_t;
#else
typedef signed long int khronos_intptr_t;
typedef unsigned long int khronos_uintptr_t;
#endif
#if defined(_WIN64)
typedef signed long long int khronos_ssize_t;
typedef unsigned long long int khronos_usize_t;
#else
typedef signed long int khronos_ssize_t;
typedef unsigned long int khronos_usize_t;
#endif
#if KHRONOS_SUPPORT_FLOAT
/*
* Float type
*/
typedef float khronos_float_t;
#endif
#if KHRONOS_SUPPORT_INT64
/* Time types
*
* These types can be used to represent a time interval in nanoseconds or
* an absolute Unadjusted System Time. Unadjusted System Time is the number
* of nanoseconds since some arbitrary system event (e.g. since the last
* time the system booted). The Unadjusted System Time is an unsigned
* 64 bit value that wraps back to 0 every 584 years. Time intervals
* may be either signed or unsigned.
*/
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
typedef khronos_int64_t khronos_stime_nanoseconds_t;
#endif
/*
* Dummy value used to pad enum types to 32 bits.
*/
#ifndef KHRONOS_MAX_ENUM
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
#endif
/*
* Enumerated boolean type
*
* Values other than zero should be considered to be true. Therefore
* comparisons should not be made against KHRONOS_TRUE.
*/
typedef enum {
KHRONOS_FALSE = 0,
KHRONOS_TRUE = 1,
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
} khronos_boolean_enum_t;
#endif /* __khrplatform_h_ */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -941,13 +941,13 @@ void AppConfig::save()
}
boost::nowide::ofstream c;
c.open(path_pid, std::ios::out | std::ios::trunc);
c << std::setw(4) << j << std::endl;
c << j.dump(1, '\t') << std::endl;
#ifdef WIN32
// WIN32 specific: The final "rename_file()" call is not safe in case of an application crash, there is no atomic "rename file" API
// provided by Windows (sic!). Therefore we save a MD5 checksum to be able to verify file corruption. In addition,
// we save the config file into a backup first before moving it to the final destination.
c << appconfig_md5_hash_line(j.dump(4));
c << appconfig_md5_hash_line(j.dump(1, '\t'));
#endif
c.close();
+10 -1
View File
@@ -527,7 +527,16 @@ bool BuildVolume::all_paths_inside(const GCodeProcessorResult& paths, const Boun
build_volume.max.z() = std::numeric_limits<double>::max();
if (ignore_bottom)
build_volume.min.z() = -std::numeric_limits<double>::max();
return build_volume.contains(paths_bbox);
// BBox-only callers may provide no moves. Validate bbox corners regardless of paths_bbox.defined.
if (paths.moves.empty())
return build_volume.contains(paths_bbox.min) && build_volume.contains(paths_bbox.max);
if (paths_bbox.defined && build_volume.contains(paths_bbox))
return true;
// Fallback: validate only relevant extrusion moves.
const BoundingBox3Base<Vec3f> build_volumef(build_volume.min.cast<float>(), build_volume.max.cast<float>());
return std::all_of(paths.moves.begin(), paths.moves.end(), [move_valid, build_volumef](const GCodeProcessorResult::MoveVertex &move)
{ return !move_valid(move) || build_volumef.contains(move.position); });
}
case BuildVolume_Type::Circle:
{
+1 -1
View File
@@ -1498,7 +1498,7 @@ void ConfigBase::save_to_json(const std::string &file, const std::string &name,
boost::nowide::ofstream c;
c.open(file, std::ios::out | std::ios::trunc);
c << std::setw(4) << j << std::endl;
c << j.dump(1, '\t') << std::endl;
c.close();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ":" <<__LINE__ << boost::format(", saved config to %1%\n")%file;
+2 -2
View File
@@ -443,9 +443,9 @@ namespace Emboss
/// Sample slice polygon by bounding boxes centers
/// slice start point has shape_center_x coor
/// </summary>
/// <param name="slice">Polygon and start point[Slic3r scaled milimeters]</param>
/// <param name="slice">Polygon and start point[Slic3r scaled millimeters]</param>
/// <param name="bbs">Bounding boxes of letter on one line[in font scales]</param>
/// <param name="scale">Scale for bbs (after multiply bb is in milimeters)</param>
/// <param name="scale">Scale for bbs (after multiply bb is in millimeters)</param>
/// <returns>Sampled polygon by bounding boxes</returns>
PolygonPoints sample_slice(const TextLine &slice, const BoundingBoxes &bbs, double scale);
+4 -3
View File
@@ -3082,6 +3082,7 @@ bool FillRectilinear::fill_surface_trapezoidal(
// Use extended object bounding box for consistent pattern across layers
BoundingBox bb = this->extended_object_bounding_box();
const size_t infill_layer_id = (surface->thickness_layers > 0) ? this->layer_id / surface->thickness_layers : this->layer_id;
switch (Pattern_type) {
case 0: // Grid / Trapezoidal
@@ -3144,8 +3145,8 @@ bool FillRectilinear::fill_surface_trapezoidal(
flip_vertical = !flip_vertical;
}
// transpose points for odd layers
if (layer_id % 2 == 1) {
// transpose points for odd infill layers (taking infill combination into account)
if (infill_layer_id % 2 == 1) {
for (Polyline& pl : polylines) {
for (Point& p : pl.points) {
std::swap(p.x(), p.y());
@@ -3174,7 +3175,7 @@ bool FillRectilinear::fill_surface_trapezoidal(
// Align bounding box to the grid
bb.merge(align_to_grid(bb.center(), Point(period,h)));
const int layer_mod = layer_id % 3;
const size_t layer_mod = infill_layer_id % 3;
const double angle = layer_mod * 2.0 * M_PI / 3.0;
const Point rotation_center = bb.center();
+14 -6
View File
@@ -313,6 +313,7 @@ static constexpr const char* TRANSFORM_ATTR = "transform";
// BBS
static constexpr const char* OFFSET_ATTR = "offset";
static constexpr const char* PRINTABLE_ATTR = "printable";
static constexpr const char* AUTO_DROP_ATTR = "auto_drop";
static constexpr const char* INSTANCESCOUNT_ATTR = "instances_count";
static constexpr const char* CUSTOM_SUPPORTS_ATTR = "paint_supports";
static constexpr const char* CUSTOM_FUZZY_SKIN_ATTR = "paint_fuzzy_skin";
@@ -1205,7 +1206,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
bool _handle_start_text_configuration(const char** attributes, unsigned int num_attributes);
bool _handle_start_shape_configuration(const char **attributes, unsigned int num_attributes);
bool _create_object_instance(std::string const & path, int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter);
bool _create_object_instance(std::string const & path, int object_id, const Transform3d& transform, const bool printable, const bool auto_drop, unsigned int recur_counter);
void _apply_transform(ModelInstance& instance, const Transform3d& transform);
@@ -3767,8 +3768,9 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
std::string path = bbs_get_attribute_value_string(attributes, num_attributes, PPATH_ATTR);
Transform3d transform = bbs_get_transform_from_3mf_specs_string(bbs_get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR));
int printable = bbs_get_attribute_value_bool(attributes, num_attributes, PRINTABLE_ATTR);
int auto_drop = bbs_get_attribute_value_bool(attributes, num_attributes, AUTO_DROP_ATTR);
return !m_load_model || _create_object_instance(path, object_id, transform, printable, 1);
return !m_load_model || _create_object_instance(path, object_id, transform, printable, auto_drop, 1);
}
bool _BBS_3MF_Importer::_handle_end_item()
@@ -3990,7 +3992,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return true;
}
bool _BBS_3MF_Importer::_create_object_instance(std::string const & path, int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter)
bool _BBS_3MF_Importer::_create_object_instance(std::string const & path, int object_id, const Transform3d& transform, const bool printable, const bool auto_drop, unsigned int recur_counter)
{
static const unsigned int MAX_RECURSIONS = 10;
@@ -4027,6 +4029,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return false;
}
instance->printable = printable;
instance->auto_drop = auto_drop;
m_instances.emplace_back(instance, transform);
@@ -4059,6 +4062,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
return false;
}
instance->printable = printable;
instance->auto_drop = auto_drop;
m_instances.emplace_back(instance, transform);
}
@@ -5618,12 +5622,14 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
unsigned int id;
Transform3d transform;
bool printable;
bool auto_drop;
BuildItem(std::string const & path, unsigned int id, const Transform3d& transform, const bool printable)
BuildItem(std::string const & path, unsigned int id, const Transform3d& transform, const bool printable, const bool auto_drop)
: path(path)
, id(id)
, transform(transform)
, printable(printable)
, auto_drop(auto_drop)
{
}
};
@@ -6788,7 +6794,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
Transform3d t = instance->get_matrix();
// instance_id is just a 1 indexed index in build_items.
//assert(m_skip_static || curr_id == build_items.size() + 1);
build_items.emplace_back("", object_it->second.object_id, t, instance->printable);
build_items.emplace_back("", object_it->second.object_id, t, instance->printable, instance->auto_drop);
count++;
}
@@ -7224,7 +7231,8 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
stream << "\" " << PPATH_ATTR << "=\"" << xml_escape(item.path);
stream << "\" " << TRANSFORM_ATTR << "=\"";
add_transformation(stream, item.transform);
stream << "\" " << PRINTABLE_ATTR << "=\"" << item.printable << "\"/>\n";
stream << "\" " << PRINTABLE_ATTR << "=\"" << item.printable;
stream << "\" " << AUTO_DROP_ATTR << "=\"" << item.auto_drop << "\"/>\n";
}
stream << " </" << BUILD_TAG << ">\n";
+9 -3
View File
@@ -14,6 +14,7 @@
#include "Format/AMF.hpp"
#include "Format/svg.hpp"
#include "Format/bbs_3mf.hpp"
#include "Format/DRC.hpp"
// BBS
#include "FaceDetector.hpp"
@@ -1088,7 +1089,6 @@ bool Model::is_fuzzy_skin_painted() const
return std::any_of(this->objects.cbegin(), this->objects.cend(), [](const ModelObject *mo) { return mo->is_fuzzy_skin_painted(); });
}
static void add_cut_volume(TriangleMesh& mesh, ModelObject* object, const ModelVolume* src_volume, const Transform3d& cut_matrix, const std::string& suffix = {}, ModelVolumeType type = ModelVolumeType::MODEL_PART)
{
if (mesh.empty())
@@ -1734,8 +1734,14 @@ void ModelObject::ensure_on_bed(bool allow_negative_z)
else
z_offset = -this->min_z();
if (z_offset != 0.0)
translate_instances(z_offset * Vec3d::UnitZ());
if (z_offset != 0.0) {
for (size_t i = 0; i < instances.size(); ++i) {
if (!instances[i]->auto_drop)
continue;
translate_instance(i, z_offset * Vec3d::UnitZ());
}
}
}
void ModelObject::translate_instances(const Vec3d& vector)
+8 -2
View File
@@ -1251,6 +1251,7 @@ public:
ModelInstanceEPrintVolumeState print_volume_state;
// Whether or not this instance is printable
bool printable;
bool auto_drop;
bool use_loaded_id_for_label {false};
int arrange_order = 0; // BBS
size_t loaded_id = 0; // BBS
@@ -1379,7 +1380,11 @@ private:
Polygon convex_hull; // BBS
// Constructor, which assigns a new unique ID.
explicit ModelInstance(ModelObject* object) : print_volume_state(ModelInstancePVS_Inside), printable(true), object(object), m_assemble_initialized(false) { assert(this->id().valid()); }
explicit ModelInstance(ModelObject* object)
: print_volume_state(ModelInstancePVS_Inside), printable(true), auto_drop(true), object(object), m_assemble_initialized(false)
{
assert(this->id().valid());
}
// Constructor, which assigns a new unique ID.
explicit ModelInstance(ModelObject *object, const ModelInstance &other) :
m_transformation(other.m_transformation)
@@ -1387,6 +1392,7 @@ private:
, m_offset_to_assembly(other.m_offset_to_assembly)
, print_volume_state(ModelInstancePVS_Inside)
, printable(other.printable)
, auto_drop(other.auto_drop)
, object(object)
, m_assemble_initialized(false) { assert(this->id().valid() && this->id() != other.id()); }
@@ -1400,7 +1406,7 @@ private:
ModelInstance() : ObjectBase(-1), object(nullptr) { assert(this->id().invalid()); }
// BBS. Add added members to archive.
template<class Archive> void serialize(Archive& ar) {
ar(m_transformation, print_volume_state, printable, m_assemble_transformation, m_offset_to_assembly, m_assemble_initialized);
ar(m_transformation, print_volume_state, printable, auto_drop, m_assemble_transformation, m_offset_to_assembly, m_assemble_initialized);
}
};
+2 -2
View File
@@ -4598,7 +4598,7 @@ int Print::export_cached_data(const std::string& directory, bool with_space)
/*boost::nowide::ofstream c;
c.open(file_name, std::ios::out | std::ios::trunc);
if (with_space)
c << std::setw(4) << root_json << std::endl;
c << root_json.dump(1, '\t') << std::endl;
else
c << root_json.dump(0) << std::endl;
c.close();*/
@@ -4620,7 +4620,7 @@ int Print::export_cached_data(const std::string& directory, bool with_space)
boost::nowide::ofstream c;
c.open(filename_vector[object_index], std::ios::out | std::ios::trunc);
if (with_space)
c << std::setw(4) << json_vector[object_index] << std::endl;
c << json_vector[object_index].dump(1, '\t') << std::endl;
else
c << json_vector[object_index].dump(0) << std::endl;
c.close();
+2 -1
View File
@@ -1163,7 +1163,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
m_ori_full_print_config = new_full_config;
new_full_config.update_values_to_printer_extruders_for_multiple_filaments(new_full_config, filament_options_with_variant, "filament_self_index", "filament_extruder_variant");
std::vector<int> filament_maps = new_full_config.option<ConfigOptionInts>("filament_map")->values;
auto opt_filament_map = new_full_config.option<ConfigOptionInts>("filament_map");
std::vector<int> filament_maps = opt_filament_map ? opt_filament_map->values : std::vector<int>();
// Find modified keys of the various configs. Resolve overrides extruder retract values by filament profiles.
DynamicPrintConfig filament_overrides;
File diff suppressed because it is too large Load Diff
+15 -3
View File
@@ -2076,9 +2076,10 @@ void TreeSupport::draw_circles()
if (!area.empty()) has_circle_node = true;
if (node.need_extra_wall) need_extra_wall = true;
// merge overhang to get a smoother interface surface
// Do not merge when buildplate_only is on, because some underneath nodes may have been deleted.
if (top_interface_layers > 0 && node.support_roof_layers_below > 0 && !on_buildplate_only && !node.is_sharp_tail) {
// Merge the overhang into the roof area so tree tips can still produce
// a continuous support interface. Suppressing this for build-plate-only
// support drops the roof polygons entirely in valid tree branches.
if (top_interface_layers > 0 && node.support_roof_layers_below > 0 && !node.is_sharp_tail) {
ExPolygons overhang_expanded;
if (node.overhang.contour.size() > 100 || node.overhang.holes.size()>1)
overhang_expanded.emplace_back(node.overhang);
@@ -2121,6 +2122,17 @@ void TreeSupport::draw_circles()
roof_1st_layer = diff_ex(roof_1st_layer, ClipperUtils::clip_clipper_polygons_with_subject_bbox(roof_areas,get_extents(roof_1st_layer)));
roof_1st_layer = intersection_ex(roof_1st_layer, m_machine_border);
// Build-plate-only pruning can collapse the roof stack down to a single
// printable layer. In that case we still need to emit an interface layer
// instead of downgrading the last roof-adjacent layer to base support.
if (on_buildplate_only && top_interface_layers > 0 && roof_areas.empty() && !roof_1st_layer.empty()) {
append(roof_areas, roof_1st_layer);
roof_1st_layer.clear();
max_layers_above_roof = std::max(max_layers_above_roof, max_layers_above_roof1);
max_layers_above_roof1 = 0;
interface_id = obj_layer_nr % top_interface_layers;
}
ExPolygons roofs; append(roofs, roof_1st_layer); append(roofs, roof_areas);append(roofs, roof_gap_areas);
base_areas = diff_ex(base_areas, ClipperUtils::clip_clipper_polygons_with_subject_bbox(roofs, get_extents(base_areas)));
base_areas = intersection_ex(base_areas, m_machine_border);
+49 -30
View File
@@ -898,6 +898,7 @@ public:
size_t dtt_roof_tip;
for (dtt_roof_tip = 0; dtt_roof_tip < roof_tip_layers && insert_layer_idx - dtt_roof_tip >= 1; ++ dtt_roof_tip) {
size_t this_layer_idx = insert_layer_idx - dtt_roof_tip;
const size_t roof_recovery_depth = dtt_roof_tip + supports_roof_layers;
auto evaluateRoofWillGenerate = [&](const std::pair<Point, LineStatus> &p) {
//FIXME Vojtech: The circle is just shifted, it has a known size, the infill should fit all the time!
#if 0
@@ -927,7 +928,9 @@ public:
// don't move until
roof_tip_layers - dtt_roof_tip,
// supports roof
dtt_roof_tip + supports_roof_layers > 0,
roof_recovery_depth > 0,
// recovered roof/contact depth for this slice
roof_recovery_depth,
// disable ovalization
false);
}
@@ -942,9 +945,10 @@ public:
roof_circle.translate(p.first);
new_roofs.emplace_back(std::move(roof_circle));
}
this->add_roof(std::move(new_roofs), this_layer_idx, dtt_roof_tip + supports_roof_layers);
this->add_roof(std::move(new_roofs), this_layer_idx, roof_recovery_depth);
}
const size_t roof_recovery_depth = dtt_roof_tip + supports_roof_layers;
for (const LineInformation &line : lines) {
// If a line consists of enough tips, the assumption is that it is not a single tip, but part of a simulated support pattern.
// Ovalisation should be disabled for these to improve the quality of the lines when tip_diameter=line_width
@@ -954,14 +958,16 @@ public:
// don't move until
dont_move_until > dtt_roof_tip ? dont_move_until - dtt_roof_tip : 0,
// supports roof
dtt_roof_tip + supports_roof_layers > 0,
roof_recovery_depth > 0,
// recovered roof/contact depth for this slice
roof_recovery_depth,
disable_ovalistation);
}
}
private:
// called by this->add_points_along_lines()
void add_point_as_influence_area(std::pair<Point, LineStatus> p, LayerIndex insert_layer, size_t dont_move_until, bool roof, bool skip_ovalisation)
void add_point_as_influence_area(std::pair<Point, LineStatus> p, LayerIndex insert_layer, size_t dont_move_until, bool roof, size_t roof_recovery_dtt, bool skip_ovalisation)
{
bool to_bp = p.second == LineStatus::TO_BP || p.second == LineStatus::TO_BP_SAFE;
bool gracious = to_bp || p.second == LineStatus::TO_MODEL_GRACIOUS || p.second == LineStatus::TO_MODEL_GRACIOUS_SAFE;
@@ -997,7 +1003,7 @@ private:
state.supports_roof = roof;
state.dont_move_until = dont_move_until;
state.can_use_safe_radius = safe_radius;
state.missing_roof_layers = force_tip_to_roof ? dont_move_until : 0;
state.set_pending_roof_recovery(force_tip_to_roof ? dont_move_until : 0, roof_recovery_dtt);
state.skip_ovalisation = skip_ovalisation;
move_bounds[insert_layer].emplace_back(state, std::move(circle));
}
@@ -1095,10 +1101,9 @@ void finalize_raft_contact(
// 1) Maximum num_support_roof_layers roof (top interface & contact) layers.
// 2) Tree tips supporting either the roof layers or the object itself.
// num_support_roof_layers should always be respected:
// If num_support_roof_layers contact layers could not be produced, then the tree tip
// is augmented with SupportElementState::missing_roof_layers
// and the top "missing_roof_layers" of such particular tree tips are supposed to be coverted to
// roofs aka interface layers by the tool path generator.
// If the requested roof/contact stack cannot be generated directly, the affected tree tips
// carry explicit pending roof recovery metadata so the sliced branch geometry can later be
// promoted back to top contacts / interfaces at the correct contact depth.
void sample_overhang_area(
// Area to support
Polygons &&overhang_area,
@@ -1606,7 +1611,6 @@ static Point move_inside_if_outside(const Polygons &polygons, Point from, int di
if (settings.increase_radius)
current_elem.effective_radius_height += 1;
coord_t radius = support_element_collision_radius(config, current_elem);
const auto _tiny_area_threshold = tiny_area_threshold();
if (settings.move) {
increased = relevant_offset;
@@ -2059,7 +2063,10 @@ static void increase_areas_one_layer(
out.supports_roof = first.supports_roof || second.supports_roof;
out.dont_move_until = std::max(first.dont_move_until, second.dont_move_until);
out.can_use_safe_radius = first.can_use_safe_radius || second.can_use_safe_radius;
out.missing_roof_layers = std::min(first.missing_roof_layers, second.missing_roof_layers);
// Preserve the deepest outstanding roof recovery request across merged sub-branches.
out.set_pending_roof_recovery(
std::max(first.missing_roof_layers, second.missing_roof_layers),
std::max(first.roof_recovery_dtt, second.roof_recovery_dtt));
out.skip_ovalisation = false;
if (first.target_height > second.target_height) {
out.target_height = first.target_height;
@@ -3473,7 +3480,6 @@ static void generate_support_areas(Print &print, TreeSupport* tree_support, cons
// value is the area where support may be placed. As this is calculated in CreateLayerPathing it is saved and reused in draw_areas
std::vector<SupportElements> move_bounds(num_support_layers);
// ### Place tips of the support tree
for (size_t mesh_idx : processing.second)
generate_initial_areas(*print.get_object(mesh_idx), volumes, config, overhangs,
@@ -3591,7 +3597,33 @@ static void generate_support_areas(Print &print, TreeSupport* tree_support, cons
// storage.support.generated = true;
}
// Organic specific: Smooth branches and produce one cummulative mesh to be sliced.
static void recover_pending_branch_roofs(
InterfacePlacer &interface_placer,
const std::vector<const SupportElement*> &branch_path,
const LayerIndex layer_begin,
std::vector<Polygons> &slices)
{
if (! interface_placer.support_parameters.has_top_contacts)
return;
for (auto it = branch_path.rbegin(); it != branch_path.rend(); ++ it) {
const SupportElement &el = **it;
if (! el.state.has_pending_roof_recovery())
break;
const LayerIndex slice_idx = el.state.layer_idx - layer_begin;
if (slice_idx < 0 || slice_idx >= LayerIndex(slices.size()))
continue;
if (slices[size_t(slice_idx)].empty())
continue;
if (el.state.roof_recovery_dtt > interface_placer.support_parameters.num_top_interface_layers)
continue;
interface_placer.add_roof(std::move(slices[size_t(slice_idx)]), el.state.layer_idx, el.state.roof_recovery_dtt);
}
}
// Organic specific: Smooth branches and produce one cumulative mesh to be sliced.
void organic_draw_branches(
PrintObject &print_object,
TreeModelVolumes &volumes,
@@ -3770,13 +3802,12 @@ void organic_draw_branches(
// ++ ielement;
}
}
const SlicingParameters &slicing_params = print_object.slicing_parameters();
MeshSlicingParams mesh_slicing_params;
mesh_slicing_params.mode = MeshSlicingParams::SlicingMode::Positive;
tbb::parallel_for(tbb::blocked_range<size_t>(0, trees.size(), 1),
[&trees, &volumes, &config, &slicing_params, &move_bounds, &mesh_slicing_params, &throw_on_cancel](const tbb::blocked_range<size_t> &range) {
[&trees, &volumes, &config, &slicing_params, &move_bounds, &mesh_slicing_params, &interface_placer, &throw_on_cancel](const tbb::blocked_range<size_t> &range) {
indexed_triangle_set partial_mesh;
std::vector<float> slice_z;
std::vector<Polygons> bottom_contacts;
@@ -3811,7 +3842,7 @@ void organic_draw_branches(
num_empty = std::find_if(slices.begin(), slices.end(), [](auto &s) { return !s.empty(); }) - slices.begin();
} else {
if (branch.has_root) {
if (branch.path.front()->state.to_model_gracious) {
if (config.support_rests_on_model && branch.path.front()->state.to_model_gracious) {
if (config.settings.support_floor_layers > 0)
//FIXME one may just take the whole tree slice as bottom interface.
bottom_contacts.emplace_back(intersection_clipped(slices.front(), volumes.getPlaceableAreas(0, layer_begin, [] {})));
@@ -3860,7 +3891,7 @@ void organic_draw_branches(
}
}
#endif
if (config.settings.support_floor_layers > 0)
if (config.support_rests_on_model && config.settings.support_floor_layers > 0)
for (int i = int(bottom_extra_slices.size()) - 2; i >= 0; -- i)
bottom_contacts.emplace_back(
intersection_clipped(bottom_extra_slices[i].polygons, volumes.getPlaceableAreas(0, layer_begin - i - 1, [] {})));
@@ -3872,19 +3903,7 @@ void organic_draw_branches(
}
}
#if 0
//FIXME branch.has_tip seems to not be reliable.
if (branch.has_tip && interface_placer.support_parameters.has_top_contacts)
// Add top slices to top contacts / interfaces / base interfaces.
for (int i = int(branch.path.size()) - 1; i >= 0; -- i) {
const SupportElement &el = *branch.path[i];
if (el.state.missing_roof_layers == 0)
break;
//FIXME Move or not?
interface_placer.add_roof(std::move(slices[int(slices.size()) - i - 1]), el.state.layer_idx,
interface_placer.support_parameters.num_top_interface_layers + 1 - el.state.missing_roof_layers);
}
#endif
recover_pending_branch_roofs(interface_placer, branch.path, layer_begin, slices);
}
layer_begin += LayerIndex(num_empty);
+18 -2
View File
@@ -199,9 +199,20 @@ struct SupportElementState : public SupportElementStateBits
AreaIncreaseSettings last_area_increase;
/*!
* \brief Amount of roof layers that were not yet added, because the branch needed to move.
* \brief Number of pending roof/contact recovery slices from this node downward, including this node.
*/
uint32_t missing_roof_layers;
uint32_t missing_roof_layers = 0;
/*!
* \brief Contact/interface depth that this node should recover when missing_roof_layers > 0.
*/
uint32_t roof_recovery_dtt = 0;
void set_pending_roof_recovery(uint32_t pending_layers, uint32_t recovery_depth)
{
this->missing_roof_layers = pending_layers;
this->roof_recovery_dtt = pending_layers > 0 ? recovery_depth : 0;
}
// called by increase_single_area() and increaseAreas()
[[nodiscard]] static SupportElementState propagate_down(const SupportElementState &src)
@@ -209,6 +220,10 @@ struct SupportElementState : public SupportElementStateBits
SupportElementState dst{ src };
++ dst.distance_to_top;
-- dst.layer_idx;
if (dst.has_pending_roof_recovery()) {
-- dst.missing_roof_layers;
++ dst.roof_recovery_dtt;
}
// set to invalid as we are a new node on a new layer
dst.result_on_layer_reset();
dst.skip_ovalisation = false;
@@ -216,6 +231,7 @@ struct SupportElementState : public SupportElementStateBits
}
[[nodiscard]] bool locked() const { return this->distance_to_top < this->dont_move_until; }
[[nodiscard]] bool has_pending_roof_recovery() const { return this->missing_roof_layers > 0; }
};
/*!
+7 -6
View File
@@ -9,11 +9,8 @@ if (EMSCRIPTEN OR SLIC3R_OPENGL_ES)
glad/src/gles2.c
)
else ()
set(GLAD_SOURCES
glad/include/glad/gl.h
glad/include/KHR/khrplatform.h
glad/src/gl.c
)
# Use shared GLAD library for GL; no local sources needed
set(GLAD_SOURCES "")
endif ()
set(LIBVGCODE_SOURCES
@@ -77,4 +74,8 @@ if (WIN32)
endif ()
# glad includes
include_directories(glad/include)
if (EMSCRIPTEN OR SLIC3R_OPENGL_ES)
target_include_directories(libvgcode PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/glad/include)
else ()
target_link_libraries(libvgcode PUBLIC glad)
endif ()
+2 -2
View File
@@ -7,9 +7,9 @@
// OpenGL loader
#ifdef ENABLE_OPENGL_ES
#include "../glad/include/glad/gles2.h"
#include <glad/gles2.h>
#else
#include "../glad/include/glad/gl.h"
#include <glad/gl.h>
#endif // ENABLE_OPENGL_ES
#include <string>
+25 -22
View File
@@ -20,34 +20,37 @@ void OptionTemplate::init(uint8_t resolution)
if (m_top_vao_id != 0)
return;
m_resolution = std::max<uint8_t>(resolution, 3);
m_vertices_count = 2 + resolution;
m_resolution = std::clamp<uint8_t>(resolution, 3, 85);
m_vertices_count = static_cast<uint8_t>(3 * m_resolution);
const float step = 2.0f * PI / float(m_resolution);
//
// top fan
// top and bottom cones (paired wedges)
//
std::vector<float> top_vertices;
top_vertices.reserve(6 * m_vertices_count);
add_vertex({ 0.0f, 0.0f, 0.5f }, { 0.0f, 0.0f, 1.0f }, top_vertices);
for (uint8_t i = 0; i <= m_resolution; ++i) {
const float ii = float(i) * step;
const Vec3 pos = { 0.5f * std::cos(ii), 0.5f * std::sin(ii), 0.0f };
const Vec3 norm = normalize(pos);
add_vertex(pos, norm, top_vertices);
}
//
// bottom fan
//
std::vector<float> bottom_vertices;
bottom_vertices.reserve(6 * m_vertices_count);
add_vertex({ 0.0f, 0.0f, -0.5f }, { 0.0f, 0.0f, -1.0f }, bottom_vertices);
for (uint8_t i = 0; i <= m_resolution; ++i) {
const float ii = -float(i) * step;
const Vec3 pos = { 0.5f * std::cos(ii), 0.5f * std::sin(ii), 0.0f };
const Vec3 norm = normalize(pos);
add_vertex(pos, norm, bottom_vertices);
const Vec3 top_apex = { 0.0f, 0.0f, 0.5f };
const Vec3 top_apex_normal = { 0.0f, 0.0f, 1.0f };
const Vec3 bottom_apex = { 0.0f, 0.0f, -0.5f };
const Vec3 bottom_apex_normal = { 0.0f, 0.0f, -1.0f };
for (uint8_t i = 0; i < m_resolution; ++i) {
const float curr_angle = float(i) * step;
const float next_angle = float(i + 1) * step;
const Vec3 curr_pos = { 0.5f * std::cos(curr_angle), 0.5f * std::sin(curr_angle), 0.0f };
const Vec3 next_pos = { 0.5f * std::cos(next_angle), 0.5f * std::sin(next_angle), 0.0f };
const Vec3 curr_norm = normalize(curr_pos);
const Vec3 next_norm = normalize(next_pos);
add_vertex(top_apex, top_apex_normal, top_vertices);
add_vertex(curr_pos, curr_norm, top_vertices);
add_vertex(next_pos, next_norm, top_vertices);
add_vertex(bottom_apex, bottom_apex_normal, bottom_vertices);
add_vertex(next_pos, next_norm, bottom_vertices);
add_vertex(curr_pos, curr_norm, bottom_vertices);
}
m_size_in_bytes_gpu += top_vertices.size() * sizeof(float);
@@ -117,9 +120,9 @@ void OptionTemplate::render(size_t count)
glsafe(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &curr_vertex_array));
glsafe(glBindVertexArray(m_top_vao_id));
glsafe(glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, static_cast<GLsizei>(m_vertices_count), static_cast<GLsizei>(count)));
glsafe(glDrawArraysInstanced(GL_TRIANGLES, 0, static_cast<GLsizei>(m_vertices_count), static_cast<GLsizei>(count)));
glsafe(glBindVertexArray(m_bottom_vao_id));
glsafe(glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, static_cast<GLsizei>(m_vertices_count), static_cast<GLsizei>(count)));
glsafe(glDrawArraysInstanced(GL_TRIANGLES, 0, static_cast<GLsizei>(m_vertices_count), static_cast<GLsizei>(count)));
glsafe(glBindVertexArray(curr_vertex_array));
}
+13 -3
View File
@@ -301,6 +301,8 @@ set(SLIC3R_GUI_SOURCES
GUI/KBShortcutsDialog.hpp
GUI/LibVGCode/LibVGCodeWrapper.hpp
GUI/LibVGCode/LibVGCodeWrapper.cpp
GUI/LinuxDisplayBackend.cpp
GUI/LinuxDisplayBackend.hpp
GUI/MainFrame.cpp
GUI/MainFrame.hpp
GUI/MarkdownTip.cpp
@@ -736,7 +738,7 @@ else()
set(_opengl_link_lib OpenGL::GL)
endif()
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo libvgcode md4c-html GLEW::GLEW OpenGL::GL hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto noise::noise)
target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo libvgcode md4c-html glad ${_opengl_link_lib} hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto noise::noise)
if (MSVC)
@@ -787,16 +789,24 @@ if (UNIX AND NOT APPLE)
find_package(PkgConfig REQUIRED)
find_package(GTK${SLIC3R_GTK} REQUIRED)
pkg_check_modules(LIBSECRET REQUIRED libsecret-1)
pkg_check_modules(webkit2gtk REQUIRED webkit2gtk-4.1)
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)
pkg_check_modules(webkit2gtk REQUIRED webkit2gtk-4.1)
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})
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})
# Propagate GDK backend detection results as compile definitions so that
# LinuxDisplayBackend.cpp can include the right GDK headers.
if (wxHAVE_GDK_X11)
target_compile_definitions(libslic3r_gui PRIVATE wxHAVE_GDK_X11)
endif ()
if (wxHAVE_GDK_WAYLAND)
target_compile_definitions(libslic3r_gui PRIVATE wxHAVE_GDK_WAYLAND)
endif ()
# We add GStreamer for bambu:/// support.
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
+1 -1
View File
@@ -15,7 +15,7 @@
#include "Plater.hpp"
#include "Camera.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem/operations.hpp>
+1 -1
View File
@@ -1,4 +1,4 @@
#include <GL/glew.h>
#include <glad/gl.h>
#include "3DScene.hpp"
#include "GLShader.hpp"
+1 -1
View File
@@ -94,7 +94,7 @@ void CopyrightsDialog::fill_entries()
{ "Eigen3", "", "http://eigen.tuxfamily.org" },
{ "Expat", "", "http://www.libexpat.org" },
{ "fast_float", "", "https://github.com/fastfloat/fast_float" },
{ "GLEW (The OpenGL Extension Wrangler Library)", "", "http://glew.sourceforge.net" },
{ "GLAD (Multi-Language GL Loader-Generator)", "", "https://github.com/Dav1dde/glad" },
{ "GLFW", "", "https://www.glfw.org" },
{ "GNU gettext", "", "https://www.gnu.org/software/gettext" },
{ "ImGUI", "", "https://github.com/ocornut/imgui" },
+36 -12
View File
@@ -6,6 +6,9 @@
#include "I18N.hpp"
#include "GUI_App.hpp"
#include "GUI.hpp"
#ifdef __WXGTK__
#include "LinuxDisplayBackend.hpp"
#endif
#include "wxExtensions.hpp"
#include "Plater.hpp"
#include "MainFrame.hpp"
@@ -56,9 +59,9 @@ CenteredTitle::CenteredTitle(wxWindow* parent)
wxString ellipsized = wxControl::Ellipsize(m_title, dc, wxELLIPSIZE_END, wxMax(0, rect.GetWidth() - FromDIP(8)));
int y = rect.y + (rect.height - textHeight) / 2;
int x = rect.x + (ellipsized != m_title) // is ellipsized
int x = rect.x + ((ellipsized != m_title) // is ellipsized
? FromDIP(4) // align to left when clipped
: (rect.width - dc.GetTextExtent(m_title).GetWidth()) / 2; // centered when has available space
: (rect.width - dc.GetTextExtent(m_title).GetWidth()) / 2); // centered when has available space
dc.DrawText(ellipsized, x, y);
});
@@ -126,9 +129,10 @@ void BBLTopbarArt::DrawButton(wxDC& dc, wxWindow* wnd, const wxAuiToolBarItem& i
int bmpX = 0, bmpY = 0;
int textX = 0, textY = 0;
const wxBitmap& bmp = item.GetState() & wxAUI_BUTTON_STATE_DISABLED
? item.GetDisabledBitmap()
: item.GetBitmap();
// ORCA resolves the toolbar item bitmap using the actual window DPI context used for painting.
// GetBitmap() / GetDisabledBitmap() was using internal window pointer (m_window), not the paint-time wnd
// m_window was created before final DPI context was known so items not scales properly
const wxBitmap bmp = item.GetCurrentBitmapFor(wnd);
const wxSize bmpSize = bmp.IsOk() ? bmp.GetScaledSize() : wxSize(0, 0);
@@ -346,6 +350,10 @@ void BBLTopbar::Init(wxFrame* parent)
this->Bind(wxEVT_LEFT_DCLICK, &BBLTopbar::OnMouseLeftDClock, this);
this->Bind(wxEVT_LEFT_DOWN, &BBLTopbar::OnMouseLeftDown, this);
this->Bind(wxEVT_LEFT_UP, &BBLTopbar::OnMouseLeftUp, this);
this->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& event) {
m_last_mouse_position = wxDefaultPosition;
event.Skip();
});
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnOpenProject, this, wxID_OPEN);
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnSaveProject, this, wxID_SAVE);
this->Bind(wxEVT_AUITOOLBAR_TOOL_DROPDOWN, &BBLTopbar::OnRedo, this, wxID_REDO);
@@ -589,8 +597,9 @@ void BBLTopbar::OnCloseFrame(wxAuiToolBarEvent& event)
void BBLTopbar::OnMouseLeftDClock(wxMouseEvent& mouse)
{
wxPoint mouse_pos = ::wxGetMousePosition();
wxAuiToolBarItem* item = this->FindToolByCurrentPosition();
m_last_mouse_position = mouse.GetPosition();
wxPoint mouse_pos = this->ClientToScreen(mouse.GetPosition());
wxAuiToolBarItem* item = this->FindToolByPosition(mouse.GetX(), mouse.GetY());
// check whether mouse is not on any tool item
if (item != NULL && item->GetWindow() != m_title_ctrl) {
mouse.Skip();
@@ -658,9 +667,12 @@ void BBLTopbar::OnCalibToolItem(wxAuiToolBarEvent &evt)
void BBLTopbar::OnMouseLeftDown(wxMouseEvent& event)
{
wxPoint mouse_pos = ::wxGetMousePosition();
m_last_mouse_position = event.GetPosition();
// Use event-relative coords converted to screen, instead of wxGetMousePosition()
// which returns (0,0) on Wayland for global screen coordinates.
wxPoint mouse_pos = this->ClientToScreen(event.GetPosition());
wxPoint frame_pos = m_frame->GetScreenPosition();
wxAuiToolBarItem* item = this->FindToolByCurrentPosition();
wxAuiToolBarItem* item = this->FindToolByPosition(event.GetX(), event.GetY());
m_delta = mouse_pos - frame_pos;
if (item == NULL || item->GetWindow() == m_title_ctrl)
@@ -688,7 +700,8 @@ void BBLTopbar::OnMouseLeftDown(wxMouseEvent& event)
void BBLTopbar::OnMouseLeftUp(wxMouseEvent& event)
{
wxPoint mouse_pos = ::wxGetMousePosition();
m_last_mouse_position = event.GetPosition();
wxPoint mouse_pos = this->ClientToScreen(event.GetPosition());
if (HasCapture())
{
ReleaseMouse();
@@ -699,7 +712,10 @@ void BBLTopbar::OnMouseLeftUp(wxMouseEvent& event)
void BBLTopbar::OnMouseMotion(wxMouseEvent& event)
{
wxPoint mouse_pos = ::wxGetMousePosition();
m_last_mouse_position = event.GetPosition();
// Use event-relative coords converted to screen, instead of wxGetMousePosition()
// which returns (0,0) on Wayland for global screen coordinates.
wxPoint mouse_pos = this->ClientToScreen(event.GetPosition());
if (!HasCapture()) {
//m_frame->OnMouseMotion(event);
@@ -743,12 +759,20 @@ void BBLTopbar::OnMenuClose(wxMenuEvent& event)
wxAuiToolBarItem* BBLTopbar::FindToolByCurrentPosition()
{
if (m_last_mouse_position != wxDefaultPosition && GetClientRect().Contains(m_last_mouse_position))
return this->FindToolByPosition(m_last_mouse_position.x, m_last_mouse_position.y);
#ifdef __WXGTK__
if (Slic3r::GUI::is_running_on_wayland())
return nullptr;
#endif
wxPoint mouse_pos = ::wxGetMousePosition();
wxPoint client_pos = this->ScreenToClient(mouse_pos);
return this->FindToolByPosition(client_pos.x, client_pos.y);
}
#ifdef __WIN32__
#ifdef __WXMSW__
WXLRESULT CenteredTitle::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
{
switch (nMsg) {
+3 -2
View File
@@ -19,7 +19,7 @@ public:
wxSize DoGetBestSize() const override;
protected:
#ifdef __WIN32__
#ifdef __WXMSW__
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override;
#endif
@@ -75,7 +75,7 @@ public:
void ShowCalibrationButton(bool show = true);
protected:
#ifdef __WIN32__
#ifdef __WXMSW__
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override;
#endif
@@ -85,6 +85,7 @@ private:
wxAuiToolBarItem* m_dropdown_menu_item;
wxRect m_normalRect;
wxPoint m_delta;
wxPoint m_last_mouse_position{wxDefaultPosition};
wxMenu m_top_menu;
wxMenu* m_file_menu;
wxMenu m_calib_menu;
+3 -3
View File
@@ -50,7 +50,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para
def.min = 0;
def.max = 214700;
def.width = 10; // increase width for large scale printers with 4 digit values
def.sidetext = L("mm"); // milimeters, CIS languages need translation
def.sidetext = L("mm"); // millimeters, CIS languages need translation
def.label = get_option_label(param);
def.tooltip = L("Size in X and Y of the rectangular plate.");
key = "rect_size";
@@ -61,7 +61,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para
def.min = -107350;
def.max = 107350;
def.width = 10; // increase width for large scale printers with 4 digit values
def.sidetext = L("mm"); // milimeters, CIS languages need translation
def.sidetext = L("mm"); // millimeters, CIS languages need translation
def.label = get_option_label(param);
def.tooltip = L("Distance of the 0,0 G-code coordinate from the front left corner of the rectangle.");
key = "rect_origin";
@@ -70,7 +70,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para
def.type = coFloat;
def.set_default_value(new ConfigOptionFloat(200));
def.width = 10; // match size
def.sidetext = L("mm"); // milimeters, CIS languages need translation
def.sidetext = L("mm"); // millimeters, CIS languages need translation
def.label = get_option_label(param);
def.tooltip = L("Diameter of the print bed. It is assumed that origin (0,0) is located in the center.");
key = "diameter";
+1 -1
View File
@@ -13,7 +13,7 @@
#include <wx/mstream.h>
#include <wx/rawbmp.h>
#endif /* __WXGTK2__ */
#include <GL/glew.h>
#include <glad/gl.h>
#define NANOSVG_IMPLEMENTATION
#include "nanosvg/nanosvg.h"
#define NANOSVGRAST_IMPLEMENTATION
+1 -1
View File
@@ -8,7 +8,7 @@
#include "Plater.hpp"
#endif // ENABLE_CAMERA_STATISTICS
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r {
namespace GUI {
+10 -6
View File
@@ -209,7 +209,7 @@ bool DesktopIntegrationDialog::is_integrated()
if (path.empty())
return false;
// confirmation that OrcaSlicer.desktop exists
// confirmation that com.orcaslicer.OrcaSlicer.desktop exists
struct stat buffer;
return (stat (path.c_str(), &buffer) == 0);
}
@@ -336,19 +336,21 @@ void DesktopIntegrationDialog::perform_desktop_integration()
"Exec=\"%3%\" %%F\n"
"Terminal=false\n"
"Type=Application\n"
"PrefersNonDefaultGPU=true\n"
"X-KDE-RunOnDiscreteGpu=true\n"
"MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;\n"
"Categories=Graphics;3DGraphics;Engineering;\n"
"Keywords=3D;Printing;Slicer;slice;3D;printer;convert;gcode;stl;obj;amf;SLA\n"
"StartupNotify=false\n"
"StartupWMClass=orca-slicer\n", name_suffix, version_suffix, excutable_path);
std::string path = GUI::format("%1%/applications/OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix);
std::string path = GUI::format("%1%/applications/com.orcaslicer.OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix);
if (create_desktop_file(path, desktop_file)){
BOOST_LOG_TRIVIAL(debug) << "OrcaSlicer.desktop file installation success.";
BOOST_LOG_TRIVIAL(debug) << "com.orcaslicer.OrcaSlicer.desktop file installation success.";
break;
} else {
// write failed - try another path
BOOST_LOG_TRIVIAL(debug) << "Attempt to OrcaSlicer.desktop file installation failed. failed path: " << target_candidates[i];
BOOST_LOG_TRIVIAL(debug) << "Attempt to com.orcaslicer.OrcaSlicer.desktop file installation failed. failed path: " << target_candidates[i];
target_dir_desktop.clear();
}
// if all failed - try creating default home folder
@@ -357,7 +359,7 @@ void DesktopIntegrationDialog::perform_desktop_integration()
create_path(into_u8(wxFileName::GetHomeDir()), ".local/share/applications");
// create desktop file
target_dir_desktop = GUI::format("%1%/.local/share",wxFileName::GetHomeDir());
std::string path = GUI::format("%1%/applications/OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix);
std::string path = GUI::format("%1%/applications/com.orcaslicer.OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix);
if (contains_path_dir(target_dir_desktop, "applications")) {
if (!create_desktop_file(path, desktop_file)) {
// Desktop file not written - end desktop integration
@@ -379,7 +381,7 @@ void DesktopIntegrationDialog::perform_desktop_integration()
return;
}
// save path to desktop file
app_config->set("desktop_integration_app_path", GUI::format("%1%/applications/OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix));
app_config->set("desktop_integration_app_path", GUI::format("%1%/applications/com.orcaslicer.OrcaSlicer%2%.desktop", target_dir_desktop, version_suffix));
// Repeat for Gcode viewer - use same paths as for slicer files
// Do NOT add gcode viewer desktop file on ChromeOS
@@ -405,6 +407,8 @@ void DesktopIntegrationDialog::perform_desktop_integration()
"Exec=\"%3%\" --gcodeviewer %%F\n"
"Terminal=false\n"
"Type=Application\n"
"PrefersNonDefaultGPU=true\n"
"X-KDE-RunOnDiscreteGpu=true\n"
"MimeType=text/x.gcode;\n"
"Categories=Graphics;3DGraphics;\n"
"Keywords=3D;Printing;Slicer;\n"
+1 -1
View File
@@ -18,7 +18,7 @@ public:
// methods that actually do / undo desktop integration. Static to be accesible from anywhere.
// returns true if path to OrcaSlicer.desktop is stored in App Config and existence of desktop file.
// returns true if path to com.orcaslicer.OrcaSlicer.desktop is stored in App Config and existence of desktop file.
// Does not check if desktop file leads to this binary or existence of icons and viewer desktop file.
static bool is_integrated();
// true if appimage
+44 -10
View File
@@ -4,16 +4,15 @@
#include "wx/dcgraph.h"
#include "I18N.hpp"
#include "PartPlate.hpp"
#include "Widgets/HyperLink.hpp"
namespace Slic3r { namespace GUI {
static const wxColour LabelEnableColor = wxColour("#262E30");
static const wxColour LabelDisableColor = wxColour("#ACACAC");
static const wxColour GreyColor = wxColour("#6B6B6B");
static const wxColour GreenColor = wxColour("#009688");
static const wxColour BackGroundColor = wxColour("#FFFFFF");
static bool should_pop_up()
{
const auto &preset_bundle = wxGetApp().preset_bundle;
@@ -47,6 +46,37 @@ static void set_prefered_map_mode(FilamentMapMode mode)
app_config->set("prefered_filament_map_mode", mode_str);
}
bool play_dual_extruder_slice_video()
{
if (wxLaunchDefaultBrowser("https://e.bambulab.com/t?c=HDB24RlwSmt77YFH")) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("Video is being played using the system's default browser.");
return true;
}
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format("launch system's default browser failed");
return false;
}
bool play_dual_extruder_print_tpu_video()
{
const wxString video_url = "https://e.bambulab.com/t?c=fwWqpBg37Liel92N";
if (wxLaunchDefaultBrowser(video_url)){
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("Print Tpu Video is being played using the system's default browser.");
return true;
}
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format("launch system's default browser failed");
return false;
}
bool open_filament_group_wiki()
{
if (wxLaunchDefaultBrowser("https://e.bambulab.com/t?c=mOkvsXkJ9pldGYp9")) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format("Wiki is being displayed using the system's default browser.");
return true;
}
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format("launch system's default browser failed");
return false;
}
void FilamentGroupPopup::CreateBmps()
{
checked_bmp = create_scaled_bitmap("radio_on", nullptr, 16);; // ORCA match icons
@@ -146,16 +176,20 @@ FilamentGroupPopup::FilamentGroupPopup(wxWindow *parent) : PopupWindow(parent, w
{
wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL);
const std::string wiki_path = Slic3r::resources_dir() + "/wiki/filament_group_wiki_zh.html"; // NEEDFIX this link is broken
auto* wiki_sizer = new wxBoxSizer(wxHORIZONTAL);
wiki_link = new HyperLink(this, _L("Wiki Guide"), wxString(wiki_path.c_str())); // ORCA
wiki_sizer->Add(wiki_link, 0, wxALIGN_CENTER | wxALL, FromDIP(3));
button_sizer->Add(wiki_sizer, 0, wxLEFT, horizontal_margin);
// ORCA Unified hyperlinks
video_link = new HyperLink(this, _L("Video tutorial"));
video_link->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent& e)
{
play_dual_extruder_slice_video();
wxGetApp().app_config->set("play_slicing_video", "false");
});
button_sizer->Add(video_link, 0, wxLEFT, horizontal_margin + FromDIP(3));
button_sizer->AddStretchSpacer();
wiki_link = new HyperLink(this, _L("Wiki Guide"));
wiki_link->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent&) { open_filament_group_wiki(); });
button_sizer->Add(wiki_link, 0, wxLEFT, horizontal_margin);
top_sizer->Add(button_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, horizontal_margin);
}
+5
View File
@@ -14,6 +14,10 @@ class PartPlate;
class Plater;
bool play_dual_extruder_slice_video();
bool play_dual_extruder_print_tpu_video();
bool open_filament_group_wiki();
class FilamentGroupPopup : public PopupWindow
{
public:
@@ -69,6 +73,7 @@ private:
wxStaticText *wiki_link;
wxStaticText *video_link;
PartPlate* partplate_ref{ nullptr };
Plater* plater_ref{ nullptr };
+8 -8
View File
@@ -21,6 +21,7 @@
#include "GUI_Utils.hpp"
#include "GUI.hpp"
#include "GLCanvas3D.hpp"
#include "FilamentGroupPopup.hpp"
#include "GLToolbar.hpp"
#include "GUI_Preview.hpp"
#include "libslic3r/Print.hpp"
@@ -33,7 +34,7 @@
#endif // ENABLE_ACTUAL_SPEED_DEBUG
#include <imgui/imgui_internal.h>
#include <GL/glew.h>
#include <glad/gl.h>
#include <boost/log/trivial.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/nowide/cstdio.hpp>
@@ -3081,13 +3082,12 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding)
auto link_filament_group_wiki = [&](const std::string& label) {
ImVec2 wiki_part_size = ImGui::CalcTextSize(label.c_str());
ImColor HyperColor = ImColor(0, 150, 136, 255).Value;
ImColor HyperColor = ImColor(0, 150, 136, 255); // ORCA match color
ImGui::PushStyleColor(ImGuiCol_Text, HyperColor.Value);
imgui.text(label.c_str());
ImGui::PopStyleColor();
// underline
// ORCA use underline to match hyperlink style
ImVec2 lineEnd = ImGui::GetItemRectMax();
lineEnd.y -= 2.0f;
ImVec2 lineStart = lineEnd;
@@ -3096,8 +3096,7 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding)
// click behavior
if (ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), true)) {
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
std::string wiki_path = Slic3r::resources_dir() + "/wiki/filament_group_wiki_zh.html";
wxLaunchDefaultBrowser(wxString(wiki_path.c_str()));
open_filament_group_wiki();
}
}
};
@@ -3304,8 +3303,9 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding)
link_text(_u8L("Regroup filament"));
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetWindowContentRegionWidth() - window_padding - ImGui::CalcTextSize("Tips").x);
link_filament_group_wiki(_u8L("Tips"));
std::string wiki_str = _u8L("Wiki Guide"); // ORCA
ImGui::SetCursorPosX(ImGui::GetWindowContentRegionWidth() - window_padding - ImGui::CalcTextSize(wiki_str.c_str()).x);
link_filament_group_wiki(wiki_str);
ImGui::EndChild();
}
+168 -130
View File
@@ -44,7 +44,7 @@
#include "slic3r/Utils/RetinaHelper.hpp"
#endif
#include <GL/glew.h>
#include <glad/gl.h>
#include <wx/glcanvas.h>
#include <wx/bitmap.h>
@@ -2194,8 +2194,12 @@ void GLCanvas3D::render(bool only_init)
wxGetApp().imgui()->render();
m_canvas->SwapBuffers();
m_render_stats.increment_fps_counter();
// On Wayland, eglSwapBuffers blocks when the canvas is hidden or
// occluded. Skip the swap to avoid stalling the render loop.
if (m_canvas->IsShownOnScreen()) {
m_canvas->SwapBuffers();
m_render_stats.increment_fps_counter();
}
}
void GLCanvas3D::render_thumbnail(ThumbnailData & thumbnail_data,
@@ -2354,6 +2358,13 @@ void GLCanvas3D::ensure_on_bed(unsigned int object_idx, bool allow_negative_z)
InstancesToZMap instances_min_z;
for (GLVolume* volume : m_volumes.volumes) {
ModelObject* mo = m_model->objects[volume->object_idx()];
ModelInstance* mi = mo->instances[volume->instance_idx()];
if (!mi->auto_drop) {
continue;
}
if (volume->object_idx() == (int)object_idx && !volume->is_modifier) {
double min_z = volume->transformed_convex_hull_bounding_box().min.z();
std::pair<int, int> instance = std::make_pair(volume->object_idx(), volume->instance_idx());
@@ -4817,14 +4828,13 @@ Vec2d GLCanvas3D::get_local_mouse_position() const
if (m_canvas == nullptr)
return Vec2d::Zero();
wxPoint mouse_pos = m_canvas->ScreenToClient(wxGetMousePosition());
const double factor =
#if ENABLE_RETINA_GL
m_retina_helper->get_scale_factor();
#else
1.0;
#endif
return Vec2d(factor * mouse_pos.x, factor * mouse_pos.y);
// Use the cached mouse position from event handlers (m_mouse.position)
// instead of wxGetMousePosition() + ScreenToClient(), because
// wxGetMousePosition() returns (0,0) on Wayland for global coords.
// m_mouse.position already stores local canvas coordinates (set from
// event.GetX(), event.GetY()) and is already scaled by the retina factor
// in on_mouse(), so we can return it directly.
return m_mouse.position;
}
void GLCanvas3D::set_tooltip(const std::string& tooltip)
@@ -4865,28 +4875,30 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
// Move instances/volumes
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance) {
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
if ((model_object->instances[instance_idx]->get_assemble_offset() - v->get_instance_offset()).norm() > 1e-2) {
model_object->instances[instance_idx]->set_assemble_transformation(v->get_instance_transformation());
}
} else {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
}
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
if (model_object == nullptr)
continue;
object_moved = true;
model_object->invalidate_bounding_box();
if (selection_mode == Selection::Instance) {
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
if ((model_object->instances[instance_idx]->get_assemble_offset() - v->get_instance_offset()).norm() > 1e-2) {
model_object->instances[instance_idx]->set_assemble_transformation(v->get_instance_transformation());
}
} else {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
}
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
object_moved = true;
model_object->invalidate_bounding_box();
}
else if (object_idx >= 1000 && object_idx < 1000 + n_plates) {
// Move a wipe tower proxy.
@@ -4897,20 +4909,27 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(-1, 0);
// Fixes flying instances
// Fixes sinking/flying instances (snaps object to buildplate)
for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first];
const double shift_z = m->get_instance_min_z(i.second);
ModelObject* mo = m_model->objects[i.first];
ModelInstance* mi = mo->instances[i.second];
if (!mi->auto_drop) {
continue;
}
const double shift_z = mo->get_instance_min_z(i.second);
//BBS: don't call translate if the z is zero
if ((current_printer_technology() == ptSLA || shift_z > SINKING_Z_THRESHOLD) && (shift_z != 0.0f)) {
const Vec3d shift(0.0, 0.0, -shift_z);
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
mo->translate_instance(i.second, shift);
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(i.first, i.second);
}
wxGetApp().obj_list()->update_info_items(static_cast<size_t>(i.first));
}
//BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
@@ -4984,40 +5003,47 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
// Rotate instances/volumes.
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance) {
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
model_object->instances[instance_idx]->set_assemble_from_transform(v->get_instance_transformation().get_matrix());
} else {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
if (model_object == nullptr)
continue;
if (selection_mode == Selection::Instance) {
if (m_canvas_type == GLCanvas3D::ECanvasType::CanvasAssembleView) {
model_object->instances[instance_idx]->set_assemble_from_transform(v->get_instance_transformation().get_matrix());
} else {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
model_object->invalidate_bounding_box();
}
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
model_object->invalidate_bounding_box();
}
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(-1, -1);
if (m_canvas_type != CanvasAssembleView) {
// Fixes sinking/flying instances
// Fixes sinking/flying instances (snaps object to buildplate)
for (const std::pair<int, int> &i : done) {
ModelObject *m = m_model->objects[i.first];
ModelObject *mo = m_model->objects[i.first];
ModelInstance* mi = mo->instances[i.second];
if (!mi->auto_drop) {
continue;
}
// BBS: don't call translate if the z is zero
const double shift_z = m->get_instance_min_z(i.second);
const double shift_z = mo->get_instance_min_z(i.second);
// leave sinking instances as sinking
if ((min_zs.find({i.first, i.second})->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) && (shift_z != 0.0f)) {
const Vec3d shift(0.0, 0.0, -shift_z);
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
mo->translate_instance(i.second, shift);
// BBS: notify instance updates to part plater list
m_selection.notify_instance_update(i.first, i.second);
}
@@ -5025,6 +5051,7 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
wxGetApp().obj_list()->update_info_items(static_cast<size_t>(i.first));
}
}
//BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
@@ -5072,42 +5099,49 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
// Rotate instances/volumes
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
model_object->invalidate_bounding_box();
if (model_object == nullptr)
continue;
if (selection_mode == Selection::Instance) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
}
else if (selection_mode == Selection::Volume) {
auto cur_mv = model_object->volumes[volume_idx];
if (cur_mv->get_transformation() != v->get_volume_transformation()) {
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
cur_mv->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
model_object->invalidate_bounding_box();
}
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(-1, -1);
// Fixes sinking/flying instances
// Fixes sinking/flying instances (snaps object to buildplate)
for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first];
ModelObject* mo = m_model->objects[i.first];
ModelInstance* mi = mo->instances[i.second];
if (!mi->auto_drop) {
continue;
}
//BBS: don't call translate if the z is zero
double shift_z = m->get_instance_min_z(i.second);
double shift_z = mo->get_instance_min_z(i.second);
// leave sinking instances as sinking
if ((min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD) && (shift_z != 0.0f)) {
Vec3d shift(0.0, 0.0, -shift_z);
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
mo->translate_instance(i.second, shift);
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(i.first, i.second);
}
wxGetApp().obj_list()->update_info_items(static_cast<size_t>(i.first));
}
//BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
//BBS: notify object info update
@@ -5177,35 +5211,41 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
// Mirror instances/volumes
ModelObject* model_object = m_model->objects[object_idx];
if (model_object != nullptr) {
if (selection_mode == Selection::Instance)
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
else if (selection_mode == Selection::Volume) {
if (model_object->volumes[volume_idx]->get_transformation() != v->get_volume_transformation()) {
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
if (model_object == nullptr)
continue;
model_object->invalidate_bounding_box();
if (selection_mode == Selection::Instance)
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
else if (selection_mode == Selection::Volume) {
if (model_object->volumes[volume_idx]->get_transformation() != v->get_volume_transformation()) {
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
// BBS: backup
Slic3r::save_object_mesh(*model_object);
}
}
model_object->invalidate_bounding_box();
}
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(-1, -1);
// Fixes sinking/flying instances
// Fixes sinking/flying instances (snaps object to buildplate)
for (const std::pair<int, int>& i : done) {
ModelObject* m = m_model->objects[i.first];
ModelObject* mo = m_model->objects[i.first];
ModelInstance* mi = mo->instances[i.second];
if (!mi->auto_drop) {
continue;
}
//BBS: don't call translate if the z is zero
double shift_z = m->get_instance_min_z(i.second);
double shift_z = mo->get_instance_min_z(i.second);
// leave sinking instances as sinking
if ((min_zs.empty() || min_zs.find({ i.first, i.second })->second >= SINKING_Z_THRESHOLD || shift_z > SINKING_Z_THRESHOLD)&&(shift_z != 0.0f)) {
Vec3d shift(0.0, 0.0, -shift_z);
m_selection.translate(i.first, i.second, shift);
m->translate_instance(i.second, shift);
mo->translate_instance(i.second, shift);
//BBS: notify instance updates to part plater list
m_selection.notify_instance_update(i.first, i.second);
}
@@ -5214,10 +5254,8 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
//BBS: notify instance updates to part plater list
PartPlateList &plate_list = wxGetApp().plater()->get_partplate_list();
plate_list.notify_instance_update(i.first, i.second);
//BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
}
}
//BBS: nofity object list to update
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
@@ -6388,21 +6426,21 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data,
// glsafe(::glEnable(GL_MULTISAMPLE));
GLint max_samples;
glsafe(::glGetIntegerv(GL_MAX_SAMPLES_EXT, &max_samples));
glsafe(::glGetIntegerv(GL_MAX_SAMPLES, &max_samples));
GLsizei num_samples = max_samples / 2;
GLuint render_fbo;
glsafe(::glGenFramebuffersEXT(1, &render_fbo));
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, render_fbo));
glsafe(::glGenFramebuffers(1, &render_fbo));
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, render_fbo));
GLuint render_tex = 0;
GLuint render_tex_buffer = 0;
if (multisample) {
// use renderbuffer instead of texture to avoid the need to use glTexImage2DMultisample which is available only since OpenGL 3.2
glsafe(::glGenRenderbuffersEXT(1, &render_tex_buffer));
glsafe(::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_tex_buffer));
glsafe(::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, num_samples, GL_RGBA8, w, h));
glsafe(::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, render_tex_buffer));
glsafe(::glGenRenderbuffers(1, &render_tex_buffer));
glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, render_tex_buffer));
glsafe(::glRenderbufferStorageMultisample(GL_RENDERBUFFER, num_samples, GL_RGBA8, w, h));
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, render_tex_buffer));
}
else {
glsafe(::glGenTextures(1, &render_tex));
@@ -6410,31 +6448,31 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data,
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, render_tex, 0));
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render_tex, 0));
}
GLuint render_depth;
glsafe(::glGenRenderbuffersEXT(1, &render_depth));
glsafe(::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_depth));
glsafe(::glGenRenderbuffers(1, &render_depth));
glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, render_depth));
if (multisample)
glsafe(::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, num_samples, GL_DEPTH_COMPONENT24, w, h));
glsafe(::glRenderbufferStorageMultisample(GL_RENDERBUFFER, num_samples, GL_DEPTH_COMPONENT24, w, h));
else
glsafe(::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, w, h));
glsafe(::glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h));
glsafe(::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, render_depth));
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_depth));
GLenum drawBufs[] = { GL_COLOR_ATTACHMENT0 };
glsafe(::glDrawBuffers(1, drawBufs));
if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT) {
if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
render_thumbnail_internal(thumbnail_data, thumbnail_params, partplate_list, model_objects, volumes, extruder_colors, shader, camera_type, camera_view_angle_type,
for_picking,
ban_light);
if (multisample) {
GLuint resolve_fbo;
glsafe(::glGenFramebuffersEXT(1, &resolve_fbo));
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, resolve_fbo));
glsafe(::glGenFramebuffers(1, &resolve_fbo));
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, resolve_fbo));
GLuint resolve_tex;
glsafe(::glGenTextures(1, &resolve_tex));
@@ -6442,21 +6480,21 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data,
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glsafe(::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, resolve_tex, 0));
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resolve_tex, 0));
glsafe(::glDrawBuffers(1, drawBufs));
if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT) {
glsafe(::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, render_fbo));
glsafe(::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, resolve_fbo));
glsafe(::glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR));
if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
glsafe(::glBindFramebuffer(GL_READ_FRAMEBUFFER, render_fbo));
glsafe(::glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo));
glsafe(::glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_LINEAR));
glsafe(::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, resolve_fbo));
glsafe(::glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo));
glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
}
glsafe(::glDeleteTextures(1, &resolve_tex));
glsafe(::glDeleteFramebuffersEXT(1, &resolve_fbo));
glsafe(::glDeleteFramebuffers(1, &resolve_fbo));
}
else
glsafe(::glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)thumbnail_data.pixels.data()));
@@ -6466,13 +6504,13 @@ void GLCanvas3D::render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data,
#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG_OUTPUT
}
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
glsafe(::glDeleteRenderbuffersEXT(1, &render_depth));
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0));
glsafe(::glDeleteRenderbuffers(1, &render_depth));
if (render_tex_buffer != 0)
glsafe(::glDeleteRenderbuffersEXT(1, &render_tex_buffer));
glsafe(::glDeleteRenderbuffers(1, &render_tex_buffer));
if (render_tex != 0)
glsafe(::glDeleteTextures(1, &render_tex));
glsafe(::glDeleteFramebuffersEXT(1, &render_fbo));
glsafe(::glDeleteFramebuffers(1, &render_fbo));
//if (!multisample)
// glsafe(::glDisable(GL_MULTISAMPLE));
@@ -7249,8 +7287,8 @@ void GLCanvas3D::_rectangular_selection_picking_pass()
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, render_fbo));
}
else {
glsafe(::glGenFramebuffersEXT(1, &render_fbo));
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, render_fbo));
glsafe(::glGenFramebuffers(1, &render_fbo));
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, render_fbo));
}
glsafe(::glGenTextures(1, &render_tex));
glsafe(::glBindTexture(GL_TEXTURE_2D, render_tex));
@@ -7265,11 +7303,11 @@ void GLCanvas3D::_rectangular_selection_picking_pass()
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_depth));
}
else {
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, render_tex, 0));
glsafe(::glGenRenderbuffersEXT(1, &render_depth));
glsafe(::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, render_depth));
glsafe(::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height));
glsafe(::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, render_depth));
glsafe(::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, render_tex, 0));
glsafe(::glGenRenderbuffers(1, &render_depth));
glsafe(::glBindRenderbuffer(GL_RENDERBUFFER, render_depth));
glsafe(::glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height));
glsafe(::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, render_depth));
}
const GLenum drawBufs[] = { GL_COLOR_ATTACHMENT0 };
glsafe(::glDrawBuffers(1, drawBufs));
@@ -7278,7 +7316,7 @@ void GLCanvas3D::_rectangular_selection_picking_pass()
use_framebuffer = false;
}
else {
if (::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
use_framebuffer = false;
}
}
@@ -7389,11 +7427,11 @@ void GLCanvas3D::_rectangular_selection_picking_pass()
glsafe(::glDeleteFramebuffers(1, &render_fbo));
}
else if (framebuffers_type == OpenGLManager::EFramebufferType::Ext) {
glsafe(::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0));
if (render_depth != 0)
glsafe(::glDeleteRenderbuffersEXT(1, &render_depth));
glsafe(::glDeleteRenderbuffers(1, &render_depth));
if (render_fbo != 0)
glsafe(::glDeleteFramebuffersEXT(1, &render_fbo));
glsafe(::glDeleteFramebuffers(1, &render_fbo));
}
if (render_tex != 0)
+1 -1
View File
@@ -954,7 +954,7 @@ public:
Camera::ViewAngleType camera_view_angle_type = Camera::ViewAngleType::Iso,
bool for_picking = false,
bool ban_light = false);
// render thumbnail using an off-screen framebuffer when GLEW_EXT_framebuffer_object is supported
// render thumbnail using an off-screen framebuffer when GL_EXT_framebuffer_object is supported
static void render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector<ColorRGBA>& extruder_colors,
GLShaderProgram * shader,
+1 -1
View File
@@ -20,7 +20,7 @@
#include <igl/per_vertex_normals.h>
#endif // ENABLE_SMOOTH_NORMALS
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r {
namespace GUI {
+1 -1
View File
@@ -7,7 +7,7 @@
#include "Plater.hpp"
#include <igl/project.h>
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r {
namespace GUI {
+1 -1
View File
@@ -7,7 +7,7 @@
#include "libslic3r/Color.hpp"
#include <boost/nowide/fstream.hpp>
#include <GL/glew.h>
#include <glad/gl.h>
#include <cassert>
#include <boost/log/trivial.hpp>
+1 -1
View File
@@ -9,7 +9,7 @@
#include <string_view>
using namespace std::literals;
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r {
+1 -1
View File
@@ -11,7 +11,7 @@
#include "GUI_App.hpp"
#include "GLModel.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <wx/image.h>
#include <boost/filesystem.hpp>
+28 -2
View File
@@ -161,6 +161,10 @@ typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS2)(
#include <boost/nowide/fstream.hpp>
#endif // ENABLE_THUMBNAIL_GENERATOR_DEBUG
#ifdef __WXGTK__
#include "LinuxDisplayBackend.hpp"
#endif
// Needed for forcing menu icons back under gtk2 and gtk3
#if defined(__WXGTK20__) || defined(__WXGTK3__)
#include <gtk/gtk.h>
@@ -909,6 +913,8 @@ void GUI_App::post_init()
}
else {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << "Found glcontext not ready, postpone the init";
plater_->canvas3D()->enable_render(true);
plater_->canvas3D()->set_as_dirty();
}
//#endif
if (is_editor())
@@ -2303,7 +2309,8 @@ bool GUI_App::init_opengl()
{
#ifdef __linux__
bool status = m_opengl_mgr.init_gl();
m_opengl_initialized = true;
if (status)
m_opengl_initialized = true;
return status;
#else
return m_opengl_mgr.init_gl();
@@ -3091,6 +3098,20 @@ bool GUI_App::on_init_inner()
// Let the libslic3r know the callback, which will translate messages on demand.
Slic3r::I18N::set_translate_callback(libslic3r_translate_callback);
#if defined(__WXGTK__) && wxHAS_EGL
// Configure GL backend before any wxGLCanvas is created.
// On X11, prefer GLX for maximum driver compatibility.
// On Wayland, EGL is used by default (only option).
if (Slic3r::GUI::is_running_on_x11()) {
wxGLCanvas::PreferGLX();
BOOST_LOG_TRIVIAL(info) << "X11 detected, using GLX for OpenGL context";
} else if (Slic3r::GUI::is_running_on_wayland()) {
BOOST_LOG_TRIVIAL(info) << "Wayland detected, using EGL for OpenGL context";
} else {
BOOST_LOG_TRIVIAL(warning) << "Unknown display backend, defaulting to EGL";
}
#endif
BOOST_LOG_TRIVIAL(info) << "create the main window";
mainframe = new MainFrame();
// hide settings tabs after first Layout
@@ -7708,7 +7729,12 @@ bool GUI_App::window_pos_restore(wxTopLevelWindow* window, const std::string &na
}
const wxRect& rect = metrics->get_rect();
window->SetPosition(rect.GetPosition());
#if defined(__WXGTK__)
// On Wayland, SetPosition() is a no-op for top-level windows.
// Only restore size and maximize state.
if (!Slic3r::GUI::is_running_on_wayland())
#endif
window->SetPosition(rect.GetPosition());
window->SetSize(rect.GetSize());
window->Maximize(metrics->get_maximized());
return true;
+52 -2
View File
@@ -855,6 +855,23 @@ wxMenuItem* MenuFactory::append_menu_item_printable(wxMenu* menu)
return menu_item_printable;
}
wxMenuItem* MenuFactory::append_menu_item_auto_drop(wxMenu* menu)
{
wxString menu_text = _L("Auto Drop");
wxString menu_tooltip = _L("Automatically drops the selected object to the build plate");
wxMenuItem* menu_item_auto_drop = append_menu_check_item(
menu, wxID_ANY, menu_text, menu_tooltip,
[](wxCommandEvent&) { obj_list()->toggle_auto_drop(); }, menu);
m_parent->Bind(wxEVT_UPDATE_UI, [](wxUpdateUIEvent& evt) {
bool check = wxGetApp().plater()->get_selection().get_auto_drop();
evt.Check(check);
},
menu_item_auto_drop->GetId());
return menu_item_auto_drop;
}
void MenuFactory::append_menu_item_rename(wxMenu* menu)
{
append_menu_item(menu, wxID_ANY, _L("Rename"), "",
@@ -1416,6 +1433,10 @@ void MenuFactory::create_extra_object_menu()
// Set filament insert menu item here
// Set Printable
wxMenuItem* menu_item_printable = append_menu_item_printable(&m_object_menu);
m_object_menu.AppendSeparator();
wxMenuItem* menu_item_auto_drop = append_menu_item_auto_drop(&m_object_menu);
m_object_menu.AppendSeparator();
append_menu_item_per_object_process(&m_object_menu);
// Enter per object parameters
append_menu_item_per_object_settings(&m_object_menu);
@@ -1845,8 +1866,14 @@ wxMenu* MenuFactory::multi_selection_menu()
menu->AppendSeparator();
append_menu_item_set_printable(menu);
menu->AppendSeparator();
append_menu_item_set_auto_drop(menu);
menu->AppendSeparator();
append_menu_item_per_object_process(menu);
menu->AppendSeparator();
append_menu_items_convert_unit(menu);
append_menu_item_replace_all_with_stl(menu);
//BBS
@@ -2032,7 +2059,7 @@ void MenuFactory::append_menu_item_drop(wxMenu* menu)
if (plater()->canvas3D()->get_canvas_type() != GLCanvas3D::ECanvasType::CanvasView3D)
return false;
else {
return (plater()->get_view3D_canvas3D()->get_selection().get_bounding_box().min.z() != 0);
return (plater()->get_view3D_canvas3D()->get_selection().get_bounding_box().min.z() > SINKING_Z_THRESHOLD);
} //disable if model is on the bed / not in View3D
}, m_parent);
}
@@ -2184,7 +2211,7 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu)
void MenuFactory::append_menu_item_set_printable(wxMenu* menu)
{
const Selection& selection = plater()->canvas3D()->get_selection();
bool all_printable = true;
bool all_printable = true;
ObjectList* list = obj_list();
wxDataViewItemArray sels;
list->GetSelections(sels);
@@ -2212,6 +2239,29 @@ void MenuFactory::append_menu_item_set_printable(wxMenu* menu)
}, menu_item_set_printable->GetId());
}
void MenuFactory::append_menu_item_set_auto_drop(wxMenu* menu)
{
const Selection& selection = plater()->canvas3D()->get_selection();
const bool current_auto_drop = selection.get_auto_drop();
wxString menu_text = _L("Auto Drop");
wxString menu_tooltip = _L("Automatically snaps the selected object to the build plate");
wxMenuItem* menu_item_set_auto_drop = append_menu_check_item(
menu, wxID_ANY, menu_text, menu_tooltip,
[this, current_auto_drop](wxCommandEvent&) {
Selection& selection = plater()->canvas3D()->get_selection();
selection.set_auto_drop(!current_auto_drop);
},
menu);
m_parent->Bind(
wxEVT_UPDATE_UI,
[current_auto_drop](wxUpdateUIEvent& evt) {
evt.Check(current_auto_drop);
plater()->set_current_canvas_as_dirty();
},
menu_item_set_auto_drop->GetId());
}
void MenuFactory::append_menu_item_locked(wxMenu* menu)
{
const std::vector<wxString> names = { _L("Unlock"), _L("Lock") };
+2
View File
@@ -137,6 +137,7 @@ private:
wxMenuItem* append_menu_item_change_type(wxMenu* menu);
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu);
wxMenuItem* append_menu_item_printable(wxMenu* menu);
wxMenuItem* append_menu_item_auto_drop(wxMenu* menu);
void append_menu_item_rename(wxMenu* menu);
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
//wxMenuItem* append_menu_item_simplify(wxMenu* menu);
@@ -171,6 +172,7 @@ private:
void append_menu_item_per_object_settings(wxMenu* menu);
void append_menu_item_change_filament(wxMenu* menu);
void append_menu_item_set_printable(wxMenu* menu);
void append_menu_item_set_auto_drop(wxMenu* menu);
void append_menu_item_locked(wxMenu* menu);
void append_menu_item_fill_bed(wxMenu *menu);
void append_menu_item_plate_name(wxMenu *menu);
+87 -5
View File
@@ -914,15 +914,15 @@ void ObjectList::object_config_options_changed(const ObjectVolumeID& ov_id)
}
}
void ObjectList::printable_state_changed(const std::vector<ObjectVolumeID>& ov_ids)
void ObjectList::printable_state_changed(const std::vector<ModelObject*> model_objects)
{
std::vector<size_t> obj_idxs;
for (const ObjectVolumeID ov_id : ov_ids) {
if (ov_id.object == nullptr)
for (const ModelObject* mo : model_objects) {
if (mo == nullptr)
continue;
ModelInstance* mi = ov_id.object->instances[0];
wxDataViewItem obj_item = m_objects_model->GetObjectItem(ov_id.object);
ModelInstance* mi = mo->instances[0];
wxDataViewItem obj_item = m_objects_model->GetObjectItem(mo);
m_objects_model->SetObjectPrintableState(mi->printable ? piPrintable : piUnprintable, obj_item);
int obj_idx = m_objects_model->GetObjectIdByItem(obj_item);
@@ -939,6 +939,19 @@ void ObjectList::printable_state_changed(const std::vector<ObjectVolumeID>& ov_i
wxGetApp().plater()->update();
}
void ObjectList::printable_state_changed(const std::vector<ObjectVolumeID>& ov_ids)
{
std::vector<ModelObject*> model_objects;
model_objects.reserve(ov_ids.size());
for (const ObjectVolumeID& ov_id : ov_ids) {
if (ov_id.object != nullptr)
model_objects.emplace_back(ov_id.object);
}
printable_state_changed(model_objects);
}
void ObjectList::assembly_plate_object_name()
{
m_objects_model->assembly_name();
@@ -1153,6 +1166,7 @@ void ObjectList::update_name_in_list(int obj_idx, int vol_idx) const
void ObjectList::selection_changed()
{
if (wxGetApp().is_closing()) return;
if (m_prevent_list_events) return;
fix_multiselection_conflicts();
@@ -1747,6 +1761,8 @@ void ObjectList::key_event(wxKeyEvent& event)
decrease_instances();
else if (event.GetUnicodeKey() == 'p')
toggle_printable_state();
else if (event.GetUnicodeKey() == 'd')
toggle_auto_drop();
else if (filaments_count() > 1) {
std::vector<wxChar> numbers = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
wxChar key_char = event.GetUnicodeKey();
@@ -3043,6 +3059,17 @@ void ObjectList::merge(bool to_multipart_object)
volume->config.set_key_value("extruder", option->clone());
}
// merge printable and auto_drop values
// non-default have priority -> if one object has printable == false,
// then merged object will also have printable == false
if (object->instances[0]->printable == false) {
new_object->printable = false;
new_object->instances[0]->printable = false;
}
if (object->instances[0]->auto_drop == false) {
new_object->instances[0]->auto_drop = false;
}
// merge layers
for (const auto& range : object->layer_config_ranges)
new_object->layer_config_ranges.emplace(range);
@@ -3076,6 +3103,9 @@ void ObjectList::merge(bool to_multipart_object)
// Add new object(merged) to the object_list
add_object_to_list(m_objects->size() - 1);
if (new_object->printable == false) {
wxGetApp().obj_list()->printable_state_changed({new_object});
}
select_item(m_objects_model->GetItemById(m_objects->size() - 1));
update_selections_on_canvas();
}
@@ -3456,6 +3486,9 @@ void ObjectList::changed_object(const int obj_idx/* = -1*/) const
void ObjectList::part_selection_changed()
{
if (wxGetApp().is_closing())
return;
if (m_extruder_editor) m_extruder_editor->Hide();
int obj_idx = -1;
int volume_id = -1;
@@ -4656,6 +4689,9 @@ int ObjectList::get_selected_layers_range_idx() const
void ObjectList::update_selections()
{
if (wxGetApp().is_closing())
return;
const Selection& selection = scene_selection();
wxDataViewItemArray sels;
@@ -6593,6 +6629,52 @@ void ObjectList::toggle_printable_state()
wxGetApp().plater()->reload_paint_after_background_process_apply();
}
void ObjectList::toggle_auto_drop()
{
wxDataViewItemArray sels;
GetSelections(sels);
if (sels.IsEmpty())
return;
for (auto item : sels) {
ItemType type = m_objects_model->GetItemType(item);
if (!(type & (itObject | itInstance)))
return;
}
const bool current_auto_drop = wxGetApp().plater()->get_selection().get_auto_drop();
take_snapshot("");
std::vector<size_t> obj_idxs;
for (auto item : sels) {
int obj_idx = m_objects_model->GetObjectIdByItem(item);
ModelObject* obj = object(obj_idx);
obj_idxs.emplace_back(static_cast<size_t>(obj_idx));
ItemType type = m_objects_model->GetItemType(item);
// set auto_drop value for selected instance/instances in object
if (type == itInstance) {
int inst_idx = m_objects_model->GetInstanceIdByItem(item);
obj->instances[inst_idx]->auto_drop = !current_auto_drop;
} else {
for (auto inst : obj->instances)
inst->auto_drop = !current_auto_drop;
if (current_auto_drop == false)
obj->ensure_on_bed();
}
}
sort(obj_idxs.begin(), obj_idxs.end());
obj_idxs.erase(unique(obj_idxs.begin(), obj_idxs.end()), obj_idxs.end());
// update scene
wxGetApp().plater()->update();
wxGetApp().plater()->reload_paint_after_background_process_apply();
}
void ObjectList::enable_layers_editing()
{
wxDataViewItemArray sels;
+2
View File
@@ -449,6 +449,7 @@ public:
//update printable state for item from objects model
void update_printable_state(int obj_idx, int instance_idx);
void toggle_printable_state();
void toggle_auto_drop();
void enable_layers_editing();
//BBS: remove const qualifier
@@ -463,6 +464,7 @@ public:
void on_plate_selected(int plate_index);
void notify_instance_updated(int obj_idx);
void object_config_options_changed(const ObjectVolumeID& ov_id);
void printable_state_changed(const std::vector<ModelObject*> model_objects);
void printable_state_changed(const std::vector<ObjectVolumeID>& ov_ids);
// search objectlist
+3
View File
@@ -86,6 +86,9 @@ bool ObjectSettings::update_settings_list()
m_settings_list_sizer->Clear(true);
m_og_settings.resize(0);
if (wxGetApp().is_closing())
return false;
auto objects_ctrl = wxGetApp().obj_list();
auto objects_model = wxGetApp().obj_list()->GetModel();
auto config = wxGetApp().obj_list()->config();
+1 -6
View File
@@ -1520,12 +1520,7 @@ void ObjectGridTable::update_value_to_object(Model* model, ObjectGridRow* grid_r
object->printable = grid_row->printable.value;
object->instances[0]->printable = object->printable;
std::vector<ObjectVolumeID> object_volume_ids;
ObjectVolumeID object_volume_id;
object_volume_id.object = object;
object_volume_id.volume = nullptr;
object_volume_ids.push_back(object_volume_id);
wxGetApp().obj_list()->printable_state_changed(object_volume_ids);
wxGetApp().obj_list()->printable_state_changed({object});
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", change object %1%'s printable to %2%")%object->module_name %object->printable;
}
}
+1 -1
View File
@@ -2,7 +2,7 @@
#include "GLGizmoAdvancedCut.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <wx/button.h>
#include <wx/checkbox.h>
+1 -1
View File
@@ -12,7 +12,7 @@
#include <numeric>
#include <GL/glew.h>
#include <glad/gl.h>
#include <tbb/parallel_for.h>
#include <future>
+1 -1
View File
@@ -1,7 +1,7 @@
#include "GLGizmoBase.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Plater.hpp"
+1 -1
View File
@@ -1,5 +1,5 @@
#include "GLGizmoBrimEars.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/Camera.hpp"
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
+1 -1
View File
@@ -1,7 +1,7 @@
#include "GLGizmoCut.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <algorithm>
+1 -1
View File
@@ -50,7 +50,7 @@
#include <cereal/types/string.hpp>
#include <cereal/archives/binary.hpp>
#include <GL/glew.h>
#include <glad/gl.h>
#include <chrono> // measure enumeration of fonts
// uncomment for easier debug
+1 -1
View File
@@ -19,7 +19,7 @@
#include "libslic3r/TextConfiguration.hpp"
#include <imgui/imgui.h>
#include <GL/glew.h>
#include <glad/gl.h>
class wxFont;
namespace Slic3r{
@@ -9,7 +9,7 @@
#include "slic3r/GUI/ImGuiWrapper.hpp"
#include "slic3r/GUI/Plater.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#ifdef __WINDOWS__
#include <windows.h>
+1 -1
View File
@@ -15,7 +15,7 @@
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/Utils/UndoRedo.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <boost/log/trivial.hpp>
+1 -1
View File
@@ -9,7 +9,7 @@
#include <numeric>
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r {
namespace GUI {
+1 -1
View File
@@ -11,7 +11,7 @@
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/Utils/UndoRedo.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <algorithm>
namespace Slic3r::GUI {
+1 -1
View File
@@ -3,7 +3,7 @@
#include "slic3r/GUI/Camera.hpp"
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/GUI_ObjectSettings.hpp"
+1 -1
View File
@@ -12,7 +12,7 @@
#include <numeric>
#include <GL/glew.h>
#include <glad/gl.h>
#include <tbb/parallel_for.h>
@@ -15,7 +15,7 @@
#include "slic3r/Utils/UndoRedo.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r::GUI {
+1 -1
View File
@@ -6,7 +6,7 @@
#include "libslic3r/AppConfig.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <wx/utils.h>
+1 -1
View File
@@ -2,7 +2,7 @@
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Camera.hpp"
+1 -1
View File
@@ -10,7 +10,7 @@
#include "libslic3r/Model.hpp"
#include <cereal/types/vector.hpp>
#include <GL/glew.h>
#include <glad/gl.h>
#include <memory>
+1 -1
View File
@@ -9,7 +9,7 @@
#include "libslic3r/PresetBundle.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r {
namespace GUI {
+1 -1
View File
@@ -32,7 +32,7 @@
#include <wx/display.h> // detection of change DPI
#include <boost/log/trivial.hpp>
#include <GL/glew.h>
#include <glad/gl.h>
#include <chrono> // measure enumeration of fonts
#include <sstream> // save for svg
#include <array>
+1 -1
View File
@@ -19,7 +19,7 @@
#include "libslic3r/Model.hpp"
#include <imgui/imgui.h>
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r{
class ModelVolume;
+1 -1
View File
@@ -3,7 +3,7 @@
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/Plater.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <wx/utils.h>
+1 -1
View File
@@ -11,7 +11,7 @@
#include "slic3r/GUI/GUI.hpp"
#include "slic3r/Utils/UndoRedo.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r::GUI {
+1 -1
View File
@@ -11,7 +11,7 @@
#include "libslic3r/Model.hpp"
#include "libslic3r/QuadricEdgeCollapse.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <thread>
+1 -1
View File
@@ -6,7 +6,7 @@
#include "slic3r/GUI/MainFrame.hpp"
#include "slic3r/Utils/UndoRedo.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <wx/msgdlg.h>
#include <wx/settings.h>
+1 -1
View File
@@ -16,7 +16,7 @@
#include <boost/log/trivial.hpp>
#include <GL/glew.h>
#include <glad/gl.h>
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
+1 -1
View File
@@ -10,7 +10,7 @@
#include "libslic3r/PresetBundle.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
namespace Slic3r {
namespace GUI {
+1 -1
View File
@@ -242,7 +242,7 @@ int HMSQuery::save_to_local(std::string lang, std::string hms_type, std::string
std::string dir_str = (hms_folder / filename).make_preferred().string();
std::ofstream json_file(encode_path(dir_str.c_str()));
if (json_file.is_open()) {
json_file << std::setw(4) << save_json << std::endl;
json_file << save_json.dump(1, '\t') << std::endl;
json_file.close();
return 0;
}
+2 -2
View File
@@ -1,7 +1,7 @@
#include "IMToolbar.hpp"
#include "3DScene.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <imgui/imgui_internal.h>
#include <imgui/imgui.h>
@@ -87,7 +87,7 @@ bool IMReturnToolbar::init()
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glsafe(::glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
if (compress && GLEW_EXT_texture_compression_s3tc)
if (compress && GLAD_GL_EXT_texture_compression_s3tc)
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, data.width, data.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
else
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, data.width, data.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
+1 -1
View File
@@ -9,7 +9,7 @@
#include "libslic3r/Utils.hpp" // ScopeGuard
#include "3DScene.hpp" // glsafe
#include "GL/glew.h"
#include <glad/gl.h>
#define STB_RECT_PACK_IMPLEMENTATION
#include "imgui/imstb_rectpack.h" // distribute rectangles
+2 -2
View File
@@ -18,7 +18,7 @@
#include <wx/clipbrd.h>
#include <wx/debug.h>
#include <GL/glew.h>
#include <glad/gl.h>
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
@@ -2839,7 +2839,7 @@ void ImGuiWrapper::init_font(bool compress)
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
glsafe(::glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
if (compress && GLEW_EXT_texture_compression_s3tc)
if (compress && GLAD_GL_EXT_texture_compression_s3tc)
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
else
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
@@ -3,7 +3,7 @@
#include <vector>
#include <string>
#include <GL/glew.h>
#include <glad/gl.h>
#include <wx/string.h>
#include <wx/fontenc.h>
#include "Job.hpp"
+1 -1
View File
@@ -219,7 +219,7 @@ void create_volume(TriangleMesh &&mesh, const ObjectID& object_id, const ModelVo
/// Create projection for cut surface from mesh
/// </summary>
/// <param name="tr">Volume transformation in object</param>
/// <param name="shape_scale">Convert shape to milimeters</param>
/// <param name="shape_scale">Convert shape to millimeters</param>
/// <param name="z_range">Bounding box 3d of model volume for projection ranges</param>
/// <returns>Orthogonal cut_projection</returns>
OrthoProject create_projection_for_cut(Transform3d tr, double shape_scale, const std::pair<float, float> &z_range);
+53
View File
@@ -0,0 +1,53 @@
#include "LinuxDisplayBackend.hpp"
#if defined(__WXGTK__)
#include <gdk/gdk.h>
#ifdef wxHAVE_GDK_X11
#include <gdk/gdkx.h>
#endif
#ifdef wxHAVE_GDK_WAYLAND
#include <gdk/gdkwayland.h>
#endif
namespace Slic3r {
namespace GUI {
LinuxDisplayBackend get_linux_display_backend()
{
static const LinuxDisplayBackend backend = []() -> LinuxDisplayBackend {
GdkDisplay *display = gdk_display_get_default();
if (!display)
return LinuxDisplayBackend::Unknown;
#ifdef wxHAVE_GDK_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY(display))
return LinuxDisplayBackend::Wayland;
#endif
#ifdef wxHAVE_GDK_X11
if (GDK_IS_X11_DISPLAY(display))
return LinuxDisplayBackend::X11;
#endif
return LinuxDisplayBackend::Unknown;
}();
return backend;
}
bool is_running_on_wayland()
{
return get_linux_display_backend() == LinuxDisplayBackend::Wayland;
}
bool is_running_on_x11()
{
return get_linux_display_backend() == LinuxDisplayBackend::X11;
}
} // namespace GUI
} // namespace Slic3r
#endif // defined(__WXGTK__)
+19
View File
@@ -0,0 +1,19 @@
#pragma once
namespace Slic3r {
namespace GUI {
#if defined(__WXGTK__)
enum class LinuxDisplayBackend { X11, Wayland, Unknown };
// Detect which display backend is in use at runtime.
// Must be called after gtk_init() / wxWidgets initialization.
LinuxDisplayBackend get_linux_display_backend();
// Convenience predicates.
bool is_running_on_wayland();
bool is_running_on_x11();
#endif // defined(__WXGTK__)
} // namespace GUI
} // namespace Slic3r
+36 -1
View File
@@ -310,6 +310,17 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
m_edge_right = new ResizeEdgePanel(this, ResizeEdgePanel::Right);
#endif
#ifdef __WXMSW__
if (HWND hWnd = GetHandle(); hWnd != nullptr) {
LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE);
if ((style & WS_CAPTION) != 0) {
SetWindowLongPtr(hWnd, GWL_STYLE, style & ~WS_CAPTION);
SetWindowPos(hWnd, nullptr, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
}
#endif
if (!wxGetApp().app_config->has("user_mode")) {
wxGetApp().app_config->set("user_mode", "simple");
wxGetApp().app_config->set_bool("developer_mode", false);
@@ -524,6 +535,28 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
update_layout();
sizer->SetSizeHints(this);
#ifdef __WXMSW__
// SetMaximize causes the window to overlap the taskbar, due to the fact this window has wxMAXIMIZE_BOX off
// https://forums.wxwidgets.org/viewtopic.php?t=50634
// Fix it here
this->Bind(wxEVT_MAXIMIZE, [this](auto &e) {
wxDisplay display(this);
auto size = display.GetClientArea().GetSize();
auto pos = display.GetClientArea().GetPosition();
HWND hWnd = GetHandle();
RECT borderThickness;
SetRectEmpty(&borderThickness);
AdjustWindowRectEx(&borderThickness, GetWindowLongPtr(hWnd, GWL_STYLE), FALSE, 0);
const auto max_size = size + wxSize{-borderThickness.left + borderThickness.right, -borderThickness.top + borderThickness.bottom};
const auto current_size = GetSize();
SetSize({std::min(max_size.x, current_size.x), std::min(max_size.y, current_size.y)});
Move(pos + wxPoint{borderThickness.left, borderThickness.top});
e.Skip();
});
#endif // __WXMSW__
// BBS
Fit();
@@ -586,6 +619,8 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
#endif
MarkdownTip::ExitTip();
// Prevent queued selection/UI refresh work from running as normal during reset.
wxGetApp().set_closing(true);
m_plater->reset();
this->shutdown();
@@ -758,7 +793,7 @@ void MainFrame::bind_diff_dialog()
}
#ifdef __WIN32__
#ifdef __WXMSW__
// Orca: Fix maximized window overlaps taskbar when taskbar auto hide is enabled (#8085)
// Adopted from https://gist.github.com/MortenChristiansen/6463580
+1 -1
View File
@@ -204,7 +204,7 @@ protected:
virtual void on_dpi_changed(const wxRect &suggested_rect) override;
virtual void on_sys_color_changed() override;
#ifdef __WIN32__
#ifdef __WXMSW__
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override;
#endif
+1 -1
View File
@@ -14,7 +14,7 @@
#include "slic3r/GUI/CameraUtils.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <igl/unproject.h>
+2 -2
View File
@@ -205,8 +205,8 @@ void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable)
if (m_printable == printable)
return;
m_printable = printable;
m_printable_icon = m_printable == piUndef ? m_empty_bmp :
create_scaled_bitmap(m_printable == piPrintable ? "check_on" : "check_off_focused");
m_printable_icon = m_printable == piUndef ?
m_empty_bmp : create_scaled_bitmap(m_printable == piPrintable ? "check_on" : "check_off_focused");
}
void ObjectDataViewModelNode::set_variable_height_icon(VaryHeightIndicator vari_height) {
+5 -5
View File
@@ -241,7 +241,7 @@ public:
void SetExtruder(const wxString &extruder) { m_extruder = extruder; }
void SetWarningIconName(const std::string& warning_icon_name) { m_warning_icon_name = warning_icon_name; }
void SetLock(bool has_lock) { m_has_lock = has_lock; }
const wxBitmap& GetBitmap() const { return m_bmp; }
const wxBitmap& GetBitmap() const { return m_bmp; }
const wxString& GetName() const { return m_name; }
ItemType GetType() const { return m_type; }
InfoItemType GetInfoItemType() const { return m_info_item_type; }
@@ -249,16 +249,16 @@ public:
int GetIdx() const { return m_idx; }
//BBS: add part plate related logic
void SetPlateIdx(const int& idx);
int GetPlateIdx() const { return m_plate_idx; }
int GetPlateIdx() const { return m_plate_idx; }
ModelVolumeType GetVolumeType() { return m_volume_type; }
t_layer_height_range GetLayerRange() const { return m_layer_range; }
wxString GetExtruder() { return m_extruder; }
PrintIndicator IsPrintable() const { return m_printable; }
VaryHeightIndicator IsVaribaleHeight() const { return m_variable_height; }
VaryHeightIndicator IsVaribaleHeight() const { return m_variable_height; }
// BBS
bool HasColorPainting() const { return m_color_enable; }
bool HasSupportPainting() const { return m_support_enable; }
bool HasSinking() const { return m_sink_enable; }
bool HasSupportPainting() const { return m_support_enable; }
bool HasSinking() const { return m_sink_enable; }
bool IsActionEnabled() const { return m_action_enable; }
void UpdateExtruderAndColorIcon(wxString extruder = "");
+42 -21
View File
@@ -7,7 +7,7 @@
#include "libslic3r/Platform.hpp"
#include <GL/glew.h>
#include <glad/gl.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
@@ -22,16 +22,11 @@
#include "../Utils/MacDarkMode.hpp"
#endif // __APPLE__
// Verify GLEW and wxWidgets use the same OpenGL backend (EGL vs GLX).
// A mismatch causes rendering failures: GLEW's function loading must match
// the context type created by wxWidgets.
#if defined(__linux__)
#if defined(GLEW_EGL) && (!defined(wxUSE_GLCANVAS_EGL) || !wxUSE_GLCANVAS_EGL)
#error "OpenGL backend mismatch: GLEW has EGL support enabled but wxWidgets does not. Ensure GLEW_USE_EGL and wxUSE_GLCANVAS_EGL are both ON or both OFF."
#endif
#if !defined(GLEW_EGL) && defined(wxUSE_GLCANVAS_EGL) && wxUSE_GLCANVAS_EGL
#error "OpenGL backend mismatch: wxWidgets has EGL support enabled but GLEW does not. Ensure GLEW_USE_EGL and wxUSE_GLCANVAS_EGL are both ON or both OFF."
#endif
#ifdef __WXGTK__
#include "LinuxDisplayBackend.hpp"
#ifdef wxHAS_EGL
#include <EGL/egl.h>
#endif
#endif
namespace Slic3r {
@@ -121,12 +116,12 @@ void OpenGLManager::GLInfo::detect() const
if (Slic3r::total_physical_memory() / (1024 * 1024 * 1024) < 6)
*max_tex_size /= 2;
if (GLEW_EXT_texture_filter_anisotropic) {
if (GLAD_GL_EXT_texture_filter_anisotropic) {
float* max_anisotropy = const_cast<float*>(&m_max_anisotropy);
glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy));
}
if (!GLEW_ARB_compatibility)
if (!GLAD_GL_ARB_compatibility)
*const_cast<bool*>(&m_core_profile) = true;
*const_cast<bool*>(&m_detected) = true;
@@ -245,24 +240,36 @@ OpenGLManager::~OpenGLManager()
bool OpenGLManager::init_gl(bool popup_error)
{
if (!m_gl_initialized) {
glewExperimental = true;
GLenum result = glewInit();
if (result != GLEW_OK) {
BOOST_LOG_TRIVIAL(error) << "Unable to init glew library, Error: " << glewGetErrorString(result);
int version = 0;
#if defined(__WXGTK__) && defined(wxHAS_EGL)
if (is_running_on_wayland()) {
// On EGL/Wayland, gladLoaderLoadGL() dlopen's libGL.so then
// immediately dlclose's it. Since nothing else holds libGL.so
// open (unlike GLX where the context keeps it loaded), the
// library gets unmapped and all function pointers become invalid.
// Use eglGetProcAddress directly to avoid this.
version = gladLoadGL((GLADloadfunc)eglGetProcAddress);
} else
#endif
{
version = gladLoaderLoadGL();
}
if (version == 0) {
BOOST_LOG_TRIVIAL(error) << "Unable to init GLAD OpenGL loader";
return false;
}
//BOOST_LOG_TRIVIAL(info) << "glewInit Success."<< std::endl;
BOOST_LOG_TRIVIAL(info) << "GLAD loaded OpenGL " << GLAD_VERSION_MAJOR(version) << "." << GLAD_VERSION_MINOR(version);
m_gl_initialized = true;
if (GLEW_EXT_texture_compression_s3tc)
if (GLAD_GL_EXT_texture_compression_s3tc)
s_compressed_textures_supported = true;
else
s_compressed_textures_supported = false;
if (GLEW_ARB_framebuffer_object) {
if (GLAD_GL_ARB_framebuffer_object) {
s_framebuffers_type = EFramebufferType::Arb;
BOOST_LOG_TRIVIAL(info) << "Found Framebuffer Type ARB."<< std::endl;
}
else if (GLEW_EXT_framebuffer_object) {
else if (GLAD_GL_EXT_framebuffer_object) {
BOOST_LOG_TRIVIAL(info) << "Found Framebuffer Type Ext."<< std::endl;
s_framebuffers_type = EFramebufferType::Ext;
}
@@ -438,6 +445,20 @@ void OpenGLManager::detect_multisample(int* attribList)
{
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER;
bool enable_multisample = wxVersion >= 30003;
#if defined(__WXGTK__)
// On Wayland, wxGLCanvas::IsDisplaySupported() requires the EGL backend.
// If wxWidgets was built without EGL, the GLX backend will crash trying
// to access a non-existent X11 display. Disable multisample in that case.
if (is_running_on_wayland()) {
#if !defined(wxHAS_EGL) || !wxHAS_EGL
BOOST_LOG_TRIVIAL(warning) << "Wayland without EGL: disabling multisample detection";
s_multisample = EMultisampleState::Disabled;
return;
#endif
}
#endif
s_multisample =
enable_multisample &&
// Disable multi-sampling on ChromeOS, as the OpenGL virtualization swaps Red/Blue channels with multi-sampling enabled,
+34 -8
View File
@@ -7,7 +7,7 @@
#include <set>
#include <regex>
#include <future>
#include <GL/glew.h>
#include <glad/gl.h>
#include <boost/algorithm/string.hpp>
#include <boost/optional.hpp>
#include <boost/filesystem/path.hpp>
@@ -1678,9 +1678,12 @@ void PartPlate::render_icon_texture(GLModel &buffer, GLTexture &texture)
void PartPlate::render_plate_name_texture()
{
if (m_name_texture.get_id() == 0)
if (m_plate_name_edit_icon.mesh_raycaster == nullptr)
generate_plate_name_texture();
if (m_name_texture.get_id() == 0)
return;
GLuint tex_id = (GLuint)m_name_texture.get_id();
glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id));
m_plate_name_icon.render();
@@ -2091,6 +2094,9 @@ void PartPlate::render_right_arrow(const ColorRGBA render_color, bool use_lighti
static void register_model_for_picking(GLCanvas3D &canvas, PickingModel &model, int id)
{
if (model.mesh_raycaster == nullptr)
return;
canvas.add_raycaster_for_picking(SceneRaycaster::EType::Bed, id, *model.mesh_raycaster, Transform3d::Identity());
}
@@ -2105,7 +2111,10 @@ void PartPlate::register_raycasters_for_picking(GLCanvas3D &canvas)
register_model_for_picking(canvas, m_plate_settings_icon, picking_id_component(5));
canvas.remove_raycasters_for_picking(SceneRaycaster::EType::Bed, picking_id_component(6));
register_model_for_picking(canvas, m_plate_name_edit_icon, picking_id_component(6));
// Plate-name edit picking is built lazily together with the plate-name texture.
// During reset / reload_scene the icon may not have a raycaster yet, which is valid.
if (m_plate_name_edit_icon.mesh_raycaster != nullptr)
register_model_for_picking(canvas, m_plate_name_edit_icon, picking_id_component(6));
register_model_for_picking(canvas, m_move_front_icon, picking_id_component(7));
// Only register filament map button for H2D (dual-extruder Bambu Lab) printers
@@ -2862,7 +2871,7 @@ void PartPlate::clear(bool clear_sliced_result)
m_ready_for_slice = true;
update_slice_result_valid_state(false);
}
m_name_texture.reset();
invalidate_plate_name_texture();
return;
}
@@ -2952,6 +2961,10 @@ Vec3d PartPlate::get_center_origin()
void PartPlate::generate_plate_name_texture()
{
auto canvas = this->m_partplate_list->m_plater->get_view3D_canvas3D();
if (canvas == nullptr)
return;
m_plate_name_icon.reset();
// generate m_name_texture texture from m_name with generate_from_text_string
@@ -2964,8 +2977,10 @@ void PartPlate::generate_plate_name_texture()
wxFont* font = &l;
wxColour foreground(0xf2, 0x75, 0x4e, 0xff);
if (!m_name_texture.generate_from_text_string(text.ToUTF8().data(), *font, *wxBLACK, foreground))
if (!m_name_texture.generate_from_text_string(text.ToUTF8().data(), *font, *wxBLACK, foreground)) {
BOOST_LOG_TRIVIAL(error) << "PartPlate::generate_plate_name_texture(): generate_from_text_string() failed";
return;
}
ExPolygon poly;
auto bed_ext = get_extents(m_shape);
@@ -2989,11 +3004,22 @@ void PartPlate::generate_plate_name_texture()
if (!init_model_from_poly(m_plate_name_icon, poly, GROUND_Z))
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "Unable to generate geometry buffers for icons\n";
auto canvas = this->m_partplate_list->m_plater->get_view3D_canvas3D();
canvas->remove_raycasters_for_picking(SceneRaycaster::EType::Bed, picking_id_component(6));
calc_vertex_for_plate_name_edit_icon(&m_name_texture, 0, m_plate_name_edit_icon);
register_model_for_picking(*canvas, m_plate_name_edit_icon, picking_id_component(6));
}
void PartPlate::invalidate_plate_name_texture()
{
m_plate_name_edit_icon.mesh_raycaster.reset();
auto canvas = (m_plater != nullptr) ? m_plater->get_view3D_canvas3D() : nullptr;
if (canvas != nullptr) {
canvas->remove_raycasters_for_picking(SceneRaycaster::EType::Bed, picking_id_component(6));
canvas->set_as_dirty();
}
}
void PartPlate::set_plate_name(const std::string& name)
{
// compare if name equal to m_name, case sensitive
@@ -3004,7 +3030,7 @@ void PartPlate::set_plate_name(const std::string& name)
if (m_print != nullptr)
m_print->set_plate_name(name);
generate_plate_name_texture();
invalidate_plate_name_texture();
}
//get the print's object, result and index
@@ -3816,7 +3842,7 @@ bool PartPlate::set_shape(const Pointfs& shape, const Pointfs& exclude_areas, co
calc_vertex_for_number(0, false, m_plate_idx_icon);
// calc vertex for plate name
generate_plate_name_texture();
invalidate_plate_name_texture();
}
}
+1
View File
@@ -217,6 +217,7 @@ private:
void render_icons(bool bottom, bool only_name = false, int hover_id = -1);
void render_only_numbers(bool bottom);
void render_plate_name_texture();
void invalidate_plate_name_texture();
void register_raycasters_for_picking(GLCanvas3D& canvas);
int picking_id_component(int idx) const;
+178 -30
View File
@@ -76,6 +76,9 @@
#include "GUI_App.hpp"
#include "GuiColor.hpp"
#include "GUI_ObjectList.hpp"
#ifdef __WXGTK__
#include "LinuxDisplayBackend.hpp"
#endif
#include "GUI_Utils.hpp"
#include "GUI_Factories.hpp"
#include "wxExtensions.hpp"
@@ -349,6 +352,57 @@ void SlicedInfo::SetTextAndShow(SlicedInfoIdx idx, const wxString& text, const w
static wxString temp_dir;
namespace {
#ifdef __WXGTK__
wxString sanitize_window_layout_for_wayland(const wxString& layout, bool* removed_floating_state = nullptr)
{
if (!Slic3r::GUI::is_running_on_wayland() || layout.empty()) {
if (removed_floating_state != nullptr)
*removed_floating_state = false;
return layout;
}
static const std::regex state_pattern(R"(state=(\d+);)");
constexpr unsigned int disabled_wayland_flags =
static_cast<unsigned int>(wxAuiPaneInfo::optionFloating) |
static_cast<unsigned int>(wxAuiPaneInfo::optionFloatable);
const std::string input = layout.utf8_string();
std::string output;
output.reserve(input.size());
bool modified = false;
std::smatch match;
auto search_start = input.cbegin();
while (std::regex_search(search_start, input.cend(), match, state_pattern)) {
output.append(search_start, match[0].first);
try {
const unsigned long state = std::stoul(match[1].str());
const unsigned long sanitized_state = state & ~static_cast<unsigned long>(disabled_wayland_flags);
modified = modified || sanitized_state != state;
output += "state=" + std::to_string(sanitized_state) + ";";
} catch (const std::exception&) {
output += match[0].str();
}
search_start = match[0].second;
}
output.append(search_start, input.cend());
if (removed_floating_state != nullptr)
*removed_floating_state = modified;
return modified ? wxString::FromUTF8(output) : layout;
}
#endif
} // namespace
// Sidebar / private
enum class ActionButtonType : int {
@@ -1782,7 +1836,11 @@ Sidebar::Sidebar(Plater *parent)
e.Skip();
});
w->Bind(wxEVT_LEAVE_WINDOW, [this, panel_color](wxMouseEvent &e) {
wxWindow* next_w = wxFindWindowAtPoint(wxGetMousePosition());
// Use event-relative coords instead of wxGetMousePosition() which
// returns (0,0) on Wayland for global screen coordinates.
wxWindow* evtObj = dynamic_cast<wxWindow*>(e.GetEventObject());
wxPoint screenPos = evtObj ? evtObj->ClientToScreen(e.GetPosition()) : wxGetMousePosition();
wxWindow* next_w = wxFindWindowAtPoint(screenPos);
if (!next_w || !p->panel_printer_preset->IsDescendant(next_w)){
if(!p->combo_printer->HasFocus())
p->panel_printer_preset->SetBorderColor(panel_color.bd_normal);
@@ -1844,7 +1902,11 @@ Sidebar::Sidebar(Plater *parent)
e.Skip();
});
w->Bind(wxEVT_LEAVE_WINDOW, [this, panel_color](wxMouseEvent &e) {
wxWindow* next_w = wxFindWindowAtPoint(wxGetMousePosition());
// Use event-relative coords instead of wxGetMousePosition() which
// returns (0,0) on Wayland for global screen coordinates.
wxWindow* evtObj = dynamic_cast<wxWindow*>(e.GetEventObject());
wxPoint screenPos = evtObj ? evtObj->ClientToScreen(e.GetPosition()) : wxGetMousePosition();
wxWindow* next_w = wxFindWindowAtPoint(screenPos);
if (!p->combo_nozzle_dia->HasFocus() && (!next_w || !p->panel_nozzle_dia->IsDescendant(next_w)))
p->panel_nozzle_dia->SetBorderColor(panel_color.bd_normal);
e.Skip();
@@ -1914,7 +1976,11 @@ Sidebar::Sidebar(Plater *parent)
e.Skip();
});
w->Bind(wxEVT_LEAVE_WINDOW, [this, w, panel_color](wxMouseEvent &e) {
wxWindow* next_w = wxFindWindowAtPoint(wxGetMousePosition());
// Use event-relative coords instead of wxGetMousePosition() which
// returns (0,0) on Wayland for global screen coordinates.
wxWindow* evtObj = dynamic_cast<wxWindow*>(e.GetEventObject());
wxPoint screenPos = evtObj ? evtObj->ClientToScreen(e.GetPosition()) : wxGetMousePosition();
wxWindow* next_w = wxFindWindowAtPoint(screenPos);
if (!p->combo_printer_bed->HasFocus() && (!next_w || !p->panel_printer_bed->IsDescendant(next_w)))
p->panel_printer_bed->SetBorderColor(panel_color.bd_normal);
if(w == p->image_printer_bed)
@@ -4442,7 +4508,7 @@ struct Plater::priv
// BBS: backup & restore
std::vector<size_t> load_files(const std::vector<fs::path>& input_files, LoadStrategy strategy, bool ask_multi = false);
std::vector<size_t> load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false, bool split_object = false);
std::vector<size_t> load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z = false, bool split_object = false, bool auto_drop = true);
fs::path get_export_file_path(GUI::FileType file_type);
wxString get_export_file(GUI::FileType file_type);
@@ -4473,7 +4539,8 @@ struct Plater::priv
void center_selection();
void drop_selection();
void mirror(Axis axis);
void split_object();
void split_object(bool auto_drop = true);
void split_object(int obj_idx, bool auto_drop = true);
void split_volume();
void scale_selection_to_fit_print_volume();
@@ -4837,8 +4904,16 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
{
m_is_dark = wxGetApp().app_config->get("dark_color_mode") == "1";
#ifdef __WXGTK__
const bool disable_wayland_floating = Slic3r::GUI::is_running_on_wayland();
#endif
m_aui_mgr.SetManagedWindow(q);
m_aui_mgr.SetDockSizeConstraint(1, 1);
#ifdef __WXGTK__
if (disable_wayland_floating)
m_aui_mgr.SetFlags(m_aui_mgr.GetFlags() & ~wxAUI_MGR_ALLOW_FLOATING);
#endif
//m_aui_mgr.GetArtProvider()->SetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE, 0);
//m_aui_mgr.GetArtProvider()->SetMetric(wxAUI_DOCKART_SASH_SIZE, 2);
m_aui_mgr.GetArtProvider()->SetMetric(wxAUI_DOCKART_CAPTION_SIZE, 18);
@@ -4930,7 +5005,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
.CloseButton(false)
.TopDockable(false)
.BottomDockable(false)
.Floatable(true)
.BestSize(wxSize(39 * wxGetApp().em_unit(), 90 * wxGetApp().em_unit())));
auto* panel_sizer = new wxBoxSizer(wxHORIZONTAL);
@@ -4949,7 +5023,19 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
const auto cfg = wxGetApp().app_config;
wxString layout = wxString::FromUTF8(cfg->get("window_layout"));
if (!layout.empty()) {
m_aui_mgr.LoadPerspective(layout, false);
bool removed_floating_state = false;
#ifdef __WXGTK__
if (disable_wayland_floating)
layout = sanitize_window_layout_for_wayland(layout, &removed_floating_state);
#endif
if (!m_aui_mgr.LoadPerspective(layout, false)) {
BOOST_LOG_TRIVIAL(warning) << "Failed to restore saved window layout";
m_aui_mgr.LoadPerspective(m_default_window_layout, false);
} else if (removed_floating_state) {
BOOST_LOG_TRIVIAL(info) << "Removed floating AUI state from saved window layout for Wayland";
}
sidebar_layout.is_collapsed = !sidebar.IsShown();
}
@@ -6632,14 +6718,37 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
if (new_model != nullptr && new_model->objects.size() > 1) {
//BBS do not popup this dialog
bool new_model_auto_drop = true;
int single_object_answer = false;
if (ask_multi) {
MessageDialog msg_dlg(q, _L("Load these files as a single object with multiple parts?\n"), _L("Object with multiple parts was detected"),
wxICON_WARNING | wxYES | wxNO);
if (msg_dlg.ShowModal() == wxID_YES) { new_model->convert_multipart_object(filaments_cnt); }
RichMessageDialog dlg(q, _L("Load these files as a single object with multiple parts?\n"),
_L("Object with multiple parts was detected"), wxICON_QUESTION | wxYES_NO);
dlg.ShowCheckBox(_L("Auto-Drop"), true);
single_object_answer = dlg.ShowModal();
if (dlg.IsCheckBoxChecked() == false)
new_model_auto_drop = false;
// convert to multipart and split after load_model_objects
// to keep relative positioning if auto_drop == false
if (single_object_answer == wxID_YES || new_model_auto_drop == false)
new_model->convert_multipart_object(filaments_cnt);
}
auto loaded_idxs = load_model_objects(new_model->objects);
// TODO
// DONE always convert to multipart, split afterwards to retain relative position
// DONE if !auto_drop move all objects over the z-position 0, so that none are clipped by the bed.
// DONE retain auto_drop (and printable) state when assembling or splitting objects.
// DONE when manually split to object ask users if looks_like_multipart and none have auto_drob disabled if they want to disable auto_drop for all resulting objects.
// - add icon in object list, similar to fuzzy painting, etc.
auto loaded_idxs = load_model_objects(new_model->objects, false, false, new_model_auto_drop);
obj_idxs.insert(obj_idxs.end(), loaded_idxs.begin(), loaded_idxs.end());
if (single_object_answer == wxID_NO && new_model_auto_drop == false) {
split_object(loaded_idxs[0], new_model_auto_drop);
}
}
if (load_config) {
@@ -6806,7 +6915,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
#define AUTOPLACEMENT_ON_LOAD
std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z, bool split_object)
std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& model_objects, bool allow_negative_z, bool split_object, bool auto_drop)
{
const Vec3d bed_size = Slic3r::to_3d(this->bed.build_volume().bounding_volume2d().size(), 1.0) - 2.0 * Vec3d::Ones();
@@ -6833,7 +6942,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
#else /* AUTOPLACEMENT_ON_LOAD */
// if object has no defined position(s) we need to rearrange everything after loading
// need_arrange = true;
// add a default instance and center object around origin
// add a default instance and center object around origin
object->center_around_origin(); // also aligns object to Z = 0
ModelInstance* instance = object->add_instance();
@@ -6842,7 +6951,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
instance->set_offset(Slic3r::to_3d(this->bed.build_volume().bed_center(), -object->origin_translation(2)));
#endif /* AUTOPLACEMENT_ON_LOAD */
}
//BBS: when the object is too large, let the user choose whether to scale it down
for (size_t i = 0; i < object->instances.size(); ++i) {
ModelInstance* instance = object->instances[i];
@@ -6872,7 +6981,20 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
}
}
object->ensure_on_bed(allow_negative_z);
if (!auto_drop) {
for (size_t i = 0; i < object->instances.size(); ++i) {
ModelInstance* instance = object->instances[i];
instance->auto_drop = auto_drop;
}
// if under the bed, move over the bed
double dist_to_bed = std::min(object->min_z(), double(0));
object->translate_instances(Vec3d(0, 0, -dist_to_bed));
}
else {
object->ensure_on_bed(allow_negative_z);
}
if (!split_object) {
//BBS initial assemble transformation
for (ModelObject* model_object : model.objects) {
@@ -6882,7 +7004,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
model_object->instances[i]->set_assemble_transformation(model_object->instances[i]->get_transformation());
}
}
}
}
}
}
@@ -6949,7 +7071,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs& mode
// which is updated after a view3D->reload_scene(false, flags & (unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH) call
for (const size_t idx : obj_idxs)
wxGetApp().obj_list()->update_info_items(idx);
object_list_changed();
this->schedule_background_process();
@@ -7401,9 +7523,16 @@ void Plater::find_new_position(const ModelInstancePtrs &instances)
m.apply();
}
void Plater::priv::split_object()
{
// split selected object into multiple objects by its volumes
void Plater::priv::split_object(bool auto_drop /* = true */)
{
int obj_idx = get_selected_object_idx();
priv::split_object(obj_idx, auto_drop);
}
// split provided object into multiple objects by its volumes
void Plater::priv::split_object(int obj_idx, bool auto_drop /* = true */)
{
if (obj_idx == -1)
return;
@@ -7429,12 +7558,30 @@ void Plater::priv::split_object()
Plater::TakeSnapshot snapshot(q, "Split to Objects");
auto is_atleast_one_floating = [new_objects]() {
for (ModelObject* new_object : new_objects) {
if (new_object->get_instance_min_z(0) >= SINKING_MIN_Z_THRESHOLD)
return true;
}
return false;
};
bool split_auto_drop = auto_drop;
if (current_model_object->instances[0]->auto_drop && is_atleast_one_floating()) {
MessageDialog dlg(q, _L("Disable Auto-Drop to preserve z positioning?\n"),
_L("Object with floating parts was detected"), wxICON_QUESTION | wxYES_NO);
if (dlg.ShowModal() == wxID_YES)
split_auto_drop = false;
}
remove(obj_idx);
// load all model objects at once, otherwise the plate would be rearranged after each one
// causing original positions not to be kept
//BBS: set split_object to true to avoid re-compute assemble matrix
std::vector<size_t> idxs = load_model_objects(new_objects, false, true);
std::vector<size_t> idxs = load_model_objects(new_objects, false, true, split_auto_drop);
wxGetApp().plater()->get_view3D_canvas3D()->update_instance_printable_state_for_objects(idxs);
// select newly added objects
for (size_t idx : idxs)
@@ -8897,11 +9044,9 @@ void Plater::priv::set_current_panel(wxPanel* panel, bool no_slice)
wxPanel* old_panel = current_panel;
//#if BBL_HAS_FIRST_PAGE
if (!old_panel) {
//BBS: only switch to the first panel when visible
// Wayland may report the first canvas as not yet shown while the frame is still mapping.
// Keep the panel switch anyway so handlers are bound and the first paint can initialize GL later.
panel->Show();
//dynamic_cast<View3D *>(panel)->get_canvas3d()->render();
if (!panel->IsShownOnScreen())
return;
}
//#endif
current_panel = panel;
@@ -10221,6 +10366,9 @@ void Plater::priv::on_action_split_volumes(SimpleEvent&)
void Plater::priv::on_object_select(SimpleEvent& evt)
{
if (wxGetApp().is_closing())
return;
wxGetApp().obj_list()->update_selections();
selection_changed();
}
@@ -16752,7 +16900,7 @@ const GLCanvas3D* Plater::canvas3D() const
GLCanvas3D* Plater::get_view3D_canvas3D()
{
return p->view3D->get_canvas3d();
return p ? p->view3D->get_canvas3d() : nullptr;
}
GLCanvas3D* Plater::get_preview_canvas3D()
@@ -16943,11 +17091,11 @@ void Plater::suppress_background_process(const bool stop_background_process)
this->p->suppressed_backround_processing_update = true;
}
void Plater::center_selection() { p->center_selection(); }
void Plater::drop_selection() { p->drop_selection(); }
void Plater::mirror(Axis axis) { p->mirror(axis); }
void Plater::split_object() { p->split_object(); }
void Plater::split_volume() { p->split_volume(); }
void Plater::center_selection() { p->center_selection(); }
void Plater::drop_selection() { p->drop_selection(); }
void Plater::mirror(Axis axis) { p->mirror(axis); }
void Plater::split_object(bool auto_drop) { p->split_object(auto_drop); }
void Plater::split_volume() { p->split_volume(); }
void Plater::optimize_rotation()
{
auto &w = get_ui_job_worker();
+2 -1
View File
@@ -643,7 +643,8 @@ public:
void drop_selection();
void search(bool plater_is_active, Preset::Type type, wxWindow *tag, TextInput *etag, wxWindow *stag);
void mirror(Axis axis);
void split_object();
void split_object(bool auto_drop = true);
void split_object(int obj_idx, bool auto_drop = true);
void split_volume();
void optimize_rotation();
// find all empty cells on the plate and won't overlap with exclusion areas
+12
View File
@@ -15,6 +15,10 @@
#include <slic3r/GUI/Widgets/WebView.hpp>
#include <wx/webview.h>
#ifdef __linux__
#include <webkit2/webkit2.h>
#endif
namespace pt = boost::property_tree;
namespace Slic3r {
@@ -33,6 +37,14 @@ PrinterWebView::PrinterWebView(wxWindow *parent)
return;
}
#ifdef __linux__
auto cookiesPath = boost::filesystem::path(data_dir() + "/cache/cookies.db");
auto wv = static_cast<WebKitWebView*>(m_browser->GetNativeBackend());
auto wv_ctx = webkit_web_view_get_context(wv);
auto cookieManager = webkit_web_context_get_cookie_manager(wv_ctx);
webkit_cookie_manager_set_persistent_storage(cookieManager, cookiesPath.c_str(), WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE);
#endif
m_browser->Bind(wxEVT_WEBVIEW_ERROR, &PrinterWebView::OnError, this);
m_browser->Bind(wxEVT_WEBVIEW_LOADED, &PrinterWebView::OnLoaded, this);

Some files were not shown because too many files have changed in this diff Show More