Simplify does not touch ModelVolume all the time (runs, but needs polishing)
This commit is contained in:
parent
ab260d005e
commit
7bcab6f795
2 changed files with 173 additions and 200 deletions
|
@ -16,12 +16,7 @@ GLGizmoSimplify::GLGizmoSimplify(GLCanvas3D & parent,
|
|||
const std::string &icon_filename,
|
||||
unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, -1)
|
||||
, m_state({ State::settings, 0 })
|
||||
, m_is_valid_result(false)
|
||||
, m_exist_preview(false)
|
||||
, m_volume(nullptr)
|
||||
, m_obj_index(0)
|
||||
, m_need_reload(false)
|
||||
, m_show_wireframe(false)
|
||||
, m_move_to_center(false)
|
||||
// translation for GUI size
|
||||
|
@ -32,16 +27,15 @@ GLGizmoSimplify::GLGizmoSimplify(GLCanvas3D & parent,
|
|||
{}
|
||||
|
||||
GLGizmoSimplify::~GLGizmoSimplify() {
|
||||
m_state.status = State::canceling;
|
||||
m_state.status = State::cancelling;
|
||||
if (m_worker.joinable()) m_worker.join();
|
||||
m_glmodel.reset();
|
||||
}
|
||||
|
||||
bool GLGizmoSimplify::on_esc_key_down() {
|
||||
if (m_state.status == State::settings || m_state.status == State::canceling)
|
||||
if (m_state.status != State::running)
|
||||
return false;
|
||||
|
||||
m_state.status = State::canceling;
|
||||
m_state.status = State::cancelling;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -106,38 +100,27 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
|
|||
{
|
||||
create_gui_cfg();
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
int obj_index = selection.get_object_idx();
|
||||
ModelVolume *act_volume = get_volume(selection, wxGetApp().plater()->model());
|
||||
if (act_volume == nullptr) {
|
||||
switch (m_state.status) {
|
||||
case State::settings: close(); break;
|
||||
case State::canceling: break;
|
||||
default: m_state.status = State::canceling;
|
||||
}
|
||||
stop_worker_thread(false);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check selection of new volume
|
||||
// Do not reselect object when processing
|
||||
if (act_volume != m_volume && m_state.status == State::settings) {
|
||||
if (act_volume != m_volume && m_state.status != State::Status::running) {
|
||||
bool change_window_position = (m_volume == nullptr);
|
||||
// select different model
|
||||
if (m_volume != nullptr && m_original_its.has_value()) {
|
||||
set_its(*m_original_its);
|
||||
}
|
||||
|
||||
// close suggestion notification
|
||||
auto notification_manager = wxGetApp().plater()->get_notification_manager();
|
||||
notification_manager->remove_simplify_suggestion_with_id(act_volume->get_object()->id());
|
||||
|
||||
m_obj_index = obj_index; // to remember correct object
|
||||
m_volume = act_volume;
|
||||
m_original_its = {};
|
||||
m_configuration.decimate_ratio = 50.; // default value
|
||||
m_configuration.fix_count_by_ratio(m_volume->mesh().its.indices.size());
|
||||
m_is_valid_result = false;
|
||||
m_exist_preview = false;
|
||||
init_model();
|
||||
init_model(m_volume->mesh().its);
|
||||
process();
|
||||
|
||||
// set window position
|
||||
|
@ -169,12 +152,6 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
|
|||
int flag = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoCollapse;
|
||||
m_imgui->begin(on_get_name(), flag);
|
||||
|
||||
size_t triangle_count = m_volume->mesh().its.indices.size();
|
||||
// already reduced mesh
|
||||
if (m_original_its.has_value())
|
||||
triangle_count = m_original_its->indices.size();
|
||||
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, tr_mesh_name + ":");
|
||||
ImGui::SameLine(m_gui_cfg->top_left_width);
|
||||
std::string name = m_volume->name;
|
||||
|
@ -183,7 +160,9 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
|
|||
m_imgui->text(name);
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, tr_triangles + ":");
|
||||
ImGui::SameLine(m_gui_cfg->top_left_width);
|
||||
m_imgui->text(std::to_string(triangle_count));
|
||||
|
||||
size_t orig_triangle_count = m_volume->mesh().its.indices.size();
|
||||
m_imgui->text(std::to_string(orig_triangle_count));
|
||||
|
||||
|
||||
ImGui::Separator();
|
||||
|
@ -226,10 +205,11 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
|
|||
ImGui::SameLine();
|
||||
|
||||
// show preview result triangle count (percent)
|
||||
if (m_need_reload && !m_configuration.use_count) {
|
||||
m_configuration.wanted_count = static_cast<uint32_t>(m_volume->mesh().its.indices.size());
|
||||
// lm_FIXME
|
||||
if (/*m_need_reload &&*/ !m_configuration.use_count) {
|
||||
m_configuration.wanted_count = static_cast<uint32_t>(m_triangle_count);
|
||||
m_configuration.decimate_ratio =
|
||||
(1.0f - (m_configuration.wanted_count / (float) triangle_count)) * 100.f;
|
||||
(1.0f - (m_configuration.wanted_count / (float) orig_triangle_count)) * 100.f;
|
||||
}
|
||||
|
||||
m_imgui->disabled_begin(!m_configuration.use_count);
|
||||
|
@ -244,7 +224,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
|
|||
m_configuration.decimate_ratio = 0.01f;
|
||||
if (m_configuration.decimate_ratio > 100.f)
|
||||
m_configuration.decimate_ratio = 100.f;
|
||||
m_configuration.fix_count_by_ratio(triangle_count);
|
||||
m_configuration.fix_count_by_ratio(orig_triangle_count);
|
||||
process();
|
||||
}
|
||||
|
||||
|
@ -255,37 +235,20 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
|
|||
|
||||
ImGui::Checkbox(_u8L("Show wireframe").c_str(), &m_show_wireframe);
|
||||
|
||||
bool is_canceling = m_state.status == State::canceling;
|
||||
m_imgui->disabled_begin(is_canceling);
|
||||
bool is_cancelling = m_state.status == State::cancelling;
|
||||
m_imgui->disabled_begin(is_cancelling);
|
||||
if (m_imgui->button(_L("Cancel"))) {
|
||||
if (m_state.status == State::settings) {
|
||||
if (m_original_its.has_value()) {
|
||||
set_its(*m_original_its);
|
||||
m_state.status = State::close_on_end;
|
||||
} else {
|
||||
close();
|
||||
}
|
||||
} else {
|
||||
m_state.status = State::canceling;
|
||||
}
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && is_canceling)
|
||||
ImGui::SetTooltip("%s", _u8L("Operation already canceling. Please wait few seconds.").c_str());
|
||||
m_imgui->disabled_end(); // state canceling
|
||||
close();
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && is_cancelling)
|
||||
ImGui::SetTooltip("%s", _u8L("Operation already cancelling. Please wait few seconds.").c_str());
|
||||
m_imgui->disabled_end(); // state cancelling
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
bool is_processing = m_state.status != State::settings;
|
||||
bool is_processing = m_state.status == State::running;
|
||||
m_imgui->disabled_begin(is_processing);
|
||||
if (m_imgui->button(_L("Apply"))) {
|
||||
if (!m_is_valid_result) {
|
||||
m_state.status = State::close_on_end;
|
||||
process();
|
||||
} else if (m_exist_preview) {
|
||||
// use preview and close
|
||||
after_apply();
|
||||
} else { // no changes made
|
||||
close();
|
||||
}
|
||||
apply_simplify();
|
||||
} else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && is_processing)
|
||||
ImGui::SetTooltip("%s", _u8L("Can't apply when proccess preview.").c_str());
|
||||
m_imgui->disabled_end(); // state !settings
|
||||
|
@ -301,28 +264,20 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi
|
|||
m_imgui->end();
|
||||
|
||||
// refresh view when needed
|
||||
if (m_need_reload) {
|
||||
// lm_FIXME
|
||||
/*if (m_need_reload) {
|
||||
m_need_reload = false;
|
||||
bool close_on_end = (m_state.status == State::close_on_end);
|
||||
request_rerender();
|
||||
// set m_state.status must be before close() !!!
|
||||
m_state.status = State::settings;
|
||||
if (close_on_end) after_apply();
|
||||
else init_model();
|
||||
else init_model(m_volume->mesh().its);
|
||||
// Fix warning icon in object list
|
||||
wxGetApp().obj_list()->update_item_error_icon(m_obj_index, -1);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void GLGizmoSimplify::after_apply() {
|
||||
// set flag to NOT revert changes when switch GLGizmoBase::m_state
|
||||
m_exist_preview = false;
|
||||
// fix hollowing, sla support points, modifiers, ...
|
||||
auto plater = wxGetApp().plater();
|
||||
plater->take_snapshot(_u8L("Simplify ") + m_volume->name);
|
||||
plater->changed_mesh(m_obj_index);
|
||||
close();
|
||||
}
|
||||
|
||||
void GLGizmoSimplify::close() {
|
||||
// close gizmo == open it again
|
||||
|
@ -330,55 +285,58 @@ void GLGizmoSimplify::close() {
|
|||
gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify);
|
||||
}
|
||||
|
||||
void GLGizmoSimplify::stop_worker_thread(bool wait)
|
||||
{
|
||||
if (! m_is_worker_running)
|
||||
return;
|
||||
|
||||
std::lock_guard lk(m_state_mutex);
|
||||
if (m_state.status == State::Status::running) {
|
||||
assert(m_worker.joinable());
|
||||
m_state.status = State::Status::cancelling;
|
||||
if (wait)
|
||||
m_worker.join();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Following is called from a UI thread when the worker terminates
|
||||
// worker calls it through a CallAfter.
|
||||
void GLGizmoSimplify::worker_finished()
|
||||
{
|
||||
assert(m_worker.joinable());
|
||||
m_worker.join();
|
||||
m_is_worker_running = false;
|
||||
if (m_state.result)
|
||||
init_model(*m_state.result);
|
||||
request_rerender();
|
||||
}
|
||||
|
||||
void GLGizmoSimplify::process()
|
||||
{
|
||||
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;
|
||||
|
||||
// re-render bargraph
|
||||
set_dirty();
|
||||
m_parent.schedule_extra_frame(0);
|
||||
if (m_is_worker_running || m_volume == nullptr || m_volume->mesh().its.indices.empty())
|
||||
return;
|
||||
}
|
||||
|
||||
// when not store original volume store it for cancelation
|
||||
if (!m_original_its.has_value()) {
|
||||
m_original_its = m_volume->mesh().its; // copy
|
||||
assert(! m_worker.joinable());
|
||||
|
||||
// store previous state
|
||||
auto plater = wxGetApp().plater();
|
||||
// LUKAS: ???
|
||||
plater->clear_before_change_mesh(m_obj_index);
|
||||
}
|
||||
// Worker is not running now. No synchronization needed.
|
||||
if (m_state.result && m_state.config == m_configuration)
|
||||
return; // The result is still valid.
|
||||
|
||||
m_state.progress = 0;
|
||||
if (m_worker.joinable())
|
||||
m_worker.join();
|
||||
// We are about to actually start simplification.
|
||||
m_state.config = m_configuration;
|
||||
|
||||
// Create a copy of current mesh to pass to the worker thread.
|
||||
// Using unique_ptr instead of pass-by-value to avoid an extra
|
||||
// copy (which would happen when passing to std::thread).
|
||||
auto its = std::make_unique<indexed_triangle_set>(*m_original_its);
|
||||
auto its = std::make_unique<indexed_triangle_set>(m_volume->mesh().its);
|
||||
|
||||
m_worker = std::thread([this](std::unique_ptr<indexed_triangle_set> its) {
|
||||
|
||||
// Checks that the UI thread did not request cancellation, throw if so.
|
||||
std::function<void(void)> throw_on_cancel = [this]() {
|
||||
std::lock_guard lk(m_state_mutex);
|
||||
if (m_state.status == State::canceling)
|
||||
if (m_state.status == State::cancelling)
|
||||
throw SimplifyCanceledException();
|
||||
};
|
||||
|
||||
|
@ -388,30 +346,61 @@ void GLGizmoSimplify::process()
|
|||
m_state.progress = percent;
|
||||
};
|
||||
|
||||
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();
|
||||
// Initialize.
|
||||
uint32_t triangle_count = 0;
|
||||
float max_error = std::numeric_limits<float>::max();
|
||||
{
|
||||
std::lock_guard lk(m_state_mutex);
|
||||
if (m_configuration.use_count)
|
||||
triangle_count = m_configuration.wanted_count;
|
||||
if (! m_configuration.use_count)
|
||||
max_error = m_configuration.max_error;
|
||||
m_state.progress = 0;
|
||||
m_state.result.reset();
|
||||
m_state.status = State::Status::running;
|
||||
}
|
||||
|
||||
// Start the actual calculation.
|
||||
try {
|
||||
its_quadric_edge_collapse(*its, triangle_count, &max_error, throw_on_cancel, statusfn);
|
||||
set_its(*its);
|
||||
m_is_valid_result = true;
|
||||
m_exist_preview = true;
|
||||
} catch (SimplifyCanceledException &) {
|
||||
// set state out of main thread
|
||||
m_state.status = State::settings;
|
||||
std::lock_guard lk(m_state_mutex);
|
||||
m_state.status = State::idle;
|
||||
}
|
||||
// need to render last status fn to change bar graph to buttons
|
||||
request_rerender();
|
||||
|
||||
std::lock_guard lk(m_state_mutex);
|
||||
if (m_state.status == State::Status::running) {
|
||||
// We were not cancelled, the result is valid.
|
||||
m_state.status = State::Status::idle;
|
||||
m_state.result = std::move(its);
|
||||
}
|
||||
|
||||
// Update UI. Use CallAfter so the function is run on UI thread.
|
||||
wxGetApp().CallAfter([this]() { worker_finished(); });
|
||||
}, std::move(its));
|
||||
|
||||
m_is_worker_running = true;
|
||||
}
|
||||
|
||||
void GLGizmoSimplify::set_its(const indexed_triangle_set &its) {
|
||||
if (m_volume == nullptr) return; // could appear after process
|
||||
m_volume->set_mesh(its);
|
||||
void GLGizmoSimplify::apply_simplify() {
|
||||
assert(! m_is_worker_running);
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
int object_idx = selection.get_object_idx();
|
||||
|
||||
auto plater = wxGetApp().plater();
|
||||
plater->take_snapshot(_u8L("Simplify ") + m_volume->name);
|
||||
plater->clear_before_change_mesh(object_idx);
|
||||
|
||||
m_volume->set_mesh(*m_state.result);
|
||||
m_volume->calculate_convex_hull();
|
||||
m_volume->set_new_unique_id();
|
||||
m_volume->get_object()->invalidate_bounding_box();
|
||||
m_need_reload = true;
|
||||
|
||||
// fix hollowing, sla support points, modifiers, ...
|
||||
|
||||
plater->changed_mesh(object_idx);
|
||||
close();
|
||||
}
|
||||
|
||||
bool GLGizmoSimplify::on_is_activable() const
|
||||
|
@ -425,40 +414,14 @@ void GLGizmoSimplify::on_set_state()
|
|||
if (GLGizmoBase::m_state == GLGizmoBase::Off) {
|
||||
m_parent.toggle_model_objects_visibility(true);
|
||||
|
||||
// can appear when delete objects
|
||||
bool empty_selection = m_parent.get_selection().is_empty();
|
||||
|
||||
// cancel processing
|
||||
if (empty_selection &&
|
||||
m_state.status != State::settings &&
|
||||
m_state.status != State::canceling)
|
||||
m_state.status = State::canceling;
|
||||
|
||||
// refuse outgoing during simlification
|
||||
// object is not selected when it is deleted(cancel and close gizmo)
|
||||
if (m_state.status != State::settings && !empty_selection) {
|
||||
GLGizmoBase::m_state = GLGizmoBase::On;
|
||||
auto notification_manager = wxGetApp().plater()->get_notification_manager();
|
||||
notification_manager->push_notification(
|
||||
NotificationType::CustomNotification,
|
||||
NotificationManager::NotificationLevel::PrintInfoNotificationLevel,
|
||||
_u8L("ERROR: Wait until Simplification ends or Cancel process."));
|
||||
return;
|
||||
}
|
||||
|
||||
// revert preview
|
||||
if (m_exist_preview) {
|
||||
m_exist_preview = false;
|
||||
if (exist_volume(m_volume)) {
|
||||
set_its(*m_original_its);
|
||||
request_rerender();
|
||||
m_need_reload = false;
|
||||
}
|
||||
}
|
||||
// Stop worker but do not wait to join it.
|
||||
stop_worker_thread(false);
|
||||
|
||||
// invalidate selected model
|
||||
m_volume = nullptr;
|
||||
} else if (GLGizmoBase::m_state == GLGizmoBase::On) {
|
||||
// Make sure the worker is not running and join it.
|
||||
stop_worker_thread(true);
|
||||
// when open by hyperlink it needs to show up
|
||||
request_rerender();
|
||||
}
|
||||
|
@ -537,10 +500,10 @@ const ModelVolume *GLGizmoSimplify::get_volume(const GLVolume::CompositeID &cid,
|
|||
return obj->volumes[cid.volume_id];
|
||||
}
|
||||
|
||||
void GLGizmoSimplify::init_model()
|
||||
void GLGizmoSimplify::init_model(const indexed_triangle_set& its)
|
||||
{
|
||||
const indexed_triangle_set &its = m_volume->mesh().its;
|
||||
if (its.indices.empty()) return;
|
||||
if (its.indices.empty())
|
||||
return;
|
||||
|
||||
m_glmodel.reset();
|
||||
m_glmodel.init_from(its);
|
||||
|
@ -549,6 +512,7 @@ void GLGizmoSimplify::init_model()
|
|||
|
||||
if (const Selection&sel = m_parent.get_selection(); sel.get_volume_idxs().size() == 1)
|
||||
m_glmodel.set_color(-1, sel.get_volume(*sel.get_volume_idxs().begin())->color);
|
||||
m_triangle_count = its.indices.size();
|
||||
}
|
||||
|
||||
void GLGizmoSimplify::on_render()
|
||||
|
@ -601,4 +565,16 @@ CommonGizmosDataID GLGizmoSimplify::on_get_requirements() const
|
|||
int(CommonGizmosDataID::SelectionInfo));
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoSimplify::Configuration::fix_count_by_ratio(size_t triangle_count)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
|
|
|
@ -49,12 +49,16 @@ protected:
|
|||
virtual CommonGizmosDataID on_get_requirements() const;
|
||||
|
||||
private:
|
||||
void after_apply();
|
||||
void apply_simplify();
|
||||
void close();
|
||||
|
||||
void process();
|
||||
void set_its(const indexed_triangle_set &its);
|
||||
void stop_worker_thread(bool wait);
|
||||
void worker_finished();
|
||||
|
||||
void create_gui_cfg();
|
||||
void request_rerender();
|
||||
void init_model(const indexed_triangle_set& its);
|
||||
|
||||
void set_center_position();
|
||||
// move to global functions
|
||||
|
@ -64,59 +68,54 @@ private:
|
|||
// return false when volume was deleted
|
||||
static bool exist_volume(const ModelVolume *volume);
|
||||
|
||||
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
|
||||
|
||||
|
||||
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;
|
||||
GLModel m_glmodel;
|
||||
|
||||
std::atomic<bool> m_need_reload; // after simplify, glReload must be on main thread
|
||||
|
||||
struct State {
|
||||
enum Status {
|
||||
settings,
|
||||
preview, // simplify to show preview
|
||||
close_on_end, // simplify with close on end
|
||||
canceling // after button click, before canceled
|
||||
};
|
||||
|
||||
Status status;
|
||||
int progress; // percent of done work
|
||||
indexed_triangle_set result;
|
||||
};
|
||||
|
||||
std::thread m_worker;
|
||||
std::mutex m_state_mutex; // guards m_state
|
||||
State m_state;
|
||||
|
||||
struct Configuration
|
||||
{
|
||||
bool use_count = false;
|
||||
// minimal triangle count
|
||||
float decimate_ratio = 50.f; // in percent
|
||||
uint32_t wanted_count = 0; // initialize by percents
|
||||
uint32_t wanted_count = 0; // initialize by percents
|
||||
float max_error = 1.; // maximal quadric error
|
||||
|
||||
// maximal quadric error
|
||||
float max_error = 1.;
|
||||
|
||||
void fix_count_by_ratio(size_t triangle_count)
|
||||
{
|
||||
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));
|
||||
void fix_count_by_ratio(size_t triangle_count);
|
||||
bool operator==(const Configuration& rhs) {
|
||||
return (use_count == rhs.use_count && decimate_ratio == rhs.decimate_ratio
|
||||
&& wanted_count == rhs.wanted_count && max_error == rhs.max_error);
|
||||
}
|
||||
} m_configuration;
|
||||
};
|
||||
|
||||
Configuration m_configuration;
|
||||
|
||||
bool m_move_to_center; // opening gizmo
|
||||
|
||||
ModelVolume *m_volume; // keep pointer to actual working volume
|
||||
|
||||
bool m_show_wireframe;
|
||||
GLModel m_glmodel;
|
||||
size_t m_triangle_count; // triangle count of the model currently shown
|
||||
|
||||
// Following struct is accessed by both UI and worker thread.
|
||||
// Accesses protected by a mutex.
|
||||
struct State {
|
||||
enum Status {
|
||||
idle,
|
||||
running,
|
||||
cancelling
|
||||
};
|
||||
|
||||
Status status = idle;
|
||||
int progress = 0; // percent of done work
|
||||
Configuration config; // Configuration we started with.
|
||||
std::unique_ptr<indexed_triangle_set> result;
|
||||
};
|
||||
|
||||
std::thread m_worker;
|
||||
std::mutex m_state_mutex; // guards m_state
|
||||
State m_state; // accessed by both threads
|
||||
|
||||
// Following variable is accessed by UI only.
|
||||
bool m_is_worker_running = false;
|
||||
|
||||
|
||||
|
||||
// This configs holds GUI layout size given by translated texts.
|
||||
// etc. When language changes, GUI is recreated and this class constructed again,
|
||||
|
@ -145,8 +144,6 @@ private:
|
|||
const std::string tr_detail_level;
|
||||
const std::string tr_decimate_ratio;
|
||||
|
||||
void init_model();
|
||||
|
||||
// cancel exception
|
||||
class SimplifyCanceledException: public std::exception
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue