mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-26 10:11:10 -06:00
Fixed conflicts after merge with master
This commit is contained in:
commit
c3d643ead3
28 changed files with 497 additions and 185 deletions
|
|
@ -1,5 +1,11 @@
|
|||
#include <GL/glew.h>
|
||||
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
#include <igl/per_face_normals.h>
|
||||
#include <igl/per_corner_normals.h>
|
||||
#include <igl/per_vertex_normals.h>
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
|
||||
#include "3DScene.hpp"
|
||||
#include "GLShader.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
|
|
@ -62,23 +68,107 @@ void glAssertRecentCallImpl(const char *file_name, unsigned int line, const char
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh &mesh)
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
static void smooth_normals_corner(TriangleMesh& mesh, std::vector<stl_normal>& normals)
|
||||
{
|
||||
mesh.repair();
|
||||
|
||||
using MapMatrixXfUnaligned = Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>>;
|
||||
using MapMatrixXiUnaligned = Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>>;
|
||||
|
||||
std::vector<stl_normal> face_normals(mesh.stl.stats.number_of_facets);
|
||||
for (uint32_t i = 0; i < mesh.stl.stats.number_of_facets; ++i) {
|
||||
face_normals[i] = mesh.stl.facet_start[i].normal;
|
||||
}
|
||||
|
||||
Eigen::MatrixXd vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(),
|
||||
Eigen::Index(mesh.its.vertices.size()), 3).cast<double>();
|
||||
Eigen::MatrixXi indices = MapMatrixXiUnaligned(mesh.its.indices.front().data(),
|
||||
Eigen::Index(mesh.its.indices.size()), 3);
|
||||
Eigen::MatrixXd in_normals = MapMatrixXfUnaligned(face_normals.front().data(),
|
||||
Eigen::Index(face_normals.size()), 3).cast<double>();
|
||||
Eigen::MatrixXd out_normals;
|
||||
|
||||
igl::per_corner_normals(vertices, indices, in_normals, 1.0, out_normals);
|
||||
|
||||
normals = std::vector<stl_normal>(mesh.its.vertices.size());
|
||||
for (size_t i = 0; i < mesh.its.indices.size(); ++i) {
|
||||
for (size_t j = 0; j < 3; ++j) {
|
||||
normals[mesh.its.indices[i][j]] = out_normals.row(i * 3 + j).cast<float>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void smooth_normals_vertex(TriangleMesh& mesh, std::vector<stl_normal>& normals)
|
||||
{
|
||||
mesh.repair();
|
||||
|
||||
using MapMatrixXfUnaligned = Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>>;
|
||||
using MapMatrixXiUnaligned = Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>>;
|
||||
|
||||
Eigen::MatrixXd vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(),
|
||||
Eigen::Index(mesh.its.vertices.size()), 3).cast<double>();
|
||||
Eigen::MatrixXi indices = MapMatrixXiUnaligned(mesh.its.indices.front().data(),
|
||||
Eigen::Index(mesh.its.indices.size()), 3);
|
||||
Eigen::MatrixXd out_normals;
|
||||
|
||||
// igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_UNIFORM, out_normals);
|
||||
// igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA, out_normals);
|
||||
igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE, out_normals);
|
||||
// igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_DEFAULT, out_normals);
|
||||
|
||||
normals = std::vector<stl_normal>(mesh.its.vertices.size());
|
||||
for (size_t i = 0; i < static_cast<size_t>(out_normals.rows()); ++i) {
|
||||
normals[i] = out_normals.row(i).cast<float>();
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh& mesh, bool smooth_normals)
|
||||
#else
|
||||
void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh& mesh)
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
{
|
||||
assert(triangle_indices.empty() && vertices_and_normals_interleaved_size == 0);
|
||||
assert(quad_indices.empty() && triangle_indices_size == 0);
|
||||
assert(vertices_and_normals_interleaved.size() % 6 == 0 && quad_indices_size == vertices_and_normals_interleaved.size());
|
||||
|
||||
this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 3 * 2 * mesh.facets_count());
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
if (smooth_normals) {
|
||||
TriangleMesh new_mesh(mesh);
|
||||
std::vector<stl_normal> normals;
|
||||
smooth_normals_corner(new_mesh, normals);
|
||||
// smooth_normals_vertex(new_mesh, normals);
|
||||
|
||||
unsigned int vertices_count = 0;
|
||||
for (int i = 0; i < (int)mesh.stl.stats.number_of_facets; ++i) {
|
||||
const stl_facet &facet = mesh.stl.facet_start[i];
|
||||
for (int j = 0; j < 3; ++j)
|
||||
this->push_geometry(facet.vertex[j](0), facet.vertex[j](1), facet.vertex[j](2), facet.normal(0), facet.normal(1), facet.normal(2));
|
||||
this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 2 * new_mesh.its.vertices.size());
|
||||
for (size_t i = 0; i < new_mesh.its.vertices.size(); ++i) {
|
||||
const stl_vertex& v = new_mesh.its.vertices[i];
|
||||
const stl_normal& n = normals[i];
|
||||
this->push_geometry(v(0), v(1), v(2), n(0), n(1), n(2));
|
||||
}
|
||||
|
||||
this->push_triangle(vertices_count, vertices_count + 1, vertices_count + 2);
|
||||
vertices_count += 3;
|
||||
for (size_t i = 0; i < new_mesh.its.indices.size(); ++i) {
|
||||
const stl_triangle_vertex_indices& idx = new_mesh.its.indices[i];
|
||||
this->push_triangle(idx(0), idx(1), idx(2));
|
||||
}
|
||||
}
|
||||
else {
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 3 * 2 * mesh.facets_count());
|
||||
|
||||
unsigned int vertices_count = 0;
|
||||
for (int i = 0; i < (int)mesh.stl.stats.number_of_facets; ++i) {
|
||||
const stl_facet& facet = mesh.stl.facet_start[i];
|
||||
for (int j = 0; j < 3; ++j)
|
||||
this->push_geometry(facet.vertex[j](0), facet.vertex[j](1), facet.vertex[j](2), facet.normal(0), facet.normal(1), facet.normal(2));
|
||||
|
||||
this->push_triangle(vertices_count, vertices_count + 1, vertices_count + 2);
|
||||
vertices_count += 3;
|
||||
}
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
}
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
}
|
||||
|
||||
void GLIndexedVertexArray::finalize_geometry(bool opengl_initialized)
|
||||
|
|
@ -466,7 +556,11 @@ int GLVolumeCollection::load_object_volume(
|
|||
this->volumes.emplace_back(new GLVolume(color));
|
||||
GLVolume& v = *this->volumes.back();
|
||||
v.set_color_from_model_volume(model_volume);
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
v.indexed_vertex_array.load_mesh(mesh, true);
|
||||
#else
|
||||
v.indexed_vertex_array.load_mesh(mesh);
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
||||
v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx);
|
||||
if (model_volume->is_model_part())
|
||||
|
|
@ -508,8 +602,12 @@ void GLVolumeCollection::load_object_auxiliary(
|
|||
const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first];
|
||||
this->volumes.emplace_back(new GLVolume((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR));
|
||||
GLVolume& v = *this->volumes.back();
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
v.indexed_vertex_array.load_mesh(mesh, true);
|
||||
#else
|
||||
v.indexed_vertex_array.load_mesh(mesh);
|
||||
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
||||
v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first);
|
||||
v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
|
||||
// Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance.
|
||||
|
|
|
|||
|
|
@ -119,8 +119,13 @@ public:
|
|||
unsigned int triangle_indices_VBO_id{ 0 };
|
||||
unsigned int quad_indices_VBO_id{ 0 };
|
||||
|
||||
void load_mesh_full_shading(const TriangleMesh &mesh);
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
void load_mesh_full_shading(const TriangleMesh& mesh, bool smooth_normals = false);
|
||||
void load_mesh(const TriangleMesh& mesh, bool smooth_normals = false) { this->load_mesh_full_shading(mesh, smooth_normals); }
|
||||
#else
|
||||
void load_mesh_full_shading(const TriangleMesh& mesh);
|
||||
void load_mesh(const TriangleMesh& mesh) { this->load_mesh_full_shading(mesh); }
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
|
||||
inline bool has_VBOs() const { return vertices_and_normals_interleaved_VBO_id != 0; }
|
||||
|
||||
|
|
|
|||
|
|
@ -2522,11 +2522,19 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles);
|
||||
assert(! mesh.empty());
|
||||
mesh.transform(sla_print->sla_trafo(*m_model->objects[volume.object_idx()]).inverse());
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
volume.indexed_vertex_array.load_mesh(mesh, true);
|
||||
#else
|
||||
volume.indexed_vertex_array.load_mesh(mesh);
|
||||
} else {
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
} else {
|
||||
// Reload the original volume.
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
|
||||
#else
|
||||
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
|
||||
}
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
}
|
||||
volume.finalize_geometry(true);
|
||||
}
|
||||
//FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable
|
||||
|
|
@ -6960,7 +6968,11 @@ void GLCanvas3D::_load_sla_shells()
|
|||
const TriangleMesh &mesh, const float color[4], bool outside_printer_detection_enabled) {
|
||||
m_volumes.volumes.emplace_back(new GLVolume(color));
|
||||
GLVolume& v = *m_volumes.volumes.back();
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
v.indexed_vertex_array.load_mesh(mesh, true);
|
||||
#else
|
||||
v.indexed_vertex_array.load_mesh(mesh);
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
v.indexed_vertex_array.finalize_geometry(this->m_initialized);
|
||||
v.shader_outside_printer_detection_enabled = outside_printer_detection_enabled;
|
||||
v.composite_id.volume_id = volume_id;
|
||||
|
|
|
|||
|
|
@ -695,33 +695,41 @@ void ObjectList::selection_changed()
|
|||
part_selection_changed();
|
||||
}
|
||||
|
||||
void ObjectList::fill_layer_config_ranges_cache()
|
||||
void ObjectList::copy_layers_to_clipboard()
|
||||
{
|
||||
wxDataViewItemArray sel_layers;
|
||||
GetSelections(sel_layers);
|
||||
|
||||
const int obj_idx = m_objects_model->GetObjectIdByItem(sel_layers[0]);
|
||||
const int obj_idx = m_objects_model->GetObjectIdByItem(sel_layers.front());
|
||||
if (obj_idx < 0 || (int)m_objects->size() <= obj_idx)
|
||||
return;
|
||||
|
||||
const t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||
m_layer_config_ranges_cache.clear();
|
||||
t_layer_config_ranges& cache_ranges = m_clipboard.get_ranges_cache();
|
||||
|
||||
if (sel_layers.Count() == 1 && m_objects_model->GetItemType(sel_layers.front()) & itLayerRoot)
|
||||
{
|
||||
cache_ranges.clear();
|
||||
cache_ranges = ranges;
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto layer_item : sel_layers)
|
||||
if (m_objects_model->GetItemType(layer_item) & itLayer) {
|
||||
auto range = m_objects_model->GetLayerRangeByItem(layer_item);
|
||||
auto it = ranges.find(range);
|
||||
if (it != ranges.end())
|
||||
m_layer_config_ranges_cache[it->first] = it->second;
|
||||
cache_ranges[it->first] = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectList::paste_layers_into_list()
|
||||
{
|
||||
const int obj_idx = m_objects_model->GetObjectIdByItem(GetSelection());
|
||||
t_layer_config_ranges& cache_ranges = m_clipboard.get_ranges_cache();
|
||||
|
||||
if (obj_idx < 0 || (int)m_objects->size() <= obj_idx ||
|
||||
m_layer_config_ranges_cache.empty() || printer_technology() == ptSLA)
|
||||
cache_ranges.empty() || printer_technology() == ptSLA)
|
||||
return;
|
||||
|
||||
const wxDataViewItem object_item = m_objects_model->GetItemById(obj_idx);
|
||||
|
|
@ -732,7 +740,7 @@ void ObjectList::paste_layers_into_list()
|
|||
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||
|
||||
// and create Layer item(s) according to the layer_config_ranges
|
||||
for (const auto range : m_layer_config_ranges_cache)
|
||||
for (const auto range : cache_ranges)
|
||||
ranges.emplace(range);
|
||||
|
||||
layers_item = add_layer_root_item(object_item);
|
||||
|
|
@ -745,6 +753,48 @@ void ObjectList::paste_layers_into_list()
|
|||
#endif //no __WXOSX__
|
||||
}
|
||||
|
||||
void ObjectList::copy_settings_to_clipboard()
|
||||
{
|
||||
wxDataViewItem item = GetSelection();
|
||||
assert(item.IsOk());
|
||||
if (m_objects_model->GetItemType(item) & itSettings)
|
||||
item = m_objects_model->GetParent(item);
|
||||
|
||||
DynamicPrintConfig& config_cache = m_clipboard.get_config_cache();
|
||||
config_cache = get_item_config(item);
|
||||
}
|
||||
|
||||
void ObjectList::paste_settings_into_list()
|
||||
{
|
||||
wxDataViewItem item = GetSelection();
|
||||
assert(item.IsOk());
|
||||
if (m_objects_model->GetItemType(item) & itSettings)
|
||||
item = m_objects_model->GetParent(item);
|
||||
|
||||
ItemType item_type = m_objects_model->GetItemType(item);
|
||||
if(!(item_type & (itObject | itVolume |itLayer)))
|
||||
return;
|
||||
|
||||
DynamicPrintConfig& config_cache = m_clipboard.get_config_cache();
|
||||
assert(!config_cache.empty());
|
||||
|
||||
auto keys = config_cache.keys();
|
||||
auto part_options = get_options(true);
|
||||
|
||||
for (const std::string& opt_key: keys) {
|
||||
if (item_type & (itVolume | itLayer) &&
|
||||
std::find(part_options.begin(), part_options.end(), opt_key) == part_options.end())
|
||||
continue; // we can't to add object specific options for the part's(itVolume | itLayer) config
|
||||
|
||||
const ConfigOption* option = config_cache.option(opt_key);
|
||||
if (option)
|
||||
m_config->set_key_value(opt_key, option->clone());
|
||||
}
|
||||
|
||||
// Add settings item for object/sub-object and show them
|
||||
show_settings(add_settings_item(item, m_config));
|
||||
}
|
||||
|
||||
void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes)
|
||||
{
|
||||
if ((obj_idx < 0) || ((int)m_objects->size() <= obj_idx))
|
||||
|
|
@ -984,20 +1034,46 @@ void ObjectList::extruder_editing()
|
|||
|
||||
void ObjectList::copy()
|
||||
{
|
||||
// if (m_selection_mode & smLayer)
|
||||
// fill_layer_config_ranges_cache();
|
||||
// else {
|
||||
// m_layer_config_ranges_cache.clear();
|
||||
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY));
|
||||
// }
|
||||
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY));
|
||||
}
|
||||
|
||||
void ObjectList::paste()
|
||||
{
|
||||
// if (!m_layer_config_ranges_cache.empty())
|
||||
// paste_layers_into_list();
|
||||
// else
|
||||
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE));
|
||||
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE));
|
||||
}
|
||||
|
||||
bool ObjectList::copy_to_clipboard()
|
||||
{
|
||||
wxDataViewItemArray sels;
|
||||
GetSelections(sels);
|
||||
ItemType type = m_objects_model->GetItemType(sels.front());
|
||||
if (!(type & (itSettings | itLayer | itLayerRoot))) {
|
||||
m_clipboard.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type & itSettings)
|
||||
copy_settings_to_clipboard();
|
||||
if (type & (itLayer | itLayerRoot))
|
||||
copy_layers_to_clipboard();
|
||||
|
||||
m_clipboard.set_type(type);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ObjectList::paste_from_clipboard()
|
||||
{
|
||||
if (!(m_clipboard.get_type() & (itSettings | itLayer | itLayerRoot))) {
|
||||
m_clipboard.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_clipboard.get_type() & itSettings)
|
||||
paste_settings_into_list();
|
||||
if (m_clipboard.get_type() & (itLayer | itLayerRoot))
|
||||
paste_layers_into_list();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ObjectList::undo()
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
#include "wxExtensions.hpp"
|
||||
#include "ObjectDataViewModel.hpp"
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
class wxBoxSizer;
|
||||
class wxBitmapComboBox;
|
||||
class wxMenuItem;
|
||||
|
|
@ -81,10 +83,32 @@ public:
|
|||
smLayerRoot = 16, // used for undo/redo
|
||||
};
|
||||
|
||||
struct Clipboard
|
||||
{
|
||||
void reset() {
|
||||
m_type = itUndef;
|
||||
m_layer_config_ranges_cache .clear();
|
||||
m_config_cache.clear();
|
||||
}
|
||||
bool empty() const { return m_type == itUndef; }
|
||||
ItemType get_type() const { return m_type; }
|
||||
void set_type(ItemType type) { m_type = type; }
|
||||
|
||||
t_layer_config_ranges& get_ranges_cache() { return m_layer_config_ranges_cache; }
|
||||
DynamicPrintConfig& get_config_cache() { return m_config_cache; }
|
||||
|
||||
private:
|
||||
ItemType m_type {itUndef};
|
||||
t_layer_config_ranges m_layer_config_ranges_cache;
|
||||
DynamicPrintConfig m_config_cache;
|
||||
};
|
||||
|
||||
private:
|
||||
SELECTION_MODE m_selection_mode {smUndef};
|
||||
int m_selected_layers_range_idx;
|
||||
|
||||
Clipboard m_clipboard;
|
||||
|
||||
struct dragged_item_data
|
||||
{
|
||||
void init(const int obj_idx, const int subobj_idx, const ItemType type) {
|
||||
|
|
@ -148,8 +172,6 @@ private:
|
|||
|
||||
std::vector<wxBitmap*> m_bmp_vector;
|
||||
|
||||
t_layer_config_ranges m_layer_config_ranges_cache;
|
||||
|
||||
int m_selected_object_id = -1;
|
||||
bool m_prevent_list_events = false; // We use this flag to avoid circular event handling Select()
|
||||
// happens to fire a wxEVT_LIST_ITEM_SELECTED on OSX, whose event handler
|
||||
|
|
@ -230,6 +252,8 @@ public:
|
|||
|
||||
void copy();
|
||||
void paste();
|
||||
bool copy_to_clipboard();
|
||||
bool paste_from_clipboard();
|
||||
void undo();
|
||||
void redo();
|
||||
|
||||
|
|
@ -385,8 +409,11 @@ public:
|
|||
void fix_through_netfabb();
|
||||
void update_item_error_icon(const int obj_idx, int vol_idx) const ;
|
||||
|
||||
void fill_layer_config_ranges_cache();
|
||||
void copy_layers_to_clipboard();
|
||||
void paste_layers_into_list();
|
||||
void copy_settings_to_clipboard();
|
||||
void paste_settings_into_list();
|
||||
bool clipboard_is_empty() const { return m_clipboard.empty(); }
|
||||
void paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes);
|
||||
void paste_objects_into_list(const std::vector<size_t>& object_idxs);
|
||||
|
||||
|
|
|
|||
|
|
@ -54,18 +54,35 @@ bool GLGizmoFdmSupports::on_init()
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::activate_internal_undo_redo_stack(bool activate)
|
||||
{
|
||||
if (activate && ! m_internal_stack_active) {
|
||||
Plater::TakeSnapshot(wxGetApp().plater(), _L("FDM gizmo turned on"));
|
||||
wxGetApp().plater()->enter_gizmos_stack();
|
||||
m_internal_stack_active = true;
|
||||
}
|
||||
if (! activate && m_internal_stack_active) {
|
||||
wxGetApp().plater()->leave_gizmos_stack();
|
||||
Plater::TakeSnapshot(wxGetApp().plater(), _L("FDM gizmo turned off"));
|
||||
m_internal_stack_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoFdmSupports::set_fdm_support_data(ModelObject* model_object, const Selection& selection)
|
||||
{
|
||||
const ModelObject* mo = m_c->selection_info() ? m_c->selection_info()->model_object() : nullptr;
|
||||
if (! mo)
|
||||
if (m_state != On)
|
||||
return;
|
||||
|
||||
const ModelObject* mo = m_c->selection_info() ? m_c->selection_info()->model_object() : nullptr;
|
||||
|
||||
if (mo && selection.is_from_single_instance()
|
||||
&& (mo->id() != m_old_mo_id || mo->volumes.size() != m_old_volumes_size))
|
||||
&& (m_schedule_update || mo->id() != m_old_mo_id || mo->volumes.size() != m_old_volumes_size))
|
||||
{
|
||||
update_from_model_object();
|
||||
m_old_mo_id = mo->id();
|
||||
m_old_volumes_size = mo->volumes.size();
|
||||
m_schedule_update = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -131,8 +148,10 @@ void GLGizmoFdmSupports::render_triangles(const Selection& selection) const
|
|||
// Now render both enforcers and blockers.
|
||||
for (int i=0; i<2; ++i) {
|
||||
glsafe(::glColor4f(i ? 1.f : 0.2f, 0.2f, i ? 0.2f : 1.0f, 0.5f));
|
||||
for (const GLIndexedVertexArray& iva : m_ivas[mesh_id][i])
|
||||
iva.render();
|
||||
for (const GLIndexedVertexArray& iva : m_ivas[mesh_id][i]) {
|
||||
if (iva.has_VBOs())
|
||||
iva.render();
|
||||
}
|
||||
}
|
||||
glsafe(::glPopMatrix());
|
||||
if (is_left_handed)
|
||||
|
|
@ -493,6 +512,7 @@ bool GLGizmoFdmSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
: (m_button_down == Button::Left
|
||||
? _L("Add supports")
|
||||
: _L("Block supports"));
|
||||
activate_internal_undo_redo_stack(true);
|
||||
Plater::TakeSnapshot(wxGetApp().plater(), action_name);
|
||||
update_model_object();
|
||||
|
||||
|
|
@ -588,6 +608,8 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool overwr
|
|||
update_vertex_buffers(&mv->mesh(), mesh_id, FacetSupportType::BLOCKER);
|
||||
}
|
||||
|
||||
activate_internal_undo_redo_stack(true);
|
||||
|
||||
Plater::TakeSnapshot(wxGetApp().plater(), block ? _L("Block supports by angle")
|
||||
: _L("Add supports by angle"));
|
||||
update_model_object();
|
||||
|
|
@ -778,12 +800,9 @@ void GLGizmoFdmSupports::on_set_state()
|
|||
return;
|
||||
|
||||
if (m_state == On && m_old_state != On) { // the gizmo was just turned on
|
||||
{
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned on")));
|
||||
}
|
||||
if (! m_parent.get_gizmos_manager().is_serializing()) {
|
||||
wxGetApp().CallAfter([]() {
|
||||
wxGetApp().plater()->enter_gizmos_stack();
|
||||
wxGetApp().CallAfter([this]() {
|
||||
activate_internal_undo_redo_stack(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -793,11 +812,7 @@ void GLGizmoFdmSupports::on_set_state()
|
|||
m_setting_angle = false;
|
||||
m_parent.use_slope(false);
|
||||
}
|
||||
|
||||
wxGetApp().plater()->leave_gizmos_stack();
|
||||
{
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("FDM gizmo turned off")));
|
||||
}
|
||||
activate_internal_undo_redo_stack(false);
|
||||
m_old_mo_id = -1;
|
||||
m_ivas.clear();
|
||||
m_selected_facets.clear();
|
||||
|
|
@ -820,14 +835,19 @@ void GLGizmoFdmSupports::on_stop_dragging()
|
|||
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::on_load(cereal::BinaryInputArchive& ar)
|
||||
void GLGizmoFdmSupports::on_load(cereal::BinaryInputArchive&)
|
||||
{
|
||||
update_from_model_object();
|
||||
// We should update the gizmo from current ModelObject, but it is not
|
||||
// possible at this point. That would require having updated selection and
|
||||
// common gizmos data, which is not done at this point. Instead, save
|
||||
// a flag to do the update in set_fdm_support_data, which will be called
|
||||
// soon after.
|
||||
m_schedule_update = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::on_save(cereal::BinaryOutputArchive& ar) const
|
||||
void GLGizmoFdmSupports::on_save(cereal::BinaryOutputArchive&) const
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ private:
|
|||
|
||||
void update_model_object() const;
|
||||
void update_from_model_object();
|
||||
void activate_internal_undo_redo_stack(bool activate);
|
||||
|
||||
void select_facets_by_angle(float threshold, bool overwrite, bool block);
|
||||
bool m_overwrite_selected = false;
|
||||
|
|
@ -74,6 +75,8 @@ private:
|
|||
float m_clipping_plane_distance = 0.f;
|
||||
std::unique_ptr<ClippingPlane> m_clipping_plane;
|
||||
bool m_setting_angle = false;
|
||||
bool m_internal_stack_active = false;
|
||||
bool m_schedule_update = false;
|
||||
|
||||
// This map holds all translated description texts, so they can be easily referenced during layout calculations
|
||||
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ bool GLGizmoFlatten::on_init()
|
|||
|
||||
void GLGizmoFlatten::on_set_state()
|
||||
{
|
||||
if (m_state == On && is_plane_update_necessary())
|
||||
update_planes();
|
||||
|
||||
}
|
||||
|
||||
CommonGizmosDataID GLGizmoFlatten::on_get_requirements() const
|
||||
|
|
@ -81,7 +80,8 @@ void GLGizmoFlatten::on_render() const
|
|||
else
|
||||
glsafe(::glColor4f(0.9f, 0.9f, 0.9f, 0.5f));
|
||||
|
||||
m_planes[i].vbo.render();
|
||||
if (m_planes[i].vbo.has_VBOs())
|
||||
m_planes[i].vbo.render();
|
||||
}
|
||||
glsafe(::glPopMatrix());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&)
|
|||
return;
|
||||
|
||||
const ModelObject* mo = m_c->selection_info()->model_object();
|
||||
if (mo) {
|
||||
if (m_state == On && mo) {
|
||||
if (m_old_mo_id != mo->id()) {
|
||||
reload_cache();
|
||||
m_old_mo_id = mo->id();
|
||||
|
|
@ -810,11 +810,6 @@ void GLGizmoHollow::on_set_state()
|
|||
if (m_state == m_old_state)
|
||||
return;
|
||||
|
||||
if (m_state == On && m_old_state != On) { // the gizmo was just turned on
|
||||
// we'll now reload support points:
|
||||
if (m_c->selection_info()->model_object())
|
||||
reload_cache();
|
||||
}
|
||||
if (m_state == Off && m_old_state != Off) // the gizmo was just turned Off
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_FORCE_UPDATE));
|
||||
m_old_state = m_state;
|
||||
|
|
|
|||
|
|
@ -67,10 +67,11 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S
|
|||
|
||||
ModelObject* mo = m_c->selection_info()->model_object();
|
||||
|
||||
if (mo && mo->id() != m_old_mo_id) {
|
||||
if (m_state == On && mo && mo->id() != m_old_mo_id) {
|
||||
disable_editing_mode();
|
||||
reload_cache();
|
||||
m_old_mo_id = mo->id();
|
||||
m_c->instances_hider()->show_supports(true);
|
||||
}
|
||||
|
||||
// If we triggered autogeneration before, check backend and fetch results if they are there
|
||||
|
|
@ -884,25 +885,23 @@ CommonGizmosDataID GLGizmoSlaSupports::on_get_requirements() const
|
|||
|
||||
void GLGizmoSlaSupports::on_set_state()
|
||||
{
|
||||
const ModelObject* mo = m_c->selection_info()->model_object();
|
||||
|
||||
if (m_state == m_old_state)
|
||||
return;
|
||||
|
||||
if (m_state == On && m_old_state != On) { // the gizmo was just turned on
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on")));
|
||||
// This function can be called from undo/redo, when selection (and hence
|
||||
// common gizmos data are not yet deserialized. The CallAfter should put
|
||||
// this off until after the update is done.
|
||||
wxGetApp().CallAfter([this]() {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on")));
|
||||
|
||||
// we'll now reload support points:
|
||||
if (mo)
|
||||
reload_cache();
|
||||
|
||||
// Set default head diameter from config.
|
||||
const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
|
||||
m_new_point_head_diameter = static_cast<const ConfigOptionFloat*>(cfg.option("support_head_front_diameter"))->value;
|
||||
m_c->instances_hider()->show_supports(true);
|
||||
// Set default head diameter from config.
|
||||
const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
|
||||
m_new_point_head_diameter = static_cast<const ConfigOptionFloat*>(cfg.option("support_head_front_diameter"))->value;
|
||||
});
|
||||
}
|
||||
if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off
|
||||
bool will_ask = mo && m_editing_mode && unsaved_changes();
|
||||
bool will_ask = m_editing_mode && unsaved_changes();
|
||||
if (will_ask) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
// Following is called through CallAfter, because otherwise there was a problem
|
||||
|
|
@ -922,7 +921,7 @@ void GLGizmoSlaSupports::on_set_state()
|
|||
disable_editing_mode(); // so it is not active next time the gizmo opens
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned off")));
|
||||
m_normal_cache.clear();
|
||||
|
||||
m_old_mo_id = -1;
|
||||
}
|
||||
}
|
||||
m_old_state = m_state;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
#include "slic3r/GUI/Camera.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
|
||||
#include "slic3r/GUI/PresetBundle.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
|
@ -170,7 +172,8 @@ void InstancesHider::show_supports(bool show) {
|
|||
void HollowedMesh::on_update()
|
||||
{
|
||||
const ModelObject* mo = get_pool()->selection_info()->model_object();
|
||||
if (! mo)
|
||||
bool is_sla = wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA;
|
||||
if (! mo || ! is_sla)
|
||||
return;
|
||||
|
||||
const GLCanvas3D* canvas = get_pool()->get_canvas();
|
||||
|
|
@ -376,7 +379,8 @@ void ObjectClipper::set_position(double pos, bool keep_normal)
|
|||
void SupportsClipper::on_update()
|
||||
{
|
||||
const ModelObject* mo = get_pool()->selection_info()->model_object();
|
||||
if (! mo)
|
||||
bool is_sla = wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA;
|
||||
if (! mo || ! is_sla)
|
||||
return;
|
||||
|
||||
const GLCanvas3D* canvas = get_pool()->get_canvas();
|
||||
|
|
|
|||
|
|
@ -1104,9 +1104,16 @@ void GLGizmosManager::activate_gizmo(EType type)
|
|||
}
|
||||
|
||||
m_current = type;
|
||||
m_common_gizmos_data->update(get_current()
|
||||
? get_current()->get_requirements()
|
||||
: CommonGizmosDataID(0));
|
||||
|
||||
// Updating common data should be left to the update_data function, which
|
||||
// is always called after this one. activate_gizmo can be called by undo/redo,
|
||||
// when selection is not yet deserialized, so the common data would update
|
||||
// incorrectly (or crash if relying on unempty selection). Undo/redo stack
|
||||
// will also call update_data, after selection is restored.
|
||||
|
||||
//m_common_gizmos_data->update(get_current()
|
||||
// ? get_current()->get_requirements()
|
||||
// : CommonGizmosDataID(0));
|
||||
|
||||
if (type != Undefined)
|
||||
m_gizmos[type]->set_state(GLGizmoBase::On);
|
||||
|
|
|
|||
|
|
@ -141,11 +141,6 @@ public:
|
|||
EType new_current = m_current;
|
||||
m_current = old_current;
|
||||
|
||||
// Update common data. They should be updated when activate_gizmo is
|
||||
// called, so it can be used in on_set_state which is called from there.
|
||||
if (new_current != Undefined)
|
||||
m_common_gizmos_data->update(m_gizmos[new_current]->get_requirements());
|
||||
|
||||
// activate_gizmo call sets m_current and calls set_state for the gizmo
|
||||
// it does nothing in case the gizmo is already activated
|
||||
// it can safely be called for Undefined gizmo
|
||||
|
|
|
|||
|
|
@ -325,21 +325,22 @@ void MainFrame::init_tabpanel()
|
|||
}
|
||||
|
||||
m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [this](wxEvent&) {
|
||||
auto panel = m_tabpanel->GetCurrentPage();
|
||||
wxWindow* panel = m_tabpanel->GetCurrentPage();
|
||||
Tab* tab = dynamic_cast<Tab*>(panel);
|
||||
|
||||
// There shouldn't be a case, when we try to select a tab, which doesn't support a printer technology
|
||||
if (panel == nullptr || !static_cast<Tab*>(panel)->supports_printer_technology(m_plater->printer_technology()))
|
||||
if (panel == nullptr || (tab && ! tab->supports_printer_technology(m_plater->printer_technology())))
|
||||
return;
|
||||
|
||||
auto& tabs_list = wxGetApp().tabs_list;
|
||||
if (find(tabs_list.begin(), tabs_list.end(), panel) != tabs_list.end()) {
|
||||
if (tab && std::find(tabs_list.begin(), tabs_list.end(), tab) != tabs_list.end()) {
|
||||
// On GTK, the wxEVT_NOTEBOOK_PAGE_CHANGED event is triggered
|
||||
// before the MainFrame is fully set up.
|
||||
static_cast<Tab*>(panel)->OnActivate();
|
||||
tab->OnActivate();
|
||||
m_last_selected_tab = m_tabpanel->GetSelection();
|
||||
}
|
||||
else
|
||||
select_tab(0);
|
||||
select_tab(0); // select Plater
|
||||
});
|
||||
|
||||
if (m_layout == slOld) {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,8 @@ void MeshClipper::render_cut()
|
|||
if (! m_triangles_valid)
|
||||
recalculate_triangles();
|
||||
|
||||
m_vertex_array.render();
|
||||
if (m_vertex_array.has_VBOs())
|
||||
m_vertex_array.render();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5495,7 +5495,10 @@ void Plater::show_action_buttons(const bool ready_to_slice) const { p->show_acti
|
|||
|
||||
void Plater::copy_selection_to_clipboard()
|
||||
{
|
||||
if (can_copy_to_clipboard())
|
||||
// At first try to copy selected values to the ObjectList's clipboard
|
||||
// to check if Settings or Layers are selected in the list
|
||||
// and then copy to 3DCanvas's clipboard if not
|
||||
if (can_copy_to_clipboard() && !p->sidebar->obj_list()->copy_to_clipboard())
|
||||
p->view3D->get_canvas3d()->get_selection().copy_to_clipboard();
|
||||
}
|
||||
|
||||
|
|
@ -5505,7 +5508,12 @@ void Plater::paste_from_clipboard()
|
|||
return;
|
||||
|
||||
Plater::TakeSnapshot snapshot(this, _L("Paste From Clipboard"));
|
||||
p->view3D->get_canvas3d()->get_selection().paste_from_clipboard();
|
||||
|
||||
// At first try to paste values from the ObjectList's clipboard
|
||||
// to check if Settings or Layers were copied
|
||||
// and then paste from the 3DCanvas's clipboard if not
|
||||
if (!p->sidebar->obj_list()->paste_from_clipboard())
|
||||
p->view3D->get_canvas3d()->get_selection().paste_from_clipboard();
|
||||
}
|
||||
|
||||
void Plater::search(bool plater_is_active)
|
||||
|
|
@ -5642,7 +5650,7 @@ bool Plater::can_paste_from_clipboard() const
|
|||
const Selection& selection = p->view3D->get_canvas3d()->get_selection();
|
||||
const Selection::Clipboard& clipboard = selection.get_clipboard();
|
||||
|
||||
if (clipboard.is_empty())
|
||||
if (clipboard.is_empty() && p->sidebar->obj_list()->clipboard_is_empty())
|
||||
return false;
|
||||
|
||||
if ((wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) && !clipboard.is_sla_compliant())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue