diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index ff4c80a05ac..da19a69d7e0 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -4952,7 +4952,7 @@ bool model_mmu_segmentation_data_changed(const ModelObject& mo, const ModelObjec template static bool model_volume_imported_vector_matches(const ModelVolumeImportedVector &lhs, const ModelVolumeImportedVector &rhs) { - return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + return lhs.id() == rhs.id() && lhs.size() == rhs.size(); } static std::string model_volume_texture_mapping_background_config_value(const ModelVolume &volume) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index f41baf3e5f9..068a4288b34 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -675,9 +675,12 @@ void GLVolume::simple_render(GLShaderProgram* shader, texture_preview_used_states_have_surface_gradient(model_volume->mmu_segmentation_facets.get_data().used_states, num_physical, texture_mgr)); + const bool has_texture_mapping_color_data = + model_volume_has_texture_mapping_color_preview_data(*model_volume); const bool has_texture_mapping_color_preview_data = - base_uses_texture_preview && model_volume_has_texture_mapping_color_preview_data(*model_volume); + base_uses_texture_preview && has_texture_mapping_color_data; const bool has_texture_preview_data = model_volume_has_texture_preview_data(*model_volume); + const bool has_vertex_color_preview_data = model_volume_has_vertex_color_preview_data(*model_volume); const Transform3d preview_world_matrix = this->world_matrix(); use_original_mesh_texture_preview = !has_mmu_segmentation && @@ -703,13 +706,23 @@ void GLVolume::simple_render(GLShaderProgram* shader, } color_volume = has_mmu_segmentation; - size_t preview_visual_signature = texture_preview_settings_signature(num_physical, texture_mgr); + const std::vector *texture_preview_used_states = has_mmu_segmentation ? + &model_volume->mmu_segmentation_facets.get_data().used_states : nullptr; + size_t preview_visual_signature = texture_preview_model_settings_signature(num_physical, + texture_mgr, + base_filament_id, + texture_preview_used_states, + has_texture_preview_data, + has_vertex_color_preview_data, + has_texture_mapping_color_data); preview_visual_signature ^= size_t(base_filament_id) + 0x9e3779b97f4a7c15ull + (preview_visual_signature << 6) + (preview_visual_signature >> 2); preview_visual_signature ^= texture_preview_simulation_generation_signature() + 0x9e3779b97f4a7c15ull + (preview_visual_signature << 6) + (preview_visual_signature >> 2); preview_visual_signature ^= model_volume_texture_preview_signature(*model_volume) + 0x9e3779b97f4a7c15ull + (preview_visual_signature << 6) + (preview_visual_signature >> 2); + preview_visual_signature ^= model_volume->imported_vertex_colors_rgba.id().id + 0x9e3779b97f4a7c15ull + + (preview_visual_signature << 6) + (preview_visual_signature >> 2); preview_visual_signature ^= model_volume->imported_vertex_colors_rgba.size() + 0x9e3779b97f4a7c15ull + (preview_visual_signature << 6) + (preview_visual_signature >> 2); preview_visual_signature ^= reinterpret_cast(model_volume->imported_vertex_colors_rgba.data()) + 0x9e3779b97f4a7c15ull + @@ -923,9 +936,13 @@ void GLVolume::render_mmu_texture_preview(const Transform3d &view_matrix, const Transform3d model_matrix = this->world_matrix(); const std::vector extruder_colors = GUI::wxGetApp().plater()->get_extruders_colors(); - auto adjusted_preview_colors = [this](const std::vector &colors) { + auto adjusted_preview_colors = [this, &extruder_colors](const std::vector &filament_ids, const std::vector &colors) { std::vector preview_colors = colors; - for (ColorRGBA &preview_color : preview_colors) { + for (size_t idx = 0; idx < preview_colors.size(); ++idx) { + ColorRGBA &preview_color = preview_colors[idx]; + const unsigned int filament_id = idx < filament_ids.size() ? filament_ids[idx] : 0u; + if (filament_id > 0 && size_t(filament_id - 1) < extruder_colors.size()) + preview_color = extruder_colors[size_t(filament_id - 1)]; preview_color = adjust_color_for_rendering(preview_color); if (force_native_color && render_color.is_transparent()) preview_color.a(render_color.a()); @@ -963,7 +980,7 @@ void GLVolume::render_mmu_texture_preview(const Transform3d &view_matrix, opaque); } else { render_model_texture_preview_models(mmuseg_texture_preview_models, - adjusted_preview_colors(mmuseg_texture_preview_colors), + adjusted_preview_colors(mmuseg_texture_preview_filament_ids, mmuseg_texture_preview_colors), mmuseg_texture_preview_filament_ids, num_physical, texture_mgr, @@ -983,7 +1000,7 @@ void GLVolume::render_mmu_texture_preview(const Transform3d &view_matrix, if (!mmuseg_vertex_color_preview_models.empty()) { render_model_vertex_color_preview_models(mmuseg_vertex_color_preview_models, - adjusted_preview_colors(mmuseg_vertex_color_preview_colors), + adjusted_preview_colors(mmuseg_vertex_color_preview_filament_ids, mmuseg_vertex_color_preview_colors), mmuseg_vertex_color_preview_filament_ids, num_physical, texture_mgr, diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index a2e388f8149..30709c1438f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -13,6 +13,8 @@ #include "slic3r/GUI/ObjColorDialog.hpp" #include "slic3r/GUI/MainFrame.hpp" #include "slic3r/GUI/Tab.hpp" +#include "slic3r/GUI/3DScene.hpp" +#include "slic3r/GUI/MMUPaintedTexturePreview.hpp" #include "libslic3r/PresetBundle.hpp" #include "libslic3r/Format/bbs_3mf.hpp" #include "libslic3r/Model.hpp" @@ -1433,6 +1435,7 @@ static void refresh_imported_texture_storage(ModelVolume &volume) { std::vector refreshed(volume.imported_texture_rgba.begin(), volume.imported_texture_rgba.end()); volume.imported_texture_rgba.swap(refreshed); + volume.imported_texture_rgba.set_new_unique_id(); } static void refresh_imported_texture_raw_storage(ModelVolume &volume) @@ -1440,13 +1443,28 @@ static void refresh_imported_texture_raw_storage(ModelVolume &volume) std::vector refreshed(volume.imported_texture_raw_filament_offsets.begin(), volume.imported_texture_raw_filament_offsets.end()); volume.imported_texture_raw_filament_offsets.swap(refreshed); + volume.imported_texture_raw_filament_offsets.set_new_unique_id(); +} + +static void touch_imported_texture_data(ModelVolume &volume) +{ + volume.imported_texture_uvs_per_face.set_new_unique_id(); + volume.imported_texture_uv_valid.set_new_unique_id(); + volume.imported_texture_rgba.set_new_unique_id(); + volume.imported_texture_raw_filament_offsets.set_new_unique_id(); } static void clear_imported_texture_raw_atlas(ModelVolume &volume) { + const bool changed = + !volume.imported_texture_raw_filament_offsets.empty() || + volume.imported_texture_raw_channels != 0 || + !volume.imported_texture_raw_metadata_json.empty(); volume.imported_texture_raw_filament_offsets.clear(); volume.imported_texture_raw_channels = 0; volume.imported_texture_raw_metadata_json.clear(); + if (changed) + volume.imported_texture_raw_filament_offsets.set_new_unique_id(); } static ColorRGBA raw_filament_color_for_projection_preview(const ImageMapRawFilament &filament) @@ -1874,6 +1892,8 @@ static bool merge_imported_texture_raw_atlas(ModelVolume &volume, const RawAtlas volume.imported_texture_raw_channels = merged_channels; volume.imported_texture_raw_metadata_json = metadata; volume.imported_texture_raw_filament_offsets = std::move(merged); + if (changed) + volume.imported_texture_raw_filament_offsets.set_new_unique_id(); return changed; } @@ -2391,6 +2411,70 @@ static std::vector rgb_existing_source_triangle_depths(const TriangleColorS return depths; } +static void true_color_rgb_preview_signature_mix(size_t &signature, size_t value) +{ + signature ^= value + 0x9e3779b97f4a7c15ull + (signature << 6) + (signature >> 2); +} + +static size_t true_color_rgb_preview_color_facets_signature(const ColorFacetsAnnotation &annotation) +{ + size_t signature = 1469598103934665603ull; + const TriangleColorSplittingData &data = annotation.get_data(); + true_color_rgb_preview_signature_mix(signature, annotation.id().id); + true_color_rgb_preview_signature_mix(signature, static_cast(annotation.timestamp())); + true_color_rgb_preview_signature_mix(signature, data.triangles_to_split.size()); + true_color_rgb_preview_signature_mix(signature, data.bitstream.size()); + true_color_rgb_preview_signature_mix(signature, data.colors_rgba.size()); + true_color_rgb_preview_signature_mix(signature, std::hash{}(data.metadata_json)); + return signature; +} + +static size_t true_color_rgb_preview_cache_signature(const ModelVolume &volume, + const ColorFacetsAnnotation &annotation, + size_t num_physical, + const TextureMappingManager *texture_mgr) +{ + size_t signature = model_volume_texture_mapping_color_preview_signature(volume); + true_color_rgb_preview_signature_mix(signature, size_t(volume.extruder_id())); + true_color_rgb_preview_signature_mix(signature, true_color_rgb_preview_color_facets_signature(annotation)); + true_color_rgb_preview_signature_mix(signature, + texture_preview_model_settings_signature(num_physical, + texture_mgr, + volume.extruder_id() > 0 ? unsigned(volume.extruder_id()) : 0u, + nullptr, + model_volume_has_texture_preview_data(volume), + model_volume_has_vertex_color_preview_data(volume), + !annotation.empty())); + true_color_rgb_preview_signature_mix(signature, texture_preview_simulation_generation_signature()); + return signature; +} + +static std::vector> true_color_rgb_preview_triangles(const ModelVolume &volume) +{ + std::vector> triangles_per_type(1); + const indexed_triangle_set &its = volume.mesh().its; + triangles_per_type.front().reserve(its.indices.size()); + for (size_t tri_idx = 0; tri_idx < its.indices.size(); ++tri_idx) { + const stl_triangle_vertex_indices &tri = its.indices[tri_idx]; + if (tri[0] < 0 || tri[1] < 0 || tri[2] < 0) + continue; + if (size_t(tri[0]) >= its.vertices.size() || + size_t(tri[1]) >= its.vertices.size() || + size_t(tri[2]) >= its.vertices.size()) + continue; + + TriangleSelector::FacetStateTriangle facet; + facet.source_triangle = int(tri_idx); + facet.vertices = { + its.vertices[size_t(tri[0])].cast(), + its.vertices[size_t(tri[1])].cast(), + its.vertices[size_t(tri[2])].cast() + }; + triangles_per_type.front().emplace_back(std::move(facet)); + } + return triangles_per_type; +} + static bool apply_rgb_stroke_to_volume(ModelVolume &volume, const std::vector &stroke_facets, const ColorRGBA &brush_color, @@ -2451,20 +2535,32 @@ static bool apply_rgb_stroke_to_volume(ModelVolume if (use_brush_path && (tri_idx >= brush_candidate_triangles.size() || !brush_candidate_triangles[tri_idx])) return pack_vertex_color_rgba(source_color); - const float alpha = use_brush_path ? - sample_rgb_brush_path_alpha(brush_stroke_points_world, - transform_point(world_matrix, point), - hardness, - opacity, - brush_radius) : - sample_rgb_stroke_alpha(stroke_facets, - stroke_by_source_triangle, - stroke_boundary_edges, - int(tri_idx), - point, - hardness, - opacity, - brush_radius); + float alpha = 0.f; + if (use_brush_path) { + alpha = sample_rgb_brush_path_alpha(brush_stroke_points_world, + transform_point(world_matrix, point), + hardness, + opacity, + brush_radius); + alpha = std::max(alpha, + sample_rgb_stroke_alpha(stroke_facets, + stroke_by_source_triangle, + stroke_boundary_edges, + int(tri_idx), + point, + hardness, + opacity, + brush_radius)); + } else { + alpha = sample_rgb_stroke_alpha(stroke_facets, + stroke_by_source_triangle, + stroke_boundary_edges, + int(tri_idx), + point, + hardness, + opacity, + brush_radius); + } if (alpha <= 0.f) return pack_vertex_color_rgba(source_color); if (alpha >= 1.f) @@ -4398,6 +4494,8 @@ static bool initialize_generated_image_texture(ModelVolume &volum } } + touch_imported_texture_data(volume); + if (atlas_out != nullptr) *atlas_out = std::move(atlas); return true; @@ -5867,6 +5965,7 @@ static bool clear_object_managed_color_data(ModelObject &object, ManagedColorDat case ManagedColorDataType::VertexColors: if (!volume->imported_vertex_colors_rgba.empty()) { volume->imported_vertex_colors_rgba.clear(); + volume->imported_vertex_colors_rgba.set_new_unique_id(); changed = true; } break; @@ -5883,6 +5982,7 @@ static bool clear_object_managed_color_data(ModelObject &object, ManagedColorDat volume->imported_texture_width = 0; volume->imported_texture_height = 0; volume->uv_map_generator_version = 0; + touch_imported_texture_data(*volume); changed = true; } break; @@ -6590,6 +6690,7 @@ static bool managed_color_data_replace_rgba(ColorFacetsAnnotation &annotation, u return false; rewritten->set_metadata_json(annotation.metadata_json()); + rewritten->touch(); annotation.assign(*rewritten); return true; } @@ -6878,6 +6979,7 @@ static bool unsplit_volume_rgba_data_once(ModelVolume &volume) if (volume.texture_mapping_color_facets.equals(*unsplit)) return false; + unsplit->touch(); volume.texture_mapping_color_facets.assign(*unsplit); return true; } @@ -6937,6 +7039,7 @@ static bool simplify_volume_rgba_data_to_one_color_per_triangle(ModelVolume &vol if (volume.texture_mapping_color_facets.equals(*simplified)) return false; + simplified->touch(); volume.texture_mapping_color_facets.assign(*simplified); return true; } @@ -7274,6 +7377,7 @@ static bool convert_object_to_vertex_colors(ModelObject &object, const ManagedCo } volume->imported_vertex_colors_rgba = std::move(vertex_colors); + volume->imported_vertex_colors_rgba.set_new_unique_id(); changed = true; } return changed; @@ -10753,6 +10857,7 @@ void GLGizmoMmuSegmentation::bake_selected_object_image_texture_to_vertex_colors continue; volume->imported_vertex_colors_rgba = std::move(vertex_colors); + volume->imported_vertex_colors_rgba.set_new_unique_id(); volume->imported_texture_uvs_per_face.clear(); volume->imported_texture_uv_valid.clear(); volume->imported_texture_rgba.clear(); @@ -10760,6 +10865,7 @@ void GLGizmoMmuSegmentation::bake_selected_object_image_texture_to_vertex_colors volume->imported_texture_width = 0; volume->imported_texture_height = 0; volume->uv_map_generator_version = 0; + touch_imported_texture_data(*volume); baked = true; } @@ -11034,6 +11140,7 @@ void GLGizmoMmuSegmentation::clear_selected_object_image_texture_data() volume->imported_texture_width = 0; volume->imported_texture_height = 0; volume->uv_map_generator_version = 0; + touch_imported_texture_data(*volume); cleared = true; } @@ -11165,6 +11272,8 @@ void GLGizmoTrueColorPainting::on_shutdown() cancel_rgb_data_preview_conversion(); m_color_picker_active = false; clear_brush_stroke_points(); + m_live_selector_preview_active = false; + clear_rgb_preview_cache(); m_preview_rgb_data_volume_ids.clear(); m_preview_rgb_data_by_volume.clear(); m_color_picker_source_cache.clear(); @@ -11238,7 +11347,20 @@ void GLGizmoTrueColorPainting::render_painter_gizmo() glsafe(::glEnable(GL_BLEND)); glsafe(::glEnable(GL_DEPTH_TEST)); - render_triangles(selection); + render_cached_rgb_data_preview(*object, selection); + if (m_brush_stroke_active || m_live_selector_preview_active) { + GLboolean depth_mask = GL_TRUE; + GLint depth_func = GL_LESS; + glsafe(::glGetBooleanv(GL_DEPTH_WRITEMASK, &depth_mask)); + glsafe(::glGetIntegerv(GL_DEPTH_FUNC, &depth_func)); + glsafe(::glDepthMask(GL_FALSE)); + glsafe(::glDepthFunc(GL_ALWAYS)); + render_triangles(selection); + glsafe(::glDepthFunc(depth_func)); + glsafe(::glDepthMask(depth_mask)); + } else { + render_triangles(selection); + } m_c->object_clipper()->render_cut(); m_c->instances_hider()->render_cut(); render_cursor(); @@ -11297,17 +11419,29 @@ bool GLGizmoTrueColorPainting::gizmo_event(SLAGizmoEventType action, if (action == SLAGizmoEventType::LeftDown) { clear_brush_stroke_points(); - m_brush_stroke_active = !shift_down && !control_down && record_brush_stroke_point(mouse_position); - } else if (action == SLAGizmoEventType::Dragging && m_brush_stroke_active && !shift_down && !control_down) { - record_brush_stroke_point(mouse_position); + int mesh_id = -1; + Vec3f hit = Vec3f::Zero(); + size_t facet = 0; + m_live_selector_preview_active = !shift_down && !control_down && !alt_down; + m_brush_stroke_active = !shift_down && + !control_down && + raycast_to_selected_mesh(mouse_position, mesh_id, hit, facet) && + mesh_id >= 0; + } else if (action == SLAGizmoEventType::Dragging && + (m_brush_stroke_active || m_live_selector_preview_active) && + !shift_down && + !control_down) { + m_parent.set_as_dirty(); } else if (action == SLAGizmoEventType::RightDown || (action == SLAGizmoEventType::Dragging && shift_down)) { clear_brush_stroke_points(); + m_live_selector_preview_active = false; } const bool handled = GLGizmoPainterBase::gizmo_event(action, mouse_position, shift_down, alt_down, control_down); if (action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::RightUp) { clear_brush_stroke_points(); m_brush_stroke_active = false; + m_live_selector_preview_active = false; } return handled; } @@ -11342,8 +11476,9 @@ void GLGizmoTrueColorPainting::init_model_triangle_selectors() if (TriangleSelectorPatch *patch = dynamic_cast(m_triangle_selectors.back().get())) { patch->set_none_state_rendered(render_normal_surface); patch->set_texture_mapping_color_preview(preview_rgb_data); - patch->set_texture_preview_needed(preview_rgb_data != nullptr); + patch->set_texture_preview_needed(false); patch->set_texture_preview_opaque(true); + patch->set_surface_offset(preview_rgb_data != nullptr ? 0.002f : 0.f); } m_triangle_selectors.back()->set_wireframe_needed(true); m_triangle_selectors.back()->request_update_render_data(true); @@ -11441,6 +11576,7 @@ void GLGizmoTrueColorPainting::update_rgb_data_preview_conversion() } if (applied) { + clear_rgb_preview_cache(); init_model_triangle_selectors(); m_parent.set_as_dirty(); m_parent.request_extra_frame(); @@ -11544,16 +11680,16 @@ void GLGizmoTrueColorPainting::start_rgb_data_preview_conversion(ModelObject &ob m_parent.request_extra_frame(); } -bool GLGizmoTrueColorPainting::record_brush_stroke_point(const Vec2d &mouse_position) +void GLGizmoTrueColorPainting::on_brush_projected_mouse_positions( + SLAGizmoEventType action, + int mesh_idx, + const std::vector &projected_mouse_positions) { - int mesh_id = -1; - Vec3f hit = Vec3f::Zero(); - size_t facet = 0; - if (!raycast_to_selected_mesh(mouse_position, mesh_id, hit, facet) || mesh_id < 0) - return false; - - if (m_brush_stroke_points_by_volume.size() <= size_t(mesh_id)) - m_brush_stroke_points_by_volume.resize(size_t(mesh_id) + 1); + if (!m_brush_stroke_active || + mesh_idx < 0 || + projected_mouse_positions.empty() || + (action != SLAGizmoEventType::LeftDown && action != SLAGizmoEventType::Dragging)) + return; const ModelObject *object = selected_model_object(); const ModelVolume *hit_volume = nullptr; @@ -11563,7 +11699,7 @@ bool GLGizmoTrueColorPainting::record_brush_stroke_point(const Vec2d &mouse_posi if (volume == nullptr || !volume->is_model_part()) continue; ++model_part_idx; - if (model_part_idx == mesh_id) { + if (model_part_idx == mesh_idx) { hit_volume = volume; break; } @@ -11576,7 +11712,22 @@ bool GLGizmoTrueColorPainting::record_brush_stroke_point(const Vec2d &mouse_posi world_matrix = projection_world_matrix_for_volume(m_parent, object, hit_volume, selection.get_instance_idx()); } - std::vector &points = m_brush_stroke_points_by_volume[size_t(mesh_id)]; + for (auto point_it = projected_mouse_positions.rbegin(); point_it != projected_mouse_positions.rend(); ++point_it) { + if (point_it->mesh_idx != mesh_idx) + continue; + append_brush_stroke_point(mesh_idx, point_it->mesh_hit, world_matrix); + } +} + +bool GLGizmoTrueColorPainting::append_brush_stroke_point(int mesh_idx, const Vec3f &hit, const Transform3d &world_matrix) +{ + if (mesh_idx < 0) + return false; + + if (m_brush_stroke_points_by_volume.size() <= size_t(mesh_idx)) + m_brush_stroke_points_by_volume.resize(size_t(mesh_idx) + 1); + + std::vector &points = m_brush_stroke_points_by_volume[size_t(mesh_idx)]; const float min_spacing = true_color_brush_subdivision_target(m_cursor_radius); if (points.empty() || (transform_point(world_matrix, points.back()) - transform_point(world_matrix, hit)).norm() >= min_spacing) @@ -11590,6 +11741,107 @@ void GLGizmoTrueColorPainting::clear_brush_stroke_points() m_brush_stroke_active = false; } +void GLGizmoTrueColorPainting::clear_rgb_preview_cache() +{ + m_rgb_preview_cache.clear(); +} + +void GLGizmoTrueColorPainting::render_cached_rgb_data_preview(const ModelObject &object, const Selection &selection) +{ + const size_t num_physical = std::max(0, wxGetApp().filaments_cnt()); + const TextureMappingManager *texture_mgr = wxGetApp().preset_bundle != nullptr ? + &wxGetApp().preset_bundle->texture_mapping_zones : nullptr; + + const Camera &camera = wxGetApp().plater()->get_camera(); + const Transform3d &view_matrix = camera.get_view_matrix(); + const Transform3d &projection_matrix = camera.get_projection_matrix(); + const ClippingPlaneDataWrapper clp_data = get_clipping_plane_data(); + const ModelInstance *instance = selection.get_instance_idx() >= 0 && + size_t(selection.get_instance_idx()) < object.instances.size() ? + object.instances[size_t(selection.get_instance_idx())] : + nullptr; + if (instance == nullptr) + return; + + for (const ModelVolume *volume : object.volumes) { + if (volume == nullptr || !volume->is_model_part()) + continue; + + const ColorFacetsAnnotation *preview_rgb_data = !volume->texture_mapping_color_facets.empty() ? + &volume->texture_mapping_color_facets : + preview_rgb_data_for_volume(*volume); + if (preview_rgb_data == nullptr || preview_rgb_data->empty()) + continue; + + const size_t signature = true_color_rgb_preview_cache_signature(*volume, *preview_rgb_data, num_physical, texture_mgr); + auto cache_it = std::find_if(m_rgb_preview_cache.begin(), + m_rgb_preview_cache.end(), + [volume_id = volume->id()](const RgbPreviewVolumeCache &cache) { + return cache.volume_id == volume_id; + }); + if (cache_it == m_rgb_preview_cache.end()) { + m_rgb_preview_cache.emplace_back(); + cache_it = m_rgb_preview_cache.end() - 1; + cache_it->volume_id = volume->id(); + } + + if (!cache_it->valid || cache_it->signature != signature) { + cache_it->models.clear(); + cache_it->colors.clear(); + cache_it->filament_ids.clear(); + const std::vector colors = { ColorRGBA(1.f, 1.f, 1.f, 0.f) }; + std::vector> triangles_per_type = + true_color_rgb_preview_triangles(*volume); + build_mmu_vertex_color_preview_models(*volume, + triangles_per_type, + colors, + volume->extruder_id() > 0 ? unsigned(volume->extruder_id()) : 0u, + num_physical, + texture_mgr, + cache_it->models, + cache_it->colors, + cache_it->filament_ids, + preview_rgb_data, + reinterpret_cast(this)); + cache_it->signature = signature; + cache_it->valid = true; + } + + if (cache_it->models.empty()) + continue; + + Transform3d matrix; + if (m_parent.get_canvas_type() == GLCanvas3D::CanvasAssembleView) { + matrix = instance->get_assemble_transformation().get_matrix() * volume->get_matrix(); + matrix.translate(volume->get_transformation().get_offset() * (GLVolume::explosion_ratio - 1.0) + + instance->get_offset_to_assembly() * (GLVolume::explosion_ratio - 1.0)); + } else { + matrix = instance->get_transformation().get_matrix() * volume->get_matrix(); + } + + std::vector preview_colors = cache_it->colors; + for (ColorRGBA &preview_color : preview_colors) { + preview_color = adjust_color_for_rendering(preview_color); + preview_color.a(1.f); + } + + render_model_vertex_color_preview_models(cache_it->models, + preview_colors, + cache_it->filament_ids, + num_physical, + texture_mgr, + matrix, + view_matrix, + projection_matrix, + clp_data.z_range, + clp_data.clp_dataf, + -1, + std::array{ 0.f, 0.f, 0.f, 0.f }, + std::array{ 0.f, 0.f }, + true); + } +} + void GLGizmoTrueColorPainting::update_triangle_selectors_color() { const std::vector colors = { @@ -11707,6 +11959,7 @@ void GLGizmoTrueColorPainting::open_color_data_management_dialog() cancel_rgb_data_preview_conversion(); m_preview_rgb_data_volume_ids.clear(); m_preview_rgb_data_by_volume.clear(); + clear_rgb_preview_cache(); Slic3r::GUI::open_color_data_management_dialog(wxGetApp().mainframe, m_parent, object, [this]() { update_selected_object_color_state(); init_model_triangle_selectors(); @@ -11734,6 +11987,7 @@ void GLGizmoTrueColorPainting::update_selected_object_color_state() cancel_rgb_data_preview_conversion(); m_preview_rgb_data_volume_ids.clear(); m_preview_rgb_data_by_volume.clear(); + clear_rgb_preview_cache(); m_color_picker_source_cache.clear(); m_background_color_edit_config_snapshot.reset(); } @@ -11909,6 +12163,7 @@ void GLGizmoTrueColorPainting::refresh_selected_object_after_rgb_change(ModelObj { remember_changed_rgb_data_object(object); update_selected_object_color_state(); + clear_rgb_preview_cache(); init_model_triangle_selectors(); m_parent.update_volumes_colors_by_extruder(); m_parent.set_as_dirty(); @@ -12716,6 +12971,7 @@ void GLGizmoTrueColorPainting::refresh_selected_object_after_background_color_ch cancel_rgb_data_preview_conversion(); m_preview_rgb_data_volume_ids.clear(); m_preview_rgb_data_by_volume.clear(); + clear_rgb_preview_cache(); m_color_picker_source_cache.clear(); update_selected_object_color_state(); init_model_triangle_selectors(); @@ -13992,6 +14248,7 @@ bool GLGizmoImageProjection::project_to_vertex_colors(ModelObject *object) } volume->imported_vertex_colors_rgba[idx] = pack_vertex_color_rgba(color); } + volume->imported_vertex_colors_rgba.set_new_unique_id(); changed = true; } return changed; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index ef36a498fe8..d8699cdb3a5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -311,6 +311,9 @@ private: void on_shutdown() override; void on_set_state() override; PainterGizmoType get_painter_type() const override; + void on_brush_projected_mouse_positions(SLAGizmoEventType action, + int mesh_idx, + const std::vector &projected_mouse_positions) override; void init_model_triangle_selectors(); ModelObject *selected_model_object() const; @@ -331,8 +334,10 @@ private: void cancel_rgb_data_preview_conversion(); bool rgb_data_preview_conversion_pending_for_selected_object() const; ColorFacetsAnnotation *preview_rgb_data_for_volume(const ModelVolume &volume) const; - bool record_brush_stroke_point(const Vec2d &mouse_position); + bool append_brush_stroke_point(int mesh_idx, const Vec3f &hit, const Transform3d &world_matrix); void clear_brush_stroke_points(); + void clear_rgb_preview_cache(); + void render_cached_rgb_data_preview(const ModelObject &object, const Selection &selection); bool pick_color_from_model(const Vec2d &mouse_position); bool sample_color_from_model(const Vec2d &mouse_position, ColorRGBA &color) const; void set_active_color_from_sample(const ColorRGBA &color); @@ -393,9 +398,20 @@ private: bool m_selected_has_raw_atlas_texture_data = false; bool m_color_picker_active = false; bool m_brush_stroke_active = false; + bool m_live_selector_preview_active = false; ObjectID m_selected_color_state_object_id; std::vector m_changed_rgb_data_object_ids; std::vector> m_brush_stroke_points_by_volume; + struct RgbPreviewVolumeCache + { + ObjectID volume_id; + bool valid = false; + size_t signature = 0; + std::vector models; + std::vector colors; + std::vector filament_ids; + }; + std::vector m_rgb_preview_cache; std::vector m_preview_rgb_data_volume_ids; std::vector> m_preview_rgb_data_by_volume; std::unique_ptr m_background_color_edit_config_snapshot; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 109197663fe..527461e7884 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -36,6 +36,47 @@ bool model_volume_has_texture_preview_data_for_painting(const ModelVolume &model size_t(model_volume.imported_texture_width) * size_t(model_volume.imported_texture_height) * 4; } +std::vector texture_preview_used_states_for_painting( + const std::vector> &triangles_per_type) +{ + std::vector used_states(triangles_per_type.size(), false); + for (size_t state_id = 1; state_id < triangles_per_type.size(); ++state_id) + used_states[state_id] = !triangles_per_type[state_id].empty(); + return used_states; +} + +size_t texture_preview_visual_signature_for_painting(const ModelVolume &model_volume, + const std::vector *used_states, + size_t num_physical, + const TextureMappingManager *texture_mgr, + const ColorFacetsAnnotation *texture_mapping_color_preview) +{ + const unsigned int base_filament_id = model_volume.extruder_id() > 0 ? unsigned(model_volume.extruder_id()) : 0u; + const bool has_texture_mapping_color_preview_data = + (texture_mapping_color_preview != nullptr && !texture_mapping_color_preview->empty()) || + model_volume_has_texture_mapping_color_preview_data(model_volume); + size_t signature = texture_preview_model_settings_signature(num_physical, + texture_mgr, + base_filament_id, + used_states, + model_volume_has_texture_preview_data(model_volume), + model_volume_has_vertex_color_preview_data(model_volume), + has_texture_mapping_color_preview_data); + signature ^= texture_preview_simulation_generation_signature() + 0x9e3779b97f4a7c15ull + + (signature << 6) + (signature >> 2); + signature ^= model_volume_texture_preview_signature(model_volume) + 0x9e3779b97f4a7c15ull + + (signature << 6) + (signature >> 2); + signature ^= model_volume.imported_vertex_colors_rgba.id().id + 0x9e3779b97f4a7c15ull + + (signature << 6) + (signature >> 2); + signature ^= model_volume.imported_vertex_colors_rgba.size() + 0x9e3779b97f4a7c15ull + + (signature << 6) + (signature >> 2); + signature ^= reinterpret_cast(model_volume.imported_vertex_colors_rgba.data()) + 0x9e3779b97f4a7c15ull + + (signature << 6) + (signature >> 2); + signature ^= model_volume_texture_mapping_color_preview_signature(model_volume) + 0x9e3779b97f4a7c15ull + + (signature << 6) + (signature >> 2); + return signature; +} + } // namespace std::shared_ptr GLGizmoPainterBase::s_sphere = nullptr; @@ -932,6 +973,8 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } else if (m_tool_type == ToolType::BRUSH) { assert(m_cursor_type == TriangleSelector::CursorType::CIRCLE || m_cursor_type == TriangleSelector::CursorType::SPHERE); + on_brush_projected_mouse_positions(action, mesh_idx, projected_mouse_positions); + if (projected_mouse_positions.size() == 1) { const ProjectedMousePosition &first_position = projected_mouse_positions.front(); std::unique_ptr cursor = TriangleSelector::SinglePointCursor::cursor_factory(first_position.mesh_hit, @@ -1509,10 +1552,11 @@ void TriangleSelectorPatch::update_triangles_per_type() int j = triangle.verts_idxs[i]; int index = int(patch.patch_vertices.size() / 9); //BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", Line %1%: i=%2%, j=%3%, index=%4%, v[%5%,%6%,%7%]")%__LINE__%i%j%index%m_vertices[j].v(0)%m_vertices[j].v(1)%m_vertices[j].v(2); - patch.patch_vertices.emplace_back(m_vertices[j].v(0)); - patch.patch_vertices.emplace_back(m_vertices[j].v(1)); - patch.patch_vertices.emplace_back(m_vertices[j].v(2)); const Vec3f normal = smooth_normal(triangle, i); + const Vec3f position = m_vertices[j].v + normal * m_surface_offset; + patch.patch_vertices.emplace_back(position(0)); + patch.patch_vertices.emplace_back(position(1)); + patch.patch_vertices.emplace_back(position(2)); patch.patch_vertices.emplace_back(normal(0)); patch.patch_vertices.emplace_back(normal(1)); patch.patch_vertices.emplace_back(normal(2)); @@ -1707,18 +1751,23 @@ void TriangleSelectorPatch::update_render_data() m_texture_preview_models.clear(); m_texture_preview_colors.clear(); m_texture_preview_filament_ids.clear(); + m_texture_preview_used_states.clear(); m_vertex_color_preview_models.clear(); m_vertex_color_preview_colors.clear(); m_vertex_color_preview_filament_ids.clear(); if (m_texture_preview_needed && m_model_volume != nullptr) { std::vector> triangles_per_type; get_facet_triangles(triangles_per_type); + m_texture_preview_used_states = texture_preview_used_states_for_painting(triangles_per_type); const size_t num_physical = std::max(0, wxGetApp().filaments_cnt()); const TextureMappingManager *texture_mgr = wxGetApp().preset_bundle != nullptr ? &wxGetApp().preset_bundle->texture_mapping_zones : nullptr; - m_texture_preview_visual_signature = texture_preview_settings_signature(num_physical, texture_mgr); - m_texture_preview_visual_signature ^= texture_preview_simulation_generation_signature() + 0x9e3779b97f4a7c15ull + - (m_texture_preview_visual_signature << 6) + (m_texture_preview_visual_signature >> 2); + m_texture_preview_visual_signature = + texture_preview_visual_signature_for_painting(*m_model_volume, + &m_texture_preview_used_states, + num_physical, + texture_mgr, + m_texture_mapping_color_preview); if (m_texture_mapping_color_preview != nullptr && !m_texture_mapping_color_preview->empty()) { build_mmu_vertex_color_preview_models(*m_model_volume, triangles_per_type, @@ -1869,6 +1918,7 @@ void TriangleSelectorPatch::release_geometry() m_texture_preview_models.clear(); m_texture_preview_colors.clear(); m_texture_preview_filament_ids.clear(); + m_texture_preview_used_states.clear(); m_texture_preview.reset(); m_texture_preview_signature = 0; m_texture_preview_visual_signature = 0; @@ -1891,9 +1941,12 @@ void TriangleSelectorPatch::render_texture_preview(const Transform3d& m const size_t num_physical = std::max(0, wxGetApp().filaments_cnt()); const TextureMappingManager *texture_mgr = wxGetApp().preset_bundle != nullptr ? &wxGetApp().preset_bundle->texture_mapping_zones : nullptr; - size_t current_visual_signature = texture_preview_settings_signature(num_physical, texture_mgr); - current_visual_signature ^= texture_preview_simulation_generation_signature() + 0x9e3779b97f4a7c15ull + - (current_visual_signature << 6) + (current_visual_signature >> 2); + size_t current_visual_signature = + texture_preview_visual_signature_for_painting(*m_model_volume, + &m_texture_preview_used_states, + num_physical, + texture_mgr, + m_texture_mapping_color_preview); if (current_visual_signature != m_texture_preview_visual_signature) { TriangleSelectorPatch *self = const_cast(this); self->request_update_render_data(true); @@ -1903,9 +1956,16 @@ void TriangleSelectorPatch::render_texture_preview(const Transform3d& m if (m_texture_preview_models.empty() && m_vertex_color_preview_models.empty()) return; - auto adjusted_preview_colors = [this](const std::vector &colors) { + const std::vector extruder_colors = wxGetApp().plater() != nullptr ? + wxGetApp().plater()->get_extruders_colors() : std::vector(); + auto adjusted_preview_colors = [this, &extruder_colors](const std::vector &filament_ids, + const std::vector &colors) { std::vector preview_colors = colors; - for (ColorRGBA &preview_color : preview_colors) { + for (size_t idx = 0; idx < preview_colors.size(); ++idx) { + ColorRGBA &preview_color = preview_colors[idx]; + const unsigned int filament_id = idx < filament_ids.size() ? filament_ids[idx] : 0u; + if (filament_id > 0 && size_t(filament_id - 1) < extruder_colors.size()) + preview_color = extruder_colors[size_t(filament_id - 1)]; preview_color = adjust_color_for_rendering(preview_color); if (m_texture_preview_opaque) preview_color.a(1.f); @@ -1916,7 +1976,7 @@ void TriangleSelectorPatch::render_texture_preview(const Transform3d& m if (!m_texture_preview_models.empty() && ensure_model_volume_texture_preview(*m_model_volume, m_texture_preview, m_texture_preview_signature)) { render_model_texture_preview_models(m_texture_preview_models, - adjusted_preview_colors(m_texture_preview_colors), + adjusted_preview_colors(m_texture_preview_filament_ids, m_texture_preview_colors), m_texture_preview_filament_ids, num_physical, texture_mgr, @@ -1935,7 +1995,7 @@ void TriangleSelectorPatch::render_texture_preview(const Transform3d& m if (!m_vertex_color_preview_models.empty()) { render_model_vertex_color_preview_models(m_vertex_color_preview_models, - adjusted_preview_colors(m_vertex_color_preview_colors), + adjusted_preview_colors(m_vertex_color_preview_filament_ids, m_vertex_color_preview_colors), m_vertex_color_preview_filament_ids, num_physical, texture_mgr, diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index dcdc6241683..f76915e110e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -133,6 +133,13 @@ public: void set_texture_preview_needed(bool needed) { m_texture_preview_needed = needed; } void set_texture_preview_opaque(bool opaque) { m_texture_preview_opaque = opaque; } void set_texture_mapping_color_preview(const ColorFacetsAnnotation *preview) { m_texture_mapping_color_preview = preview; } + void set_surface_offset(float surface_offset) + { + if (m_surface_offset != surface_offset) { + m_surface_offset = surface_offset; + request_update_render_data(true); + } + } constexpr static float GapAreaMin = 0.f; constexpr static float GapAreaMax = 5.f; @@ -191,6 +198,7 @@ protected: mutable std::vector m_texture_preview_models; std::vector m_texture_preview_colors; std::vector m_texture_preview_filament_ids; + std::vector m_texture_preview_used_states; mutable GLTexture m_texture_preview; mutable size_t m_texture_preview_signature { 0 }; size_t m_texture_preview_visual_signature { 0 }; @@ -203,6 +211,7 @@ protected: bool m_render_none_state = true; bool m_texture_preview_needed = true; bool m_texture_preview_opaque = false; + float m_surface_offset = 0.f; private: void update_render_data(); @@ -307,6 +316,10 @@ protected: size_t facet_idx; }; + virtual void on_brush_projected_mouse_positions(SLAGizmoEventType, + int, + const std::vector &) {} + // BBS: projected result of mouse height range for a mesh struct ProjectedHeightRange { diff --git a/src/slic3r/GUI/MMUPaintedTexturePreview.cpp b/src/slic3r/GUI/MMUPaintedTexturePreview.cpp index 5f62e98a090..f0f06846712 100644 --- a/src/slic3r/GUI/MMUPaintedTexturePreview.cpp +++ b/src/slic3r/GUI/MMUPaintedTexturePreview.cpp @@ -3783,6 +3783,21 @@ size_t texture_preview_state_triangles_signature(const std::vector> 2); + }; + + const TriangleColorSplittingData &data = color_source.get_data(); + mix(color_source.id().id); + mix(static_cast(color_source.timestamp())); + mix(data.triangles_to_split.size()); + mix(data.bitstream.size()); + mix(data.colors_rgba.size()); + mix(std::hash{}(data.metadata_json)); +} + size_t texture_preview_vertex_color_source_signature(const ModelVolume &model_volume, const std::vector &state_triangles) { @@ -3792,11 +3807,15 @@ size_t texture_preview_vertex_color_source_signature(const ModelVolume }; mix(reinterpret_cast(model_volume.mesh_ptr().get())); + mix(model_volume.id().id); mix(model_volume.mesh().its.vertices.size()); mix(model_volume.mesh().its.indices.size()); + mix(model_volume.mmu_segmentation_facets.id().id); + mix(static_cast(model_volume.mmu_segmentation_facets.timestamp())); + mix(model_volume.imported_vertex_colors_rgba.id().id); mix(model_volume.imported_vertex_colors_rgba.size()); mix(reinterpret_cast(model_volume.imported_vertex_colors_rgba.data())); - mix(texture_preview_state_triangles_signature(state_triangles)); + mix(state_triangles.size()); const ColorRGBA background = texture_mapping_background_color_for_preview(model_volume); auto background_signature_component = [](float value) { return size_t(std::clamp(value, 0.f, 1.f) * 255.f + 0.5f); @@ -3817,24 +3836,13 @@ size_t texture_preview_color_facets_source_signature(const ModelVolume }; mix(reinterpret_cast(model_volume.mesh_ptr().get())); + mix(model_volume.id().id); mix(model_volume.mesh().its.vertices.size()); mix(model_volume.mesh().its.indices.size()); - const TriangleColorSplittingData &data = color_source.get_data(); - mix(data.triangles_to_split.size()); - mix(data.bitstream.size()); - mix(data.colors_rgba.size()); - for (const ColorTriangleBitStreamMapping &mapping : data.triangles_to_split) { - mix(size_t(mapping.triangle_idx)); - mix(size_t(mapping.bitstream_start_idx)); - mix(size_t(mapping.color_start_idx)); - } - for (const bool bit : data.bitstream) - mix(bit ? 1u : 0u); - for (const uint32_t color : data.colors_rgba) - mix(size_t(color)); - for (const char ch : data.metadata_json) - mix(size_t(static_cast(ch))); - mix(texture_preview_state_triangles_signature(state_triangles)); + mix(model_volume.mmu_segmentation_facets.id().id); + mix(static_cast(model_volume.mmu_segmentation_facets.timestamp())); + mix_color_facets_signature(signature, color_source); + mix(state_triangles.size()); const ColorRGBA background = texture_mapping_background_color_for_preview(model_volume, &color_source); auto background_signature_component = [](float value) { return size_t(std::clamp(value, 0.f, 1.f) * 255.f + 0.5f); @@ -3853,10 +3861,13 @@ size_t texture_preview_image_halftone_source_signature(const ModelVolume auto mix = [&signature](size_t value) { signature ^= value + 0x9e3779b97f4a7c15ull + (signature << 6) + (signature >> 2); }; + mix(model_volume.id().id); mix(reinterpret_cast(model_volume.mesh_ptr().get())); mix(model_volume.mesh().its.vertices.size()); mix(model_volume.mesh().its.indices.size()); - mix(texture_preview_state_triangles_signature(state_triangles)); + mix(model_volume.mmu_segmentation_facets.id().id); + mix(static_cast(model_volume.mmu_segmentation_facets.timestamp())); + mix(state_triangles.size()); for (int row = 0; row < 4; ++row) for (int col = 0; col < 4; ++col) mix(std::hash{}(int(std::lround(world_matrix(row, col) * 1000000.0)))); @@ -4826,16 +4837,24 @@ size_t model_volume_texture_preview_signature(const ModelVolume &model_volume) auto mix = [&signature](size_t value) { signature ^= value + 0x9e3779b97f4a7c15ull + (signature << 6) + (signature >> 2); }; + mix(model_volume.id().id); + mix(reinterpret_cast(model_volume.mesh_ptr().get())); + mix(model_volume.mesh().its.vertices.size()); + mix(model_volume.mesh().its.indices.size()); mix(size_t(model_volume.imported_texture_width)); mix(size_t(model_volume.imported_texture_height)); + mix(model_volume.imported_texture_rgba.id().id); mix(model_volume.imported_texture_rgba.size()); mix(reinterpret_cast(model_volume.imported_texture_rgba.data())); mix(size_t(model_volume.imported_texture_raw_channels)); mix(std::hash{}(model_volume.imported_texture_raw_metadata_json)); + mix(model_volume.imported_texture_raw_filament_offsets.id().id); mix(model_volume.imported_texture_raw_filament_offsets.size()); mix(reinterpret_cast(model_volume.imported_texture_raw_filament_offsets.data())); + mix(model_volume.imported_texture_uvs_per_face.id().id); mix(model_volume.imported_texture_uvs_per_face.size()); mix(reinterpret_cast(model_volume.imported_texture_uvs_per_face.data())); + mix(model_volume.imported_texture_uv_valid.id().id); mix(model_volume.imported_texture_uv_valid.size()); mix(reinterpret_cast(model_volume.imported_texture_uv_valid.data())); const ColorRGBA background = texture_mapping_background_color_for_preview(model_volume); @@ -4855,21 +4874,9 @@ size_t model_volume_texture_mapping_color_preview_signature(const ModelVolume &m signature ^= value + 0x9e3779b97f4a7c15ull + (signature << 6) + (signature >> 2); }; - const TriangleColorSplittingData &data = model_volume.texture_mapping_color_facets.get_data(); - mix(data.triangles_to_split.size()); - mix(data.bitstream.size()); - mix(data.colors_rgba.size()); - for (const ColorTriangleBitStreamMapping &mapping : data.triangles_to_split) { - mix(size_t(mapping.triangle_idx)); - mix(size_t(mapping.bitstream_start_idx)); - mix(size_t(mapping.color_start_idx)); - } - for (const bool bit : data.bitstream) - mix(bit ? 1u : 0u); - for (const uint32_t color : data.colors_rgba) - mix(size_t(color)); - for (const char ch : data.metadata_json) - mix(size_t(static_cast(ch))); + mix(model_volume.id().id); + mix(reinterpret_cast(model_volume.mesh_ptr().get())); + mix_color_facets_signature(signature, model_volume.texture_mapping_color_facets); const ColorRGBA background = texture_mapping_background_color_for_preview(model_volume); auto background_signature_component = [](float value) { return size_t(std::clamp(value, 0.f, 1.f) * 255.f + 0.5f); @@ -4904,7 +4911,9 @@ bool ensure_model_volume_texture_preview(const ModelVolume &model_volume, return true; } -size_t texture_preview_settings_signature(size_t num_physical, const TextureMappingManager *texture_mgr) +static size_t texture_preview_settings_signature_impl(size_t num_physical, + const TextureMappingManager *texture_mgr, + const std::vector *active_zone_ids) { size_t signature = 1469598103934665603ull; auto signature_mix = [&signature](size_t value) { @@ -4927,7 +4936,14 @@ size_t texture_preview_settings_signature(size_t num_physical, const TextureMapp if (texture_mgr == nullptr) return signature; + auto zone_is_active = [active_zone_ids](unsigned int zone_id) { + return active_zone_ids == nullptr || + std::find(active_zone_ids->begin(), active_zone_ids->end(), zone_id) != active_zone_ids->end(); + }; + for (const TextureMappingZone &zone : texture_mgr->zones()) { + if (!zone_is_active(zone.zone_id)) + continue; signature_mix(std::hash{}(zone.stable_id)); signature_mix(std::hash{}(zone.zone_id)); signature_mix(std::hash{}(zone.enabled ? 1 : 0)); @@ -4978,6 +4994,174 @@ size_t texture_preview_settings_signature(size_t num_physical, const TextureMapp return signature; } +static std::vector active_texture_preview_zone_ids(const TextureMappingManager *texture_mgr, + unsigned int base_filament_id, + const std::vector *used_states) +{ + std::vector active_zone_ids; + if (texture_mgr == nullptr) + return active_zone_ids; + + auto append_active_zone_id = [texture_mgr, &active_zone_ids](unsigned int zone_id) { + if (zone_id != 0 && texture_mgr->zone_from_id(zone_id) != nullptr) + active_zone_ids.emplace_back(zone_id); + }; + append_active_zone_id(base_filament_id); + if (used_states != nullptr) { + for (size_t idx = 1; idx < used_states->size(); ++idx) + if ((*used_states)[idx]) + append_active_zone_id(unsigned(idx)); + } + std::sort(active_zone_ids.begin(), active_zone_ids.end()); + active_zone_ids.erase(std::unique(active_zone_ids.begin(), active_zone_ids.end()), active_zone_ids.end()); + return active_zone_ids; +} + +static bool active_texture_preview_zone_ids_contains(const std::vector &active_zone_ids, unsigned int zone_id) +{ + return std::binary_search(active_zone_ids.begin(), active_zone_ids.end(), zone_id); +} + +static bool texture_preview_zone_uses_halftone_model(const TextureMappingZone &zone) +{ + if (!zone.enabled || zone.deleted || !zone.is_image_texture() || !zone.preview_simulate_colors) + return false; + const int mapping_mode = std::clamp(zone.texture_mapping_mode, + int(TextureMappingZone::TextureMappingFilamentBlending), + int(TextureMappingZone::TextureMappingRawValues)); + const int method = std::clamp(zone.dithering_method, + int(TextureMappingZone::DitheringClosest), + int(TextureMappingZone::DitheringHalftoneIncreasedDetail)); + return mapping_mode != int(TextureMappingZone::TextureMappingRawValues) && + zone.dithering_enabled && + (method == int(TextureMappingZone::DitheringHalftone) || + method == int(TextureMappingZone::DitheringHalftoneIncreasedDetail)); +} + +static void texture_preview_mix_zone_baked_model_settings(size_t &signature, + const TextureMappingZone &zone, + size_t num_physical) +{ + auto signature_mix = [&signature](size_t value) { + signature ^= value + 0x9e3779b97f4a7c15ull + (signature << 6) + (signature >> 2); + }; + auto signature_mix_float = [&signature_mix](float value, float scale = 1000.f) { + const float safe_value = std::isfinite(value) ? value : 0.f; + signature_mix(std::hash{}(int(std::lround(safe_value * scale)))); + }; + + signature_mix(std::hash{}(zone.component_a)); + signature_mix(std::hash{}(zone.component_b)); + signature_mix(std::hash{}(zone.component_ids)); + signature_mix(std::hash{}(zone.component_weights)); + signature_mix(std::hash{}(zone.offset_distances)); + signature_mix(std::hash{}(zone.offset_angles)); + signature_mix(std::hash{}(zone.offset_mode)); + signature_mix(std::hash{}(zone.offset_rotation_enabled ? 1 : 0)); + signature_mix_float(zone.offset_rotations); + signature_mix_float(zone.offset_repeats); + signature_mix(std::hash{}(zone.offset_reverse_repeats ? 1 : 0)); + signature_mix(std::hash{}(zone.offset_clockwise ? 1 : 0)); + signature_mix(std::hash{}(zone.offset_fade_mode)); + signature_mix(std::hash{}(zone.offset_angle_mode)); + signature_mix(std::hash{}(zone.texture_mapping_mode)); + signature_mix(std::hash{}(zone.filament_color_mode)); + signature_mix(std::hash{}(zone.force_sequential_filaments ? 1 : 0)); + signature_mix(std::hash{}(zone.nonlinear_offset_adjustment ? 1 : 0)); + signature_mix(std::hash{}(zone.compact_offset_mode ? 1 : 0)); + signature_mix(std::hash{}(zone.use_legacy_fixed_color_mode ? 1 : 0)); + signature_mix(std::hash{}(zone.dithering_enabled ? 1 : 0)); + signature_mix(std::hash{}(zone.dithering_method)); + if (zone.dithering_method == int(TextureMappingZone::DitheringHalftone) || + zone.dithering_method == int(TextureMappingZone::DitheringHalftoneIncreasedDetail)) + signature_mix_float(zone.halftone_dot_size_mm, 1000.f); + else + signature_mix_float(zone.dithering_resolution_mm, 1000.f); + signature_mix(std::hash{}(zone.minimum_visibility_offset_enabled ? 1 : 0)); + signature_mix_float(zone.minimum_visibility_offset_pct, 100.f); + signature_mix(std::hash{}(zone.generic_solver_lookup_mode)); + signature_mix(std::hash{}(zone.generic_solver_mode)); + signature_mix(std::hash{}(TextureMappingZone::DefaultGenericSolverMixModel)); + signature_mix(std::hash{}(zone.preview_simulate_colors ? 1 : 0)); + signature_mix(std::hash{}(zone.preview_limit_resolution ? 1 : 0)); + signature_mix_float(zone.contrast_pct, 100.f); + signature_mix_float(zone.tone_gamma); + for (const float strength_pct : zone.filament_strengths_pct) + signature_mix_float(strength_pct, 100.f); + for (const float minimum_offset_pct : zone.filament_minimum_offsets_pct) + signature_mix_float(minimum_offset_pct, 100.f); + + if (zone.is_2d_gradient()) { + signature_mix_float(texture_preview_config_float("texture_mapping_outer_wall_gradient_global_strength", 100.f), 100.f); + signature_mix_float(texture_preview_config_float("texture_mapping_outer_wall_gradient_max_line_width", 0.95f), 1000.f); + signature_mix_float(texture_preview_config_float("texture_mapping_outer_wall_gradient_min_line_width", 0.32f), 1000.f); + } + + const std::vector physical_colors = physical_filament_colors_for_texture_preview(num_physical); + for (const std::string &color : physical_colors) + signature_mix(std::hash{}(color)); +} + +size_t texture_preview_settings_signature(size_t num_physical, const TextureMappingManager *texture_mgr) +{ + return texture_preview_settings_signature_impl(num_physical, texture_mgr, nullptr); +} + +size_t texture_preview_settings_signature(size_t num_physical, + const TextureMappingManager *texture_mgr, + unsigned int base_filament_id, + const std::vector *used_states) +{ + if (texture_mgr == nullptr) + return texture_preview_settings_signature_impl(num_physical, texture_mgr, nullptr); + + std::vector active_zone_ids = active_texture_preview_zone_ids(texture_mgr, base_filament_id, used_states); + return texture_preview_settings_signature_impl(num_physical, texture_mgr, &active_zone_ids); +} + +size_t texture_preview_model_settings_signature(size_t num_physical, + const TextureMappingManager *texture_mgr, + unsigned int base_filament_id, + const std::vector *used_states, + bool has_texture_preview_data, + bool has_vertex_color_preview_data, + bool has_texture_mapping_color_preview_data) +{ + size_t signature = 1469598103934665603ull; + auto signature_mix = [&signature](size_t value) { + signature ^= value + 0x9e3779b97f4a7c15ull + (signature << 6) + (signature >> 2); + }; + + signature_mix(std::hash{}(num_physical)); + if (texture_mgr == nullptr) + return signature; + + const std::vector active_zone_ids = active_texture_preview_zone_ids(texture_mgr, base_filament_id, used_states); + for (const TextureMappingZone &zone : texture_mgr->zones()) { + if (!active_texture_preview_zone_ids_contains(active_zone_ids, zone.zone_id)) + continue; + + signature_mix(std::hash{}(zone.zone_id)); + signature_mix(std::hash{}(zone.enabled ? 1 : 0)); + signature_mix(std::hash{}(zone.deleted ? 1 : 0)); + signature_mix(std::hash{}(zone.surface_pattern)); + + const bool image_zone = zone.enabled && !zone.deleted && zone.is_image_texture(); + const bool gradient_zone = zone.enabled && !zone.deleted && zone.is_2d_gradient(); + const bool halftone_model = texture_preview_zone_uses_halftone_model(zone); + const bool simulated_vertex_color_model = + image_zone && + zone.preview_simulate_colors && + (has_texture_mapping_color_preview_data || (!has_texture_preview_data && has_vertex_color_preview_data)); + signature_mix(std::hash{}(halftone_model ? 1 : 0)); + signature_mix(std::hash{}(simulated_vertex_color_model ? 1 : 0)); + + if (gradient_zone || halftone_model || simulated_vertex_color_model) + texture_preview_mix_zone_baked_model_settings(signature, zone, num_physical); + } + return signature; +} + void render_model_texture_preview_models( std::vector &models, const std::vector &colors, diff --git a/src/slic3r/GUI/MMUPaintedTexturePreview.hpp b/src/slic3r/GUI/MMUPaintedTexturePreview.hpp index dd5ef210011..29a5d6672f9 100644 --- a/src/slic3r/GUI/MMUPaintedTexturePreview.hpp +++ b/src/slic3r/GUI/MMUPaintedTexturePreview.hpp @@ -80,6 +80,17 @@ bool texture_preview_simulation_enabled_for_all_filaments(const std::vector *used_states); +size_t texture_preview_model_settings_signature(size_t num_physical, + const TextureMappingManager *texture_mgr, + unsigned int base_filament_id, + const std::vector *used_states, + bool has_texture_preview_data, + bool has_vertex_color_preview_data, + bool has_texture_mapping_color_preview_data); void render_model_texture_preview_models( std::vector &models, diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 50f6388a597..a51fa2e4ebc 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -555,6 +555,52 @@ static bool assign_imported_texture_mapping_zone(Model &model) return true; } +static bool texture_mapping_config_uses_zone_id(const ConfigOptionResolver &config, unsigned int zone_id) +{ + static constexpr std::array filament_keys = { + "extruder", + "wall_filament", + "sparse_infill_filament", + "solid_infill_filament", + "support_filament", + "support_interface_filament" + }; + const int target = int(zone_id); + for (const char *key : filament_keys) { + const ConfigOptionInt *opt = dynamic_cast(config.option(key)); + if (opt != nullptr && opt->getInt() == target) + return true; + } + return false; +} + +static bool model_uses_texture_mapping_zone_id(const Model &model, const ConfigOptionResolver *print_config, unsigned int zone_id) +{ + if (zone_id == 0) + return false; + if (print_config != nullptr && texture_mapping_config_uses_zone_id(*print_config, zone_id)) + return true; + for (const ModelObject *object : model.objects) { + if (object == nullptr) + continue; + if (texture_mapping_config_uses_zone_id(object->config.get(), zone_id)) + return true; + for (const auto &layer_range : object->layer_config_ranges) + if (texture_mapping_config_uses_zone_id(layer_range.second.get(), zone_id)) + return true; + for (const ModelVolume *volume : object->volumes) { + if (volume == nullptr) + continue; + if (texture_mapping_config_uses_zone_id(volume->config.get(), zone_id)) + return true; + const std::vector &used_states = volume->mmu_segmentation_facets.get_data().used_states; + if (size_t(zone_id) < used_states.size() && used_states[zone_id]) + return true; + } + } + return false; +} + static wxColour parse_texture_mapping_color(const std::string &hex) { unsigned char rgba[4] = {38, 166, 154, 255}; @@ -4052,12 +4098,12 @@ Sidebar::Sidebar(Plater *parent) bundle->project_config.set_key_value("texture_mapping_definitions", new ConfigOptionString(serialized)); if (auto *print_tab = wxGetApp().get_tab(Preset::TYPE_PRINT)) print_tab->update_dirty(); - if (wxGetApp().mainframe != nullptr) - wxGetApp().mainframe->on_config_changed(print_cfg); if (wxGetApp().plater() != nullptr) wxGetApp().plater()->update_project_dirty_from_presets(); - update_texture_mapping_panel(false); + CallAfter([this]() { update_texture_mapping_panel(false); }); update_dynamic_filament_list(); + if (obj_list() != nullptr) + obj_list()->update_filament_colors(); }; auto add_texture_map_action = [this, persist_texture_mapping]() { PresetBundle *bundle = wxGetApp().preset_bundle; @@ -5730,14 +5776,14 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) bundle->project_config.set_key_value(key, new ConfigOptionString(value)); }; - auto notify_change = [this, print_cfg]() { + auto notify_change = [this, print_cfg](bool affects_scene) { if (auto *print_tab = wxGetApp().get_tab(Preset::TYPE_PRINT)) print_tab->update_dirty(); - if (wxGetApp().mainframe != nullptr && print_cfg != nullptr) + if (affects_scene && wxGetApp().mainframe != nullptr && print_cfg != nullptr) wxGetApp().mainframe->on_config_changed(print_cfg); if (wxGetApp().plater() != nullptr) { wxGetApp().plater()->update_project_dirty_from_presets(); - if (wxGetApp().plater()->get_view3D_canvas3D() != nullptr) + if (affects_scene && wxGetApp().plater()->get_view3D_canvas3D() != nullptr) wxGetApp().plater()->get_view3D_canvas3D()->reload_scene(false); } update_dynamic_filament_list(); @@ -5763,12 +5809,9 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) return; content_sizer->Clear(true); content_sizer->AddSpacer(FromDIP(SidebarProps::ContentMargin())); - auto update_texture_mapping_area_height = [this, scroll_texture_mapping_content_to]() { + auto update_texture_mapping_area_height = [this]() { if (p->m_panel_texture_mapping_content == nullptr || p->m_panel_texture_mapping_content->GetSizer() == nullptr) return; - int scroll_x = 0; - int scroll_y = 0; - p->m_panel_texture_mapping_content->GetViewStart(&scroll_x, &scroll_y); const int max_height = FromDIP(260); p->m_panel_texture_mapping_content->SetMaxSize(wxSize(-1, max_height)); p->m_panel_texture_mapping_content->Layout(); @@ -5777,7 +5820,6 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) if (min_size.y > max_height) min_size.y = max_height; p->m_panel_texture_mapping_content->SetMinSize(wxSize(-1, std::max(FromDIP(1), min_size.y))); - scroll_texture_mapping_content_to(scroll_x, scroll_y); }; if (p->m_btn_add_texture_map != nullptr) @@ -5896,9 +5938,13 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) canvas->reload_scene(true, true); }; - auto persist_rows = [mgr_ptr, set_config_string, notify_change]() { + auto texture_mapping_zone_affects_scene = [print_cfg](unsigned int zone_id) { + return model_uses_texture_mapping_zone_id(wxGetApp().model(), print_cfg, zone_id); + }; + + auto persist_rows = [mgr_ptr, set_config_string, notify_change](bool affects_scene) { set_config_string("texture_mapping_definitions", mgr_ptr->serialize_entries()); - notify_change(); + notify_change(affects_scene); }; for (const size_t zone_index : visible_zone_indices) { @@ -5972,19 +6018,30 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) }; auto apply_zone = [zone_index, mgr_ptr, num_physical, set_config_string, notify_change, refresh_texture_mapping_preview, - is_preview_only_texture_row_change, refresh_summary_preview](TextureMappingZone updated) { + is_preview_only_texture_row_change, refresh_summary_preview, texture_mapping_zone_affects_scene](TextureMappingZone updated) { auto &rows = mgr_ptr->zones(); if (zone_index >= rows.size()) - return; - const bool preview_only_change = is_preview_only_texture_row_change(rows[zone_index], updated); + return false; + const TextureMappingZone before = rows[zone_index]; + if (before == updated) + return false; + const unsigned int before_zone_id = before.zone_id; + const bool preview_only_change = is_preview_only_texture_row_change(before, updated); rows[zone_index] = std::move(updated); mgr_ptr->normalize_zone_ids(num_physical); + const unsigned int after_zone_id = rows[zone_index].zone_id; + const bool affects_scene = texture_mapping_zone_affects_scene(before_zone_id) || + texture_mapping_zone_affects_scene(after_zone_id); refresh_summary_preview(rows[zone_index]); set_config_string("texture_mapping_definitions", mgr_ptr->serialize_entries()); - if (preview_only_change) - refresh_texture_mapping_preview(); + if (preview_only_change) { + notify_change(false); + if (affects_scene) + refresh_texture_mapping_preview(); + } else - notify_change(); + notify_change(affects_scene); + return affects_scene; }; auto *surface_row = new wxBoxSizer(wxHORIZONTAL); @@ -6202,7 +6259,7 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) return; updated.surface_pattern = int(TextureMappingZone::Gradient2D); apply_zone(std::move(updated)); - update_texture_mapping_panel(false); + CallAfter([this]() { update_texture_mapping_panel(false); }); }); advanced_btn->Bind(wxEVT_BUTTON, [this, zone_index, @@ -6344,14 +6401,14 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) while (!updated.filament_transmission_distances_mm.empty() && std::abs(updated.filament_transmission_distances_mm.back()) <= 1e-6f) updated.filament_transmission_distances_mm.pop_back(); - apply_zone(std::move(updated)); - if (p->plater != nullptr && !p->plater->is_preview_shown()) { + const bool affects_scene = apply_zone(std::move(updated)); + if (affects_scene && p->plater != nullptr && !p->plater->is_preview_shown()) { if (GLCanvas3D *canvas = p->plater->get_view3D_canvas3D()) canvas->reload_scene(true, true); if (GLCanvas3D *canvas = p->plater->get_assmeble_canvas3D()) canvas->reload_scene(true, true); } - update_texture_mapping_panel(false); + CallAfter([this]() { update_texture_mapping_panel(false); }); }); auto toggle_editor = [this, zone_index, editor, row, update_texture_mapping_area_height]() { @@ -6385,7 +6442,7 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) evt.StopPropagation(); evt.Skip(); }); - menu_btn->Bind(wxEVT_BUTTON, [this, zone_index, num_physical, physical_colors, mgr_ptr, persist_rows, menu_btn, bundle, set_config_string](wxCommandEvent &) { + menu_btn->Bind(wxEVT_BUTTON, [this, zone_index, num_physical, physical_colors, mgr_ptr, persist_rows, menu_btn, bundle, set_config_string, texture_mapping_zone_affects_scene](wxCommandEvent &) { if (menu_btn == nullptr) return; wxMenu menu; @@ -6393,18 +6450,19 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) const int delete_id = wxWindow::NewControlId(); menu.Append(duplicate_id, _L("Duplicate")); menu.Append(delete_id, _L("Delete")); - menu.Bind(wxEVT_COMMAND_MENU_SELECTED, [this, zone_index, num_physical, physical_colors, mgr_ptr, persist_rows, duplicate_id, delete_id, bundle, set_config_string](wxCommandEvent &evt) { + menu.Bind(wxEVT_COMMAND_MENU_SELECTED, [this, zone_index, num_physical, physical_colors, mgr_ptr, persist_rows, duplicate_id, delete_id, bundle, set_config_string, texture_mapping_zone_affects_scene](wxCommandEvent &evt) { auto &rows = mgr_ptr->zones(); if (zone_index >= rows.size()) return; if (evt.GetId() == duplicate_id) { mgr_ptr->duplicate_zone(zone_index, num_physical, physical_colors); - persist_rows(); - update_texture_mapping_panel(false); + persist_rows(false); + CallAfter([this]() { update_texture_mapping_panel(false); }); return; } if (evt.GetId() == delete_id) { const uint64_t deleted_stable_id = rows[zone_index].stable_id; + const bool affects_scene = texture_mapping_zone_affects_scene(rows[zone_index].zone_id); rows.erase(rows.begin() + ptrdiff_t(zone_index)); if (deleted_stable_id != 0 && bundle->texture_mapping_global_settings.prime_tower_settings_zone_uid == deleted_stable_id) { @@ -6414,8 +6472,8 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager) set_config_string("texture_mapping_global_settings", bundle->texture_mapping_global_settings.serialize()); } p->m_expanded_texture_mapping_rows.clear(); - persist_rows(); - update_texture_mapping_panel(false); + persist_rows(affects_scene); + CallAfter([this]() { update_texture_mapping_panel(false); }); } }); menu_btn->PopupMenu(&menu, wxPoint(0, menu_btn->GetSize().GetHeight()));