Merge remote-tracking branch 'remotes/origin/vb_picking_fix'

This commit is contained in:
bubnikv 2019-08-08 09:50:02 +02:00
commit 23b2b4c59f
27 changed files with 650 additions and 225 deletions

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="eye_x5F_close">
<path fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M2,8c0,0,2,4,6,4s6-4,6-4s-2-4-6-4S2,8,2,8z"/>
<circle fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" cx="8" cy="8" r="1"/>
<line fill="none" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="2" y1="14" x2="14" y2="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 856 B

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="eye_x5F_open">
<path fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M2,8c0,0,2,4,6,4s6-4,6-4s-2-4-6-4S2,8,2,8z"/>
<circle fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" cx="8" cy="8" r="1"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 697 B

View file

@ -71,6 +71,7 @@ const char* V2_ATTR = "v2";
const char* V3_ATTR = "v3"; const char* V3_ATTR = "v3";
const char* OBJECTID_ATTR = "objectid"; const char* OBJECTID_ATTR = "objectid";
const char* TRANSFORM_ATTR = "transform"; const char* TRANSFORM_ATTR = "transform";
const char* PRINTABLE_ATTR = "printable";
const char* KEY_ATTR = "key"; const char* KEY_ATTR = "key";
const char* VALUE_ATTR = "value"; const char* VALUE_ATTR = "value";
@ -131,6 +132,12 @@ int get_attribute_value_int(const char** attributes, unsigned int attributes_siz
return (text != nullptr) ? ::atoi(text) : 0; return (text != nullptr) ? ::atoi(text) : 0;
} }
bool get_attribute_value_bool(const char** attributes, unsigned int attributes_size, const char* attribute_key)
{
const char* text = get_attribute_value_charptr(attributes, attributes_size, attribute_key);
return (text != nullptr) ? (bool)::atoi(text) : true;
}
Slic3r::Transform3d get_transform_from_string(const std::string& mat_str) Slic3r::Transform3d get_transform_from_string(const std::string& mat_str)
{ {
if (mat_str.empty()) if (mat_str.empty())
@ -428,7 +435,7 @@ namespace Slic3r {
bool _handle_start_metadata(const char** attributes, unsigned int num_attributes); bool _handle_start_metadata(const char** attributes, unsigned int num_attributes);
bool _handle_end_metadata(); bool _handle_end_metadata();
bool _create_object_instance(int object_id, const Transform3d& transform, unsigned int recur_counter); bool _create_object_instance(int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter);
void _apply_transform(ModelInstance& instance, const Transform3d& transform); void _apply_transform(ModelInstance& instance, const Transform3d& transform);
@ -1367,8 +1374,9 @@ namespace Slic3r {
int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR); int object_id = get_attribute_value_int(attributes, num_attributes, OBJECTID_ATTR);
Transform3d transform = get_transform_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR)); Transform3d transform = get_transform_from_string(get_attribute_value_string(attributes, num_attributes, TRANSFORM_ATTR));
int printable = get_attribute_value_bool(attributes, num_attributes, PRINTABLE_ATTR);
return _create_object_instance(object_id, transform, 1); return _create_object_instance(object_id, transform, printable, 1);
} }
bool _3MF_Importer::_handle_end_item() bool _3MF_Importer::_handle_end_item()
@ -1396,7 +1404,7 @@ namespace Slic3r {
return true; return true;
} }
bool _3MF_Importer::_create_object_instance(int object_id, const Transform3d& transform, unsigned int recur_counter) bool _3MF_Importer::_create_object_instance(int object_id, const Transform3d& transform, const bool printable, unsigned int recur_counter)
{ {
static const unsigned int MAX_RECURSIONS = 10; static const unsigned int MAX_RECURSIONS = 10;
@ -1432,6 +1440,7 @@ namespace Slic3r {
add_error("Unable to add object instance"); add_error("Unable to add object instance");
return false; return false;
} }
instance->printable = printable;
m_instances.emplace_back(instance, transform); m_instances.emplace_back(instance, transform);
} }
@ -1441,7 +1450,7 @@ namespace Slic3r {
// recursively process nested components // recursively process nested components
for (const Component& component : it->second) for (const Component& component : it->second)
{ {
if (!_create_object_instance(component.object_id, transform * component.transform, recur_counter + 1)) if (!_create_object_instance(component.object_id, transform * component.transform, printable, recur_counter + 1))
return false; return false;
} }
} }
@ -1655,10 +1664,12 @@ namespace Slic3r {
{ {
unsigned int id; unsigned int id;
Transform3d transform; Transform3d transform;
bool printable;
BuildItem(unsigned int id, const Transform3d& transform) BuildItem(unsigned int id, const Transform3d& transform, const bool printable)
: id(id) : id(id)
, transform(transform) , transform(transform)
, printable(printable)
{ {
} }
}; };
@ -1951,7 +1962,7 @@ namespace Slic3r {
Transform3d t = instance->get_matrix(); Transform3d t = instance->get_matrix();
// instance_id is just a 1 indexed index in build_items. // instance_id is just a 1 indexed index in build_items.
assert(instance_id == build_items.size() + 1); assert(instance_id == build_items.size() + 1);
build_items.emplace_back(instance_id, t); build_items.emplace_back(instance_id, t, instance->printable);
stream << " </" << OBJECT_TAG << ">\n"; stream << " </" << OBJECT_TAG << ">\n";
@ -2059,7 +2070,7 @@ namespace Slic3r {
stream << " "; stream << " ";
} }
} }
stream << "\" />\n"; stream << "\" printable =\"" << item.printable << "\" />\n";
} }
stream << " </" << BUILD_TAG << ">\n"; stream << " </" << BUILD_TAG << ">\n";

View file

@ -137,6 +137,7 @@ struct AMFParserContext
NODE_TYPE_MIRRORX, // amf/constellation/instance/mirrorx NODE_TYPE_MIRRORX, // amf/constellation/instance/mirrorx
NODE_TYPE_MIRRORY, // amf/constellation/instance/mirrory NODE_TYPE_MIRRORY, // amf/constellation/instance/mirrory
NODE_TYPE_MIRRORZ, // amf/constellation/instance/mirrorz NODE_TYPE_MIRRORZ, // amf/constellation/instance/mirrorz
NODE_TYPE_PRINTABLE, // amf/constellation/instance/mirrorz
NODE_TYPE_METADATA, // anywhere under amf/*/metadata NODE_TYPE_METADATA, // anywhere under amf/*/metadata
}; };
@ -145,7 +146,8 @@ struct AMFParserContext
: deltax_set(false), deltay_set(false), deltaz_set(false) : deltax_set(false), deltay_set(false), deltaz_set(false)
, rx_set(false), ry_set(false), rz_set(false) , rx_set(false), ry_set(false), rz_set(false)
, scalex_set(false), scaley_set(false), scalez_set(false) , scalex_set(false), scaley_set(false), scalez_set(false)
, mirrorx_set(false), mirrory_set(false), mirrorz_set(false) {} , mirrorx_set(false), mirrory_set(false), mirrorz_set(false)
, printable(true) {}
// Shift in the X axis. // Shift in the X axis.
float deltax; float deltax;
bool deltax_set; bool deltax_set;
@ -178,6 +180,8 @@ struct AMFParserContext
bool mirrory_set; bool mirrory_set;
float mirrorz; float mirrorz;
bool mirrorz_set; bool mirrorz_set;
// printable property
bool printable;
bool anything_set() const { return deltax_set || deltay_set || deltaz_set || bool anything_set() const { return deltax_set || deltay_set || deltaz_set ||
rx_set || ry_set || rz_set || rx_set || ry_set || rz_set ||
@ -321,6 +325,8 @@ void AMFParserContext::startElement(const char *name, const char **atts)
node_type_new = NODE_TYPE_MIRRORY; node_type_new = NODE_TYPE_MIRRORY;
else if (strcmp(name, "mirrorz") == 0) else if (strcmp(name, "mirrorz") == 0)
node_type_new = NODE_TYPE_MIRRORZ; node_type_new = NODE_TYPE_MIRRORZ;
else if (strcmp(name, "printable") == 0)
node_type_new = NODE_TYPE_PRINTABLE;
} }
else if (m_path[2] == NODE_TYPE_LAYER_CONFIG && strcmp(name, "range") == 0) { else if (m_path[2] == NODE_TYPE_LAYER_CONFIG && strcmp(name, "range") == 0) {
assert(m_object); assert(m_object);
@ -397,7 +403,8 @@ void AMFParserContext::characters(const XML_Char *s, int len)
m_path.back() == NODE_TYPE_SCALE || m_path.back() == NODE_TYPE_SCALE ||
m_path.back() == NODE_TYPE_MIRRORX || m_path.back() == NODE_TYPE_MIRRORX ||
m_path.back() == NODE_TYPE_MIRRORY || m_path.back() == NODE_TYPE_MIRRORY ||
m_path.back() == NODE_TYPE_MIRRORZ) m_path.back() == NODE_TYPE_MIRRORZ ||
m_path.back() == NODE_TYPE_PRINTABLE)
m_value[0].append(s, len); m_value[0].append(s, len);
break; break;
case 6: case 6:
@ -507,6 +514,11 @@ void AMFParserContext::endElement(const char * /* name */)
m_instance->mirrorz_set = true; m_instance->mirrorz_set = true;
m_value[0].clear(); m_value[0].clear();
break; break;
case NODE_TYPE_PRINTABLE:
assert(m_instance);
m_instance->printable = bool(atoi(m_value[0].c_str()));
m_value[0].clear();
break;
// Object vertices: // Object vertices:
case NODE_TYPE_VERTEX: case NODE_TYPE_VERTEX:
@ -685,6 +697,7 @@ void AMFParserContext::endDocument()
mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0)); mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0));
mi->set_scaling_factor(Vec3d(instance.scalex_set ? (double)instance.scalex : 1.0, instance.scaley_set ? (double)instance.scaley : 1.0, instance.scalez_set ? (double)instance.scalez : 1.0)); mi->set_scaling_factor(Vec3d(instance.scalex_set ? (double)instance.scalex : 1.0, instance.scaley_set ? (double)instance.scaley : 1.0, instance.scalez_set ? (double)instance.scalez : 1.0));
mi->set_mirror(Vec3d(instance.mirrorx_set ? (double)instance.mirrorx : 1.0, instance.mirrory_set ? (double)instance.mirrory : 1.0, instance.mirrorz_set ? (double)instance.mirrorz : 1.0)); mi->set_mirror(Vec3d(instance.mirrorx_set ? (double)instance.mirrorx : 1.0, instance.mirrory_set ? (double)instance.mirrory : 1.0, instance.mirrorz_set ? (double)instance.mirrorz : 1.0));
mi->printable = instance.printable;
} }
} }
} }
@ -1037,6 +1050,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
" <mirrorx>%lf</mirrorx>\n" " <mirrorx>%lf</mirrorx>\n"
" <mirrory>%lf</mirrory>\n" " <mirrory>%lf</mirrory>\n"
" <mirrorz>%lf</mirrorz>\n" " <mirrorz>%lf</mirrorz>\n"
" <printable>%d</printable>\n"
" </instance>\n", " </instance>\n",
object_id, object_id,
instance->get_offset(X), instance->get_offset(X),
@ -1050,7 +1064,8 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
instance->get_scaling_factor(Z), instance->get_scaling_factor(Z),
instance->get_mirror(X), instance->get_mirror(X),
instance->get_mirror(Y), instance->get_mirror(Y),
instance->get_mirror(Z)); instance->get_mirror(Z),
instance->printable);
//FIXME missing instance->scaling_factor //FIXME missing instance->scaling_factor
instances.append(buf); instances.append(buf);

View file

@ -600,6 +600,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
this->sla_points_status = rhs.sla_points_status; this->sla_points_status = rhs.sla_points_status;
this->layer_config_ranges = rhs.layer_config_ranges; // #ys_FIXME_experiment this->layer_config_ranges = rhs.layer_config_ranges; // #ys_FIXME_experiment
this->layer_height_profile = rhs.layer_height_profile; this->layer_height_profile = rhs.layer_height_profile;
this->printable = rhs.printable;
this->origin_translation = rhs.origin_translation; this->origin_translation = rhs.origin_translation;
m_bounding_box = rhs.m_bounding_box; m_bounding_box = rhs.m_bounding_box;
m_bounding_box_valid = rhs.m_bounding_box_valid; m_bounding_box_valid = rhs.m_bounding_box_valid;

View file

