mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	WIP Restoration of the layer editing.
This commit is contained in:
		
							parent
							
								
									3e28905621
								
							
						
					
					
						commit
						d64b55d27d
					
				
					 17 changed files with 398 additions and 569 deletions
				
			
		| 
						 | 
				
			
			@ -582,10 +582,7 @@ namespace Slic3r {
 | 
			
		|||
 | 
			
		||||
            IdToLayerHeightsProfileMap::iterator obj_layer_heights_profile = m_layer_heights_profiles.find(object.first);
 | 
			
		||||
            if (obj_layer_heights_profile != m_layer_heights_profiles.end())
 | 
			
		||||
            {
 | 
			
		||||
                object.second->layer_height_profile = obj_layer_heights_profile->second;
 | 
			
		||||
                object.second->layer_height_profile_valid = true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            IdToSlaSupportPointsMap::iterator obj_sla_support_points = m_sla_support_points.find(object.first);
 | 
			
		||||
            if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty())
 | 
			
		||||
| 
						 | 
				
			
			@ -1926,7 +1923,7 @@ namespace Slic3r {
 | 
			
		|||
        for (const ModelObject* object : model.objects)
 | 
			
		||||
        {
 | 
			
		||||
            ++count;
 | 
			
		||||
            std::vector<double> layer_height_profile = object->layer_height_profile_valid ? object->layer_height_profile : std::vector<double>();
 | 
			
		||||
            const std::vector<double> &layer_height_profile = object->layer_height_profile;
 | 
			
		||||
            if ((layer_height_profile.size() >= 4) && ((layer_height_profile.size() % 2) == 0))
 | 
			
		||||
            {
 | 
			
		||||
                sprintf(buffer, "object_id=%d|", count);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -578,7 +578,6 @@ void AMFParserContext::endElement(const char * /* name */)
 | 
			
		|||
						break;
 | 
			
		||||
					p = end + 1;
 | 
			
		||||
                }
 | 
			
		||||
                m_object->layer_height_profile_valid = true;
 | 
			
		||||
            }
 | 
			
		||||
            else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "sla_support_points") == 0) {
 | 
			
		||||
                // Parse object's layer height profile, a semicolon separated list of floats.
 | 
			
		||||
| 
						 | 
				
			
			@ -885,7 +884,7 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
 | 
			
		|||
            stream << "    <metadata type=\"slic3r." << key << "\">" << object->config.serialize(key) << "</metadata>\n";
 | 
			
		||||
        if (!object->name.empty())
 | 
			
		||||
            stream << "    <metadata type=\"name\">" << xml_escape(object->name) << "</metadata>\n";
 | 
			
		||||
        std::vector<double> layer_height_profile = object->layer_height_profile_valid ? object->layer_height_profile : std::vector<double>();
 | 
			
		||||
        const std::vector<double> &layer_height_profile = object->layer_height_profile;
 | 
			
		||||
        if (layer_height_profile.size() >= 4 && (layer_height_profile.size() % 2) == 0) {
 | 
			
		||||
            // Store the layer height profile as a single semicolon separated list.
 | 
			
		||||
            stream << "    <metadata type=\"slic3r.layer_height_profile\">";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -570,7 +570,6 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
 | 
			
		|||
    this->sla_support_points          = rhs.sla_support_points;
 | 
			
		||||
    this->layer_height_ranges         = rhs.layer_height_ranges;
 | 
			
		||||
    this->layer_height_profile        = rhs.layer_height_profile;
 | 
			
		||||
    this->layer_height_profile_valid  = rhs.layer_height_profile_valid;
 | 
			
		||||
    this->origin_translation          = rhs.origin_translation;
 | 
			
		||||
    m_bounding_box                    = rhs.m_bounding_box;
 | 
			
		||||
    m_bounding_box_valid              = rhs.m_bounding_box_valid;
 | 
			
		||||
| 
						 | 
				
			
			@ -602,7 +601,6 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
 | 
			
		|||
    this->sla_support_points          = std::move(rhs.sla_support_points);
 | 
			
		||||
    this->layer_height_ranges         = std::move(rhs.layer_height_ranges);
 | 
			
		||||
    this->layer_height_profile        = std::move(rhs.layer_height_profile);
 | 
			
		||||
    this->layer_height_profile_valid  = std::move(rhs.layer_height_profile_valid);
 | 
			
		||||
    this->origin_translation          = std::move(rhs.origin_translation);
 | 
			
		||||
    m_bounding_box                    = std::move(rhs.m_bounding_box);
 | 
			
		||||
    m_bounding_box_valid              = std::move(rhs.m_bounding_box_valid);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -170,12 +170,8 @@ public:
 | 
			
		|||
    // Variation of a layer thickness for spans of Z coordinates.
 | 
			
		||||
    t_layer_height_ranges   layer_height_ranges;
 | 
			
		||||
    // 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 to simplify handling by the Perl XS.
 | 
			
		||||
    // The pairs of <z, layer_height> are packed into a 1D array.
 | 
			
		||||
    std::vector<coordf_t>   layer_height_profile;
 | 
			
		||||
    // layer_height_profile is initialized when the layer editing mode is entered.
 | 
			
		||||
    // Only if the user really modified the layer height, layer_height_profile_valid is set
 | 
			
		||||
    // and used subsequently by the PrintObject.
 | 
			
		||||
    bool                    layer_height_profile_valid;
 | 
			
		||||
 | 
			
		||||
    // This vector holds position of selected support points for SLA. The data are
 | 
			
		||||
    // saved in mesh coordinates to allow using them for several instances.
 | 
			
		||||
| 
						 | 
				
			
			@ -261,7 +257,7 @@ protected:
 | 
			
		|||
    void        set_model(Model *model) { m_model = model; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {}
 | 
			
		||||
    ModelObject(Model *model) : m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {}
 | 
			
		||||
    ~ModelObject();
 | 
			
		||||
 | 
			
		||||
    /* To be able to return an object from own copy / clone methods. Hopefully the compiler will do the "Copy elision" */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -287,18 +287,8 @@ std::vector<unsigned int> Print::object_extruders() const
 | 
			
		|||
{
 | 
			
		||||
    std::vector<unsigned int> extruders;
 | 
			
		||||
    extruders.reserve(m_regions.size() * 3);
 | 
			
		||||
    
 | 
			
		||||
    for (const PrintRegion *region : m_regions) {
 | 
			
		||||
        // these checks reflect the same logic used in the GUI for enabling/disabling
 | 
			
		||||
        // extruder selection fields
 | 
			
		||||
        if (region->config().perimeters.value > 0 || m_config.brim_width.value > 0)
 | 
			
		||||
            extruders.emplace_back(region->config().perimeter_extruder - 1);
 | 
			
		||||
        if (region->config().fill_density.value > 0)
 | 
			
		||||
            extruders.emplace_back(region->config().infill_extruder - 1);
 | 
			
		||||
        if (region->config().top_solid_layers.value > 0 || region->config().bottom_solid_layers.value > 0)
 | 
			
		||||
            extruders.emplace_back(region->config().solid_infill_extruder - 1);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    for (const PrintRegion *region : m_regions)
 | 
			
		||||
        region->collect_object_printing_extruders(extruders);
 | 
			
		||||
    sort_remove_duplicates(extruders);
 | 
			
		||||
    return extruders;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -366,37 +356,6 @@ double Print::max_allowed_layer_height() const
 | 
			
		|||
    return nozzle_diameter_max;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders)
 | 
			
		||||
{
 | 
			
		||||
    if (opt.value > (int)num_extruders)
 | 
			
		||||
        // assign the default extruder
 | 
			
		||||
        opt.value = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PrintObjectConfig object_config_from_model(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders)
 | 
			
		||||
{
 | 
			
		||||
    PrintObjectConfig config = default_object_config;
 | 
			
		||||
    normalize_and_apply_config(config, object.config);
 | 
			
		||||
    // Clamp invalid extruders to the default extruder (with index 1).
 | 
			
		||||
    clamp_exturder_to_default(config.support_material_extruder,           num_extruders);
 | 
			
		||||
    clamp_exturder_to_default(config.support_material_interface_extruder, num_extruders);
 | 
			
		||||
    return config;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders)
 | 
			
		||||
{
 | 
			
		||||
    PrintRegionConfig config = default_region_config;
 | 
			
		||||
    normalize_and_apply_config(config, volume.get_object()->config);
 | 
			
		||||
    normalize_and_apply_config(config, volume.config);
 | 
			
		||||
    if (! volume.material_id().empty())
 | 
			
		||||
        normalize_and_apply_config(config, volume.material()->config);
 | 
			
		||||
    // Clamp invalid extruders to the default extruder (with index 1).
 | 
			
		||||
    clamp_exturder_to_default(config.infill_extruder,       num_extruders);
 | 
			
		||||
    clamp_exturder_to_default(config.perimeter_extruder,    num_extruders);
 | 
			
		||||
    clamp_exturder_to_default(config.solid_infill_extruder, num_extruders);
 | 
			
		||||
    return config;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Caller is responsible for supplying models whose objects don't collide
 | 
			
		||||
// and have explicit instance positions.
 | 
			
		||||
void Print::add_model_object(ModelObject* model_object, int idx)
 | 
			
		||||
| 
						 | 
				
			
			@ -433,7 +392,7 @@ void Print::add_model_object(ModelObject* model_object, int idx)
 | 
			
		|||
        if (! volume->is_model_part() && ! volume->is_modifier())
 | 
			
		||||
            continue;
 | 
			
		||||
        // Get the config applied to this volume.
 | 
			
		||||
        PrintRegionConfig config = region_config_from_model_volume(m_default_region_config, *volume, 99999);
 | 
			
		||||
        PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, 99999);
 | 
			
		||||
        // Find an existing print region with the same config.
 | 
			
		||||
        size_t region_id = size_t(-1);
 | 
			
		||||
        for (size_t i = 0; i < m_regions.size(); ++ i)
 | 
			
		||||
| 
						 | 
				
			
			@ -514,12 +473,12 @@ bool Print::apply_config(DynamicPrintConfig config)
 | 
			
		|||
                            // If the new config for this volume differs from the other
 | 
			
		||||
                            // volume configs currently associated to this region, it means
 | 
			
		||||
                            // the region subdivision does not make sense anymore.
 | 
			
		||||
                            if (! this_region_config.equals(region_config_from_model_volume(m_default_region_config, volume, 99999))) {
 | 
			
		||||
                            if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, volume, 99999))) {
 | 
			
		||||
                                rearrange_regions = true;
 | 
			
		||||
                                goto exit_for_rearrange_regions;
 | 
			
		||||
                            }
 | 
			
		||||
                        } else {
 | 
			
		||||
                            this_region_config = region_config_from_model_volume(m_default_region_config, volume, 99999);
 | 
			
		||||
                            this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, 99999);
 | 
			
		||||
                            this_region_config_set = true;
 | 
			
		||||
                        }
 | 
			
		||||
                        for (const PrintRegionConfig &cfg : other_region_configs) {
 | 
			
		||||
| 
						 | 
				
			
			@ -563,10 +522,6 @@ exit_for_rearrange_regions:
 | 
			
		|||
        invalidated = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Always make sure that the layer_height_profiles are set, as they should not be modified from the worker threads.
 | 
			
		||||
    for (PrintObject *object : m_objects)
 | 
			
		||||
        object->update_layer_height_profile();
 | 
			
		||||
    
 | 
			
		||||
    return invalidated;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -888,8 +843,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
 | 
			
		|||
        if (model_parts_differ || modifiers_differ || 
 | 
			
		||||
            model_object.origin_translation         != model_object_new.origin_translation   ||
 | 
			
		||||
            model_object.layer_height_ranges        != model_object_new.layer_height_ranges  || 
 | 
			
		||||
            model_object.layer_height_profile       != model_object_new.layer_height_profile ||
 | 
			
		||||
            model_object.layer_height_profile_valid != model_object_new.layer_height_profile_valid) {
 | 
			
		||||
            model_object.layer_height_profile       != model_object_new.layer_height_profile) {
 | 
			
		||||
            // The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
 | 
			
		||||
            auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
 | 
			
		||||
            for (auto it = range.first; it != range.second; ++ it) {
 | 
			
		||||
| 
						 | 
				
			
			@ -915,7 +869,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
 | 
			
		|||
			if (object_config_changed)
 | 
			
		||||
                model_object.config = model_object_new.config;
 | 
			
		||||
            if (! object_diff.empty() || object_config_changed) {
 | 
			
		||||
                PrintObjectConfig new_config = object_config_from_model(m_default_object_config, model_object, num_extruders);
 | 
			
		||||
                PrintObjectConfig new_config = PrintObject::object_config_from_model_object(m_default_object_config, model_object, num_extruders);
 | 
			
		||||
                auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
 | 
			
		||||
                for (auto it = range.first; it != range.second; ++ it) {
 | 
			
		||||
                    t_config_option_keys diff = it->print_object->config().diff(new_config);
 | 
			
		||||
| 
						 | 
				
			
			@ -957,7 +911,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
 | 
			
		|||
                        old.emplace_back(&(*it));
 | 
			
		||||
            }
 | 
			
		||||
            // Generate a list of trafos and XY offsets for instances of a ModelObject
 | 
			
		||||
            PrintObjectConfig config = object_config_from_model(m_default_object_config, *model_object, num_extruders);
 | 
			
		||||
            PrintObjectConfig config = PrintObject::object_config_from_model_object(m_default_object_config, *model_object, num_extruders);
 | 
			
		||||
            std::vector<PrintInstances> new_print_instances = print_objects_from_model_object(*model_object);
 | 
			
		||||
            if (old.empty()) {
 | 
			
		||||
                // Simple case, just generate new instances.
 | 
			
		||||
| 
						 | 
				
			
			@ -1048,11 +1002,11 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
 | 
			
		|||
                        // If the new config for this volume differs from the other
 | 
			
		||||
                        // volume configs currently associated to this region, it means
 | 
			
		||||
                        // the region subdivision does not make sense anymore.
 | 
			
		||||
                        if (! this_region_config.equals(region_config_from_model_volume(m_default_region_config, volume, num_extruders)))
 | 
			
		||||
                        if (! this_region_config.equals(PrintObject::region_config_from_model_volume(m_default_region_config, volume, num_extruders)))
 | 
			
		||||
                            // Regions were split. Reset this print_object.
 | 
			
		||||
                            goto print_object_end;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        this_region_config = region_config_from_model_volume(m_default_region_config, volume, num_extruders);
 | 
			
		||||
                        this_region_config = PrintObject::region_config_from_model_volume(m_default_region_config, volume, num_extruders);
 | 
			
		||||
						for (size_t i = 0; i < region_id; ++i) {
 | 
			
		||||
							const PrintRegion ®ion_other = *m_regions[i];
 | 
			
		||||
							if (region_other.m_refcnt != 0 && region_other.config().equals(this_region_config))
 | 
			
		||||
| 
						 | 
				
			
			@ -1103,7 +1057,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
 | 
			
		|||
                int region_id = -1;
 | 
			
		||||
                if (&print_object == &print_object0) {
 | 
			
		||||
                    // Get the config applied to this volume.
 | 
			
		||||
                    PrintRegionConfig config = region_config_from_model_volume(m_default_region_config, *volume, num_extruders);
 | 
			
		||||
                    PrintRegionConfig config = PrintObject::region_config_from_model_volume(m_default_region_config, *volume, num_extruders);
 | 
			
		||||
                    // Find an existing print region with the same config.
 | 
			
		||||
					int idx_empty_slot = -1;
 | 
			
		||||
					for (int i = 0; i < (int)m_regions.size(); ++ i) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1139,13 +1093,6 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Always make sure that the layer_height_profiles are set, as they should not be modified from the worker threads.
 | 
			
		||||
    for (PrintObject *object : m_objects)
 | 
			
		||||
        if (! object->layer_height_profile_valid)
 | 
			
		||||
            // No need to call the next line as the step should already be invalidated above.
 | 
			
		||||
            // update_apply_status(object->invalidate_step(posSlice));
 | 
			
		||||
            object->update_layer_height_profile();
 | 
			
		||||
 | 
			
		||||
    //FIXME there may be a race condition with the G-code export running at the background thread.
 | 
			
		||||
    this->update_object_placeholders();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,6 +45,10 @@ public:
 | 
			
		|||
    // Average diameter of nozzles participating on extruding this region.
 | 
			
		||||
    coordf_t                    bridging_height_avg(const PrintConfig &print_config) const;
 | 
			
		||||
 | 
			
		||||
    // Collect extruder indices used to print this region's object.
 | 
			
		||||
	void                        collect_object_printing_extruders(std::vector<unsigned int> &object_extruders) const;
 | 
			
		||||
	static void                 collect_object_printing_extruders(const PrintConfig &print_config, const PrintRegionConfig ®ion_config, std::vector<unsigned int> &object_extruders);
 | 
			
		||||
 | 
			
		||||
// Methods modifying the PrintRegion's state:
 | 
			
		||||
public:
 | 
			
		||||
    Print*                      print() { return m_print; }
 | 
			
		||||
| 
						 | 
				
			
			@ -80,14 +84,8 @@ public:
 | 
			
		|||
    std::vector<std::vector<int>> region_volumes;
 | 
			
		||||
 | 
			
		||||
    // 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 to simplify handling by the Perl XS.
 | 
			
		||||
    // layer_height_profile must not be set by the background thread.
 | 
			
		||||
    // The pairs of <z, layer_height> are packed into a 1D array.
 | 
			
		||||
    std::vector<coordf_t>   layer_height_profile;
 | 
			
		||||
    // There is a layer_height_profile at both PrintObject and ModelObject. The layer_height_profile at the ModelObject
 | 
			
		||||
    // is used for interactive editing and for loading / storing into a project file (AMF file as of today).
 | 
			
		||||
    // This flag indicates that the layer_height_profile at the UI has been updated, therefore the backend needs to get it.
 | 
			
		||||
    // This flag is necessary as we cannot safely clear the layer_height_profile if the background calculation is running.
 | 
			
		||||
    bool                    layer_height_profile_valid;
 | 
			
		||||
    
 | 
			
		||||
    // this is set to true when LayerRegion->slices is split in top/internal/bottom
 | 
			
		||||
    // so that next call to make_perimeters() performs a union() before computing loops
 | 
			
		||||
| 
						 | 
				
			
			@ -129,23 +127,19 @@ public:
 | 
			
		|||
    SupportLayerPtrs::const_iterator insert_support_layer(SupportLayerPtrs::const_iterator pos, int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
 | 
			
		||||
    void delete_support_layer(int idx);
 | 
			
		||||
    
 | 
			
		||||
    // To be used over the layer_height_profile of both the PrintObject and ModelObject
 | 
			
		||||
    // to initialize the height profile with the height ranges.
 | 
			
		||||
    bool update_layer_height_profile(std::vector<coordf_t> &layer_height_profile) const;
 | 
			
		||||
 | 
			
		||||
    // Process layer_height_ranges, the raft layers and first layer thickness into layer_height_profile.
 | 
			
		||||
    // The layer_height_profile may be later modified interactively by the user to refine layers at sloping surfaces.
 | 
			
		||||
    bool update_layer_height_profile();
 | 
			
		||||
 | 
			
		||||
    void reset_layer_height_profile();
 | 
			
		||||
 | 
			
		||||
    void adjust_layer_height_profile(coordf_t z, coordf_t layer_thickness_delta, coordf_t band_width, int action);
 | 
			
		||||
    // Initialize the layer_height_profile from the model_object's layer_height_profile, from model_object's layer height table, or from slicing parameters.
 | 
			
		||||
    // Returns true, if the layer_height_profile was changed.
 | 
			
		||||
    static bool update_layer_height_profile(const ModelObject &model_object, const SlicingParameters &slicing_parameters, std::vector<coordf_t> &layer_height_profile);
 | 
			
		||||
 | 
			
		||||
    // Collect the slicing parameters, to be used by variable layer thickness algorithm,
 | 
			
		||||
    // by the interactive layer height editor and by the printing process itself.
 | 
			
		||||
    // The slicing parameters are dependent on various configuration values
 | 
			
		||||
    // (layer height, first layer height, raft settings, print nozzle diameter etc).
 | 
			
		||||
    SlicingParameters slicing_parameters() const;
 | 
			
		||||
    SlicingParameters           slicing_parameters() const;
 | 
			
		||||
    static SlicingParameters    slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object);
 | 
			
		||||
 | 
			
		||||
    // returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
 | 
			
		||||
    std::vector<unsigned int>   object_extruders() const;
 | 
			
		||||
 | 
			
		||||
    // Called when slicing to SVG (see Print.pm sub export_svg), and used by perimeters.t
 | 
			
		||||
    void slice();
 | 
			
		||||
| 
						 | 
				
			
			@ -172,6 +166,9 @@ protected:
 | 
			
		|||
    // Invalidate steps based on a set of parameters changed.
 | 
			
		||||
    bool                    invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
 | 
			
		||||
 | 
			
		||||
    static PrintObjectConfig object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders);
 | 
			
		||||
    static PrintRegionConfig region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void make_perimeters();
 | 
			
		||||
    void prepare_infill();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,8 +38,7 @@ namespace Slic3r {
 | 
			
		|||
PrintObject::PrintObject(Print* print, ModelObject* model_object, bool add_instances) :
 | 
			
		||||
    PrintObjectBaseWithState(print, model_object),
 | 
			
		||||
    typed_slices(false),
 | 
			
		||||
    size(Vec3crd::Zero()),
 | 
			
		||||
    layer_height_profile_valid(false)
 | 
			
		||||
    size(Vec3crd::Zero())
 | 
			
		||||
{
 | 
			
		||||
    // Compute the translation to be applied to our meshes so that we work with smaller coordinates
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -106,6 +105,8 @@ void PrintObject::slice()
 | 
			
		|||
    if (! this->set_started(posSlice))
 | 
			
		||||
        return;
 | 
			
		||||
    m_print->set_status(10, "Processing triangulated mesh");
 | 
			
		||||
    this->update_layer_height_profile(*this->model_object(), this->slicing_parameters(), this->layer_height_profile);
 | 
			
		||||
    m_print->throw_if_canceled();
 | 
			
		||||
    this->_slice();
 | 
			
		||||
    m_print->throw_if_canceled();
 | 
			
		||||
    // Fix the model.
 | 
			
		||||
| 
						 | 
				
			
			@ -455,7 +456,6 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
 | 
			
		|||
            || opt_key == "first_layer_height"
 | 
			
		||||
            || opt_key == "raft_layers") {
 | 
			
		||||
            steps.emplace_back(posSlice);
 | 
			
		||||
			this->reset_layer_height_profile();
 | 
			
		||||
		}
 | 
			
		||||
		else if (
 | 
			
		||||
               opt_key == "clip_multipart_objects"
 | 
			
		||||
| 
						 | 
				
			
			@ -542,7 +542,6 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
 | 
			
		|||
        } else {
 | 
			
		||||
            // for legacy, if we can't handle this option let's invalidate all steps
 | 
			
		||||
            this->invalidate_all_steps();
 | 
			
		||||
			this->reset_layer_height_profile();
 | 
			
		||||
            invalidated = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1329,55 +1328,107 @@ void PrintObject::bridge_over_infill()
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void clamp_exturder_to_default(ConfigOptionInt &opt, size_t num_extruders)
 | 
			
		||||
{
 | 
			
		||||
    if (opt.value > (int)num_extruders)
 | 
			
		||||
        // assign the default extruder
 | 
			
		||||
        opt.value = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PrintObjectConfig PrintObject::object_config_from_model_object(const PrintObjectConfig &default_object_config, const ModelObject &object, size_t num_extruders)
 | 
			
		||||
{
 | 
			
		||||
    PrintObjectConfig config = default_object_config;
 | 
			
		||||
    normalize_and_apply_config(config, object.config);
 | 
			
		||||
    // Clamp invalid extruders to the default extruder (with index 1).
 | 
			
		||||
    clamp_exturder_to_default(config.support_material_extruder,           num_extruders);
 | 
			
		||||
    clamp_exturder_to_default(config.support_material_interface_extruder, num_extruders);
 | 
			
		||||
    return config;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PrintRegionConfig PrintObject::region_config_from_model_volume(const PrintRegionConfig &default_region_config, const ModelVolume &volume, size_t num_extruders)
 | 
			
		||||
{
 | 
			
		||||
    PrintRegionConfig config = default_region_config;
 | 
			
		||||
    normalize_and_apply_config(config, volume.get_object()->config);
 | 
			
		||||
    normalize_and_apply_config(config, volume.config);
 | 
			
		||||
    if (! volume.material_id().empty())
 | 
			
		||||
        normalize_and_apply_config(config, volume.material()->config);
 | 
			
		||||
    // Clamp invalid extruders to the default extruder (with index 1).
 | 
			
		||||
    clamp_exturder_to_default(config.infill_extruder,       num_extruders);
 | 
			
		||||
    clamp_exturder_to_default(config.perimeter_extruder,    num_extruders);
 | 
			
		||||
    clamp_exturder_to_default(config.solid_infill_extruder, num_extruders);
 | 
			
		||||
    return config;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SlicingParameters PrintObject::slicing_parameters() const
 | 
			
		||||
{
 | 
			
		||||
    return SlicingParameters::create_from_config(
 | 
			
		||||
        this->print()->config(), m_config, 
 | 
			
		||||
        unscale<double>(this->size(2)), this->print()->object_extruders());
 | 
			
		||||
        unscale<double>(this->size(2)), this->object_extruders());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PrintObject::update_layer_height_profile(std::vector<coordf_t> &layer_height_profile) const
 | 
			
		||||
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig &full_config, const ModelObject &model_object)
 | 
			
		||||
{
 | 
			
		||||
    PrintConfig         print_config;
 | 
			
		||||
    PrintObjectConfig   object_config;
 | 
			
		||||
    PrintRegionConfig   default_region_config;
 | 
			
		||||
    print_config .apply(full_config, true);
 | 
			
		||||
    object_config.apply(full_config, true);
 | 
			
		||||
    default_region_config.apply(full_config, true);
 | 
			
		||||
    size_t              num_extruders = print_config.nozzle_diameter.size();
 | 
			
		||||
    object_config = object_config_from_model_object(object_config, model_object, num_extruders);
 | 
			
		||||
 | 
			
		||||
    std::vector<unsigned int> object_extruders;
 | 
			
		||||
    for (const ModelVolume *model_volume : model_object.volumes)
 | 
			
		||||
        if (model_volume->is_model_part())
 | 
			
		||||
            PrintRegion::collect_object_printing_extruders(
 | 
			
		||||
                print_config,
 | 
			
		||||
                region_config_from_model_volume(default_region_config, *model_volume, num_extruders),
 | 
			
		||||
                object_extruders);
 | 
			
		||||
    sort_remove_duplicates(object_extruders);
 | 
			
		||||
 | 
			
		||||
    return SlicingParameters::create_from_config(print_config, object_config, model_object.bounding_box().max.z(), object_extruders);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// returns 0-based indices of extruders used to print the object (without brim, support and other helper extrusions)
 | 
			
		||||
std::vector<unsigned int> PrintObject::object_extruders() const
 | 
			
		||||
{
 | 
			
		||||
    std::vector<unsigned int> extruders;
 | 
			
		||||
    extruders.reserve(this->region_volumes.size() * 3);    
 | 
			
		||||
    for (size_t idx_region = 0; idx_region < this->region_volumes.size(); ++ idx_region)
 | 
			
		||||
        if (! this->region_volumes[idx_region].empty())
 | 
			
		||||
            m_print->get_region(idx_region)->collect_object_printing_extruders(extruders);
 | 
			
		||||
    sort_remove_duplicates(extruders);
 | 
			
		||||
    return extruders;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PrintObject::update_layer_height_profile(const ModelObject &model_object, const SlicingParameters &slicing_parameters, std::vector<coordf_t> &layer_height_profile)
 | 
			
		||||
{
 | 
			
		||||
    bool updated = false;
 | 
			
		||||
 | 
			
		||||
    // If the layer height profile is not set, try to use the one stored at the ModelObject.
 | 
			
		||||
    if (layer_height_profile.empty()) {
 | 
			
		||||
        layer_height_profile = this->model_object()->layer_height_profile;
 | 
			
		||||
        layer_height_profile = model_object.layer_height_profile;
 | 
			
		||||
        updated = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Verify the layer_height_profile.
 | 
			
		||||
    SlicingParameters slicing_params = this->slicing_parameters();
 | 
			
		||||
    if (! layer_height_profile.empty() && 
 | 
			
		||||
            // Must not be of even length.
 | 
			
		||||
            ((layer_height_profile.size() & 1) != 0 || 
 | 
			
		||||
            // Last entry must be at the top of the object.
 | 
			
		||||
             std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_params.object_print_z_height()) > 1e-3))
 | 
			
		||||
             std::abs(layer_height_profile[layer_height_profile.size() - 2] - slicing_parameters.object_print_z_height()) > 1e-3))
 | 
			
		||||
        layer_height_profile.clear();
 | 
			
		||||
 | 
			
		||||
    if (layer_height_profile.empty()) {
 | 
			
		||||
        if (0)
 | 
			
		||||
//        if (this->layer_height_profile.empty())
 | 
			
		||||
			layer_height_profile = layer_height_profile_adaptive(slicing_params, this->model_object()->layer_height_ranges, this->model_object()->volumes);
 | 
			
		||||
            layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_height_ranges, model_object.volumes);
 | 
			
		||||
        else
 | 
			
		||||
			layer_height_profile = layer_height_profile_from_ranges(slicing_params, this->model_object()->layer_height_ranges);
 | 
			
		||||
            layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_height_ranges);
 | 
			
		||||
        updated = true;
 | 
			
		||||
    }
 | 
			
		||||
    return updated;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This must be called from the main thread as it modifies the layer_height_profile.
 | 
			
		||||
bool PrintObject::update_layer_height_profile()
 | 
			
		||||
{
 | 
			
		||||
    // If the layer height profile has been marked as invalid for some reason (modified at the UI level 
 | 
			
		||||
    // or invalidated due to the slicing parameters), clear it now.
 | 
			
		||||
    if (! this->layer_height_profile_valid) { 
 | 
			
		||||
        this->layer_height_profile.clear();
 | 
			
		||||
        this->layer_height_profile_valid = true;
 | 
			
		||||
    }
 | 
			
		||||
    return this->update_layer_height_profile(this->layer_height_profile);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 1) Decides Z positions of the layers,
 | 
			
		||||
// 2) Initializes layers and their regions
 | 
			
		||||
// 3) Slices the object meshes
 | 
			
		||||
| 
						 | 
				
			
			@ -2198,22 +2249,4 @@ void PrintObject::_generate_support_material()
 | 
			
		|||
    support_material.generate(*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PrintObject::reset_layer_height_profile()
 | 
			
		||||
{
 | 
			
		||||
    // Reset the layer_heigth_profile.
 | 
			
		||||
    this->layer_height_profile.clear();
 | 
			
		||||
	this->layer_height_profile_valid = false;
 | 
			
		||||
    // Reset the source layer_height_profile if it exists at the ModelObject.
 | 
			
		||||
    this->model_object()->layer_height_profile.clear();
 | 
			
		||||
    this->model_object()->layer_height_profile_valid = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PrintObject::adjust_layer_height_profile(coordf_t z, coordf_t layer_thickness_delta, coordf_t band_width, int action)
 | 
			
		||||
{
 | 
			
		||||
    update_layer_height_profile(m_model_object->layer_height_profile);
 | 
			
		||||
    Slic3r::adjust_layer_height_profile(slicing_parameters(), m_model_object->layer_height_profile, z, layer_thickness_delta, band_width, LayerHeightEditActionType(action));
 | 
			
		||||
    m_model_object->layer_height_profile_valid = true;
 | 
			
		||||
    layer_height_profile_valid = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Slic3r
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,4 +61,20 @@ coordf_t PrintRegion::bridging_height_avg(const PrintConfig &print_config) const
 | 
			
		|||
    return this->nozzle_dmr_avg(print_config) * sqrt(m_config.bridge_flow_ratio.value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PrintRegion::collect_object_printing_extruders(const PrintConfig &print_config, const PrintRegionConfig ®ion_config, std::vector<unsigned int> &object_extruders)
 | 
			
		||||
{
 | 
			
		||||
    // These checks reflect the same logic used in the GUI for enabling/disabling extruder selection fields.
 | 
			
		||||
    if (region_config.perimeters.value > 0 || print_config.brim_width.value > 0)
 | 
			
		||||
        object_extruders.emplace_back(region_config.perimeter_extruder - 1);
 | 
			
		||||
    if (region_config.fill_density.value > 0)
 | 
			
		||||
        object_extruders.emplace_back(region_config.infill_extruder - 1);
 | 
			
		||||
    if (region_config.top_solid_layers.value > 0 || region_config.bottom_solid_layers.value > 0)
 | 
			
		||||
        object_extruders.emplace_back(region_config.solid_infill_extruder - 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PrintRegion::collect_object_printing_extruders(std::vector<unsigned int> &object_extruders) const
 | 
			
		||||
{
 | 
			
		||||
    collect_object_printing_extruders(print()->config(), this->config(), object_extruders);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -131,7 +131,7 @@ extern std::vector<coordf_t> layer_height_profile_adaptive(
 | 
			
		|||
    const ModelVolumePtrs       &volumes);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
enum LayerHeightEditActionType {
 | 
			
		||||
enum LayerHeightEditActionType : unsigned int {
 | 
			
		||||
    LAYER_HEIGHT_EDIT_ACTION_INCREASE = 0,
 | 
			
		||||
    LAYER_HEIGHT_EDIT_ACTION_DECREASE = 1,
 | 
			
		||||
    LAYER_HEIGHT_EDIT_ACTION_REDUCE   = 2,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -386,58 +386,6 @@ void GLVolume::render() const
 | 
			
		|||
    ::glPopMatrix();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLVolume::render_using_layer_height() const
 | 
			
		||||
{
 | 
			
		||||
    if (!is_active)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    GLint current_program_id;
 | 
			
		||||
    glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id);
 | 
			
		||||
 | 
			
		||||
    if ((layer_height_texture_data.shader_id > 0) && (layer_height_texture_data.shader_id != current_program_id))
 | 
			
		||||
        glUseProgram(layer_height_texture_data.shader_id);
 | 
			
		||||
 | 
			
		||||
    GLint z_to_texture_row_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_to_texture_row") : -1;
 | 
			
		||||
    GLint z_texture_row_to_normalized_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_texture_row_to_normalized") : -1;
 | 
			
		||||
    GLint z_cursor_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_cursor") : -1;
 | 
			
		||||
    GLint z_cursor_band_width_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "z_cursor_band_width") : -1;
 | 
			
		||||
    GLint world_matrix_id = (layer_height_texture_data.shader_id > 0) ? glGetUniformLocation(layer_height_texture_data.shader_id, "volume_world_matrix") : -1;
 | 
			
		||||
 | 
			
		||||
    if (z_to_texture_row_id  >= 0)
 | 
			
		||||
        glUniform1f(z_to_texture_row_id, (GLfloat)layer_height_texture_z_to_row_id());
 | 
			
		||||
 | 
			
		||||
    if (z_texture_row_to_normalized_id >= 0)
 | 
			
		||||
        glUniform1f(z_texture_row_to_normalized_id, (GLfloat)(1.0f / layer_height_texture_height()));
 | 
			
		||||
 | 
			
		||||
    if (z_cursor_id >= 0)
 | 
			
		||||
        glUniform1f(z_cursor_id, (GLfloat)(layer_height_texture_data.print_object->model_object()->bounding_box().max(2) * layer_height_texture_data.z_cursor_relative));
 | 
			
		||||
 | 
			
		||||
    if (z_cursor_band_width_id >= 0)
 | 
			
		||||
        glUniform1f(z_cursor_band_width_id, (GLfloat)layer_height_texture_data.edit_band_width);
 | 
			
		||||
 | 
			
		||||
    if (world_matrix_id >= 0)
 | 
			
		||||
        ::glUniformMatrix4fv(world_matrix_id, 1, GL_FALSE, (const GLfloat*)world_matrix().cast<float>().data());
 | 
			
		||||
 | 
			
		||||
    GLsizei w = (GLsizei)layer_height_texture_width();
 | 
			
		||||
    GLsizei h = (GLsizei)layer_height_texture_height();
 | 
			
		||||
    GLsizei half_w = w / 2;
 | 
			
		||||
    GLsizei half_h = h / 2;
 | 
			
		||||
 | 
			
		||||
    ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, layer_height_texture_data.texture_id);
 | 
			
		||||
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
 | 
			
		||||
    glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
 | 
			
		||||
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level0());
 | 
			
		||||
    glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, layer_height_texture_data_ptr_level1());
 | 
			
		||||
 | 
			
		||||
    render();
 | 
			
		||||
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, 0);
 | 
			
		||||
 | 
			
		||||
    if ((current_program_id > 0) && (layer_height_texture_data.shader_id != current_program_id))
 | 
			
		||||
        glUseProgram(current_program_id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) const
 | 
			
		||||
{
 | 
			
		||||
    if (!is_active)
 | 
			
		||||
| 
						 | 
				
			
			@ -446,16 +394,6 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c
 | 
			
		|||
    if (!indexed_vertex_array.vertices_and_normals_interleaved_VBO_id)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (layer_height_texture_data.can_use())
 | 
			
		||||
    {
 | 
			
		||||
        ::glDisableClientState(GL_VERTEX_ARRAY);
 | 
			
		||||
        ::glDisableClientState(GL_NORMAL_ARRAY);
 | 
			
		||||
        render_using_layer_height();
 | 
			
		||||
        ::glEnableClientState(GL_VERTEX_ARRAY);
 | 
			
		||||
        ::glEnableClientState(GL_NORMAL_ARRAY);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    GLsizei n_triangles = GLsizei(std::min(indexed_vertex_array.triangle_indices_size, tverts_range.second - tverts_range.first));
 | 
			
		||||
    GLsizei n_quads = GLsizei(std::min(indexed_vertex_array.quad_indices_size, qverts_range.second - qverts_range.first));
 | 
			
		||||
    if (n_triangles + n_quads == 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -558,44 +496,6 @@ void GLVolume::render_legacy() const
 | 
			
		|||
    ::glPopMatrix();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double GLVolume::layer_height_texture_z_to_row_id() const
 | 
			
		||||
{
 | 
			
		||||
    return (this->layer_height_texture.get() == nullptr) ? 0.0 : double(this->layer_height_texture->cells - 1) / (double(this->layer_height_texture->width) * this->layer_height_texture_data.print_object->model_object()->bounding_box().max(2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLVolume::generate_layer_height_texture(const PrintObject *print_object, bool force)
 | 
			
		||||
{
 | 
			
		||||
    LayersTexture *tex = this->layer_height_texture.get();
 | 
			
		||||
    if (tex == nullptr)
 | 
			
		||||
		// No layer_height_texture is assigned to this GLVolume, therefore the layer height texture cannot be filled.
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	// Always try to update the layer height profile.
 | 
			
		||||
	bool update = print_object->update_layer_height_profile(const_cast<ModelObject*>(print_object->model_object())->layer_height_profile) || force;
 | 
			
		||||
	// Update if the layer height profile was changed, or when the texture is not valid.
 | 
			
		||||
	if (! update && ! tex->data.empty() && tex->cells > 0)
 | 
			
		||||
        // Texture is valid, don't update.
 | 
			
		||||
        return; 
 | 
			
		||||
 | 
			
		||||
    if (tex->data.empty()) {
 | 
			
		||||
        tex->width  = 1024;
 | 
			
		||||
        tex->height = 1024;
 | 
			
		||||
        tex->levels = 2;
 | 
			
		||||
        tex->data.assign(tex->width * tex->height * 5, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SlicingParameters slicing_params = print_object->slicing_parameters();
 | 
			
		||||
    bool level_of_detail_2nd_level = true;
 | 
			
		||||
    tex->cells = Slic3r::generate_layer_height_texture(
 | 
			
		||||
        slicing_params, 
 | 
			
		||||
        Slic3r::generate_object_layers(slicing_params, print_object->model_object()->layer_height_profile), 
 | 
			
		||||
        tex->data.data(), tex->height, tex->width, level_of_detail_2nd_level);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 512x512 bitmaps are supported everywhere, but that may not be sufficent for super large print volumes.
 | 
			
		||||
#define LAYER_HEIGHT_TEXTURE_WIDTH  1024
 | 
			
		||||
#define LAYER_HEIGHT_TEXTURE_HEIGHT 1024
 | 
			
		||||
 | 
			
		||||
std::vector<int> GLVolumeCollection::load_object(
 | 
			
		||||
    const ModelObject       *model_object,
 | 
			
		||||
    int                      obj_idx,
 | 
			
		||||
| 
						 | 
				
			
			@ -603,19 +503,15 @@ std::vector<int> GLVolumeCollection::load_object(
 | 
			
		|||
    const std::string       &color_by,
 | 
			
		||||
    bool                     use_VBOs)
 | 
			
		||||
{
 | 
			
		||||
    // Object will share a single common layer height texture between all printable volumes.
 | 
			
		||||
    std::shared_ptr<LayersTexture> layer_height_texture = std::make_shared<LayersTexture>();
 | 
			
		||||
    std::vector<int> volumes_idx;
 | 
			
		||||
    for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++ volume_idx)
 | 
			
		||||
        for (int instance_idx : instance_idxs)
 | 
			
		||||
			volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, layer_height_texture, obj_idx, volume_idx, instance_idx, color_by, use_VBOs));
 | 
			
		||||
			volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by, use_VBOs));
 | 
			
		||||
    return volumes_idx; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int GLVolumeCollection::load_object_volume(
 | 
			
		||||
	const ModelObject              *model_object,
 | 
			
		||||
    // Layer height texture is shared between all printable volumes of a single ModelObject.
 | 
			
		||||
	std::shared_ptr<LayersTexture> &layer_height_texture,
 | 
			
		||||
    int                             obj_idx,
 | 
			
		||||
    int                             volume_idx,
 | 
			
		||||
    int                             instance_idx,
 | 
			
		||||
| 
						 | 
				
			
			@ -666,7 +562,6 @@ int GLVolumeCollection::load_object_volume(
 | 
			
		|||
        v.set_convex_hull(&model_volume->get_convex_hull(), false);
 | 
			
		||||
        if (extruder_id != -1)
 | 
			
		||||
            v.extruder_id = extruder_id;
 | 
			
		||||
        v.layer_height_texture = layer_height_texture;
 | 
			
		||||
    }
 | 
			
		||||
    v.is_modifier = ! model_volume->is_model_part();
 | 
			
		||||
    v.shader_outside_printer_detection_enabled = model_volume->is_model_part();
 | 
			
		||||
| 
						 | 
				
			
			@ -795,17 +690,19 @@ int GLVolumeCollection::load_wipe_tower_preview(
 | 
			
		|||
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
 | 
			
		||||
typedef std::pair<GLVolume*, double> GLVolumeWithZ;
 | 
			
		||||
typedef std::vector<GLVolumeWithZ> GLVolumesWithZList;
 | 
			
		||||
GLVolumesWithZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type)
 | 
			
		||||
static GLVolumesWithZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, std::function<bool(const GLVolume&)> filter_func)
 | 
			
		||||
{
 | 
			
		||||
    GLVolumesWithZList list;
 | 
			
		||||
    list.reserve(volumes.size());
 | 
			
		||||
 | 
			
		||||
    for (GLVolume* volume : volumes)
 | 
			
		||||
    {
 | 
			
		||||
        bool is_transparent = (volume->render_color[3] < 1.0f);
 | 
			
		||||
        if (((type == GLVolumeCollection::Opaque) && !is_transparent) ||
 | 
			
		||||
            ((type == GLVolumeCollection::Transparent) && is_transparent) ||
 | 
			
		||||
            (type == GLVolumeCollection::All))
 | 
			
		||||
            list.push_back(std::make_pair(volume, 0.0));
 | 
			
		||||
        if ((((type == GLVolumeCollection::Opaque) && !is_transparent) ||
 | 
			
		||||
             ((type == GLVolumeCollection::Transparent) && is_transparent) ||
 | 
			
		||||
             (type == GLVolumeCollection::All)) &&
 | 
			
		||||
            (! filter_func || filter_func(*volume)))
 | 
			
		||||
            list.emplace_back(std::make_pair(volume, 0.0));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((type == GLVolumeCollection::Transparent) && (list.size() > 1))
 | 
			
		||||
| 
						 | 
				
			
			@ -826,7 +723,7 @@ GLVolumesWithZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollec
 | 
			
		|||
    return list;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLVolumeCollection::render_VBOs(GLVolumeCollection::ERenderType type, bool disable_cullface) const
 | 
			
		||||
void GLVolumeCollection::render_VBOs(GLVolumeCollection::ERenderType type, bool disable_cullface, std::function<bool(const GLVolume&)> filter_func) const
 | 
			
		||||
#else
 | 
			
		||||
void GLVolumeCollection::render_VBOs() const
 | 
			
		||||
#endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
 | 
			
		||||
| 
						 | 
				
			
			@ -862,26 +759,17 @@ void GLVolumeCollection::render_VBOs() const
 | 
			
		|||
        ::glUniform2fv(z_range_id, 1, (const GLfloat*)z_range);
 | 
			
		||||
 | 
			
		||||
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
 | 
			
		||||
    GLVolumesWithZList to_render = volumes_to_render(this->volumes, type);
 | 
			
		||||
    for (GLVolumeWithZ& volume : to_render)
 | 
			
		||||
    {
 | 
			
		||||
        if (volume.first->layer_height_texture_data.can_use())
 | 
			
		||||
            volume.first->generate_layer_height_texture(volume.first->layer_height_texture_data.print_object, false);
 | 
			
		||||
        else
 | 
			
		||||
            volume.first->set_render_color();
 | 
			
		||||
 | 
			
		||||
    GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, filter_func);
 | 
			
		||||
    for (GLVolumeWithZ& volume : to_render) {
 | 
			
		||||
        volume.first->set_render_color();
 | 
			
		||||
        volume.first->render_VBOs(color_id, print_box_detection_id, print_box_worldmatrix_id);
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    for (GLVolume *volume : this->volumes)
 | 
			
		||||
    {
 | 
			
		||||
        if (volume->layer_height_texture_data.can_use())
 | 
			
		||||
            volume->generate_layer_height_texture(volume->layer_height_texture_data.print_object, false);
 | 
			
		||||
        else
 | 
			
		||||
        if (! filter_func || filter_func(*volume)) {
 | 
			
		||||
            volume->set_render_color();
 | 
			
		||||
 | 
			
		||||
        volume->render_VBOs(color_id, print_box_detection_id, print_box_worldmatrix_id);
 | 
			
		||||
    }
 | 
			
		||||
            volume->render_VBOs(color_id, print_box_detection_id, print_box_worldmatrix_id);
 | 
			
		||||
        }
 | 
			
		||||
#endif // ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
 | 
			
		||||
 | 
			
		||||
    ::glBindBuffer(GL_ARRAY_BUFFER, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -917,7 +805,7 @@ void GLVolumeCollection::render_legacy() const
 | 
			
		|||
    glEnableClientState(GL_NORMAL_ARRAY);
 | 
			
		||||
 
 | 
			
		||||
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
 | 
			
		||||
    GLVolumesWithZList to_render = volumes_to_render(this->volumes, type);
 | 
			
		||||
	GLVolumesWithZList to_render = volumes_to_render(this->volumes, type, std::function<bool(const GLVolume&)>());
 | 
			
		||||
    for (GLVolumeWithZ& volume : to_render)
 | 
			
		||||
    {
 | 
			
		||||
        volume.first->set_render_color();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,8 @@
 | 
			
		|||
#include "libslic3r/Model.hpp"
 | 
			
		||||
#include "slic3r/GUI/GLCanvas3DManager.hpp"
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
namespace Slic3r {
 | 
			
		||||
 | 
			
		||||
class Print;
 | 
			
		||||
| 
						 | 
				
			
			@ -199,50 +201,7 @@ private:
 | 
			
		|||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class LayersTexture
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    LayersTexture() : width(0), height(0), levels(0), cells(0) {}
 | 
			
		||||
 | 
			
		||||
    // Texture data
 | 
			
		||||
    std::vector<char>   data;
 | 
			
		||||
    // Width of the texture, top level.
 | 
			
		||||
    size_t              width;
 | 
			
		||||
    // Height of the texture, top level.
 | 
			
		||||
    size_t              height;
 | 
			
		||||
    // For how many levels of detail is the data allocated?
 | 
			
		||||
    size_t              levels;
 | 
			
		||||
    // Number of texture cells allocated for the height texture.
 | 
			
		||||
    size_t              cells;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class GLVolume {
 | 
			
		||||
    struct LayerHeightTextureData
 | 
			
		||||
    {
 | 
			
		||||
        // ID of the layer height texture
 | 
			
		||||
        unsigned int texture_id;
 | 
			
		||||
        // ID of the shader used to render with the layer height texture
 | 
			
		||||
        unsigned int shader_id;
 | 
			
		||||
        // The print object to update when generating the layer height texture
 | 
			
		||||
        const PrintObject* print_object;
 | 
			
		||||
 | 
			
		||||
        float        z_cursor_relative;
 | 
			
		||||
        float        edit_band_width;
 | 
			
		||||
 | 
			
		||||
        LayerHeightTextureData() { reset(); }
 | 
			
		||||
 | 
			
		||||
        void reset()
 | 
			
		||||
        {
 | 
			
		||||
            texture_id = 0;
 | 
			
		||||
            shader_id = 0;
 | 
			
		||||
            print_object = nullptr;
 | 
			
		||||
            z_cursor_relative = 0.0f;
 | 
			
		||||
            edit_band_width = 0.0f;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool can_use() const { return (texture_id > 0) && (shader_id > 0) && (print_object != nullptr); }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    static const float SELECTED_COLOR[4];
 | 
			
		||||
    static const float HOVER_COLOR[4];
 | 
			
		||||
| 
						 | 
				
			
			@ -406,7 +365,7 @@ public:
 | 
			
		|||
    int                 volume_idx() const { return this->composite_id.volume_id; }
 | 
			
		||||
    int                 instance_idx() const { return this->composite_id.instance_id; }
 | 
			
		||||
 | 
			
		||||
    Transform3d world_matrix() const;
 | 
			
		||||
    Transform3d         world_matrix() const;
 | 
			
		||||
 | 
			
		||||
    const BoundingBoxf3& transformed_bounding_box() const;
 | 
			
		||||
    const BoundingBoxf3& transformed_convex_hull_bounding_box() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -416,49 +375,13 @@ public:
 | 
			
		|||
 | 
			
		||||
    void                set_range(coordf_t low, coordf_t high);
 | 
			
		||||
    void                render() const;
 | 
			
		||||
    void                render_using_layer_height() const;
 | 
			
		||||
    void                render_VBOs(int color_id, int detection_id, int worldmatrix_id) const;
 | 
			
		||||
    void                render_legacy() const;
 | 
			
		||||
 | 
			
		||||
    void                finalize_geometry(bool use_VBOs) { this->indexed_vertex_array.finalize_geometry(use_VBOs); }
 | 
			
		||||
    void                release_geometry() { this->indexed_vertex_array.release_geometry(); }
 | 
			
		||||
 | 
			
		||||
    /************************************************ Layer height texture ****************************************************/
 | 
			
		||||
    std::shared_ptr<LayersTexture>  layer_height_texture;
 | 
			
		||||
    // Data to render this volume using the layer height texture
 | 
			
		||||
    LayerHeightTextureData layer_height_texture_data;
 | 
			
		||||
 | 
			
		||||
    bool                has_layer_height_texture() const 
 | 
			
		||||
        { return this->layer_height_texture.get() != nullptr; }
 | 
			
		||||
    size_t              layer_height_texture_width() const 
 | 
			
		||||
        { return (this->layer_height_texture.get() == nullptr) ? 0 : this->layer_height_texture->width; }
 | 
			
		||||
    size_t              layer_height_texture_height() const 
 | 
			
		||||
        { return (this->layer_height_texture.get() == nullptr) ? 0 : this->layer_height_texture->height; }
 | 
			
		||||
    size_t              layer_height_texture_cells() const 
 | 
			
		||||
        { return (this->layer_height_texture.get() == nullptr) ? 0 : this->layer_height_texture->cells; }
 | 
			
		||||
    void*               layer_height_texture_data_ptr_level0() const {
 | 
			
		||||
        return (layer_height_texture.get() == nullptr) ? 0 :
 | 
			
		||||
            (void*)layer_height_texture->data.data();
 | 
			
		||||
    }
 | 
			
		||||
    void*               layer_height_texture_data_ptr_level1() const {
 | 
			
		||||
        return (layer_height_texture.get() == nullptr) ? 0 :
 | 
			
		||||
            (void*)(layer_height_texture->data.data() + layer_height_texture->width * layer_height_texture->height * 4);
 | 
			
		||||
    }
 | 
			
		||||
    double              layer_height_texture_z_to_row_id() const;
 | 
			
		||||
    void                generate_layer_height_texture(const PrintObject *print_object, bool force);
 | 
			
		||||
 | 
			
		||||
    void set_layer_height_texture_data(unsigned int texture_id, unsigned int shader_id, const PrintObject* print_object, float z_cursor_relative, float edit_band_width)
 | 
			
		||||
    {
 | 
			
		||||
        layer_height_texture_data.texture_id = texture_id;
 | 
			
		||||
        layer_height_texture_data.shader_id = shader_id;
 | 
			
		||||
        layer_height_texture_data.print_object = print_object;
 | 
			
		||||
        layer_height_texture_data.z_cursor_relative = z_cursor_relative;
 | 
			
		||||
        layer_height_texture_data.edit_band_width = edit_band_width;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void reset_layer_height_texture_data() { layer_height_texture_data.reset(); }
 | 
			
		||||
 | 
			
		||||
    void set_bounding_boxes_as_dirty() { m_transformed_bounding_box_dirty = true; m_transformed_convex_hull_bounding_box_dirty = true; }
 | 
			
		||||
    void                set_bounding_boxes_as_dirty() { m_transformed_bounding_box_dirty = true; m_transformed_convex_hull_bounding_box_dirty = true; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef std::vector<GLVolume*> GLVolumePtrs;
 | 
			
		||||
| 
						 | 
				
			
			@ -498,7 +421,6 @@ public:
 | 
			
		|||
 | 
			
		||||
    int load_object_volume(
 | 
			
		||||
        const ModelObject       *model_object,
 | 
			
		||||
        std::shared_ptr<LayersTexture> &layer_height_texture,
 | 
			
		||||
        int                      obj_idx,
 | 
			
		||||
        int                      volume_idx,
 | 
			
		||||
        int                      instance_idx,
 | 
			
		||||
| 
						 | 
				
			
			@ -521,7 +443,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    // Render the volumes by OpenGL.
 | 
			
		||||
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
 | 
			
		||||
    void render_VBOs(ERenderType type, bool disable_cullface) const;
 | 
			
		||||
	void render_VBOs(ERenderType type, bool disable_cullface, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const;
 | 
			
		||||
    void render_legacy(ERenderType type, bool disable_cullface) const;
 | 
			
		||||
#else
 | 
			
		||||
    void render_VBOs() const;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -819,12 +819,16 @@ GLCanvas3D::LayersEditing::LayersEditing()
 | 
			
		|||
    : m_use_legacy_opengl(false)
 | 
			
		||||
    , m_enabled(false)
 | 
			
		||||
    , m_z_texture_id(0)
 | 
			
		||||
    , m_model_object(nullptr)
 | 
			
		||||
    , m_object_max_z(0.f)
 | 
			
		||||
    , m_slicing_parameters(new SlicingParameters)
 | 
			
		||||
    , m_layer_height_profile_modified(false)
 | 
			
		||||
    , state(Unknown)
 | 
			
		||||
    , band_width(2.0f)
 | 
			
		||||
    , strength(0.005f)
 | 
			
		||||
    , last_object_id(-1)
 | 
			
		||||
    , last_z(0.0f)
 | 
			
		||||
    , last_action(0)
 | 
			
		||||
    , last_action(LAYER_HEIGHT_EDIT_ACTION_INCREASE)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -835,6 +839,7 @@ GLCanvas3D::LayersEditing::~LayersEditing()
 | 
			
		|||
        ::glDeleteTextures(1, &m_z_texture_id);
 | 
			
		||||
        m_z_texture_id = 0;
 | 
			
		||||
    }
 | 
			
		||||
    delete m_slicing_parameters;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GLCanvas3D::LayersEditing::init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename)
 | 
			
		||||
| 
						 | 
				
			
			@ -854,9 +859,20 @@ bool GLCanvas3D::LayersEditing::init(const std::string& vertex_shader_filename,
 | 
			
		|||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::LayersEditing::select_object(const Model &model, int object_id)
 | 
			
		||||
{
 | 
			
		||||
    m_model_object   = (object_id >= 0) ? model.objects[object_id] : nullptr;
 | 
			
		||||
    m_object_max_z   = (m_model_object == nullptr) ? 0.f : m_model_object->bounding_box().max.z();
 | 
			
		||||
    if (m_model_object == nullptr || this->last_object_id != object_id) {
 | 
			
		||||
        m_layer_height_profile.clear();
 | 
			
		||||
        m_layer_height_profile_modified = false;
 | 
			
		||||
    }
 | 
			
		||||
    this->last_object_id = object_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GLCanvas3D::LayersEditing::is_allowed() const
 | 
			
		||||
{
 | 
			
		||||
    return !m_use_legacy_opengl && m_shader.is_initialized();
 | 
			
		||||
    return !m_use_legacy_opengl && m_shader.is_initialized() && m_shader.get_shader()->shader_program_id > 0 && m_z_texture_id > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::LayersEditing::set_use_legacy_opengl(bool use_legacy_opengl)
 | 
			
		||||
| 
						 | 
				
			
			@ -874,12 +890,7 @@ void GLCanvas3D::LayersEditing::set_enabled(bool enabled)
 | 
			
		|||
    m_enabled = is_allowed() && enabled;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int GLCanvas3D::LayersEditing::get_z_texture_id() const
 | 
			
		||||
{
 | 
			
		||||
    return m_z_texture_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::LayersEditing::render(const GLCanvas3D& canvas, const PrintObject& print_object, const GLVolume& volume) const
 | 
			
		||||
void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
 | 
			
		||||
{
 | 
			
		||||
    if (!m_enabled)
 | 
			
		||||
        return;
 | 
			
		||||
| 
						 | 
				
			
			@ -896,8 +907,8 @@ void GLCanvas3D::LayersEditing::render(const GLCanvas3D& canvas, const PrintObje
 | 
			
		|||
 | 
			
		||||
    _render_tooltip_texture(canvas, bar_rect, reset_rect);
 | 
			
		||||
    _render_reset_texture(reset_rect);
 | 
			
		||||
    _render_active_object_annotations(canvas, volume, print_object, bar_rect);
 | 
			
		||||
    _render_profile(print_object, bar_rect);
 | 
			
		||||
    _render_active_object_annotations(canvas, bar_rect);
 | 
			
		||||
    _render_profile(bar_rect);
 | 
			
		||||
 | 
			
		||||
    // Revert the matrices.
 | 
			
		||||
    ::glPopMatrix();
 | 
			
		||||
| 
						 | 
				
			
			@ -905,12 +916,6 @@ void GLCanvas3D::LayersEditing::render(const GLCanvas3D& canvas, const PrintObje
 | 
			
		|||
    ::glEnable(GL_DEPTH_TEST);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int GLCanvas3D::LayersEditing::get_shader_program_id() const
 | 
			
		||||
{
 | 
			
		||||
    const GLShader* shader = m_shader.get_shader();
 | 
			
		||||
    return (shader != nullptr) ? shader->shader_program_id : -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float GLCanvas3D::LayersEditing::get_cursor_z_relative(const GLCanvas3D& canvas)
 | 
			
		||||
{
 | 
			
		||||
    const Point& mouse_pos = canvas.get_local_mouse_position();
 | 
			
		||||
| 
						 | 
				
			
			@ -1023,21 +1028,19 @@ void GLCanvas3D::LayersEditing::_render_reset_texture(const Rect& reset_rect) co
 | 
			
		|||
    GLTexture::render_texture(m_reset_texture.get_id(), reset_rect.get_left(), reset_rect.get_right(), reset_rect.get_bottom(), reset_rect.get_top());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas3D& canvas, const GLVolume& volume, const PrintObject& print_object, const Rect& bar_rect) const
 | 
			
		||||
void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const
 | 
			
		||||
{
 | 
			
		||||
    float max_z = print_object.model_object()->bounding_box().max(2);
 | 
			
		||||
 | 
			
		||||
    m_shader.start_using();
 | 
			
		||||
 | 
			
		||||
    m_shader.set_uniform("z_to_texture_row", (float)volume.layer_height_texture_z_to_row_id());
 | 
			
		||||
    m_shader.set_uniform("z_texture_row_to_normalized", 1.0f / (float)volume.layer_height_texture_height());
 | 
			
		||||
    m_shader.set_uniform("z_cursor", max_z * get_cursor_z_relative(canvas));
 | 
			
		||||
    m_shader.set_uniform("z_to_texture_row", float(m_layers_texture.cells - 1) / (float(m_layers_texture.width) * m_object_max_z));
 | 
			
		||||
	m_shader.set_uniform("z_texture_row_to_normalized", 1.0f / (float)m_layers_texture.height);
 | 
			
		||||
    m_shader.set_uniform("z_cursor", m_object_max_z * this->get_cursor_z_relative(canvas));
 | 
			
		||||
    m_shader.set_uniform("z_cursor_band_width", band_width);
 | 
			
		||||
    // The shader requires the original model coordinates when rendering to the texture, so we pass it the unit matrix
 | 
			
		||||
    m_shader.set_uniform("volume_world_matrix", UNIT_MATRIX);
 | 
			
		||||
 | 
			
		||||
    GLsizei w = (GLsizei)volume.layer_height_texture_width();
 | 
			
		||||
    GLsizei h = (GLsizei)volume.layer_height_texture_height();
 | 
			
		||||
	GLsizei w = (GLsizei)m_layers_texture.width;
 | 
			
		||||
	GLsizei h = (GLsizei)m_layers_texture.height;
 | 
			
		||||
    GLsizei half_w = w / 2;
 | 
			
		||||
    GLsizei half_h = h / 2;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1045,8 +1048,8 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas
 | 
			
		|||
    ::glBindTexture(GL_TEXTURE_2D, m_z_texture_id);
 | 
			
		||||
    ::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
 | 
			
		||||
    ::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
 | 
			
		||||
    ::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, volume.layer_height_texture_data_ptr_level0());
 | 
			
		||||
    ::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, volume.layer_height_texture_data_ptr_level1());
 | 
			
		||||
	::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data());
 | 
			
		||||
	::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4);
 | 
			
		||||
 | 
			
		||||
    // Render the color bar
 | 
			
		||||
    float l = bar_rect.get_left();
 | 
			
		||||
| 
						 | 
				
			
			@ -1057,25 +1060,24 @@ void GLCanvas3D::LayersEditing::_render_active_object_annotations(const GLCanvas
 | 
			
		|||
    ::glBegin(GL_QUADS);
 | 
			
		||||
    ::glVertex3f(l, b, 0.0f);
 | 
			
		||||
    ::glVertex3f(r, b, 0.0f);
 | 
			
		||||
    ::glVertex3f(r, t, max_z);
 | 
			
		||||
    ::glVertex3f(l, t, max_z);
 | 
			
		||||
    ::glVertex3f(r, t, m_object_max_z);
 | 
			
		||||
    ::glVertex3f(l, t, m_object_max_z);
 | 
			
		||||
    ::glEnd();
 | 
			
		||||
    ::glBindTexture(GL_TEXTURE_2D, 0);
 | 
			
		||||
 | 
			
		||||
    m_shader.stop_using();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::LayersEditing::_render_profile(const PrintObject& print_object, const Rect& bar_rect) const
 | 
			
		||||
void GLCanvas3D::LayersEditing::_render_profile(const Rect& bar_rect) const
 | 
			
		||||
{
 | 
			
		||||
    // FIXME show some kind of legend.
 | 
			
		||||
    //FIXME show some kind of legend.
 | 
			
		||||
 | 
			
		||||
    // Get a maximum layer height value.
 | 
			
		||||
    // FIXME This is a duplicate code of Slicing.cpp.
 | 
			
		||||
    //FIXME This is a duplicate code of Slicing.cpp.
 | 
			
		||||
    double layer_height_max = DBL_MAX;
 | 
			
		||||
    const PrintConfig& print_config = print_object.print()->config();
 | 
			
		||||
    const std::vector<double>& nozzle_diameters = dynamic_cast<const ConfigOptionFloats*>(print_config.option("nozzle_diameter"))->values;
 | 
			
		||||
    const std::vector<double>& layer_heights_min = dynamic_cast<const ConfigOptionFloats*>(print_config.option("min_layer_height"))->values;
 | 
			
		||||
    const std::vector<double>& layer_heights_max = dynamic_cast<const ConfigOptionFloats*>(print_config.option("max_layer_height"))->values;
 | 
			
		||||
    const std::vector<double>& nozzle_diameters  = dynamic_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values;
 | 
			
		||||
    const std::vector<double>& layer_heights_min = dynamic_cast<const ConfigOptionFloats*>(m_config->option("min_layer_height"))->values;
 | 
			
		||||
    const std::vector<double>& layer_heights_max = dynamic_cast<const ConfigOptionFloats*>(m_config->option("max_layer_height"))->values;
 | 
			
		||||
    for (unsigned int i = 0; i < (unsigned int)nozzle_diameters.size(); ++i)
 | 
			
		||||
    {
 | 
			
		||||
        double lh_min = (layer_heights_min[i] == 0.0) ? 0.07 : std::max(0.01, layer_heights_min[i]);
 | 
			
		||||
| 
						 | 
				
			
			@ -1086,15 +1088,19 @@ void GLCanvas3D::LayersEditing::_render_profile(const PrintObject& print_object,
 | 
			
		|||
    // Make the vertical bar a bit wider so the layer height curve does not touch the edge of the bar region.
 | 
			
		||||
    layer_height_max *= 1.12;
 | 
			
		||||
 | 
			
		||||
    double max_z = unscale<double>(print_object.size(2));
 | 
			
		||||
    double layer_height = dynamic_cast<const ConfigOptionFloat*>(print_object.config().option("layer_height"))->value;
 | 
			
		||||
    // Get global layer height.
 | 
			
		||||
    double layer_height = dynamic_cast<const ConfigOptionFloat*>(m_config->option("layer_height"))->value;
 | 
			
		||||
    // Override the global layer height with object's layer height if set.
 | 
			
		||||
    const ConfigOption *opt_object_layer_height = m_model_object->config.option("layer_height");
 | 
			
		||||
    if (opt_object_layer_height != nullptr)
 | 
			
		||||
        layer_height = dynamic_cast<const ConfigOptionFloat*>(opt_object_layer_height)->value;
 | 
			
		||||
    float l = bar_rect.get_left();
 | 
			
		||||
    float w = bar_rect.get_right() - l;
 | 
			
		||||
    float b = bar_rect.get_bottom();
 | 
			
		||||
    float t = bar_rect.get_top();
 | 
			
		||||
    float h = t - b;
 | 
			
		||||
    float scale_x = w / (float)layer_height_max;
 | 
			
		||||
    float scale_y = h / (float)max_z;
 | 
			
		||||
    float scale_y = h / m_object_max_z;
 | 
			
		||||
    float x = l + (float)layer_height * scale_x;
 | 
			
		||||
 | 
			
		||||
    // Baseline
 | 
			
		||||
| 
						 | 
				
			
			@ -1105,19 +1111,129 @@ void GLCanvas3D::LayersEditing::_render_profile(const PrintObject& print_object,
 | 
			
		|||
    ::glEnd();
 | 
			
		||||
 | 
			
		||||
    // Curve
 | 
			
		||||
    const ModelObject* model_object = print_object.model_object();
 | 
			
		||||
    if (model_object->layer_height_profile_valid)
 | 
			
		||||
    {
 | 
			
		||||
        const std::vector<double>& profile = model_object->layer_height_profile;
 | 
			
		||||
    ::glColor3f(0.0f, 0.0f, 1.0f);
 | 
			
		||||
    ::glBegin(GL_LINE_STRIP);
 | 
			
		||||
    for (unsigned int i = 0; i < m_layer_height_profile.size(); i += 2)
 | 
			
		||||
        ::glVertex2f(l + (float)m_layer_height_profile[i + 1] * scale_x, b + (float)m_layer_height_profile[i] * scale_y);
 | 
			
		||||
    ::glEnd();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
        ::glColor3f(0.0f, 0.0f, 1.0f);
 | 
			
		||||
        ::glBegin(GL_LINE_STRIP);
 | 
			
		||||
        for (unsigned int i = 0; i < profile.size(); i += 2)
 | 
			
		||||
        {
 | 
			
		||||
            ::glVertex2f(l + (float)profile[i + 1] * scale_x, b + (float)profile[i] * scale_y);
 | 
			
		||||
void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const GLVolumeCollection &volumes) const
 | 
			
		||||
{
 | 
			
		||||
    assert(this->is_allowed());
 | 
			
		||||
    assert(this->last_object_id != -1);
 | 
			
		||||
    GLint shader_id = m_shader.get_shader()->shader_program_id;
 | 
			
		||||
    assert(shader_id > 0);
 | 
			
		||||
 | 
			
		||||
    GLint current_program_id;
 | 
			
		||||
    glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id);
 | 
			
		||||
    if (shader_id > 0 && shader_id != current_program_id)
 | 
			
		||||
        // The layer editing shader is not yet active. Activate it.
 | 
			
		||||
        glUseProgram(shader_id);
 | 
			
		||||
    else
 | 
			
		||||
        // The layer editing shader was already active.
 | 
			
		||||
        current_program_id = -1;
 | 
			
		||||
 | 
			
		||||
    GLint z_to_texture_row_id               = glGetUniformLocation(shader_id, "z_to_texture_row");
 | 
			
		||||
    GLint z_texture_row_to_normalized_id    = glGetUniformLocation(shader_id, "z_texture_row_to_normalized");
 | 
			
		||||
    GLint z_cursor_id                       = glGetUniformLocation(shader_id, "z_cursor");
 | 
			
		||||
    GLint z_cursor_band_width_id            = glGetUniformLocation(shader_id, "z_cursor_band_width");
 | 
			
		||||
    GLint world_matrix_id                   = glGetUniformLocation(shader_id, "volume_world_matrix");
 | 
			
		||||
 | 
			
		||||
    if (z_to_texture_row_id != -1 && z_texture_row_to_normalized_id != -1 && z_cursor_id != -1 && z_cursor_band_width_id != -1 && world_matrix_id != -1) 
 | 
			
		||||
    {
 | 
			
		||||
        const_cast<LayersEditing*>(this)->generate_layer_height_texture();
 | 
			
		||||
 | 
			
		||||
        // Uniforms were resolved, go ahead using the layer editing shader.
 | 
			
		||||
        glUniform1f(z_to_texture_row_id, GLfloat(m_layers_texture.cells - 1) / (GLfloat(m_layers_texture.width) * GLfloat(m_object_max_z)));
 | 
			
		||||
        glUniform1f(z_texture_row_to_normalized_id, GLfloat(1.0f / m_layers_texture.height));
 | 
			
		||||
		glUniform1f(z_cursor_id, GLfloat(m_object_max_z) * GLfloat(this->get_cursor_z_relative(canvas)));
 | 
			
		||||
		glUniform1f(z_cursor_band_width_id, GLfloat(this->band_width));
 | 
			
		||||
        // Initialize the layer height texture mapping.
 | 
			
		||||
        GLsizei w = (GLsizei)m_layers_texture.width;
 | 
			
		||||
        GLsizei h = (GLsizei)m_layers_texture.height;
 | 
			
		||||
        GLsizei half_w = w / 2;
 | 
			
		||||
        GLsizei half_h = h / 2;
 | 
			
		||||
        ::glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 | 
			
		||||
        glBindTexture(GL_TEXTURE_2D, m_z_texture_id);
 | 
			
		||||
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
 | 
			
		||||
        glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
 | 
			
		||||
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data());
 | 
			
		||||
        glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4);
 | 
			
		||||
        for (const GLVolume *glvolume : volumes.volumes) {
 | 
			
		||||
            // Render the object using the layer editing shader and texture.
 | 
			
		||||
            if (! glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier)
 | 
			
		||||
                continue;
 | 
			
		||||
            ::glUniformMatrix4fv(world_matrix_id, 1, GL_FALSE, (const GLfloat*)glvolume->world_matrix().cast<float>().data());
 | 
			
		||||
            glvolume->render();
 | 
			
		||||
        }
 | 
			
		||||
        ::glEnd();
 | 
			
		||||
        // Revert back to the previous shader.
 | 
			
		||||
        glBindTexture(GL_TEXTURE_2D, 0);
 | 
			
		||||
        if (current_program_id > 0)
 | 
			
		||||
            glUseProgram(current_program_id);
 | 
			
		||||
    } 
 | 
			
		||||
    else 
 | 
			
		||||
    {
 | 
			
		||||
        // Something went wrong. Just render the object.
 | 
			
		||||
        assert(false);
 | 
			
		||||
		for (const GLVolume *glvolume : volumes.volumes) {
 | 
			
		||||
			// Render the object using the layer editing shader and texture.
 | 
			
		||||
			if (!glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier)
 | 
			
		||||
				continue;
 | 
			
		||||
			::glUniformMatrix4fv(world_matrix_id, 1, GL_FALSE, (const GLfloat*)glvolume->world_matrix().cast<float>().data());
 | 
			
		||||
			glvolume->render();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::LayersEditing::adjust_layer_height_profile()
 | 
			
		||||
{
 | 
			
		||||
    *m_slicing_parameters = PrintObject::slicing_parameters(*m_config, *m_model_object);
 | 
			
		||||
	PrintObject::update_layer_height_profile(*m_model_object, *m_slicing_parameters, m_layer_height_profile);
 | 
			
		||||
	Slic3r::adjust_layer_height_profile(*m_slicing_parameters, m_layer_height_profile, this->last_z, this->strength, this->band_width, this->last_action);
 | 
			
		||||
	m_layer_height_profile_modified = true;
 | 
			
		||||
    m_layers_texture.valid = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::LayersEditing::generate_layer_height_texture()
 | 
			
		||||
{
 | 
			
		||||
    // Always try to update the layer height profile.
 | 
			
		||||
    bool update = ! m_layers_texture.valid;
 | 
			
		||||
    *m_slicing_parameters = PrintObject::slicing_parameters(*m_config, *m_model_object);
 | 
			
		||||
    if (PrintObject::update_layer_height_profile(*m_model_object, *m_slicing_parameters, m_layer_height_profile)) {
 | 
			
		||||
        // Initialized to the default value.
 | 
			
		||||
        m_layer_height_profile_modified = false;
 | 
			
		||||
        update = true;
 | 
			
		||||
    }
 | 
			
		||||
    // Update if the layer height profile was changed, or when the texture is not valid.
 | 
			
		||||
    if (! update && ! m_layers_texture.data.empty() && m_layers_texture.cells > 0)
 | 
			
		||||
        // Texture is valid, don't update.
 | 
			
		||||
        return; 
 | 
			
		||||
 | 
			
		||||
    if (m_layers_texture.data.empty()) {
 | 
			
		||||
        m_layers_texture.width  = 1024;
 | 
			
		||||
        m_layers_texture.height = 1024;
 | 
			
		||||
        m_layers_texture.levels = 2;
 | 
			
		||||
        m_layers_texture.data.assign(m_layers_texture.width * m_layers_texture.height * 5, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool level_of_detail_2nd_level = true;
 | 
			
		||||
    m_layers_texture.cells = Slic3r::generate_layer_height_texture(
 | 
			
		||||
        *m_slicing_parameters, 
 | 
			
		||||
        Slic3r::generate_object_layers(*m_slicing_parameters, m_layer_height_profile), 
 | 
			
		||||
		m_layers_texture.data.data(), m_layers_texture.height, m_layers_texture.width, level_of_detail_2nd_level);
 | 
			
		||||
	m_layers_texture.valid = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::LayersEditing::accept_changes(GLCanvas3D& canvas)
 | 
			
		||||
{
 | 
			
		||||
    if (last_object_id >= 0) {
 | 
			
		||||
        if (m_layer_height_profile_modified) {
 | 
			
		||||
            const_cast<ModelObject*>(m_model_object)->layer_height_profile = m_layer_height_profile;
 | 
			
		||||
			canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    m_layer_height_profile_modified = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Point GLCanvas3D::Mouse::Drag::Invalid_2D_Point(INT_MAX, INT_MAX);
 | 
			
		||||
| 
						 | 
				
			
			@ -3689,7 +3805,6 @@ wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
 | 
			
		|||
wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
 | 
			
		||||
wxDEFINE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent);
 | 
			
		||||
wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent);
 | 
			
		||||
wxDEFINE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent);
 | 
			
		||||
wxDEFINE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
 | 
			
		||||
wxDEFINE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent);
 | 
			
		||||
wxDEFINE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent);
 | 
			
		||||
| 
						 | 
				
			
			@ -3916,9 +4031,10 @@ int GLCanvas3D::check_volumes_outside_state() const
 | 
			
		|||
    return (int)state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::set_config(DynamicPrintConfig* config)
 | 
			
		||||
void GLCanvas3D::set_config(const DynamicPrintConfig* config)
 | 
			
		||||
{
 | 
			
		||||
    m_config = config;
 | 
			
		||||
    m_layers_editing.set_config(config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::set_process(BackgroundSlicingProcess *process)
 | 
			
		||||
| 
						 | 
				
			
			@ -4262,7 +4378,8 @@ void GLCanvas3D::render()
 | 
			
		|||
    _resize_toolbars();
 | 
			
		||||
    _render_toolbar();
 | 
			
		||||
    _render_view_toolbar();
 | 
			
		||||
    _render_layer_editing_overlay();
 | 
			
		||||
    if (m_layers_editing.last_object_id >= 0)
 | 
			
		||||
        m_layers_editing.render_overlay(*this);
 | 
			
		||||
 | 
			
		||||
#if ENABLE_IMGUI
 | 
			
		||||
    wxGetApp().imgui()->render();
 | 
			
		||||
| 
						 | 
				
			
			@ -4502,8 +4619,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
 | 
			
		|||
        m_volumes.volumes = std::move(glvolumes_new);
 | 
			
		||||
        for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++ obj_idx) {
 | 
			
		||||
            const ModelObject &model_object = *m_model->objects[obj_idx];
 | 
			
		||||
            // Object will share a single common layer height texture between all printable volumes.
 | 
			
		||||
            std::shared_ptr<LayersTexture> layer_height_texture;
 | 
			
		||||
            for (int volume_idx = 0; volume_idx < (int)model_object.volumes.size(); ++ volume_idx) {
 | 
			
		||||
				const ModelVolume &model_volume = *model_object.volumes[volume_idx];
 | 
			
		||||
                for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) {
 | 
			
		||||
| 
						 | 
				
			
			@ -4513,33 +4628,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
 | 
			
		|||
					assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id);
 | 
			
		||||
                    if (it->new_geometry()) {
 | 
			
		||||
                        // New volume.
 | 
			
		||||
						if (model_volume.is_model_part() && ! layer_height_texture) {
 | 
			
		||||
                            // New object part needs to have the layer height texture assigned, which is shared with the other volumes of the same part.
 | 
			
		||||
                            // Search for the layer height texture in the other volumes.
 | 
			
		||||
                            for (int iv = volume_idx; iv < (int)model_object.volumes.size(); ++ iv) {
 | 
			
		||||
								const ModelVolume &mv = *model_object.volumes[iv];
 | 
			
		||||
								if (mv.is_model_part())
 | 
			
		||||
									for (int ii = instance_idx; ii < (int)model_object.instances.size(); ++ ii) {
 | 
			
		||||
										const ModelInstance &mi = *model_object.instances[ii];
 | 
			
		||||
										ModelVolumeState key(mv.id(), mi.id());
 | 
			
		||||
										auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower);
 | 
			
		||||
										assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id);
 | 
			
		||||
										if (! it->new_geometry()) {
 | 
			
		||||
											// Found an old printable GLVolume (existing before this function was called).
 | 
			
		||||
                                            assert(m_volumes.volumes[it->volume_idx]->geometry_id == key.geometry_id);
 | 
			
		||||
											// Reuse the layer height texture.
 | 
			
		||||
											const GLVolume *volume = m_volumes.volumes[it->volume_idx];
 | 
			
		||||
											assert(volume->layer_height_texture);
 | 
			
		||||
											layer_height_texture = volume->layer_height_texture;
 | 
			
		||||
											goto iv_end;
 | 
			
		||||
										}
 | 
			
		||||
									}
 | 
			
		||||
							}
 | 
			
		||||
                        iv_end:
 | 
			
		||||
                            if (! layer_height_texture)
 | 
			
		||||
                                layer_height_texture = std::make_shared<LayersTexture>();
 | 
			
		||||
                        }
 | 
			
		||||
                        m_volumes.load_object_volume(&model_object, layer_height_texture, obj_idx, volume_idx, instance_idx, m_color_by, m_use_VBOs && m_initialized);
 | 
			
		||||
                        m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_use_VBOs && m_initialized);
 | 
			
		||||
						m_volumes.volumes.back()->geometry_id = key.geometry_id;
 | 
			
		||||
                    } else {
 | 
			
		||||
						// Recycling an old GLVolume.
 | 
			
		||||
| 
						 | 
				
			
			@ -4547,11 +4636,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
 | 
			
		|||
                        assert(existing_volume.geometry_id == key.geometry_id);
 | 
			
		||||
						// Update the Object/Volume/Instance indices into the current Model.
 | 
			
		||||
                        existing_volume.composite_id = it->composite_id;
 | 
			
		||||
						if (model_volume.is_model_part() && ! layer_height_texture) {
 | 
			
		||||
                            assert(existing_volume.layer_height_texture);
 | 
			
		||||
                            // cache its layer height texture
 | 
			
		||||
                            layer_height_texture = existing_volume.layer_height_texture;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -4945,10 +5029,8 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt)
 | 
			
		|||
 | 
			
		||||
void GLCanvas3D::on_timer(wxTimerEvent& evt)
 | 
			
		||||
{
 | 
			
		||||
    if (m_layers_editing.state != LayersEditing::Editing)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    _perform_layer_editing_action();
 | 
			
		||||
    if (m_layers_editing.state == LayersEditing::Editing)
 | 
			
		||||
        _perform_layer_editing_action();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 | 
			
		||||
| 
						 | 
				
			
			@ -4967,7 +5049,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 | 
			
		|||
 | 
			
		||||
    int selected_object_idx = m_selection.get_object_idx();
 | 
			
		||||
    int layer_editing_object_idx = is_layers_editing_enabled() ? selected_object_idx : -1;
 | 
			
		||||
    m_layers_editing.last_object_id = layer_editing_object_idx;
 | 
			
		||||
    m_layers_editing.select_object(*m_model, layer_editing_object_idx);
 | 
			
		||||
    bool gizmos_overlay_contains_mouse = m_gizmos.overlay_contains_mouse(*this, m_mouse.position);
 | 
			
		||||
    int toolbar_contains_mouse = m_toolbar.contains_mouse(m_mouse.position, *this);
 | 
			
		||||
    int view_toolbar_contains_mouse = (m_view_toolbar != nullptr) ? m_view_toolbar->contains_mouse(m_mouse.position, *this) : -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -5032,10 +5114,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 | 
			
		|||
        {
 | 
			
		||||
            if (evt.LeftDown())
 | 
			
		||||
            {
 | 
			
		||||
                // A volume is selected and the mouse is inside the reset button.
 | 
			
		||||
                // The PrintObject::adjust_layer_height_profile() call adjusts the profile of its associated ModelObject, it does not modify the profile of the PrintObject itself,
 | 
			
		||||
                // therefore it is safe to call it while the background processing is running.
 | 
			
		||||
                const_cast<PrintObject*>(this->fff_print()->get_object(layer_editing_object_idx))->reset_layer_height_profile();
 | 
			
		||||
                // A volume is selected and the mouse is inside the reset button. Reset the ModelObject's layer height profile.
 | 
			
		||||
				m_model->objects[layer_editing_object_idx]->layer_height_profile.clear();
 | 
			
		||||
                // Index 2 means no editing, just wait for mouse up event.
 | 
			
		||||
                m_layers_editing.state = LayersEditing::Completed;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -5296,9 +5376,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 | 
			
		|||
        {
 | 
			
		||||
            m_layers_editing.state = LayersEditing::Unknown;
 | 
			
		||||
            _stop_timer();
 | 
			
		||||
 | 
			
		||||
            if (layer_editing_object_idx != -1)
 | 
			
		||||
                post_event(SimpleEvent(EVT_GLCANVAS_MODEL_UPDATE));
 | 
			
		||||
            m_layers_editing.accept_changes(*this);
 | 
			
		||||
        }
 | 
			
		||||
        else if ((m_mouse.drag.move_volume_idx != -1) && m_mouse.dragging)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -6074,28 +6152,6 @@ float GLCanvas3D::_get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) co
 | 
			
		|||
    return (float)std::min((double)cnv_size.get_width() / max_x, (double)cnv_size.get_height() / max_y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::_mark_volumes_for_layer_height() const
 | 
			
		||||
{
 | 
			
		||||
    const Print *print = (m_process == nullptr) ? nullptr : m_process->fff_print();
 | 
			
		||||
    if (print == nullptr)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    for (GLVolume* vol : m_volumes.volumes)
 | 
			
		||||
    {
 | 
			
		||||
        int object_id = vol->object_idx();
 | 
			
		||||
        int shader_id = m_layers_editing.get_shader_program_id();
 | 
			
		||||
 | 
			
		||||
        if (is_layers_editing_enabled() && (shader_id != -1) && vol->selected &&
 | 
			
		||||
            vol->has_layer_height_texture() && (object_id < (int)print->objects().size()))
 | 
			
		||||
        {
 | 
			
		||||
            vol->set_layer_height_texture_data(m_layers_editing.get_z_texture_id(), shader_id,
 | 
			
		||||
                print->get_object(object_id), _get_layers_editing_cursor_z_relative(), m_layers_editing.band_width);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            vol->reset_layer_height_texture_data();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::_refresh_if_shown_on_screen()
 | 
			
		||||
{
 | 
			
		||||
    if (_is_shown_on_screen())
 | 
			
		||||
| 
						 | 
				
			
			@ -6241,7 +6297,8 @@ void GLCanvas3D::_render_objects() const
 | 
			
		|||
    {
 | 
			
		||||
        if (m_picking_enabled)
 | 
			
		||||
        {
 | 
			
		||||
            _mark_volumes_for_layer_height();
 | 
			
		||||
            // Update the layer editing selection to the first object selected, update the current object maximum Z.
 | 
			
		||||
            const_cast<LayersEditing&>(m_layers_editing).select_object(*m_model, this->is_layers_editing_enabled() ? m_selection.get_object_idx() : -1);
 | 
			
		||||
 | 
			
		||||
            if (m_config != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -6262,8 +6319,18 @@ void GLCanvas3D::_render_objects() const
 | 
			
		|||
 | 
			
		||||
        m_shader.start_using();
 | 
			
		||||
#if ENABLE_IMPROVED_TRANSPARENT_VOLUMES_RENDERING
 | 
			
		||||
        // do not cull backfaces to show broken geometry, if any
 | 
			
		||||
        m_volumes.render_VBOs(GLVolumeCollection::Opaque, m_picking_enabled);
 | 
			
		||||
        if (m_picking_enabled && m_layers_editing.is_enabled() && m_layers_editing.last_object_id != -1) {
 | 
			
		||||
			int object_id = m_layers_editing.last_object_id;
 | 
			
		||||
			m_volumes.render_VBOs(GLVolumeCollection::Opaque, false, [object_id](const GLVolume &volume) {
 | 
			
		||||
                // Which volume to paint without the layer height profile shader?
 | 
			
		||||
				return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id);
 | 
			
		||||
            });
 | 
			
		||||
            // Let LayersEditing handle rendering of the active object using the layer height profile shader.
 | 
			
		||||
            m_layers_editing.render_volumes(*this, this->m_volumes);
 | 
			
		||||
        } else {
 | 
			
		||||
            // do not cull backfaces to show broken geometry, if any
 | 
			
		||||
            m_volumes.render_VBOs(GLVolumeCollection::Opaque, m_picking_enabled);
 | 
			
		||||
        }
 | 
			
		||||
        m_volumes.render_VBOs(GLVolumeCollection::Transparent, false);
 | 
			
		||||
#else
 | 
			
		||||
        m_volumes.render_VBOs();
 | 
			
		||||
| 
						 | 
				
			
			@ -6344,39 +6411,6 @@ void GLCanvas3D::_render_legend_texture() const
 | 
			
		|||
    m_legend_texture.render(*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::_render_layer_editing_overlay() const
 | 
			
		||||
{
 | 
			
		||||
    const Print *print = this->fff_print();
 | 
			
		||||
    if ((print == nullptr) || print->objects().empty())
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    GLVolume* volume = nullptr;
 | 
			
		||||
 | 
			
		||||
    for (GLVolume* vol : m_volumes.volumes)
 | 
			
		||||
    {
 | 
			
		||||
        if ((vol != nullptr) && vol->selected && vol->has_layer_height_texture())
 | 
			
		||||
        {
 | 
			
		||||
            volume = vol;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (volume == nullptr)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // If the active object was not allocated at the Print, go away.This should only be a momentary case between an object addition / deletion
 | 
			
		||||
    // and an update by Platter::async_apply_config.
 | 
			
		||||
    int object_idx = volume->object_idx();
 | 
			
		||||
    if ((int)print->objects().size() <= object_idx)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    const PrintObject* print_object = print->get_object(object_idx);
 | 
			
		||||
    if (print_object == nullptr)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    m_layers_editing.render(*this, *print_object, *volume);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::_render_volumes(bool fake_colors) const
 | 
			
		||||
{
 | 
			
		||||
    static const GLfloat INV_255 = 1.0f / 255.0f;
 | 
			
		||||
| 
						 | 
				
			
			@ -6776,55 +6810,24 @@ void GLCanvas3D::_update_gizmos_data()
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float GLCanvas3D::_get_layers_editing_cursor_z_relative() const
 | 
			
		||||
{
 | 
			
		||||
    return m_layers_editing.get_cursor_z_relative(*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLCanvas3D::_perform_layer_editing_action(wxMouseEvent* evt)
 | 
			
		||||
{
 | 
			
		||||
    int object_idx_selected = m_layers_editing.last_object_id;
 | 
			
		||||
    if (object_idx_selected == -1)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    const Print *print = this->fff_print();
 | 
			
		||||
    if (print == nullptr)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    const PrintObject* selected_obj = print->get_object(object_idx_selected);
 | 
			
		||||
    if (selected_obj == nullptr)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // A volume is selected. Test, whether hovering over a layer thickness bar.
 | 
			
		||||
    if (evt != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        const Rect& rect = LayersEditing::get_bar_rect_screen(*this);
 | 
			
		||||
        float b = rect.get_bottom();
 | 
			
		||||
        m_layers_editing.last_z = unscale<double>(selected_obj->size(2)) * (b - evt->GetY() - 1.0f) / (b - rect.get_top());
 | 
			
		||||
        m_layers_editing.last_action = evt->ShiftDown() ? (evt->RightIsDown() ? 3 : 2) : (evt->RightIsDown() ? 0 : 1);
 | 
			
		||||
        m_layers_editing.last_z = m_layers_editing.object_max_z() * (b - evt->GetY() - 1.0f) / (b - rect.get_top());
 | 
			
		||||
        m_layers_editing.last_action = 
 | 
			
		||||
            evt->ShiftDown() ? (evt->RightIsDown() ? LAYER_HEIGHT_EDIT_ACTION_SMOOTH : LAYER_HEIGHT_EDIT_ACTION_REDUCE) : 
 | 
			
		||||
                               (evt->RightIsDown() ? LAYER_HEIGHT_EDIT_ACTION_INCREASE : LAYER_HEIGHT_EDIT_ACTION_DECREASE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Mark the volume as modified, so Print will pick its layer height profile ? Where to mark it ?
 | 
			
		||||
    // Start a timer to refresh the print ? schedule_background_process() ?
 | 
			
		||||
    // The PrintObject::adjust_layer_height_profile() call adjusts the profile of its associated ModelObject, it does not modify the profile of the PrintObject itself,
 | 
			
		||||
    // therefore it is safe to call it while the background processing is running.
 | 
			
		||||
    const_cast<PrintObject*>(selected_obj)->adjust_layer_height_profile(m_layers_editing.last_z, m_layers_editing.strength, m_layers_editing.band_width, m_layers_editing.last_action);
 | 
			
		||||
 | 
			
		||||
    // searches the id of the first volume of the selected object
 | 
			
		||||
    int volume_idx = 0;
 | 
			
		||||
    for (int i = 0; i < object_idx_selected; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        const PrintObject* obj = print->get_object(i);
 | 
			
		||||
        if (obj != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            for (int j = 0; j < (int)obj->region_volumes.size(); ++j)
 | 
			
		||||
            {
 | 
			
		||||
                volume_idx += (int)obj->region_volumes[j].size();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_volumes.volumes[volume_idx]->generate_layer_height_texture(selected_obj, 1);
 | 
			
		||||
    m_layers_editing.adjust_layer_height_profile();
 | 
			
		||||
    _refresh_if_shown_on_screen();
 | 
			
		||||
 | 
			
		||||
    // Automatic action on mouse down with the same coordinate.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,6 +29,8 @@ class GLShader;
 | 
			
		|||
class ExPolygon;
 | 
			
		||||
class BackgroundSlicingProcess;
 | 
			
		||||
class GCodePreviewData;
 | 
			
		||||
struct SlicingParameters;
 | 
			
		||||
enum LayerHeightEditActionType : unsigned int;
 | 
			
		||||
 | 
			
		||||
namespace GUI {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -101,7 +103,6 @@ wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent);
 | 
			
		|||
wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
 | 
			
		||||
wxDECLARE_EVENT(EVT_GLCANVAS_VIEWPORT_CHANGED, SimpleEvent);
 | 
			
		||||
wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent);
 | 
			
		||||
wxDECLARE_EVENT(EVT_GLCANVAS_MODEL_UPDATE, SimpleEvent);
 | 
			
		||||
wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
 | 
			
		||||
wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent);
 | 
			
		||||
wxDECLARE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent);
 | 
			
		||||
| 
						 | 
				
			
			@ -293,12 +294,42 @@ class GLCanvas3D
 | 
			
		|||
        };
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        bool m_use_legacy_opengl;
 | 
			
		||||
        bool m_enabled;
 | 
			
		||||
        Shader m_shader;
 | 
			
		||||
        unsigned int m_z_texture_id;
 | 
			
		||||
        mutable GLTexture m_tooltip_texture;
 | 
			
		||||
        mutable GLTexture m_reset_texture;
 | 
			
		||||
        bool                        m_use_legacy_opengl;
 | 
			
		||||
        bool                        m_enabled;
 | 
			
		||||
        Shader                      m_shader;
 | 
			
		||||
        unsigned int                m_z_texture_id;
 | 
			
		||||
        mutable GLTexture           m_tooltip_texture;
 | 
			
		||||
        mutable GLTexture           m_reset_texture;
 | 
			
		||||
        // Not owned by LayersEditing.
 | 
			
		||||
        const DynamicPrintConfig   *m_config;
 | 
			
		||||
        // ModelObject for the currently selected object (Model::objects[last_object_id]).
 | 
			
		||||
        const ModelObject          *m_model_object;
 | 
			
		||||
        // Maximum z of the currently selected object (Model::objects[last_object_id]).
 | 
			
		||||
        float                       m_object_max_z;
 | 
			
		||||
        // Owned by LayersEditing.
 | 
			
		||||
        SlicingParameters          *m_slicing_parameters;
 | 
			
		||||
        std::vector<coordf_t>       m_layer_height_profile;
 | 
			
		||||
        bool                        m_layer_height_profile_modified;
 | 
			
		||||
 | 
			
		||||
        class LayersTexture
 | 
			
		||||
        {
 | 
			
		||||
        public:
 | 
			
		||||
            LayersTexture() : width(0), height(0), levels(0), cells(0), valid(false) {}
 | 
			
		||||
 | 
			
		||||
            // Texture data
 | 
			
		||||
            std::vector<char>   data;
 | 
			
		||||
            // Width of the texture, top level.
 | 
			
		||||
            size_t              width;
 | 
			
		||||
            // Height of the texture, top level.
 | 
			
		||||
            size_t              height;
 | 
			
		||||
            // For how many levels of detail is the data allocated?
 | 
			
		||||
            size_t              levels;
 | 
			
		||||
            // Number of texture cells allocated for the height texture.
 | 
			
		||||
            size_t              cells;
 | 
			
		||||
            // Does it need to be refreshed?
 | 
			
		||||
            bool                valid;
 | 
			
		||||
        };
 | 
			
		||||
        LayersTexture   m_layers_texture;
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        EState state;
 | 
			
		||||
| 
						 | 
				
			
			@ -306,12 +337,14 @@ class GLCanvas3D
 | 
			
		|||
        float strength;
 | 
			
		||||
        int last_object_id;
 | 
			
		||||
        float last_z;
 | 
			
		||||
        unsigned int last_action;
 | 
			
		||||
        LayerHeightEditActionType last_action;
 | 
			
		||||
 | 
			
		||||
        LayersEditing();
 | 
			
		||||
        ~LayersEditing();
 | 
			
		||||
 | 
			
		||||
        bool init(const std::string& vertex_shader_filename, const std::string& fragment_shader_filename);
 | 
			
		||||
        void set_config(const DynamicPrintConfig* config) { m_config = config; }
 | 
			
		||||
        void select_object(const Model &model, int object_id);
 | 
			
		||||
 | 
			
		||||
        bool is_allowed() const;
 | 
			
		||||
        void set_use_legacy_opengl(bool use_legacy_opengl);
 | 
			
		||||
| 
						 | 
				
			
			@ -319,11 +352,12 @@ class GLCanvas3D
 | 
			
		|||
        bool is_enabled() const;
 | 
			
		||||
        void set_enabled(bool enabled);
 | 
			
		||||
 | 
			
		||||
        unsigned int get_z_texture_id() const;
 | 
			
		||||
        void render_overlay(const GLCanvas3D& canvas) const;
 | 
			
		||||
        void render_volumes(const GLCanvas3D& canvas, const GLVolumeCollection& volumes) const;
 | 
			
		||||
 | 
			
		||||
        void render(const GLCanvas3D& canvas, const PrintObject& print_object, const GLVolume& volume) const;
 | 
			
		||||
 | 
			
		||||
        int get_shader_program_id() const;
 | 
			
		||||
        void generate_layer_height_texture();
 | 
			
		||||
		void adjust_layer_height_profile();
 | 
			
		||||
		void accept_changes(GLCanvas3D& canvas);
 | 
			
		||||
 | 
			
		||||
        static float get_cursor_z_relative(const GLCanvas3D& canvas);
 | 
			
		||||
        static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y);
 | 
			
		||||
| 
						 | 
				
			
			@ -333,12 +367,14 @@ class GLCanvas3D
 | 
			
		|||
        static Rect get_bar_rect_viewport(const GLCanvas3D& canvas);
 | 
			
		||||
        static Rect get_reset_rect_viewport(const GLCanvas3D& canvas);
 | 
			
		||||
 | 
			
		||||
        float object_max_z() const { return m_object_max_z; }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        bool _is_initialized() const;
 | 
			
		||||
        void _render_tooltip_texture(const GLCanvas3D& canvas, const Rect& bar_rect, const Rect& reset_rect) const;
 | 
			
		||||
        void _render_reset_texture(const Rect& reset_rect) const;
 | 
			
		||||
        void _render_active_object_annotations(const GLCanvas3D& canvas, const GLVolume& volume, const PrintObject& print_object, const Rect& bar_rect) const;
 | 
			
		||||
        void _render_profile(const PrintObject& print_object, const Rect& bar_rect) const;
 | 
			
		||||
        void _render_active_object_annotations(const GLCanvas3D& canvas, const Rect& bar_rect) const;
 | 
			
		||||
        void _render_profile(const Rect& bar_rect) const;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct Mouse
 | 
			
		||||
| 
						 | 
				
			
			@ -821,7 +857,7 @@ private:
 | 
			
		|||
 | 
			
		||||
    mutable GLVolumeCollection m_volumes;
 | 
			
		||||
    Selection m_selection;
 | 
			
		||||
    DynamicPrintConfig* m_config;
 | 
			
		||||
    const DynamicPrintConfig* m_config;
 | 
			
		||||
    Model* m_model;
 | 
			
		||||
    BackgroundSlicingProcess *m_process;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -881,7 +917,7 @@ public:
 | 
			
		|||
    void reset_volumes();
 | 
			
		||||
    int check_volumes_outside_state() const;
 | 
			
		||||
 | 
			
		||||
    void set_config(DynamicPrintConfig* config);
 | 
			
		||||
    void set_config(const DynamicPrintConfig* config);
 | 
			
		||||
    void set_process(BackgroundSlicingProcess* process);
 | 
			
		||||
    void set_model(Model* model);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1023,7 +1059,6 @@ private:
 | 
			
		|||
    void _zoom_to_bounding_box(const BoundingBoxf3& bbox);
 | 
			
		||||
    float _get_zoom_to_bounding_box_factor(const BoundingBoxf3& bbox) const;
 | 
			
		||||
 | 
			
		||||
    void _mark_volumes_for_layer_height() const;
 | 
			
		||||
    void _refresh_if_shown_on_screen();
 | 
			
		||||
 | 
			
		||||
    void _camera_tranform() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -1038,7 +1073,6 @@ private:
 | 
			
		|||
#endif // ENABLE_RENDER_SELECTION_CENTER
 | 
			
		||||
    void _render_warning_texture() const;
 | 
			
		||||
    void _render_legend_texture() const;
 | 
			
		||||
    void _render_layer_editing_overlay() const;
 | 
			
		||||
    void _render_volumes(bool fake_colors) const;
 | 
			
		||||
    void _render_current_gizmo() const;
 | 
			
		||||
    void _render_gizmos_overlay() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -1055,7 +1089,6 @@ private:
 | 
			
		|||
    void _update_volumes_hover_state() const;
 | 
			
		||||
    void _update_gizmos_data();
 | 
			
		||||
 | 
			
		||||
    float _get_layers_editing_cursor_z_relative() const;
 | 
			
		||||
    void _perform_layer_editing_action(wxMouseEvent* evt = nullptr);
 | 
			
		||||
 | 
			
		||||
    // Convert the screen space coordinate to an object space coordinate.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@
 | 
			
		|||
namespace Slic3r {
 | 
			
		||||
namespace GUI {
 | 
			
		||||
 | 
			
		||||
    View3D::View3D(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
 | 
			
		||||
View3D::View3D(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
 | 
			
		||||
    : m_canvas_widget(nullptr)
 | 
			
		||||
    , m_canvas(nullptr)
 | 
			
		||||
#if !ENABLE_IMGUI
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -159,6 +159,7 @@ void MainFrame::create_preset_tabs()
 | 
			
		|||
    add_created_tab(new TabSLAPrint(m_tabpanel));
 | 
			
		||||
    add_created_tab(new TabSLAMaterial(m_tabpanel));
 | 
			
		||||
    add_created_tab(new TabPrinter(m_tabpanel));
 | 
			
		||||
    GUI::wxGetApp().load_current_presets();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MainFrame::add_created_tab(Tab* panel)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1088,7 +1088,10 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
 | 
			
		|||
        "brim_width", "variable_layer_height", "serial_port", "serial_speed", "host_type", "print_host",
 | 
			
		||||
        "printhost_apikey", "printhost_cafile", "nozzle_diameter", "single_extruder_multi_material",
 | 
			
		||||
        "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle",
 | 
			
		||||
        "extruder_colour", "filament_colour", "max_print_height", "printer_model", "printer_technology"
 | 
			
		||||
        "extruder_colour", "filament_colour", "max_print_height", "printer_model", "printer_technology",
 | 
			
		||||
        // The following three layer height config values are passed here for View3D::m_canvas to receive
 | 
			
		||||
        // layer height updates for the layer height.
 | 
			
		||||
        "min_layer_height", "max_layer_height", "layer_height", "first_layer_height"
 | 
			
		||||
        }))
 | 
			
		||||
    , sidebar(new Sidebar(q))
 | 
			
		||||
    , delayed_scene_refresh(false)
 | 
			
		||||
| 
						 | 
				
			
			@ -1157,7 +1160,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
 | 
			
		|||
    view3D_canvas->Bind(EVT_GLCANVAS_OBJECT_SELECT, &priv::on_object_select, this);
 | 
			
		||||
    view3D_canvas->Bind(EVT_GLCANVAS_VIEWPORT_CHANGED, &priv::on_viewport_changed, this);
 | 
			
		||||
    view3D_canvas->Bind(EVT_GLCANVAS_RIGHT_CLICK, &priv::on_right_click, this);
 | 
			
		||||
    view3D_canvas->Bind(EVT_GLCANVAS_MODEL_UPDATE, [this](SimpleEvent&) { this->schedule_background_process(); });
 | 
			
		||||
    view3D_canvas->Bind(EVT_GLCANVAS_REMOVE_OBJECT, [q](SimpleEvent&) { q->remove_selected(); });
 | 
			
		||||
    view3D_canvas->Bind(EVT_GLCANVAS_ARRANGE, [this](SimpleEvent&) { arrange(); });
 | 
			
		||||
    view3D_canvas->Bind(EVT_GLCANVAS_QUESTION_MARK, [this](SimpleEvent&) { wxGetApp().keyboard_shortcuts(); });
 | 
			
		||||
| 
						 | 
				
			
			@ -2035,7 +2037,7 @@ void Plater::priv::reload_from_disk()
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // XXX: Restore more: layer_height_ranges, layer_height_profile, layer_height_profile_valid (?)
 | 
			
		||||
        // XXX: Restore more: layer_height_ranges, layer_height_profile (?)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    remove(obj_orig_idx);
 | 
			
		||||
| 
						 | 
				
			
			@ -2066,7 +2068,7 @@ void Plater::priv::fix_through_netfabb(const int obj_idx)
 | 
			
		|||
                o->volumes[i]->config.apply(model_object->volumes[i]->config);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile, layer_height_profile_valid,
 | 
			
		||||
        // FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    remove(obj_idx);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -245,9 +245,6 @@ void Tab::create_preset_tab()
 | 
			
		|||
	// Initialize the DynamicPrintConfig by default keys/values.
 | 
			
		||||
	build();
 | 
			
		||||
	rebuild_page_tree();
 | 
			
		||||
// 	update();
 | 
			
		||||
    // Load the currently selected preset into the GUI, update the preset selection box.
 | 
			
		||||
    load_current_preset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tab::load_initial_data()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue