Merge branch 'master' into fs_emboss

# Conflicts:
#	src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp
This commit is contained in:
Filip Sykala 2021-10-20 12:41:49 +02:00
commit 5224e9c5cb
5 changed files with 214 additions and 75 deletions

View file

@ -65,6 +65,7 @@ SET PS_DESTDIR=
CALL :RESOLVE_DESTDIR_CACHE
REM Set up parameters used by help menu
SET EXIT_STATUS=0
SET PS_CONFIG_DEFAULT=%PS_CONFIG%
SET PS_ARCH_HOST=%PS_ARCH%
(echo " -help /help -h /h -? /? ")| findstr /I /C:" %~1 ">nul && GOTO :HELP
@ -159,11 +160,14 @@ REM Build deps
:BUILD_DEPS
SET EXIT_STATUS=3
SET PS_CURRENT_STEP=deps
IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY deps\build "%PS_DEPS_PATH_FILE_NAME%"
IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY deps\build "%PS_DEPS_PATH_FILE_NAME%" .vs
cd deps\build || GOTO :END
cmake.exe .. -DDESTDIR="%PS_DESTDIR%" || GOTO :END
cmake.exe .. -DDESTDIR="%PS_DESTDIR%"
IF %ERRORLEVEL% NEQ 0 IF "%PS_STEPS_DIRTY%" NEQ "" (
(del CMakeCache.txt && cmake.exe .. -DDESTDIR="%PS_DESTDIR%") || GOTO :END
) ELSE GOTO :END
(echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE%"
msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% || GOTO :END
msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% /v:quiet || GOTO :END
cd ..\..
IF /I "%PS_STEPS:~0,4%" EQU "deps" GOTO :RUN_APP
@ -171,7 +175,7 @@ REM Build app
:BUILD_APP
SET EXIT_STATUS=4
SET PS_CURRENT_STEP=app
IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY build "%PS_CUSTOM_RUN_FILE%"
IF "%PS_STEPS_DIRTY%" EQU "" CALL :MAKE_OR_CLEAN_DIRECTORY build "%PS_CUSTOM_RUN_FILE%" .vs
cd build || GOTO :END
REM Make sure we have a custom batch file skeleton for the run stage
set PS_CUSTOM_BAT=%PS_CUSTOM_RUN_FILE%
@ -181,9 +185,12 @@ SET PS_PROJECT_IS_OPEN=
FOR /F "tokens=2 delims=," %%I in (
'tasklist /V /FI "IMAGENAME eq devenv.exe " /NH /FO CSV ^| find "%PS_SOLUTION_NAME%"'
) do SET PS_PROJECT_IS_OPEN=%%~I
cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST% || GOTO :END
cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST%
IF %ERRORLEVEL% NEQ 0 IF "%PS_STEPS_DIRTY%" NEQ "" (
(del CMakeCache.txt && cmake.exe .. -DCMAKE_PREFIX_PATH="%PS_DESTDIR%\usr\local" -DCMAKE_CONFIGURATION_TYPES=%PS_CONFIG_LIST%) || GOTO :END
) ELSE GOTO :END
REM Skip the build step if we're using the undocumented app-cmake to regenerate the full config from inside devenv
IF "%PS_STEPS%" NEQ "app-cmake" msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% || GOTO :END
IF "%PS_STEPS%" NEQ "app-cmake" msbuild /m ALL_BUILD.vcxproj /p:Configuration=%PS_CONFIG% /v:quiet || GOTO :END
(echo %PS_DESTDIR%)> "%PS_DEPS_PATH_FILE_FOR_CONFIG%"
REM Run app
@ -262,8 +269,11 @@ REM Functions and stubs start here.
:RESOLVE_DESTDIR_CACHE
@REM Resolves all DESTDIR cache values and sets PS_STEPS_DEFAULT
@REM Note: This just sets global variableq, so it doesn't use setlocal.
SET PS_DEPS_PATH_FILE_FOR_CONFIG=%~dp0build\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%
@REM Note: This just sets global variables, so it doesn't use setlocal.
SET PS_DEPS_PATH_FILE_FOR_CONFIG=%~dp0build\.vs\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%
mkdir "%~dp0build\.vs\%PS_ARCH%\%PS_CONFIG%" > nul 2> nul
REM Copy a legacy file if we don't have one in the proper location.
echo f|xcopy /D "%~dp0build\%PS_ARCH%\%PS_CONFIG%\%PS_DEPS_PATH_FILE_NAME%" "%PS_DEPS_PATH_FILE_FOR_CONFIG%"
CALL :CANONICALIZE_PATH PS_DEPS_PATH_FILE_FOR_CONFIG
IF EXIST "%PS_DEPS_PATH_FILE_FOR_CONFIG%" (
FOR /F "tokens=* USEBACKQ" %%I IN ("%PS_DEPS_PATH_FILE_FOR_CONFIG%") DO (

View file

@ -3,7 +3,7 @@
### Install the tools
Install Visual Studio Community 2019 from [visualstudio.microsoft.com/vs/](https://visualstudio.microsoft.com/vs/). Older versions are not supported as PrusaSlicer requires support for C++17.
Select all workload options for C++
Select all workload options for C++ and make sure to launch Visual Studio after install (to ensure that the full setup completes).
Install git for Windows from [gitforwindows.org](https://gitforwindows.org/)
Download and run the exe accepting all defaults
@ -17,6 +17,42 @@ c:> cd src
c:\src> git clone https://github.com/prusa3d/PrusaSlicer.git
```
### Run the automatic build script
The script `build_win.bat` will automatically find the default Visual Studio installation, set up the build environment, and then run both CMake and MSBuild to generate the dependencies and application as needed. If you'd rather do these steps manually, you can skip to the [Manual Build Instructions](#manual-build-instructions) in the next section. Otherwise, just run the following command to get everything going with the default configs:
```
c:\src>cd c:\src\PrusaSlicer
c:\src\PrusaSlicer>build_win.bat -d=..\PrusaSlicer-deps -r=console
```
The build script will run for a while (over an hour, depending on your machine) and automatically perform the following steps:
1. Configure and build [deps](#compile-the-dependencies) as RelWithDebInfo with `c:\src\PrusaSlicer-deps` as the destination directory
2. Configure and build all [application targets](#compile-prusaslicer) as RelWithDebInfo
3. Launch the resulting `prusa-slicer-console.exe` binary
You can change the above command line options to do things like:
* Change the destination for the dependencies by pointing `-d` to a different directory such as: `build_win.bat -d=s:\PrusaSlicerDeps`
* Open the solution in Visual Studio after the build completes by changing the `-r` switch to `-r=ide`
* Generate a release build without debug info by adding `-c=Release` or a full debug build with `-c=Debug`
* Perform an incremental application build (the default) with: `build_win.bat -s=app-dirty`
* Clean and rebuild the application: `build_win.bat -s=app`
* Clean and rebuild the dependencies: `build_win.bat -s=deps`
* Clean and rebuild everything (app and deps): `build_win.bat -s=all`
* _The full list of build script options can be listed by running:_ `build_win.bat -?`
### Troubleshooting
You're best off initiating builds from within Visual Studio for day-to-day development. However, the `build_win.bat` script can be very helpful if you run into build failures after updating your source tree. Here are some tips to keep in mind:
* The last several lines of output from `build_win.bat` will usually have the most helpful error messages.
* If CMake complains about missing binaries or paths (e.g. after updating Visual Studio), building with `build_win.bat` will force CMake to regenerate its cache on an error.
* After a deps change, you may just need to rebuild everything with the `-s=all` switch.
* Reading through the instructions in the next section may help diagnose more complex issues.
# Manual Build Instructions
_Follow the steps below if you want to understand how to perform a manual build, or if you're troubleshooting issues with the automatic build script._
### Compile the dependencies.
Dependencies are updated seldomly, thus they are compiled out of the PrusaSlicer source tree.
Go to the Windows Start Menu and Click on "Visual Studio 2019" folder, then select the ->"x64 Native Tools Command Prompt" to open a command window and run the following:

View file

@ -22,6 +22,7 @@ GLGizmoSimplify::GLGizmoSimplify(GLCanvas3D &parent)
, m_obj_index(0)
, m_need_reload(false)
, m_show_wireframe(false)
, m_move_to_center(false)
// translation for GUI size
, tr_mesh_name(_u8L("Mesh name"))
, tr_triangles(_u8L("Triangles"))
@ -48,6 +49,62 @@ bool GLGizmoSimplify::on_esc_key_down() {
return true;
}
// while opening needs GLGizmoSimplify to set window position
void GLGizmoSimplify::add_simplify_suggestion_notification(
const std::vector<size_t> &object_ids,
const ModelObjectPtrs & objects,
NotificationManager & manager)
{
std::vector<size_t> big_ids;
big_ids.reserve(object_ids.size());
auto is_big_object = [&objects](size_t object_id) {
const uint32_t triangles_to_suggest_simplify = 1000000;
if (object_id >= objects.size()) return false; // out of object index
ModelVolumePtrs &volumes = objects[object_id]->volumes;
if (volumes.size() != 1) return false; // not only one volume
size_t triangle_count = volumes.front()->mesh().its.indices.size();
if (triangle_count < triangles_to_suggest_simplify)
return false; // small volume
return true;
};
std::copy_if(object_ids.begin(), object_ids.end(),
std::back_inserter(big_ids), is_big_object);
if (big_ids.empty()) return;
for (size_t object_id : big_ids) {
std::string t = _u8L(
"Processing model '@object_name' with more than 1M triangles "
"could be slow. It is highly recommend to reduce "
"amount of triangles.");
t.replace(t.find("@object_name"), sizeof("@object_name") - 1,
objects[object_id]->name);
// std::stringstream text;
// text << t << "\n";
std::string hypertext = _u8L("Simplify model");
std::function<bool(wxEvtHandler *)> open_simplify =
[object_id](wxEvtHandler *) {
auto plater = wxGetApp().plater();
if (object_id >= plater->model().objects.size()) return true;
Selection &selection = plater->canvas3D()->get_selection();
selection.clear();
selection.add_object((unsigned int) object_id);
auto &manager = plater->canvas3D()->get_gizmos_manager();
bool close_notification = true;
if(!manager.open_gizmo(GLGizmosManager::Simplify))
return close_notification;
GLGizmoSimplify* simplify = dynamic_cast<GLGizmoSimplify*>(manager.get_current());
if (simplify == nullptr) return close_notification;
simplify->set_center_position();
return close_notification;
};
manager.push_simplify_suggestion_notification(
t, objects[object_id]->id(), hypertext, open_simplify);
}
}
std::string GLGizmoSimplify::on_get_name() const
{
return _u8L("Simplify");
@ -89,8 +146,16 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
m_is_valid_result = false;
m_exist_preview = false;
init_wireframe();
if (change_window_position) {
live_preview();
// set window position
if (m_move_to_center && change_window_position) {
m_move_to_center = false;
auto parent_size = m_parent.get_canvas_size();
ImVec2 pos(parent_size.get_width() / 2 - m_gui_cfg->window_offset_x,
parent_size.get_height() / 2 - m_gui_cfg->window_offset_y);
ImGui::SetNextWindowPos(pos, ImGuiCond_Always);
}else if (change_window_position) {
ImVec2 pos = ImGui::GetMousePos();
pos.x -= m_gui_cfg->window_offset_x;
pos.y -= m_gui_cfg->window_offset_y;
@ -292,6 +357,7 @@ void GLGizmoSimplify::live_preview() {
// wait until cancel
if (m_worker.joinable()) {
m_state = State::canceling;
m_dealy_process_cv.notify_one();
m_worker.join();
}
}
@ -302,20 +368,52 @@ void GLGizmoSimplify::live_preview() {
void GLGizmoSimplify::process()
{
class SimplifyCanceledException : public std::exception {
public:
const char* what() const throw() { return L("Model simplification has been canceled"); }
};
if (m_volume == nullptr) return;
if (m_volume->mesh().its.indices.empty()) return;
size_t count_triangles = m_volume->mesh().its.indices.size();
// Is neccessary simplification
if ((m_configuration.use_count && m_configuration.wanted_count >= count_triangles) ||
(!m_configuration.use_count && m_configuration.max_error <= 0.f)) {
// Exist different original volume?
if (m_original_its.has_value() &&
m_original_its->indices.size() != count_triangles) {
indexed_triangle_set its = *m_original_its; // copy
set_its(its);
}
m_is_valid_result = true;
if (!m_original_its.has_value())
// re-render bargraph
set_dirty();
m_parent.schedule_extra_frame(0);
return;
}
// when not store original volume store it for cancelation
if (!m_original_its.has_value()) {
m_original_its = m_volume->mesh().its; // copy
auto plater = wxGetApp().plater();
plater->take_snapshot(_L("Simplify ") + m_volume->name);
plater->clear_before_change_mesh(m_obj_index);
// store previous state
auto plater = wxGetApp().plater();
plater->take_snapshot(_L("Simplify ") + m_volume->name);
plater->clear_before_change_mesh(m_obj_index);
}
m_progress = 0;
if (m_worker.joinable()) m_worker.join();
m_worker = std::thread([this]() {
m_worker = std::thread([this]() {
{// delay before process
std::unique_lock<std::mutex> lk(m_state_mutex);
auto is_modify = [this]() { return m_state == State::canceling; };
if (m_dealy_process_cv.wait_for(lk, m_gui_cfg->prcess_delay, is_modify)) {
// exist modification
m_state = State::settings;
request_rerender();
return;
}
}
// store original triangles
uint32_t triangle_count = (m_configuration.use_count) ? m_configuration.wanted_count : 0;
float max_error = (!m_configuration.use_count) ? m_configuration.max_error : std::numeric_limits<float>::max();
@ -355,6 +453,7 @@ void GLGizmoSimplify::process()
}
void GLGizmoSimplify::set_its(indexed_triangle_set &its) {
if (m_volume == nullptr) return; // could appear after process
m_volume->set_mesh(its);
m_volume->calculate_convex_hull();
m_volume->set_new_unique_id();
@ -438,6 +537,10 @@ void GLGizmoSimplify::request_rerender() {
});
}
void GLGizmoSimplify::set_center_position() {
m_move_to_center = true;
}
bool GLGizmoSimplify::exist_volume(ModelVolume *volume) {
auto objs = wxGetApp().plater()->model().objects;
for (const auto &obj : objs) {

View file

@ -7,17 +7,22 @@
#include "GLGizmoPainterBase.hpp" // for render wireframe
#include "admesh/stl.h" // indexed_triangle_set
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <optional>
#include <atomic>
#include <GL/glew.h> // GLUint
namespace Slic3r {
// for simplify suggestion
class ModelObjectPtrs; // std::vector<ModelObject*>
namespace Slic3r {
class ModelVolume;
namespace GUI {
class NotificationManager; // for simplify suggestion
class GLGizmoSimplify: public GLGizmoBase, public GLGizmoTransparentRender // GLGizmoBase
{
@ -25,6 +30,10 @@ public:
GLGizmoSimplify(GLCanvas3D& parent);
virtual ~GLGizmoSimplify();
bool on_esc_key_down();
static void add_simplify_suggestion_notification(
const std::vector<size_t> &object_ids,
const ModelObjectPtrs & objects,
NotificationManager & manager);
protected:
virtual std::string on_get_name() const override;
virtual void on_render_input_window(float x, float y, float bottom_limit) override;
@ -47,6 +56,8 @@ private:
void set_its(indexed_triangle_set &its);
void create_gui_cfg();
void request_rerender();
void set_center_position();
// move to global functions
static ModelVolume *get_volume(const Selection &selection, Model &model);
static const ModelVolume *get_volume(const GLVolume::CompositeID &cid, const Model &model);
@ -57,15 +68,21 @@ private:
std::atomic_bool m_is_valid_result; // differ what to do in apply
std::atomic_bool m_exist_preview; // set when process end
bool m_move_to_center; // opening gizmo
volatile int m_progress; // percent of done work
ModelVolume *m_volume; // keep pointer to actual working volume
size_t m_obj_index;
std::optional<indexed_triangle_set> m_original_its;
bool m_show_wireframe;
bool m_show_wireframe;
volatile bool m_need_reload; // after simplify, glReload must be on main thread
std::thread m_worker;
// wait before process
std::mutex m_state_mutex;
std::condition_variable m_dealy_process_cv;
enum class State {
settings,
@ -87,8 +104,13 @@ private:
void fix_count_by_ratio(size_t triangle_count)
{
wanted_count = static_cast<uint32_t>(
std::round(triangle_count * (100.f-decimate_ratio) / 100.f));
if (decimate_ratio <= 0.f)
wanted_count = static_cast<uint32_t>(triangle_count);
else if (decimate_ratio >= 100.f)
wanted_count = 0;
else
wanted_count = static_cast<uint32_t>(std::round(
triangle_count * (100.f - decimate_ratio) / 100.f));
}
} m_configuration;
@ -106,6 +128,10 @@ private:
// trunc model name when longer
size_t max_char_in_name = 30;
// to prevent freezing when move in gui
// delay before process in [ms]
std::chrono::duration<long int, std::milli> prcess_delay = std::chrono::milliseconds(250);
};
std::optional<GuiCfg> m_gui_cfg;
@ -123,6 +149,16 @@ private:
GLuint m_wireframe_VBO_id, m_wireframe_IBO_id;
size_t m_wireframe_IBO_size;
// cancel exception
class SimplifyCanceledException: public std::exception
{
public:
const char *what() const throw()
{
return L("Model simplification has been canceled");
}
};
// only temporary solution
static const std::string M_ICON_FILENAME;
};

View file

@ -89,6 +89,7 @@
#include "PresetComboBoxes.hpp"
#include "MsgDialog.hpp"
#include "ProjectDirtyStateManager.hpp"
#include "Gizmos/GLGizmoSimplify.hpp" // create suggestion notification
#ifdef __APPLE__
#include "Gizmos/GLGizmosManager.hpp"
@ -1779,7 +1780,6 @@ struct Plater::priv
#endif // ENABLE_RELOAD_FROM_DISK_REPLACE_FILE
void replace_with_stl();
void reload_all_from_disk();
void create_simplify_notification(const std::vector<size_t>& obj_ids);
void set_current_panel(wxPanel* panel);
void on_select_preset(wxCommandEvent&);
@ -2564,8 +2564,9 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
// this is required because the selected object changed and the flatten on face an sla support gizmos need to be updated accordingly
view3D->get_canvas3d()->update_gizmos_on_off_state();
}
create_simplify_notification(obj_idxs);
GLGizmoSimplify::add_simplify_suggestion_notification(
obj_idxs, model.objects, *notification_manager);
return obj_idxs;
}
@ -3755,53 +3756,6 @@ void Plater::priv::reload_all_from_disk()
}
}
void Plater::priv::create_simplify_notification(const std::vector<size_t>& obj_ids) {
const uint32_t triangles_to_suggest_simplify = 1000000;
std::vector<size_t> big_ids;
big_ids.reserve(obj_ids.size());
std::copy_if(obj_ids.begin(), obj_ids.end(), std::back_inserter(big_ids),
[this, triangles_to_suggest_simplify](size_t object_id) {
if (object_id >= model.objects.size()) return false; // out of object index
ModelVolumePtrs& volumes = model.objects[object_id]->volumes;
if (volumes.size() != 1) return false; // not only one volume
size_t triangle_count = volumes.front()->mesh().its.indices.size();
if (triangle_count < triangles_to_suggest_simplify) return false; // small volume
return true;
});
if (big_ids.empty()) return;
for (size_t object_id : big_ids) {
std::string t = _u8L(
"Processing model '@object_name' with more than 1M triangles "
"could be slow. It is highly recommend to reduce "
"amount of triangles.");
t.replace(t.find("@object_name"), sizeof("@object_name") - 1,
model.objects[object_id]->name);
//std::stringstream text;
//text << t << "\n";
std::string hypertext = _u8L("Simplify model");
std::function<bool(wxEvtHandler *)> open_simplify = [object_id](wxEvtHandler *) {
auto plater = wxGetApp().plater();
if (object_id >= plater->model().objects.size()) return true;
Selection &selection = plater->canvas3D()->get_selection();
selection.clear();
selection.add_object((unsigned int) object_id);
auto &manager = plater->canvas3D()->get_gizmos_manager();
manager.open_gizmo(GLGizmosManager::EType::Simplify);
return true;
};
notification_manager->push_simplify_suggestion_notification(t,
model.objects[object_id]->id(),
hypertext,
open_simplify);
}
}
void Plater::priv::set_current_panel(wxPanel* panel)
{
if (std::find(panels.begin(), panels.end(), panel) == panels.end())