@ -192,6 +192,8 @@ public:
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers. // Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
// The pairs of <z, layer_height> are packed into a 1D array. // The pairs of <z, layer_height> are packed into a 1D array.
std::vector<coordf_t> layer_height_profile; std::vector<coordf_t> layer_height_profile;
// Whether or not this object is printable
bool printable;
// This vector holds position of selected support points for SLA. The data are // This vector holds position of selected support points for SLA. The data are
// saved in mesh coordinates to allow using them for several instances. // saved in mesh coordinates to allow using them for several instances.
@ -304,10 +306,10 @@ public:
private: private:
friend class Model; friend class Model;
// This constructor assigns new ID to this ModelObject and its config. // This constructor assigns new ID to this ModelObject and its config.
explicit ModelObject(Model *model) : m_model(model), origin_translation(Vec3d::Zero()), explicit ModelObject(Model* model) : m_model(model), printable(true), origin_translation(Vec3d::Zero()),
m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false)
{ assert(this->id().valid()); } { assert(this->id().valid()); }
explicit ModelObject(int) : ObjectBase(-1), config(-1), m_model(nullptr), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false) explicit ModelObject(int) : ObjectBase(-1), config(-1), m_model(nullptr), printable(true), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false), m_raw_bounding_box_valid(false), m_raw_mesh_bounding_box_valid(false)
{ assert(this->id().invalid()); assert(this->config.id().invalid()); } { assert(this->id().invalid()); assert(this->config.id().invalid()); }
~ModelObject(); ~ModelObject();
void assign_new_unique_ids_recursive() override; void assign_new_unique_ids_recursive() override;
@ -370,7 +372,7 @@ private:
template<class Archive> void serialize(Archive &ar) { template<class Archive> void serialize(Archive &ar) {
ar(cereal::base_class<ObjectBase>(this)); ar(cereal::base_class<ObjectBase>(this));
Internal::StaticSerializationWrapper<ModelConfig> config_wrapper(config); Internal::StaticSerializationWrapper<ModelConfig> config_wrapper(config);
ar(name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_height_profile, sla_support_points, sla_points_status, origin_translation, ar(name, input_file, instances, volumes, config_wrapper, layer_config_ranges, layer_height_profile, sla_support_points, sla_points_status, printable, origin_translation,
m_bounding_box, m_bounding_box_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid); m_bounding_box, m_bounding_box_valid, m_raw_bounding_box, m_raw_bounding_box_valid, m_raw_mesh_bounding_box, m_raw_mesh_bounding_box_valid);
} }
}; };
@ -595,6 +597,8 @@ private:
public: public:
// flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state()) // flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state())
EPrintVolumeState print_volume_state; EPrintVolumeState print_volume_state;
// Whether or not this instance is printable
bool printable;
ModelObject* get_object() const { return this->object; } ModelObject* get_object() const { return this->object; }
@ -639,7 +643,7 @@ public:
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); } const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); }
bool is_printable() const { return print_volume_state == PVS_Inside; } bool is_printable() const { return object->printable && printable && (print_volume_state == PVS_Inside); }
// Getting the input polygon for arrange // Getting the input polygon for arrange
arrangement::ArrangePolygon get_arrange_polygon() const; arrangement::ArrangePolygon get_arrange_polygon() const;
@ -667,10 +671,10 @@ private:
ModelObject* object; ModelObject* object;
// Constructor, which assigns a new unique ID. // Constructor, which assigns a new unique ID.
explicit ModelInstance(ModelObject *object) : print_volume_state(PVS_Inside), object(object) { assert(this->id().valid()); } explicit ModelInstance(ModelObject* object) : print_volume_state(PVS_Inside), printable(true), object(object) { assert(this->id().valid()); }
// Constructor, which assigns a new unique ID. // Constructor, which assigns a new unique ID.
explicit ModelInstance(ModelObject *object, const ModelInstance &other) : explicit ModelInstance(ModelObject *object, const ModelInstance &other) :
m_transformation(other.m_transformation), print_volume_state(PVS_Inside), object(object) { assert(this->id().valid() && this->id() != other.id()); } m_transformation(other.m_transformation), print_volume_state(PVS_Inside), printable(true), object(object) {assert(this->id().valid() && this->id() != other.id());}
explicit ModelInstance(ModelInstance &&rhs) = delete; explicit ModelInstance(ModelInstance &&rhs) = delete;
ModelInstance& operator=(const ModelInstance &rhs) = delete; ModelInstance& operator=(const ModelInstance &rhs) = delete;
@ -681,7 +685,7 @@ private:
// Used for deserialization, therefore no IDs are allocated. // Used for deserialization, therefore no IDs are allocated.
ModelInstance() : ObjectBase(-1), object(nullptr) { assert(this->id().invalid()); } ModelInstance() : ObjectBase(-1), object(nullptr) { assert(this->id().invalid()); }
template<class Archive> void serialize(Archive &ar) { template<class Archive> void serialize(Archive &ar) {
ar(m_transformation, print_volume_state); ar(m_transformation, print_volume_state, printable);
} }
}; };

View file

@ -213,6 +213,7 @@ GLVolume::GLVolume(float r, float g, float b, float a)
, extruder_id(0) , extruder_id(0)
, selected(false) , selected(false)
, disabled(false) , disabled(false)
, printable(true)
, is_active(true) , is_active(true)
, zoom_to_volumes(true) , zoom_to_volumes(true)
, shader_outside_printer_detection_enabled(false) , shader_outside_printer_detection_enabled(false)
@ -270,6 +271,13 @@ void GLVolume::set_render_color()
set_render_color(color, 4); set_render_color(color, 4);
} }
if (!printable)
{
render_color[0] /= 4;
render_color[1] /= 4;
render_color[2] /= 4;
}
if (force_transparent) if (force_transparent)
render_color[3] = color[3]; render_color[3] = color[3];
} }

View file

@ -316,6 +316,8 @@ public:
bool selected; bool selected;
// Is this object disabled from selection? // Is this object disabled from selection?
bool disabled; bool disabled;
// Is this object printable?
bool printable;
// Whether or not this volume is active for rendering // Whether or not this volume is active for rendering
bool is_active; bool is_active;
// Whether or not to use this volume when applying zoom_to_volumes() // Whether or not to use this volume when applying zoom_to_volumes()

View file

@ -1319,6 +1319,23 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject
_set_warning_texture(WarningTexture::SomethingNotShown, false); _set_warning_texture(WarningTexture::SomethingNotShown, false);
} }
void GLCanvas3D::update_instance_printable_state_for_objects(std::vector<size_t>& object_idxs)
{
for (size_t obj_idx : object_idxs)
{
ModelObject* model_object = m_model->objects[obj_idx];
for (int inst_idx = 0; inst_idx < model_object->instances.size(); inst_idx++)
{
ModelInstance* instance = model_object->instances[inst_idx];
for (GLVolume* volume : m_volumes.volumes)
{
if ((volume->object_idx() == obj_idx) && (volume->instance_idx() == inst_idx))
volume->printable = instance->printable;
}
}
}
}
void GLCanvas3D::set_config(const DynamicPrintConfig* config) void GLCanvas3D::set_config(const DynamicPrintConfig* config)
{ {
@ -3747,6 +3764,7 @@ void GLCanvas3D::_picking_pass() const
// Better to use software ray - casting on a bounding - box hierarchy. // Better to use software ray - casting on a bounding - box hierarchy.
if (m_multisample_allowed) if (m_multisample_allowed)
// This flag is often ignored by NVIDIA drivers if rendering into a screen buffer.
glsafe(::glDisable(GL_MULTISAMPLE)); glsafe(::glDisable(GL_MULTISAMPLE));
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
@ -3776,6 +3794,8 @@ void GLCanvas3D::_picking_pass() const
if (inside) if (inside)
{ {
glsafe(::glReadPixels(m_mouse.position(0), cnv_size.get_height() - m_mouse.position(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color)); glsafe(::glReadPixels(m_mouse.position(0), cnv_size.get_height() - m_mouse.position(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color));
if (picking_checksum_alpha_channel(color[0], color[1], color[2]) == color[3])
// Only non-interpolated colors are valid, those have their lowest three bits zeroed.
volume_id = color[0] + (color[1] << 8) + (color[2] << 16); volume_id = color[0] + (color[1] << 8) + (color[2] << 16);
} }
if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size()))
@ -3799,6 +3819,7 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const
if (m_picking_enabled) if (m_picking_enabled)
{ {
if (m_multisample_allowed) if (m_multisample_allowed)
// This flag is often ignored by NVIDIA drivers if rendering into a screen buffer.
glsafe(::glDisable(GL_MULTISAMPLE)); glsafe(::glDisable(GL_MULTISAMPLE));
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
@ -3824,6 +3845,8 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const
struct Pixel struct Pixel
{ {
std::array<GLubyte, 4> data; std::array<GLubyte, 4> data;
// Only non-interpolated colors are valid, those have their lowest three bits zeroed.
bool valid() const { return picking_checksum_alpha_channel(data[0], data[1], data[2]) == data[3]; }
int id() const { return data[0] + (data[1] << 8) + (data[2] << 16); } int id() const { return data[0] + (data[1] << 8) + (data[2] << 16); }
}; };
@ -3834,17 +3857,15 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const
tbb::parallel_for(tbb::blocked_range<size_t>(0, frame.size(), (size_t)width), tbb::parallel_for(tbb::blocked_range<size_t>(0, frame.size(), (size_t)width),
[this, &frame, &idxs, &mutex](const tbb::blocked_range<size_t>& range) { [this, &frame, &idxs, &mutex](const tbb::blocked_range<size_t>& range) {
for (size_t i = range.begin(); i < range.end(); ++i) for (size_t i = range.begin(); i < range.end(); ++i)
{ if (frame[i].valid()) {
int volume_id = frame[i].id(); int volume_id = frame[i].id();
if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) {
{
mutex.lock(); mutex.lock();
idxs.insert(volume_id); idxs.insert(volume_id);
mutex.unlock(); mutex.unlock();
} }
} }
} });
);
#else #else
std::vector<GLubyte> frame(4 * px_count); std::vector<GLubyte> frame(4 * px_count);
glsafe(::glReadPixels(left, top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)frame.data())); glsafe(::glReadPixels(left, top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)frame.data()));
@ -4023,42 +4044,27 @@ void GLCanvas3D::_render_volumes_for_picking() const
// do not cull backfaces to show broken geometry, if any // do not cull backfaces to show broken geometry, if any
glsafe(::glDisable(GL_CULL_FACE)); glsafe(::glDisable(GL_CULL_FACE));
glsafe(::glEnable(GL_BLEND));
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
const Transform3d& view_matrix = m_camera.get_view_matrix(); const Transform3d& view_matrix = m_camera.get_view_matrix();
GLVolumeWithIdAndZList to_render = volumes_to_render(m_volumes.volumes, GLVolumeCollection::Opaque, view_matrix); for (size_t type = 0; type < 2; ++ type) {
GLVolumeWithIdAndZList to_render = volumes_to_render(m_volumes.volumes, (type == 0) ? GLVolumeCollection::Opaque : GLVolumeCollection::Transparent, view_matrix);
for (const GLVolumeWithIdAndZ& volume : to_render) for (const GLVolumeWithIdAndZ& volume : to_render)
{ if (!volume.first->disabled && ((volume.first->composite_id.volume_id >= 0) || m_render_sla_auxiliaries)) {
// Object picking mode. Render the object with a color encoding the object index. // Object picking mode. Render the object with a color encoding the object index.
unsigned int r = (volume.second.first & 0x000000FF) >> 0; unsigned int id = volume.second.first;
unsigned int g = (volume.second.first & 0x0000FF00) >> 8; unsigned int r = (id & (0x000000FF << 0)) << 0;
unsigned int b = (volume.second.first & 0x00FF0000) >> 16; unsigned int g = (id & (0x000000FF << 8)) >> 8;
glsafe(::glColor3f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255)); unsigned int b = (id & (0x000000FF << 16)) >> 16;
unsigned int a = picking_checksum_alpha_channel(r, g, b);
if (!volume.first->disabled && ((volume.first->composite_id.volume_id >= 0) || m_render_sla_auxiliaries)) glsafe(::glColor4f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255, (GLfloat)a * INV_255));
volume.first->render(); volume.first->render();
} }
to_render = volumes_to_render(m_volumes.volumes, GLVolumeCollection::Transparent, view_matrix);
for (const GLVolumeWithIdAndZ& volume : to_render)
{
// Object picking mode. Render the object with a color encoding the object index.
unsigned int r = (volume.second.first & 0x000000FF) >> 0;
unsigned int g = (volume.second.first & 0x0000FF00) >> 8;
unsigned int b = (volume.second.first & 0x00FF0000) >> 16;
glsafe(::glColor3f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255));
if (!volume.first->disabled && ((volume.first->composite_id.volume_id >= 0) || m_render_sla_auxiliaries))
volume.first->render();
} }
glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glDisable(GL_BLEND));
glsafe(::glEnable(GL_CULL_FACE)); glsafe(::glEnable(GL_CULL_FACE));
} }

View file

@ -482,6 +482,7 @@ public:
void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1); void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1); void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
void update_instance_printable_state_for_objects(std::vector<size_t>& object_idxs);
void set_config(const DynamicPrintConfig* config); void set_config(const DynamicPrintConfig* config);
void set_process(BackgroundSlicingProcess* process); void set_process(BackgroundSlicingProcess* process);

View file

@ -290,7 +290,21 @@ GLCanvas3D* GLCanvas3DManager::get_canvas(wxGLCanvas* canvas)
wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent) wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent)
{ {
int attribList[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 24, WX_GL_SAMPLE_BUFFERS, GL_TRUE, WX_GL_SAMPLES, 4, 0 }; int attribList[] = {
WX_GL_RGBA,
WX_GL_DOUBLEBUFFER,
// RGB channels each should be allocated with 8 bit depth. One should almost certainly get these bit depths by default.
WX_GL_MIN_RED, 8,
WX_GL_MIN_GREEN, 8,
WX_GL_MIN_BLUE, 8,
// Requesting an 8 bit alpha channel. Interestingly, the NVIDIA drivers would most likely work with some alpha plane, but glReadPixels would not return
// the alpha channel on NVIDIA if not requested when the GL context is created.
WX_GL_MIN_ALPHA, 8,
WX_GL_DEPTH_SIZE, 24,
WX_GL_SAMPLE_BUFFERS, GL_TRUE,
WX_GL_SAMPLES, 4,
0
};
if (s_multisample == MS_Unknown) if (s_multisample == MS_Unknown)
{ {
@ -300,7 +314,7 @@ wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent)
} }
if (! can_multisample()) if (! can_multisample())
attribList[4] = 0; attribList[12] = 0;
return new wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS); return new wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS);
} }

View file

@ -223,16 +223,20 @@ void ObjectList::create_objects_ctrl()
EnableDropTarget(wxDF_UNICODETEXT); EnableDropTarget(wxDF_UNICODETEXT);
#endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE #endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
// column 0(Icon+Text) of the view control: // column ItemName(Icon+Text) of the view control:
// And Icon can be consisting of several bitmaps // And Icon can be consisting of several bitmaps
AppendColumn(new wxDataViewColumn(_(L("Name")), new BitmapTextRenderer(), AppendColumn(new wxDataViewColumn(_(L("Name")), new BitmapTextRenderer(),
0, 20*wxGetApp().em_unit()/*200*/, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE)); colName, 20*wxGetApp().em_unit()/*200*/, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE));
// column 1 of the view control: // column PrintableProperty (Icon) of the view control:
AppendBitmapColumn(" ", colPrint, wxDATAVIEW_CELL_INERT, int(2 * wxGetApp().em_unit()),
wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
// column Extruder of the view control:
AppendColumn(create_objects_list_extruder_column(4)); AppendColumn(create_objects_list_extruder_column(4));
// column 2 of the view control: // column ItemEditing of the view control:
AppendBitmapColumn(" ", 2, wxDATAVIEW_CELL_INERT, int(2.5 * wxGetApp().em_unit())/*25*/, AppendBitmapColumn("Editing", colEditing, wxDATAVIEW_CELL_INERT, int(2.5 * wxGetApp().em_unit())/*25*/,
wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
} }
@ -332,7 +336,7 @@ void ObjectList::set_tooltip_for_item(const wxPoint& pt)
return; return;
} }
if (col->GetTitle() == " " && GetSelectedItemsCount()<2) if (col->GetTitle() == _(L("Editing")) && GetSelectedItemsCount()<2)
GetMainWindow()->SetToolTip(_(L("Right button click the icon to change the object settings"))); GetMainWindow()->SetToolTip(_(L("Right button click the icon to change the object settings")));
else if (col->GetTitle() == _("Name")) else if (col->GetTitle() == _("Name"))
{ {
@ -388,7 +392,7 @@ wxDataViewColumn* ObjectList::create_objects_list_extruder_column(int extruders_
choices.Add(wxString::Format("%d", i)); choices.Add(wxString::Format("%d", i));
wxDataViewChoiceRenderer *c = wxDataViewChoiceRenderer *c =
new wxDataViewChoiceRenderer(choices, wxDATAVIEW_CELL_EDITABLE, wxALIGN_CENTER_HORIZONTAL); new wxDataViewChoiceRenderer(choices, wxDATAVIEW_CELL_EDITABLE, wxALIGN_CENTER_HORIZONTAL);
wxDataViewColumn* column = new wxDataViewColumn(_(L("Extruder")), c, 1, wxDataViewColumn* column = new wxDataViewColumn(_(L("Extruder")), c, colExtruder,
8*wxGetApp().em_unit()/*80*/, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); 8*wxGetApp().em_unit()/*80*/, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
return column; return column;
} }
@ -408,7 +412,7 @@ void ObjectList::update_extruder_values_for_items(const int max_extruder)
else else
extruder = wxString::Format("%d", object->config.option<ConfigOptionInt>("extruder")->value); extruder = wxString::Format("%d", object->config.option<ConfigOptionInt>("extruder")->value);
m_objects_model->SetValue(extruder, item, 1); m_objects_model->SetValue(extruder, item, colExtruder);
if (object->volumes.size() > 1) { if (object->volumes.size() > 1) {
for (auto id = 0; id < object->volumes.size(); id++) { for (auto id = 0; id < object->volumes.size(); id++) {
@ -420,7 +424,7 @@ void ObjectList::update_extruder_values_for_items(const int max_extruder)
else else
extruder = wxString::Format("%d", object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value); extruder = wxString::Format("%d", object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value);
m_objects_model->SetValue(extruder, item, 1); m_objects_model->SetValue(extruder, item, colExtruder);
} }
} }
} }
@ -432,7 +436,7 @@ void ObjectList::update_objects_list_extruder_column(int extruders_count)
if (printer_technology() == ptSLA) if (printer_technology() == ptSLA)
extruders_count = 1; extruders_count = 1;
wxDataViewChoiceRenderer* ch_render = dynamic_cast<wxDataViewChoiceRenderer*>(GetColumn(1)->GetRenderer()); wxDataViewChoiceRenderer* ch_render = dynamic_cast<wxDataViewChoiceRenderer*>(GetColumn(colExtruder)->GetRenderer());
if (ch_render->GetChoices().GetCount() - 1 == extruders_count) if (ch_render->GetChoices().GetCount() - 1 == extruders_count)
return; return;
@ -441,21 +445,21 @@ void ObjectList::update_objects_list_extruder_column(int extruders_count)
if (m_objects && extruders_count > 1) if (m_objects && extruders_count > 1)
update_extruder_values_for_items(extruders_count); update_extruder_values_for_items(extruders_count);
// delete old 2nd column // delete old extruder column
DeleteColumn(GetColumn(1)); DeleteColumn(GetColumn(colExtruder));
// insert new created 3rd column // insert new created extruder column
InsertColumn(1, create_objects_list_extruder_column(extruders_count)); InsertColumn(colExtruder, create_objects_list_extruder_column(extruders_count));
// set show/hide for this column // set show/hide for this column
set_extruder_column_hidden(extruders_count <= 1); set_extruder_column_hidden(extruders_count <= 1);
//a workaround for a wrong last column width updating under OSX //a workaround for a wrong last column width updating under OSX
GetColumn(2)->SetWidth(25); GetColumn(colEditing)->SetWidth(25);
m_prevent_update_extruder_in_config = false; m_prevent_update_extruder_in_config = false;
} }
void ObjectList::set_extruder_column_hidden(const bool hide) const void ObjectList::set_extruder_column_hidden(const bool hide) const
{ {
GetColumn(1)->SetHidden(hide); GetColumn(colExtruder)->SetHidden(hide);
} }
void ObjectList::update_extruder_in_config(const wxDataViewItem& item) void ObjectList::update_extruder_in_config(const wxDataViewItem& item)
@ -482,7 +486,7 @@ void ObjectList::update_extruder_in_config(const wxDataViewItem& item)
} }
wxVariant variant; wxVariant variant;
m_objects_model->GetValue(variant, item, 1); m_objects_model->GetValue(variant, item, colExtruder);
const wxString selection = variant.GetString(); const wxString selection = variant.GetString();
if (!m_config || selection.empty()) if (!m_config || selection.empty())
@ -745,21 +749,21 @@ void ObjectList::OnContextMenu(wxDataViewEvent&)
wxDataViewColumn* col; wxDataViewColumn* col;
const wxPoint pt = get_mouse_position_in_control(); const wxPoint pt = get_mouse_position_in_control();
HitTest(pt, item, col); HitTest(pt, item, col);
if (!item)
#ifdef __WXOSX__ // temporary workaround for OSX #ifdef __WXOSX__ // temporary workaround for OSX
// after Yosemite OS X version, HitTest return undefined item // after Yosemite OS X version, HitTest return undefined item
item = GetSelection(); if (!item) item = GetSelection();
if (item) #endif // __WXOSX__
show_context_menu();
else if (!item) {
printf("undefined item\n"); printf("undefined item\n");
return; return;
#else }
return;
#endif // __WXOSX__
const wxString title = col->GetTitle(); const wxString title = col->GetTitle();
if (title == " ") if (title == " ")
toggle_printable_state(item);
else if (title == _("Editing"))
show_context_menu(); show_context_menu();
else if (title == _("Name")) else if (title == _("Name"))
{ {
@ -1386,6 +1390,13 @@ wxMenuItem* ObjectList::append_menu_item_instance_to_object(wxMenu* menu, wxWind
[this](wxCommandEvent&) { split_instances(); }, "", menu, [](){return wxGetApp().plater()->can_set_instance_to_object(); }, parent); [this](wxCommandEvent&) { split_instances(); }, "", menu, [](){return wxGetApp().plater()->can_set_instance_to_object(); }, parent);
} }
wxMenuItem* ObjectList::append_menu_item_printable(wxMenu* menu, wxWindow* parent)
{
return append_menu_check_item(menu, wxID_ANY, _(L("Printable")), "", [this](wxCommandEvent&) {
wxGetApp().plater()->canvas3D()->get_selection().toggle_instance_printable_state();
}, menu);
}
void ObjectList::append_menu_items_osx(wxMenu* menu) void ObjectList::append_menu_items_osx(wxMenu* menu)
{ {
append_menu_item(menu, wxID_ANY, _(L("Rename")), "", append_menu_item(menu, wxID_ANY, _(L("Rename")), "",
@ -2271,7 +2282,17 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed)
// add instances to the object, if it has those // add instances to the object, if it has those
if (model_object->instances.size()>1) if (model_object->instances.size()>1)
increase_object_instances(obj_idx, model_object->instances.size()); {
std::vector<bool> print_idicator(model_object->instances.size());
for (int i = 0; i < model_object->instances.size(); ++i)
print_idicator[i] = model_object->instances[i]->is_printable();
const wxDataViewItem object_item = m_objects_model->GetItemById(obj_idx);
m_objects_model->AddInstanceChild(object_item, print_idicator);
Expand(m_objects_model->GetInstanceRootItem(object_item));
}
else
m_objects_model->SetPrintableState(model_object->instances[0]->is_printable() ? piPrintable : piUnprintable, obj_idx);
// add settings to the object, if it has those // add settings to the object, if it has those
add_settings_item(item, &model_object->config); add_settings_item(item, &model_object->config);
@ -2353,7 +2374,7 @@ void ObjectList::delete_from_model_and_list(const std::vector<ItemForDelete>& it
(*m_objects)[item->obj_idx]->config.has("extruder")) (*m_objects)[item->obj_idx]->config.has("extruder"))
{ {
const wxString extruder = wxString::Format("%d", (*m_objects)[item->obj_idx]->config.option<ConfigOptionInt>("extruder")->value); const wxString extruder = wxString::Format("%d", (*m_objects)[item->obj_idx]->config.option<ConfigOptionInt>("extruder")->value);
m_objects_model->SetValue(extruder, m_objects_model->GetItemById(item->obj_idx), 1); m_objects_model->SetValue(extruder, m_objects_model->GetItemById(item->obj_idx), colExtruder);
} }
wxGetApp().plater()->canvas3D()->ensure_on_bed(item->obj_idx); wxGetApp().plater()->canvas3D()->ensure_on_bed(item->obj_idx);
} }
@ -3317,7 +3338,8 @@ void ObjectList::instances_to_separated_object(const int obj_idx, const std::set
} }
// Add new object to the object_list // Add new object to the object_list
add_object_to_list(m_objects->size() - 1); const size_t new_obj_indx = static_cast<size_t>(m_objects->size() - 1);
add_object_to_list(new_obj_indx);
for (std::set<int>::const_reverse_iterator it = inst_idxs.rbegin(); it != inst_idxs.rend(); ++it) for (std::set<int>::const_reverse_iterator it = inst_idxs.rbegin(); it != inst_idxs.rend(); ++it)
{ {
@ -3325,12 +3347,18 @@ void ObjectList::instances_to_separated_object(const int obj_idx, const std::set
del_subobject_from_object(obj_idx, *it, itInstance); del_subobject_from_object(obj_idx, *it, itInstance);
delete_instance_from_list(obj_idx, *it); delete_instance_from_list(obj_idx, *it);
} }
std::vector<size_t> object_idxs = { new_obj_indx };
// update printable state for new volumes on canvas3D
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_objects(object_idxs);
} }
void ObjectList::instances_to_separated_objects(const int obj_idx) void ObjectList::instances_to_separated_objects(const int obj_idx)
{ {
const int inst_cnt = (*m_objects)[obj_idx]->instances.size(); const int inst_cnt = (*m_objects)[obj_idx]->instances.size();
std::vector<size_t> object_idxs;
for (int i = inst_cnt-1; i > 0 ; i--) for (int i = inst_cnt-1; i > 0 ; i--)
{ {
// create new object from initial // create new object from initial
@ -3344,12 +3372,17 @@ void ObjectList::instances_to_separated_objects(const int obj_idx)
} }
// Add new object to the object_list // Add new object to the object_list
add_object_to_list(m_objects->size() - 1); const size_t new_obj_indx = static_cast<size_t>(m_objects->size() - 1);
add_object_to_list(new_obj_indx);
object_idxs.push_back(new_obj_indx);
// delete current instance from the initial object // delete current instance from the initial object
del_subobject_from_object(obj_idx, i, itInstance); del_subobject_from_object(obj_idx, i, itInstance);
delete_instance_from_list(obj_idx, i); delete_instance_from_list(obj_idx, i);
} }
// update printable state for new volumes on canvas3D
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_objects(object_idxs);
} }
void ObjectList::split_instances() void ObjectList::split_instances()
@ -3404,7 +3437,7 @@ void ObjectList::rename_item()
// The icon can't be edited so get its old value and reuse it. // The icon can't be edited so get its old value and reuse it.
wxVariant valueOld; wxVariant valueOld;
m_objects_model->GetValue(valueOld, item, 0); m_objects_model->GetValue(valueOld, item, colName);
DataViewBitmapText bmpText; DataViewBitmapText bmpText;
bmpText << valueOld; bmpText << valueOld;
@ -3414,7 +3447,7 @@ void ObjectList::rename_item()
wxVariant value; wxVariant value;
value << bmpText; value << bmpText;
m_objects_model->SetValue(value, item, 0); m_objects_model->SetValue(value, item, colName);
m_objects_model->ItemChanged(item); m_objects_model->ItemChanged(item);
update_name_in_model(item); update_name_in_model(item);
@ -3455,9 +3488,10 @@ void ObjectList::msw_rescale()
// update min size !!! A width of control shouldn't be a wxDefaultCoord // update min size !!! A width of control shouldn't be a wxDefaultCoord
SetMinSize(wxSize(1, 15 * em)); SetMinSize(wxSize(1, 15 * em));
GetColumn(0)->SetWidth(19 * em); GetColumn(colName)->SetWidth(19 * em);
GetColumn(1)->SetWidth( 8 * em); GetColumn(colPrint)->SetWidth( 2 * em);
GetColumn(2)->SetWidth( 2 * em); GetColumn(colExtruder)->SetWidth( 8 * em);
GetColumn(colEditing)->SetWidth( 2 * em);
// rescale all icons, used by ObjectList // rescale all icons, used by ObjectList
msw_rescale_icons(); msw_rescale_icons();
@ -3478,18 +3512,18 @@ void ObjectList::msw_rescale()
void ObjectList::ItemValueChanged(wxDataViewEvent &event) void ObjectList::ItemValueChanged(wxDataViewEvent &event)
{ {
if (event.GetColumn() == 0) if (event.GetColumn() == colName)
update_name_in_model(event.GetItem()); update_name_in_model(event.GetItem());
else if (event.GetColumn() == 1) else if (event.GetColumn() == colExtruder)
update_extruder_in_config(event.GetItem()); update_extruder_in_config(event.GetItem());
} }
void ObjectList::OnEditingDone(wxDataViewEvent &event) void ObjectList::OnEditingDone(wxDataViewEvent &event)
{ {
if (event.GetColumn() != 0) if (event.GetColumn() != colName)
return; return;
const auto renderer = dynamic_cast<BitmapTextRenderer*>(GetColumn(0)->GetRenderer()); const auto renderer = dynamic_cast<BitmapTextRenderer*>(GetColumn(colName)->GetRenderer());
if (renderer->WasCanceled()) if (renderer->WasCanceled())
wxTheApp->CallAfter([this]{ wxTheApp->CallAfter([this]{
@ -3571,7 +3605,7 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const
/* We can change extruder for Object/Volume only. /* We can change extruder for Object/Volume only.
* So, if Instance is selected, get its Object item and change it * So, if Instance is selected, get its Object item and change it
*/ */
m_objects_model->SetValue(extruder_str, type & itInstance ? m_objects_model->GetTopParent(item) : item, 1); m_objects_model->SetValue(extruder_str, type & itInstance ? m_objects_model->GetTopParent(item) : item, colExtruder);
const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) : const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) :
m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
@ -3594,18 +3628,70 @@ void ObjectList::update_after_undo_redo()
m_objects_model->DeleteAll(); m_objects_model->DeleteAll();
size_t obj_idx = 0; size_t obj_idx = 0;
std::vector<size_t> obj_idxs;
obj_idxs.reserve(m_objects->size());
while (obj_idx < m_objects->size()) { while (obj_idx < m_objects->size()) {
add_object_to_list(obj_idx, false); add_object_to_list(obj_idx, false);
obj_idxs.push_back(obj_idx);
++obj_idx; ++obj_idx;
} }
#ifndef __WXOSX__
// selection_changed();
#endif /* __WXOSX__ */
update_selections(); update_selections();
m_prevent_canvas_selection_update = false; m_prevent_canvas_selection_update = false;
// update printable states on canvas
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_objects(obj_idxs);
// update scene
wxGetApp().plater()->update();
}
void ObjectList::update_printable_state(int obj_idx, int instance_idx)
{
ModelObject* object = (*m_objects)[obj_idx];
const PrintIndicator printable = object->instances[instance_idx]->printable ? piPrintable : piUnprintable;
if (object->instances.size() == 1)
instance_idx = -1;
m_objects_model->SetPrintableState(printable, obj_idx, instance_idx);
}
void ObjectList::toggle_printable_state(wxDataViewItem item)
{
const ItemType type = m_objects_model->GetItemType(item);
if (!(type&(itObject|itInstance/*|itVolume*/)))
return;
if (type & itObject)
{
const int obj_idx = m_objects_model->GetObjectIdByItem(item);
ModelObject* object = (*m_objects)[obj_idx];
// get object's printable and change it
const bool printable = !m_objects_model->IsPrintable(item);
const wxString snapshot_text = wxString::Format("%s %s",
printable ? _(L("Set Printable")) : _(L("Set Unprintable")),
object->name);
take_snapshot(snapshot_text);
// set printable value for all instances in object
for (auto inst : object->instances)
inst->printable = printable;
// update printable state on canvas
std::vector<size_t> obj_idxs = {(size_t)obj_idx};
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_objects(obj_idxs);
// update printable state in ObjectList
m_objects_model->SetObjectPrintableState(printable ? piPrintable : piUnprintable , item);
}
else
wxGetApp().plater()->canvas3D()->get_selection().toggle_instance_printable_state();
// update scene
wxGetApp().plater()->update();
} }
ModelObject* ObjectList::object(const int obj_idx) const ModelObject* ObjectList::object(const int obj_idx) const

View file

@ -225,6 +225,7 @@ public:
wxMenuItem* append_menu_item_settings(wxMenu* menu); wxMenuItem* append_menu_item_settings(wxMenu* menu);
wxMenuItem* append_menu_item_change_type(wxMenu* menu); wxMenuItem* append_menu_item_change_type(wxMenu* menu);
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent); wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent);
wxMenuItem* append_menu_item_printable(wxMenu* menu, wxWindow* parent);
void append_menu_items_osx(wxMenu* menu); void append_menu_items_osx(wxMenu* menu);
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu); wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
void append_menu_item_export_stl(wxMenu* menu) const ; void append_menu_item_export_stl(wxMenu* menu) const ;
@ -348,6 +349,9 @@ public:
void msw_rescale(); void msw_rescale();
void update_after_undo_redo(); void update_after_undo_redo();
//update printable state for item from objects model
void update_printable_state(int obj_idx, int instance_idx);
void toggle_printable_state(wxDataViewItem item);
private: private:
#ifdef __WXOSX__ #ifdef __WXOSX__

View file

@ -29,19 +29,21 @@ GLGizmoBase::Grabber::Grabber()
color[0] = 1.0f; color[0] = 1.0f;
color[1] = 1.0f; color[1] = 1.0f;
color[2] = 1.0f; color[2] = 1.0f;
color[3] = 1.0f;
} }
void GLGizmoBase::Grabber::render(bool hover, float size) const void GLGizmoBase::Grabber::render(bool hover, float size) const
{ {
float render_color[3]; float render_color[4];
if (hover) if (hover)
{ {
render_color[0] = 1.0f - color[0]; render_color[0] = 1.0f - color[0];
render_color[1] = 1.0f - color[1]; render_color[1] = 1.0f - color[1];
render_color[2] = 1.0f - color[2]; render_color[2] = 1.0f - color[2];
render_color[3] = color[3];
} }
else else
::memcpy((void*)render_color, (const void*)color, 3 * sizeof(float)); ::memcpy((void*)render_color, (const void*)color, 4 * sizeof(float));
render(size, render_color, true); render(size, render_color, true);
} }
@ -63,7 +65,7 @@ void GLGizmoBase::Grabber::render(float size, const float* render_color, bool us
if (use_lighting) if (use_lighting)
glsafe(::glEnable(GL_LIGHTING)); glsafe(::glEnable(GL_LIGHTING));
glsafe(::glColor3fv(render_color)); glsafe(::glColor4fv(render_color));
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslated(center(0), center(1), center(2))); glsafe(::glTranslated(center(0), center(1), center(2)));
@ -144,9 +146,9 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, u
, m_dragging(false) , m_dragging(false)
, m_imgui(wxGetApp().imgui()) , m_imgui(wxGetApp().imgui())
{ {
::memcpy((void*)m_base_color, (const void*)DEFAULT_BASE_COLOR, 3 * sizeof(float)); ::memcpy((void*)m_base_color, (const void*)DEFAULT_BASE_COLOR, 4 * sizeof(float));
::memcpy((void*)m_drag_color, (const void*)DEFAULT_DRAG_COLOR, 3 * sizeof(float)); ::memcpy((void*)m_drag_color, (const void*)DEFAULT_DRAG_COLOR, 4 * sizeof(float));
::memcpy((void*)m_highlight_color, (const void*)DEFAULT_HIGHLIGHT_COLOR, 3 * sizeof(float)); ::memcpy((void*)m_highlight_color, (const void*)DEFAULT_HIGHLIGHT_COLOR, 4 * sizeof(float));
} }
void GLGizmoBase::set_hover_id(int id) void GLGizmoBase::set_hover_id(int id)
@ -161,7 +163,7 @@ void GLGizmoBase::set_hover_id(int id)
void GLGizmoBase::set_highlight_color(const float* color) void GLGizmoBase::set_highlight_color(const float* color)
{ {
if (color != nullptr) if (color != nullptr)
::memcpy((void*)m_highlight_color, (const void*)color, 3 * sizeof(float)); ::memcpy((void*)m_highlight_color, (const void*)color, 4 * sizeof(float));
} }
void GLGizmoBase::enable_grabber(unsigned int id) void GLGizmoBase::enable_grabber(unsigned int id)
@ -210,7 +212,7 @@ void GLGizmoBase::update(const UpdateData& data)
on_update(data); on_update(data);
} }
std::array<float, 3> GLGizmoBase::picking_color_component(unsigned int id) const std::array<float, 4> GLGizmoBase::picking_color_component(unsigned int id) const
{ {
static const float INV_255 = 1.0f / 255.0f; static const float INV_255 = 1.0f / 255.0f;
@ -220,9 +222,12 @@ std::array<float, 3> GLGizmoBase::picking_color_component(unsigned int id) const
id -= m_group_id; id -= m_group_id;
// color components are encoded to match the calculation of volume_id made into GLCanvas3D::_picking_pass() // color components are encoded to match the calculation of volume_id made into GLCanvas3D::_picking_pass()
return std::array<float, 3> { (float)((id >> 0) & 0xff) * INV_255, // red return std::array<float, 4> {
(float)((id >> 8) & 0xff) * INV_255, // green float((id >> 0) & 0xff) * INV_255, // red
(float)((id >> 16) & 0xff) * INV_255 }; // blue float((id >> 8) & 0xff) * INV_255, // green
float((id >> 16) & 0xff) * INV_255, // blue
float(picking_checksum_alpha_channel(id & 0xff, (id >> 8) & 0xff, (id >> 16) & 0xff))* INV_255 // checksum for validating against unwanted alpha blending and multi sampling
};
} }
void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const
@ -247,10 +252,11 @@ void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const
{ {
if (m_grabbers[i].enabled) if (m_grabbers[i].enabled)
{ {
std::array<float, 3> color = picking_color_component(i); std::array<float, 4> color = picking_color_component(i);
m_grabbers[i].color[0] = color[0]; m_grabbers[i].color[0] = color[0];
m_grabbers[i].color[1] = color[1]; m_grabbers[i].color[1] = color[1];
m_grabbers[i].color[2] = color[2]; m_grabbers[i].color[2] = color[2];
m_grabbers[i].color[3] = color[3];
m_grabbers[i].render_for_picking(mean_size); m_grabbers[i].render_for_picking(mean_size);
} }
} }
@ -267,5 +273,20 @@ std::string GLGizmoBase::format(float value, unsigned int decimals) const
return Slic3r::string_printf("%.*f", decimals, value); return Slic3r::string_printf("%.*f", decimals, value);
} }
// Produce an alpha channel checksum for the red green blue components. The alpha channel may then be used to verify, whether the rgb components
// were not interpolated by alpha blending or multi sampling.
unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue)
{
// 8 bit hash for the color
unsigned char b = ((((37 * red) + green) & 0x0ff) * 37 + blue) & 0x0ff;
// Increase enthropy by a bit reversal
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
// Flip every second bit to increase the enthropy even more.
b ^= 0x55;
return b;
}
} // namespace GUI } // namespace GUI
} // namespace Slic3r } // namespace Slic3r

View file

@ -21,11 +21,11 @@ class ModelObject;
namespace GUI { namespace GUI {
static const float DEFAULT_BASE_COLOR[3] = { 0.625f, 0.625f, 0.625f }; static const float DEFAULT_BASE_COLOR[4] = { 0.625f, 0.625f, 0.625f, 1.0f };
static const float DEFAULT_DRAG_COLOR[3] = { 1.0f, 1.0f, 1.0f }; static const float DEFAULT_DRAG_COLOR[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
static const float DEFAULT_HIGHLIGHT_COLOR[3] = { 1.0f, 0.38f, 0.0f }; static const float DEFAULT_HIGHLIGHT_COLOR[4] = { 1.0f, 0.38f, 0.0f, 1.0f };
static const float AXES_COLOR[3][3] = { { 0.75f, 0.0f, 0.0f }, { 0.0f, 0.75f, 0.0f }, { 0.0f, 0.0f, 0.75f } }; static const float AXES_COLOR[][4] = { { 0.75f, 0.0f, 0.0f, 1.0f }, { 0.0f, 0.75f, 0.0f, 1.0f }, { 0.0f, 0.0f, 0.75f, 1.0f } };
static const float CONSTRAINED_COLOR[3] = { 0.5f, 0.5f, 0.5f }; static const float CONSTRAINED_COLOR[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
@ -48,7 +48,7 @@ protected:
Vec3d center; Vec3d center;
Vec3d angles; Vec3d angles;
float color[3]; float color[4];
bool enabled; bool enabled;
bool dragging; bool dragging;
@ -94,9 +94,9 @@ protected:
unsigned int m_sprite_id; unsigned int m_sprite_id;
int m_hover_id; int m_hover_id;
bool m_dragging; bool m_dragging;
float m_base_color[3]; float m_base_color[4];
float m_drag_color[3]; float m_drag_color[4];
float m_highlight_color[3]; float m_highlight_color[4];
mutable std::vector<Grabber> m_grabbers; mutable std::vector<Grabber> m_grabbers;
ImGuiWrapper* m_imgui; ImGuiWrapper* m_imgui;
@ -166,7 +166,7 @@ protected:
// Returns the picking color for the given id, based on the BASE_ID constant // Returns the picking color for the given id, based on the BASE_ID constant
// No check is made for clashing with other picking color (i.e. GLVolumes) // No check is made for clashing with other picking color (i.e. GLVolumes)
std::array<float, 3> picking_color_component(unsigned int id) const; std::array<float, 4> picking_color_component(unsigned int id) const;
void render_grabbers(const BoundingBoxf3& box) const; void render_grabbers(const BoundingBoxf3& box) const;
void render_grabbers(float size) const; void render_grabbers(float size) const;
void render_grabbers_for_picking(const BoundingBoxf3& box) const; void render_grabbers_for_picking(const BoundingBoxf3& box) const;
@ -175,6 +175,10 @@ protected:
std::string format(float value, unsigned int decimals) const; std::string format(float value, unsigned int decimals) const;
}; };
// Produce an alpha channel checksum for the red green blue components. The alpha channel may then be used to verify, whether the rgb components
// were not interpolated by alpha blending or multi sampling.
extern unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue);
} // namespace GUI } // namespace GUI
} // namespace Slic3r } // namespace Slic3r

View file

@ -17,7 +17,7 @@ namespace GUI {
const double GLGizmoCut::Offset = 10.0; const double GLGizmoCut::Offset = 10.0;
const double GLGizmoCut::Margin = 20.0; const double GLGizmoCut::Margin = 20.0;
const std::array<float, 3> GLGizmoCut::GrabberColor = { 1.0, 0.5, 0.0 }; const std::array<float, 4> GLGizmoCut::GrabberColor = { 1.0, 0.5, 0.0, 1.0 };
GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoBase(parent, icon_filename, sprite_id) : GLGizmoBase(parent, icon_filename, sprite_id)

View file

@ -11,7 +11,7 @@ class GLGizmoCut : public GLGizmoBase
{ {
static const double Offset; static const double Offset;
static const double Margin; static const double Margin;
static const std::array<float, 3> GrabberColor; static const std::array<float, 4> GrabberColor;
mutable double m_cut_z; mutable double m_cut_z;
double m_start_z; double m_start_z;

View file

@ -115,7 +115,7 @@ void GLGizmoFlatten::on_render_for_picking() const
const_cast<GLGizmoFlatten*>(this)->update_planes(); const_cast<GLGizmoFlatten*>(this)->update_planes();
for (int i = 0; i < (int)m_planes.size(); ++i) for (int i = 0; i < (int)m_planes.size(); ++i)
{ {
glsafe(::glColor3fv(picking_color_component(i).data())); glsafe(::glColor4fv(picking_color_component(i).data()));
::glBegin(GL_POLYGON); ::glBegin(GL_POLYGON);
for (const Vec3d& vertex : m_planes[i].vertices) for (const Vec3d& vertex : m_planes[i].vertices)
{ {

View file

@ -104,15 +104,15 @@ void GLGizmoMove3D::on_render() const
// x axis // x axis
m_grabbers[0].center = Vec3d(box.max(0) + Offset, center(1), center(2)); m_grabbers[0].center = Vec3d(box.max(0) + Offset, center(1), center(2));
::memcpy((void*)m_grabbers[0].color, (const void*)&AXES_COLOR[0], 3 * sizeof(float)); ::memcpy((void*)m_grabbers[0].color, (const void*)&AXES_COLOR[0], 4 * sizeof(float));
// y axis // y axis
m_grabbers[1].center = Vec3d(center(0), box.max(1) + Offset, center(2)); m_grabbers[1].center = Vec3d(center(0), box.max(1) + Offset, center(2));
::memcpy((void*)m_grabbers[1].color, (const void*)&AXES_COLOR[1], 3 * sizeof(float)); ::memcpy((void*)m_grabbers[1].color, (const void*)&AXES_COLOR[1], 4 * sizeof(float));
// z axis // z axis
m_grabbers[2].center = Vec3d(center(0), center(1), box.max(2) + Offset); m_grabbers[2].center = Vec3d(center(0), center(1), box.max(2) + Offset);
::memcpy((void*)m_grabbers[2].color, (const void*)&AXES_COLOR[2], 3 * sizeof(float)); ::memcpy((void*)m_grabbers[2].color, (const void*)&AXES_COLOR[2], 4 * sizeof(float));
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
@ -123,7 +123,7 @@ void GLGizmoMove3D::on_render() const
{ {
if (m_grabbers[i].enabled) if (m_grabbers[i].enabled)
{ {
glsafe(::glColor3fv(AXES_COLOR[i])); glsafe(::glColor4fv(AXES_COLOR[i]));
::glBegin(GL_LINES); ::glBegin(GL_LINES);
::glVertex3dv(center.data()); ::glVertex3dv(center.data());
::glVertex3dv(m_grabbers[i].center.data()); ::glVertex3dv(m_grabbers[i].center.data());
@ -142,7 +142,7 @@ void GLGizmoMove3D::on_render() const
else else
{ {
// draw axis // draw axis
glsafe(::glColor3fv(AXES_COLOR[m_hover_id])); glsafe(::glColor4fv(AXES_COLOR[m_hover_id]));
::glBegin(GL_LINES); ::glBegin(GL_LINES);
::glVertex3dv(center.data()); ::glVertex3dv(center.data());
::glVertex3dv(m_grabbers[m_hover_id].center.data()); ::glVertex3dv(m_grabbers[m_hover_id].center.data());
@ -220,19 +220,20 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box
float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0);
double size = m_dragging ? (double)m_grabbers[axis].get_dragging_half_size(mean_size) : (double)m_grabbers[axis].get_half_size(mean_size); double size = m_dragging ? (double)m_grabbers[axis].get_dragging_half_size(mean_size) : (double)m_grabbers[axis].get_half_size(mean_size);
float color[3]; float color[4];
::memcpy((void*)color, (const void*)m_grabbers[axis].color, 3 * sizeof(float)); ::memcpy((void*)color, (const void*)m_grabbers[axis].color, 4 * sizeof(float));
if (!picking && (m_hover_id != -1)) if (!picking && (m_hover_id != -1))
{ {
color[0] = 1.0f - color[0]; color[0] = 1.0f - color[0];
color[1] = 1.0f - color[1]; color[1] = 1.0f - color[1];
color[2] = 1.0f - color[2]; color[2] = 1.0f - color[2];
color[3] = color[3];
} }
if (!picking) if (!picking)
glsafe(::glEnable(GL_LIGHTING)); glsafe(::glEnable(GL_LIGHTING));
glsafe(::glColor3fv(color)); glsafe(::glColor4fv(color));
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslated(m_grabbers[axis].center(0), m_grabbers[axis].center(1), m_grabbers[axis].center(2))); glsafe(::glTranslated(m_grabbers[axis].center(0), m_grabbers[axis].center(1), m_grabbers[axis].center(2)));
if (axis == X) if (axis == X)

View file

@ -155,7 +155,7 @@ void GLGizmoRotate::on_render() const
transform_to_local(selection); transform_to_local(selection);
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f)); glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
glsafe(::glColor3fv((m_hover_id != -1) ? m_drag_color : m_highlight_color)); glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color : m_highlight_color));
render_circle(); render_circle();
@ -166,7 +166,7 @@ void GLGizmoRotate::on_render() const
render_reference_radius(); render_reference_radius();
} }
glsafe(::glColor3fv(m_highlight_color)); glsafe(::glColor4fv(m_highlight_color));
if (m_hover_id != -1) if (m_hover_id != -1)
render_angle(); render_angle();
@ -287,14 +287,14 @@ void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const
m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0); m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0);
m_grabbers[0].angles(2) = m_angle; m_grabbers[0].angles(2) = m_angle;
glsafe(::glColor3fv((m_hover_id != -1) ? m_drag_color : m_highlight_color)); glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color : m_highlight_color));
::glBegin(GL_LINES); ::glBegin(GL_LINES);
::glVertex3f(0.0f, 0.0f, 0.0f); ::glVertex3f(0.0f, 0.0f, 0.0f);
::glVertex3dv(m_grabbers[0].center.data()); ::glVertex3dv(m_grabbers[0].center.data());
glsafe(::glEnd()); glsafe(::glEnd());
::memcpy((void*)m_grabbers[0].color, (const void*)m_highlight_color, 3 * sizeof(float)); ::memcpy((void*)m_grabbers[0].color, (const void*)m_highlight_color, 4 * sizeof(float));
render_grabbers(box); render_grabbers(box);
} }
@ -306,8 +306,8 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick
float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0); float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0);
double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size); double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size);
float color[3]; float color[4];
::memcpy((void*)color, (const void*)m_grabbers[0].color, 3 * sizeof(float)); ::memcpy((void*)color, (const void*)m_grabbers[0].color, 4 * sizeof(float));
if (!picking && (m_hover_id != -1)) if (!picking && (m_hover_id != -1))
{ {
color[0] = 1.0f - color[0]; color[0] = 1.0f - color[0];
@ -318,7 +318,7 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick
if (!picking) if (!picking)
glsafe(::glEnable(GL_LIGHTING)); glsafe(::glEnable(GL_LIGHTING));
glsafe(::glColor3fv(color)); glsafe(::glColor4fv(color));
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glTranslated(m_grabbers[0].center(0), m_grabbers[0].center(1), m_grabbers[0].center(2))); glsafe(::glTranslated(m_grabbers[0].center(0), m_grabbers[0].center(1), m_grabbers[0].center(2)));
glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0)); glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0));

View file

@ -172,20 +172,20 @@ void GLGizmoScale3D::on_render() const
// x axis // x axis
m_grabbers[0].center = m_transform * Vec3d(m_box.min(0), center(1), center(2)) - offset_x; m_grabbers[0].center = m_transform * Vec3d(m_box.min(0), center(1), center(2)) - offset_x;
m_grabbers[1].center = m_transform * Vec3d(m_box.max(0), center(1), center(2)) + offset_x; m_grabbers[1].center = m_transform * Vec3d(m_box.max(0), center(1), center(2)) + offset_x;
::memcpy((void*)m_grabbers[0].color, (ctrl_down && (m_hover_id == 1)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[0], 3 * sizeof(float)); ::memcpy((void*)m_grabbers[0].color, (ctrl_down && (m_hover_id == 1)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[0], 4 * sizeof(float));
::memcpy((void*)m_grabbers[1].color, (ctrl_down && (m_hover_id == 0)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[0], 3 * sizeof(float)); ::memcpy((void*)m_grabbers[1].color, (ctrl_down && (m_hover_id == 0)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[0], 4 * sizeof(float));
// y axis // y axis
m_grabbers[2].center = m_transform * Vec3d(center(0), m_box.min(1), center(2)) - offset_y; m_grabbers[2].center = m_transform * Vec3d(center(0), m_box.min(1), center(2)) - offset_y;
m_grabbers[3].center = m_transform * Vec3d(center(0), m_box.max(1), center(2)) + offset_y; m_grabbers[3].center = m_transform * Vec3d(center(0), m_box.max(1), center(2)) + offset_y;
::memcpy((void*)m_grabbers[2].color, (ctrl_down && (m_hover_id == 3)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[1], 3 * sizeof(float)); ::memcpy((void*)m_grabbers[2].color, (ctrl_down && (m_hover_id == 3)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[1], 4 * sizeof(float));
::memcpy((void*)m_grabbers[3].color, (ctrl_down && (m_hover_id == 2)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[1], 3 * sizeof(float)); ::memcpy((void*)m_grabbers[3].color, (ctrl_down && (m_hover_id == 2)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[1], 4 * sizeof(float));
// z axis // z axis
m_grabbers[4].center = m_transform * Vec3d(center(0), center(1), m_box.min(2)) - offset_z; m_grabbers[4].center = m_transform * Vec3d(center(0), center(1), m_box.min(2)) - offset_z;
m_grabbers[5].center = m_transform * Vec3d(center(0), center(1), m_box.max(2)) + offset_z; m_grabbers[5].center = m_transform * Vec3d(center(0), center(1), m_box.max(2)) + offset_z;
::memcpy((void*)m_grabbers[4].color, (ctrl_down && (m_hover_id == 5)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[2], 3 * sizeof(float)); ::memcpy((void*)m_grabbers[4].color, (ctrl_down && (m_hover_id == 5)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[2], 4 * sizeof(float));
::memcpy((void*)m_grabbers[5].color, (ctrl_down && (m_hover_id == 4)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[2], 3 * sizeof(float)); ::memcpy((void*)m_grabbers[5].color, (ctrl_down && (m_hover_id == 4)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[2], 4 * sizeof(float));
// uniform // uniform
m_grabbers[6].center = m_transform * Vec3d(m_box.min(0), m_box.min(1), center(2)) - offset_x - offset_y; m_grabbers[6].center = m_transform * Vec3d(m_box.min(0), m_box.min(1), center(2)) - offset_x - offset_y;
@ -194,7 +194,7 @@ void GLGizmoScale3D::on_render() const
m_grabbers[9].center = m_transform * Vec3d(m_box.min(0), m_box.max(1), center(2)) - offset_x + offset_y; m_grabbers[9].center = m_transform * Vec3d(m_box.min(0), m_box.max(1), center(2)) - offset_x + offset_y;
for (int i = 6; i < 10; ++i) for (int i = 6; i < 10; ++i)
{ {
::memcpy((void*)m_grabbers[i].color, (const void*)m_highlight_color, 3 * sizeof(float)); ::memcpy((void*)m_grabbers[i].color, (const void*)m_highlight_color, 4 * sizeof(float));
} }
// sets grabbers orientation // sets grabbers orientation
@ -214,20 +214,20 @@ void GLGizmoScale3D::on_render() const
// draw connections // draw connections
if (m_grabbers[0].enabled && m_grabbers[1].enabled) if (m_grabbers[0].enabled && m_grabbers[1].enabled)
{ {
glsafe(::glColor3fv(m_grabbers[0].color)); glsafe(::glColor4fv(m_grabbers[0].color));
render_grabbers_connection(0, 1); render_grabbers_connection(0, 1);
} }
if (m_grabbers[2].enabled && m_grabbers[3].enabled) if (m_grabbers[2].enabled && m_grabbers[3].enabled)
{ {
glsafe(::glColor3fv(m_grabbers[2].color)); glsafe(::glColor4fv(m_grabbers[2].color));
render_grabbers_connection(2, 3); render_grabbers_connection(2, 3);
} }
if (m_grabbers[4].enabled && m_grabbers[5].enabled) if (m_grabbers[4].enabled && m_grabbers[5].enabled)
{ {
glsafe(::glColor3fv(m_grabbers[4].color)); glsafe(::glColor4fv(m_grabbers[4].color));
render_grabbers_connection(4, 5); render_grabbers_connection(4, 5);
} }
glsafe(::glColor3fv(m_base_color)); glsafe(::glColor4fv(m_base_color));
render_grabbers_connection(6, 7); render_grabbers_connection(6, 7);
render_grabbers_connection(7, 8); render_grabbers_connection(7, 8);
render_grabbers_connection(8, 9); render_grabbers_connection(8, 9);
@ -238,7 +238,7 @@ void GLGizmoScale3D::on_render() const
else if ((m_hover_id == 0) || (m_hover_id == 1)) else if ((m_hover_id == 0) || (m_hover_id == 1))
{ {
// draw connection // draw connection
glsafe(::glColor3fv(m_grabbers[0].color)); glsafe(::glColor4fv(m_grabbers[0].color));
render_grabbers_connection(0, 1); render_grabbers_connection(0, 1);
// draw grabbers // draw grabbers
m_grabbers[0].render(true, grabber_mean_size); m_grabbers[0].render(true, grabber_mean_size);
@ -247,7 +247,7 @@ void GLGizmoScale3D::on_render() const
else if ((m_hover_id == 2) || (m_hover_id == 3)) else if ((m_hover_id == 2) || (m_hover_id == 3))
{ {
// draw connection // draw connection
glsafe(::glColor3fv(m_grabbers[2].color)); glsafe(::glColor4fv(m_grabbers[2].color));
render_grabbers_connection(2, 3); render_grabbers_connection(2, 3);
// draw grabbers // draw grabbers
m_grabbers[2].render(true, grabber_mean_size); m_grabbers[2].render(true, grabber_mean_size);
@ -256,7 +256,7 @@ void GLGizmoScale3D::on_render() const
else if ((m_hover_id == 4) || (m_hover_id == 5)) else if ((m_hover_id == 4) || (m_hover_id == 5))
{ {
// draw connection // draw connection
glsafe(::glColor3fv(m_grabbers[4].color)); glsafe(::glColor4fv(m_grabbers[4].color));
render_grabbers_connection(4, 5); render_grabbers_connection(4, 5);
// draw grabbers // draw grabbers
m_grabbers[4].render(true, grabber_mean_size); m_grabbers[4].render(true, grabber_mean_size);
@ -265,7 +265,7 @@ void GLGizmoScale3D::on_render() const
else if (m_hover_id >= 6) else if (m_hover_id >= 6)
{ {
// draw connection // draw connection
glsafe(::glColor3fv(m_drag_color)); glsafe(::glColor4fv(m_drag_color));
render_grabbers_connection(6, 7); render_grabbers_connection(6, 7);
render_grabbers_connection(7, 8); render_grabbers_connection(7, 8);
render_grabbers_connection(8, 9); render_grabbers_connection(8, 9);

View file

@ -286,7 +286,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
glsafe(::glTranslated(0.0, 0.0, m_z_shift)); glsafe(::glTranslated(0.0, 0.0, m_z_shift));
glsafe(::glMultMatrixd(instance_matrix.data())); glsafe(::glMultMatrixd(instance_matrix.data()));
float render_color[3]; float render_color[4];
size_t cache_size = m_editing_mode ? m_editing_cache.size() : m_normal_cache.size(); size_t cache_size = m_editing_mode ? m_editing_cache.size() : m_normal_cache.size();
for (size_t i = 0; i < cache_size; ++i) for (size_t i = 0; i < cache_size; ++i)
{ {
@ -298,12 +298,14 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
// First decide about the color of the point. // First decide about the color of the point.
if (picking) { if (picking) {
std::array<float, 3> color = picking_color_component(i); std::array<float, 4> color = picking_color_component(i);
render_color[0] = color[0]; render_color[0] = color[0];
render_color[1] = color[1]; render_color[1] = color[1];
render_color[2] = color[2]; render_color[2] = color[2];
render_color[3] = color[3];
} }
else { else {
render_color[3] = 1.f;
if ((m_hover_id == i && m_editing_mode)) { // ignore hover state unless editing mode is active if ((m_hover_id == i && m_editing_mode)) { // ignore hover state unless editing mode is active
render_color[0] = 0.f; render_color[0] = 0.f;
render_color[1] = 1.0f; render_color[1] = 1.0f;
@ -320,7 +322,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
for (unsigned char i=0; i<3; ++i) render_color[i] = 0.5f; for (unsigned char i=0; i<3; ++i) render_color[i] = 0.5f;
} }
} }
glsafe(::glColor3fv(render_color)); glsafe(::glColor4fv(render_color));
float render_color_emissive[4] = { 0.5f * render_color[0], 0.5f * render_color[1], 0.5f * render_color[2], 1.f}; float render_color_emissive[4] = { 0.5f * render_color[0], 0.5f * render_color[1], 0.5f * render_color[2], 1.f};
glsafe(::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive)); glsafe(::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive));

View file

@ -2342,6 +2342,9 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
// automatic selection of added objects // automatic selection of added objects
if (!obj_idxs.empty() && (view3D != nullptr)) if (!obj_idxs.empty() && (view3D != nullptr))
{ {
// update printable state for new volumes on canvas3D
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_objects(obj_idxs);
Selection& selection = view3D->get_canvas3d()->get_selection(); Selection& selection = view3D->get_canvas3d()->get_selection();
selection.clear(); selection.clear();
for (size_t idx : obj_idxs) for (size_t idx : obj_idxs)
@ -3506,6 +3509,9 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/
sidebar->obj_list()->append_menu_item_instance_to_object(menu, q); sidebar->obj_list()->append_menu_item_instance_to_object(menu, q);
menu->AppendSeparator(); menu->AppendSeparator();
wxMenuItem* menu_item_printable = sidebar->obj_list()->append_menu_item_printable(menu, q);
menu->AppendSeparator();
append_menu_item(menu, wxID_ANY, _(L("Reload from Disk")), _(L("Reload the selected file from Disk")), append_menu_item(menu, wxID_ANY, _(L("Reload from Disk")), _(L("Reload the selected file from Disk")),
[this](wxCommandEvent&) { reload_from_disk(); }); [this](wxCommandEvent&) { reload_from_disk(); });
@ -3513,6 +3519,17 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/
[this](wxCommandEvent&) { q->export_stl(false, true); }); [this](wxCommandEvent&) { q->export_stl(false, true); });
menu->AppendSeparator(); menu->AppendSeparator();
q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) {
const Selection& selection = get_selection();
int instance_idx = selection.get_instance_idx();
evt.Enable(instance_idx != -1);
if (instance_idx != -1)
{
evt.Check(model.objects[selection.get_object_idx()]->instances[instance_idx]->printable);
view3D->set_as_dirty();
}
}, menu_item_printable->GetId());
} }
sidebar->obj_list()->append_menu_item_fix_through_netfabb(menu); sidebar->obj_list()->append_menu_item_fix_through_netfabb(menu);

View file

@ -1462,6 +1462,32 @@ std::vector<unsigned int> Selection::get_unselected_volume_idxs_from(const std::
return idxs; return idxs;
} }
void Selection::toggle_instance_printable_state()
{
int instance_idx = get_instance_idx();
if (instance_idx == -1)
return;
int obj_idx = get_object_idx();
if ((0 <= obj_idx) && (obj_idx < (int)m_model->objects.size()))
{
ModelObject* model_object = m_model->objects[obj_idx];
if ((0 <= instance_idx) && (instance_idx < (int)model_object->instances.size()))
{
ModelInstance* instance = model_object->instances[instance_idx];
instance->printable = !instance->printable;
for (GLVolume* volume : *m_volumes)
{
if ((volume->object_idx() == obj_idx) && (volume->instance_idx() == instance_idx))
volume->printable = instance->printable;
}
wxGetApp().obj_list()->update_printable_state(obj_idx, instance_idx);
}
}
}
void Selection::update_valid() void Selection::update_valid()
{ {
m_valid = (m_volumes != nullptr) && (m_model != nullptr); m_valid = (m_volumes != nullptr) && (m_model != nullptr);

View file

@ -336,6 +336,8 @@ public:
// returns the list of idxs of the volumes contained in the given list but not in the selection // returns the list of idxs of the volumes contained in the given list but not in the selection
std::vector<unsigned int> get_unselected_volume_idxs_from(const std::vector<unsigned int>& volume_idxs) const; std::vector<unsigned int> get_unselected_volume_idxs_from(const std::vector<unsigned int>& volume_idxs) const;
void toggle_instance_printable_state();
private: private:
void update_valid(); void update_valid();
void update_type(); void update_type();

View file

@ -157,6 +157,24 @@ wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string,
return item; return item;
} }
wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler)
{
if (id == wxID_ANY)
id = wxNewId();
wxMenuItem* item = menu->AppendCheckItem(id, string, description);
#ifdef __WXMSW__
if (event_handler != nullptr && event_handler != menu)
event_handler->Bind(wxEVT_MENU, cb, id);
else
#endif // __WXMSW__
menu->Bind(wxEVT_MENU, cb, id);
return item;
}
const unsigned int wxCheckListBoxComboPopup::DefaultWidth = 200; const unsigned int wxCheckListBoxComboPopup::DefaultWidth = 200;
const unsigned int wxCheckListBoxComboPopup::DefaultHeight = 200; const unsigned int wxCheckListBoxComboPopup::DefaultHeight = 200;
const unsigned int wxCheckListBoxComboPopup::DefaultItemHeight = 18; const unsigned int wxCheckListBoxComboPopup::DefaultItemHeight = 18;
@ -432,6 +450,16 @@ wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in,
// ObjectDataViewModelNode // ObjectDataViewModelNode
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
void ObjectDataViewModelNode::init_container()
{
#ifdef __WXGTK__
// it's necessary on GTK because of control have to know if this item will be container
// in another case you couldn't to add subitem for this item
// it will be produce "segmentation fault"
m_container = true;
#endif //__WXGTK__
}
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type) : ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type) :
m_parent(parent), m_parent(parent),
m_type(type), m_type(type),
@ -454,13 +482,8 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
m_name = _(L("Layers")); m_name = _(L("Layers"));
} }
#ifdef __WXGTK__
// it's necessary on GTK because of control have to know if this item will be container
// in another case you couldn't to add subitem for this item
// it will be produce "segmentation fault"
if (type & (itInstanceRoot | itLayerRoot)) if (type & (itInstanceRoot | itLayerRoot))
m_container = true; init_container();
#endif //__WXGTK__
} }
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
@ -486,14 +509,8 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")"; m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
m_bmp = create_scaled_bitmap(nullptr, "edit_layers_some"); // FIXME: pass window ptr m_bmp = create_scaled_bitmap(nullptr, "edit_layers_some"); // FIXME: pass window ptr
#ifdef __WXGTK__
// it's necessary on GTK because of control have to know if this item will be container
// in another case you couldn't to add subitem for this item
// it will be produce "segmentation fault"
m_container = true;
#endif //__WXGTK__
set_action_icon(); set_action_icon();
init_container();
} }
#ifndef NDEBUG #ifndef NDEBUG
@ -512,6 +529,13 @@ void ObjectDataViewModelNode::set_action_icon()
m_action_icon = create_scaled_bitmap(nullptr, m_action_icon_name); // FIXME: pass window ptr m_action_icon = create_scaled_bitmap(nullptr, m_action_icon_name); // FIXME: pass window ptr
} }
void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable)
{
m_printable = printable;
m_printable_icon = m_printable == piUndef ? m_empty_bmp :
create_scaled_bitmap(nullptr, m_printable == piPrintable ? "eye_open.png" : "eye_closed.png");
}
Slic3r::GUI::BitmapCache *m_bitmap_cache = nullptr; Slic3r::GUI::BitmapCache *m_bitmap_cache = nullptr;
void ObjectDataViewModelNode::update_settings_digest_bitmaps() void ObjectDataViewModelNode::update_settings_digest_bitmaps()
{ {
@ -565,17 +589,20 @@ bool ObjectDataViewModelNode::SetValue(const wxVariant& variant, unsigned col)
{ {
switch (col) switch (col)
{ {
case 0: { case colPrint:
m_printable_icon << variant;
return true;
case colName: {
DataViewBitmapText data; DataViewBitmapText data;
data << variant; data << variant;
m_bmp = data.GetBitmap(); m_bmp = data.GetBitmap();
m_name = data.GetText(); m_name = data.GetText();
return true; } return true; }
case 1: { case colExtruder: {
const wxString & val = variant.GetString(); const wxString & val = variant.GetString();
m_extruder = val == "0" ? _(L("default")) : val; m_extruder = val == "0" ? _(L("default")) : val;
return true; } return true; }
case 2: case colEditing:
m_action_icon << variant; m_action_icon << variant;
return true; return true;
default: default:
@ -735,26 +762,52 @@ static bool append_root_node(ObjectDataViewModelNode *parent_node,
return false; return false;
} }
wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num) wxDataViewItem ObjectDataViewModel::AddRoot(const wxDataViewItem &parent_item, ItemType root_type)
{ {
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID(); ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
if (!parent_node) return wxDataViewItem(0); if (!parent_node) return wxDataViewItem(0);
// get InstanceRoot node // get InstanceRoot node
ObjectDataViewModelNode *inst_root_node { nullptr }; ObjectDataViewModelNode *root_node { nullptr };
const bool appended = append_root_node(parent_node, &root_node, root_type);
if (!root_node) return wxDataViewItem(0);
const bool appended = append_root_node(parent_node, &inst_root_node, itInstanceRoot); const wxDataViewItem root_item((void*)root_node);
const wxDataViewItem inst_root_item((void*)inst_root_node);
if (!inst_root_node) return wxDataViewItem(0);
if (appended) if (appended)
ItemAdded(parent_item, inst_root_item);// notify control ItemAdded(parent_item, root_item);// notify control
return root_item;
}
wxDataViewItem ObjectDataViewModel::AddInstanceRoot(const wxDataViewItem &parent_item)
{
return AddRoot(parent_item, itInstanceRoot);
}
wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num)
{
const std::vector<bool> print_indicator(num, true);
return wxDataViewItem((void*)AddInstanceChild(parent_item, print_indicator));
}
wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem& parent_item,
const std::vector<bool>& print_indicator)
{
const wxDataViewItem inst_root_item = AddInstanceRoot(parent_item);
if (!inst_root_item) return wxDataViewItem(0);
ObjectDataViewModelNode* inst_root_node = (ObjectDataViewModelNode*)inst_root_item.GetID();
const bool just_created = inst_root_node->GetChildren().Count() == 0;
// Add instance nodes // Add instance nodes
ObjectDataViewModelNode *instance_node = nullptr; ObjectDataViewModelNode *instance_node = nullptr;
size_t counter = 0; size_t counter = 0;
while (counter < num) { while (counter < print_indicator.size()) {
instance_node = new ObjectDataViewModelNode(inst_root_node, itInstance); instance_node = new ObjectDataViewModelNode(inst_root_node, itInstance);
instance_node->set_printable_icon(print_indicator[counter] ? piPrintable : piUnprintable);
inst_root_node->Append(instance_node); inst_root_node->Append(instance_node);
// notify control // notify control
const wxDataViewItem instance_item((void*)instance_node); const wxDataViewItem instance_item((void*)instance_node);
@ -762,25 +815,67 @@ wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &paren
++counter; ++counter;
} }
// update object_node printable property
UpdateObjectPrintable(parent_item);
return wxDataViewItem((void*)instance_node); return wxDataViewItem((void*)instance_node);
} }
void ObjectDataViewModel::UpdateObjectPrintable(wxDataViewItem parent_item)
{
const wxDataViewItem inst_root_item = GetInstanceRootItem(parent_item);
if (!inst_root_item)
return;
ObjectDataViewModelNode* inst_root_node = (ObjectDataViewModelNode*)inst_root_item.GetID();
const size_t child_cnt = inst_root_node->GetChildren().Count();
PrintIndicator obj_pi = piUnprintable;
for (size_t i=0; i < child_cnt; i++)
if (inst_root_node->GetNthChild(i)->IsPrintable() & piPrintable) {
obj_pi = piPrintable;
break;
}
// and set printable state for object_node to piUndef
ObjectDataViewModelNode* obj_node = (ObjectDataViewModelNode*)parent_item.GetID();
obj_node->set_printable_icon(obj_pi);
ItemChanged(parent_item);
}
// update printable property for all instances from object
void ObjectDataViewModel::UpdateInstancesPrintable(wxDataViewItem parent_item)
{
const wxDataViewItem inst_root_item = GetInstanceRootItem(parent_item);
if (!inst_root_item)
return;
ObjectDataViewModelNode* obj_node = (ObjectDataViewModelNode*)parent_item.GetID();
const PrintIndicator obj_pi = obj_node->IsPrintable();
ObjectDataViewModelNode* inst_root_node = (ObjectDataViewModelNode*)inst_root_item.GetID();
const size_t child_cnt = inst_root_node->GetChildren().Count();
for (size_t i=0; i < child_cnt; i++)
{
ObjectDataViewModelNode* inst_node = inst_root_node->GetNthChild(i);
// and set printable state for object_node to piUndef
inst_node->set_printable_icon(obj_pi);
ItemChanged(wxDataViewItem((void*)inst_node));
}
}
bool ObjectDataViewModel::IsPrintable(const wxDataViewItem& item) const
{
ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID();
if (!node)
return false;
return node->IsPrintable() == piPrintable;
}
wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_item) wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_item)
{ {
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID(); return AddRoot(parent_item, itLayerRoot);
if (!parent_node) return wxDataViewItem(0);
// get LayerRoot node
ObjectDataViewModelNode *layer_root_node{ nullptr };
const bool appended = append_root_node(parent_node, &layer_root_node, itLayerRoot);
if (!layer_root_node) return wxDataViewItem(0);
const wxDataViewItem layer_root_item((void*)layer_root_node);
if (appended)
ItemAdded(parent_item, layer_root_item);// notify control
return layer_root_item;
} }
wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item, wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item,
@ -878,11 +973,13 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
ItemDeleted(parent, item); ItemDeleted(parent, item);
ObjectDataViewModelNode *last_instance_node = node_parent->GetNthChild(0); ObjectDataViewModelNode *last_instance_node = node_parent->GetNthChild(0);
PrintIndicator last_instance_printable = last_instance_node->IsPrintable();
node_parent->GetChildren().Remove(last_instance_node); node_parent->GetChildren().Remove(last_instance_node);
delete last_instance_node; delete last_instance_node;
ItemDeleted(parent, wxDataViewItem(last_instance_node)); ItemDeleted(parent, wxDataViewItem(last_instance_node));
ObjectDataViewModelNode *obj_node = node_parent->GetParent(); ObjectDataViewModelNode *obj_node = node_parent->GetParent();
obj_node->set_printable_icon(last_instance_printable);
obj_node->GetChildren().Remove(node_parent); obj_node->GetChildren().Remove(node_parent);
delete node_parent; delete node_parent;
ret_item = wxDataViewItem(obj_node); ret_item = wxDataViewItem(obj_node);
@ -895,6 +992,9 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
return ret_item; return ret_item;
} }
if (node->m_type & itInstance)
UpdateObjectPrintable(wxDataViewItem(node_parent->GetParent()));
// if there was last layer item, delete this one and layers root item // if there was last layer item, delete this one and layers root item
if (node_parent->GetChildCount() == 0 && node_parent->m_type == itLayerRoot) if (node_parent->GetChildCount() == 0 && node_parent->m_type == itLayerRoot)
{ {
@ -1004,9 +1104,12 @@ wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &par
const int inst_cnt = inst_root_node->GetChildCount(); const int inst_cnt = inst_root_node->GetChildCount();
const bool delete_inst_root_item = inst_cnt - num < 2 ? true : false; const bool delete_inst_root_item = inst_cnt - num < 2 ? true : false;
PrintIndicator last_inst_printable = piUndef;
int stop = delete_inst_root_item ? 0 : inst_cnt - num; int stop = delete_inst_root_item ? 0 : inst_cnt - num;
for (int i = inst_cnt - 1; i >= stop;--i) { for (int i = inst_cnt - 1; i >= stop;--i) {
ObjectDataViewModelNode *last_instance_node = inst_root_node->GetNthChild(i); ObjectDataViewModelNode *last_instance_node = inst_root_node->GetNthChild(i);
if (i==0) last_inst_printable = last_instance_node->IsPrintable();
inst_root_node->GetChildren().Remove(last_instance_node); inst_root_node->GetChildren().Remove(last_instance_node);
delete last_instance_node; delete last_instance_node;
ItemDeleted(inst_root_item, wxDataViewItem(last_instance_node)); ItemDeleted(inst_root_item, wxDataViewItem(last_instance_node));
@ -1015,13 +1118,18 @@ wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &par
if (delete_inst_root_item) { if (delete_inst_root_item) {
ret_item = parent_item; ret_item = parent_item;
parent_node->GetChildren().Remove(inst_root_node); parent_node->GetChildren().Remove(inst_root_node);
parent_node->set_printable_icon(last_inst_printable);
ItemDeleted(parent_item, inst_root_item); ItemDeleted(parent_item, inst_root_item);
ItemChanged(parent_item);
#ifndef __WXGTK__ #ifndef __WXGTK__
if (parent_node->GetChildCount() == 0) if (parent_node->GetChildCount() == 0)
parent_node->m_container = false; parent_node->m_container = false;
#endif //__WXGTK__ #endif //__WXGTK__
} }
// update object_node printable property
UpdateObjectPrintable(parent_item);
return ret_item; return ret_item;
} }
@ -1359,13 +1467,16 @@ void ObjectDataViewModel::GetValue(wxVariant &variant, const wxDataViewItem &ite
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID(); ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
switch (col) switch (col)
{ {
case 0: case colPrint:
variant << node->m_printable_icon;
break;
case colName:
variant << DataViewBitmapText(node->m_name, node->m_bmp); variant << DataViewBitmapText(node->m_name, node->m_bmp);
break; break;
case 1: case colExtruder:
variant = node->m_extruder; variant = node->m_extruder;
break; break;
case 2: case colEditing:
variant << node->m_action_icon; variant << node->m_action_icon;
break; break;
default: default:
@ -1428,7 +1539,7 @@ bool ObjectDataViewModel::IsEnabled(const wxDataViewItem &item, unsigned int col
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID(); ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
// disable extruder selection for the non "itObject|itVolume" item // disable extruder selection for the non "itObject|itVolume" item
return !(col == 1 && node->m_extruder.IsEmpty()); return !(col == colExtruder && node->m_extruder.IsEmpty());
} }
wxDataViewItem ObjectDataViewModel::GetParent(const wxDataViewItem &item) const wxDataViewItem ObjectDataViewModel::GetParent(const wxDataViewItem &item) const
@ -1593,6 +1704,46 @@ void ObjectDataViewModel::SetVolumeType(const wxDataViewItem &item, const Slic3r
ItemChanged(item); ItemChanged(item);
} }
wxDataViewItem ObjectDataViewModel::SetPrintableState(
PrintIndicator printable,
int obj_idx,
int subobj_idx /* = -1*/,
ItemType subobj_type/* = itInstance*/)
{
wxDataViewItem item = wxDataViewItem(0);
if (subobj_idx < 0)
item = GetItemById(obj_idx);
else
item = subobj_type&itInstance ? GetItemByInstanceId(obj_idx, subobj_idx) :
GetItemByVolumeId(obj_idx, subobj_idx);
ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID();
if (!node)
return wxDataViewItem(0);
node->set_printable_icon(printable);
ItemChanged(item);
if (subobj_idx >= 0)
UpdateObjectPrintable(GetItemById(obj_idx));
return item;
}
wxDataViewItem ObjectDataViewModel::SetObjectPrintableState(
PrintIndicator printable,
wxDataViewItem obj_item)
{
ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)obj_item.GetID();
if (!node)
return wxDataViewItem(0);
node->set_printable_icon(printable);
ItemChanged(obj_item);
UpdateInstancesPrintable(obj_item);
return obj_item;
}
void ObjectDataViewModel::Rescale() void ObjectDataViewModel::Rescale()
{ {
wxDataViewItemArray all_items; wxDataViewItemArray all_items;
@ -1777,7 +1928,7 @@ bool BitmapTextRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value
// The icon can't be edited so get its old value and reuse it. // The icon can't be edited so get its old value and reuse it.
wxVariant valueOld; wxVariant valueOld;
GetView()->GetModel()->GetValue(valueOld, m_item, 0); GetView()->GetModel()->GetValue(valueOld, m_item, colName);
DataViewBitmapText bmpText; DataViewBitmapText bmpText;
bmpText << valueOld; bmpText << valueOld;

View file

@ -43,6 +43,9 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin
wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, const wxString& description, wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler); std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler);
wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler);
class wxDialog; class wxDialog;
void edit_tooltip(wxString& tooltip); void edit_tooltip(wxString& tooltip);
void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector<int>& btn_ids); void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector<int>& btn_ids);
@ -172,6 +175,21 @@ enum ItemType {
itLayer = 64, itLayer = 64,
}; };
enum ColumnNumber
{
colName = 0, // item name
colPrint , // printable property
colExtruder , // extruder selection
colEditing , // item editing
};
enum PrintIndicator
{
piUndef = 0, // no print indicator
piPrintable , // printable
piUnprintable , // unprintable
};
class ObjectDataViewModelNode; class ObjectDataViewModelNode;
WX_DEFINE_ARRAY_PTR(ObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray); WX_DEFINE_ARRAY_PTR(ObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray);
@ -191,6 +209,8 @@ class ObjectDataViewModelNode
bool m_container = false; bool m_container = false;
wxString m_extruder = "default"; wxString m_extruder = "default";
wxBitmap m_action_icon; wxBitmap m_action_icon;
PrintIndicator m_printable {piUndef};
wxBitmap m_printable_icon;
std::string m_action_icon_name = ""; std::string m_action_icon_name = "";
Slic3r::ModelVolumeType m_volume_type; Slic3r::ModelVolumeType m_volume_type;
@ -203,14 +223,8 @@ public:
m_type(itObject), m_type(itObject),
m_extruder(extruder) m_extruder(extruder)
{ {
#ifdef __WXGTK__
// it's necessary on GTK because of control have to know if this item will be container
// in another case you couldn't to add subitem for this item
// it will be produce "segmentation fault"
m_container = true;
#endif //__WXGTK__
set_action_icon(); set_action_icon();
init_container();
} }
ObjectDataViewModelNode(ObjectDataViewModelNode* parent, ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
@ -225,14 +239,8 @@ public:
m_extruder (extruder) m_extruder (extruder)
{ {
m_bmp = bmp; m_bmp = bmp;
#ifdef __WXGTK__
// it's necessary on GTK because of control have to know if this item will be container
// in another case you couldn't to add subitem for this item
// it will be produce "segmentation fault"
m_container = true;
#endif //__WXGTK__
set_action_icon(); set_action_icon();
init_container();
} }
ObjectDataViewModelNode(ObjectDataViewModelNode* parent, ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
@ -257,6 +265,7 @@ public:
#endif /* NDEBUG */ #endif /* NDEBUG */
} }
void init_container();
bool IsContainer() const bool IsContainer() const
{ {
return m_container; return m_container;
@ -315,6 +324,7 @@ public:
void SetIdx(const int& idx); void SetIdx(const int& idx);
int GetIdx() const { return m_idx; } int GetIdx() const { return m_idx; }
t_layer_height_range GetLayerRange() const { return m_layer_range; } t_layer_height_range GetLayerRange() const { return m_layer_range; }
PrintIndicator IsPrintable() const { return m_printable; }
// use this function only for childrens // use this function only for childrens
void AssignAllVal(ObjectDataViewModelNode& from_node) void AssignAllVal(ObjectDataViewModelNode& from_node)
@ -346,6 +356,8 @@ public:
// Set action icons for node // Set action icons for node
void set_action_icon(); void set_action_icon();
// Set printable icon for node
void set_printable_icon(PrintIndicator printable);
void update_settings_digest_bitmaps(); void update_settings_digest_bitmaps();
bool update_settings_digest(const std::vector<std::string>& categories); bool update_settings_digest(const std::vector<std::string>& categories);
@ -391,6 +403,7 @@ public:
const bool create_frst_child = true); const bool create_frst_child = true);
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num); wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, const std::vector<bool>& print_indicator);
wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item); wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item, wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item,
const t_layer_height_range& layer_range, const t_layer_height_range& layer_range,
@ -469,9 +482,17 @@ public:
void UpdateSettingsDigest( const wxDataViewItem &item, void UpdateSettingsDigest( const wxDataViewItem &item,
const std::vector<std::string>& categories); const std::vector<std::string>& categories);
bool IsPrintable(const wxDataViewItem &item) const;
void UpdateObjectPrintable(wxDataViewItem parent_item);
void UpdateInstancesPrintable(wxDataViewItem parent_item);
void SetVolumeBitmaps(const std::vector<wxBitmap*>& volume_bmps) { m_volume_bmps = volume_bmps; } void SetVolumeBitmaps(const std::vector<wxBitmap*>& volume_bmps) { m_volume_bmps = volume_bmps; }
void SetWarningBitmap(wxBitmap* bitmap) { m_warning_bmp = bitmap; } void SetWarningBitmap(wxBitmap* bitmap) { m_warning_bmp = bitmap; }
void SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type); void SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type);
wxDataViewItem SetPrintableState( PrintIndicator printable, int obj_idx,
int subobj_idx = -1,
ItemType subobj_type = itInstance);
wxDataViewItem SetObjectPrintableState(PrintIndicator printable, wxDataViewItem obj_item);
void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; } void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; }
// Rescale bitmaps for existing Items // Rescale bitmaps for existing Items
@ -481,6 +502,10 @@ public:
const bool is_marked = false); const bool is_marked = false);
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false); void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const; t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const;
private:
wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type);
wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item);
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------