Optimize RGB color painting. Avoid unnecessary scene reloads

This commit is contained in:
sentientstardust
2026-05-19 23:48:56 +01:00
parent 11a6b694d8
commit 0adef6ec19
9 changed files with 730 additions and 114 deletions

View File

@@ -4952,7 +4952,7 @@ bool model_mmu_segmentation_data_changed(const ModelObject& mo, const ModelObjec
template<class T>
static bool model_volume_imported_vector_matches(const ModelVolumeImportedVector<T> &lhs, const ModelVolumeImportedVector<T> &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)

View File

@@ -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<bool> *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<size_t>(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<ColorRGBA> extruder_colors = GUI::wxGetApp().plater()->get_extruders_colors();
auto adjusted_preview_colors = [this](const std::vector<ColorRGBA> &colors) {
auto adjusted_preview_colors = [this, &extruder_colors](const std::vector<unsigned int> &filament_ids, const std::vector<ColorRGBA> &colors) {
std::vector<ColorRGBA> 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,

View File

@@ -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<uint8_t> 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<uint8_t> 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<int> 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<size_t>(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<std::string>{}(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<std::vector<TriangleSelector::FacetStateTriangle>> true_color_rgb_preview_triangles(const ModelVolume &volume)
{
std::vector<std::vector<TriangleSelector::FacetStateTriangle>> 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<float>(),
its.vertices[size_t(tri[1])].cast<float>(),
its.vertices[size_t(tri[2])].cast<float>()
};
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<TriangleSelector::FacetStateTriangle> &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<TriangleSelectorPatch *>(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<ProjectedMousePosition> &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<Vec3f> &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<Vec3f> &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<ColorRGBA> colors = { ColorRGBA(1.f, 1.f, 1.f, 0.f) };
std::vector<std::vector<TriangleSelector::FacetStateTriangle>> 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<size_t>(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<ColorRGBA> 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<float, 4>{ 0.f, 0.f, 0.f, 0.f },
std::array<float, 2>{ 0.f, 0.f },
true);
}
}
void GLGizmoTrueColorPainting::update_triangle_selectors_color()
{
const std::vector<ColorRGBA> 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;

View File

@@ -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<ProjectedMousePosition> &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<ObjectID> m_changed_rgb_data_object_ids;
std::vector<std::vector<Vec3f>> m_brush_stroke_points_by_volume;
struct RgbPreviewVolumeCache
{
ObjectID volume_id;
bool valid = false;
size_t signature = 0;
std::vector<GLModel> models;
std::vector<ColorRGBA> colors;
std::vector<unsigned int> filament_ids;
};
std::vector<RgbPreviewVolumeCache> m_rgb_preview_cache;
std::vector<ObjectID> m_preview_rgb_data_volume_ids;
std::vector<std::unique_ptr<ColorFacetsAnnotation>> m_preview_rgb_data_by_volume;
std::unique_ptr<TextureMappingBackgroundConfigSnapshot> m_background_color_edit_config_snapshot;

View File

@@ -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<bool> texture_preview_used_states_for_painting(
const std::vector<std::vector<TriangleSelector::FacetStateTriangle>> &triangles_per_type)
{
std::vector<bool> 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<bool> *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<size_t>(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<GLModel> 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<TriangleSelector::Cursor> 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<std::vector<TriangleSelector::FacetStateTriangle>> 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<TriangleSelectorPatch *>(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<ColorRGBA> &colors) {
const std::vector<ColorRGBA> extruder_colors = wxGetApp().plater() != nullptr ?
wxGetApp().plater()->get_extruders_colors() : std::vector<ColorRGBA>();
auto adjusted_preview_colors = [this, &extruder_colors](const std::vector<unsigned int> &filament_ids,
const std::vector<ColorRGBA> &colors) {
std::vector<ColorRGBA> 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,

View File

@@ -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<GLModel> m_texture_preview_models;
std::vector<ColorRGBA> m_texture_preview_colors;
std::vector<unsigned int> m_texture_preview_filament_ids;
std::vector<bool> 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<ProjectedMousePosition> &) {}
// BBS: projected result of mouse height range for a mesh
struct ProjectedHeightRange
{

View File

@@ -3783,6 +3783,21 @@ size_t texture_preview_state_triangles_signature(const std::vector<TriangleSelec
return signature;
}
void mix_color_facets_signature(size_t &signature, const ColorFacetsAnnotation &color_source)
{
auto mix = [&signature](size_t value) {
signature ^= value + 0x9e3779b97f4a7c15ull + (signature << 6) + (signature >> 2);
};
const TriangleColorSplittingData &data = color_source.get_data();
mix(color_source.id().id);
mix(static_cast<size_t>(color_source.timestamp()));
mix(data.triangles_to_split.size());
mix(data.bitstream.size());
mix(data.colors_rgba.size());
mix(std::hash<std::string>{}(data.metadata_json));
}
size_t texture_preview_vertex_color_source_signature(const ModelVolume &model_volume,
const std::vector<TriangleSelector::FacetStateTriangle> &state_triangles)
{
@@ -3792,11 +3807,15 @@ size_t texture_preview_vertex_color_source_signature(const ModelVolume
};
mix(reinterpret_cast<size_t>(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<size_t>(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<size_t>(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<size_t>(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<unsigned char>(ch)));
mix(texture_preview_state_triangles_signature(state_triangles));
mix(model_volume.mmu_segmentation_facets.id().id);
mix(static_cast<size_t>(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<size_t>(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<size_t>(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>{}(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<size_t>(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<size_t>(model_volume.imported_texture_rgba.data()));
mix(size_t(model_volume.imported_texture_raw_channels));
mix(std::hash<std::string>{}(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<size_t>(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<size_t>(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<size_t>(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<unsigned char>(ch)));
mix(model_volume.id().id);
mix(reinterpret_cast<size_t>(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<unsigned int> *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<uint64_t>{}(zone.stable_id));
signature_mix(std::hash<unsigned int>{}(zone.zone_id));
signature_mix(std::hash<int>{}(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<unsigned int> active_texture_preview_zone_ids(const TextureMappingManager *texture_mgr,
unsigned int base_filament_id,
const std::vector<bool> *used_states)
{
std::vector<unsigned int> 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<unsigned int> &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>{}(int(std::lround(safe_value * scale))));
};
signature_mix(std::hash<unsigned int>{}(zone.component_a));
signature_mix(std::hash<unsigned int>{}(zone.component_b));
signature_mix(std::hash<std::string>{}(zone.component_ids));
signature_mix(std::hash<std::string>{}(zone.component_weights));
signature_mix(std::hash<std::string>{}(zone.offset_distances));
signature_mix(std::hash<std::string>{}(zone.offset_angles));
signature_mix(std::hash<int>{}(zone.offset_mode));
signature_mix(std::hash<int>{}(zone.offset_rotation_enabled ? 1 : 0));
signature_mix_float(zone.offset_rotations);
signature_mix_float(zone.offset_repeats);
signature_mix(std::hash<int>{}(zone.offset_reverse_repeats ? 1 : 0));
signature_mix(std::hash<int>{}(zone.offset_clockwise ? 1 : 0));
signature_mix(std::hash<int>{}(zone.offset_fade_mode));
signature_mix(std::hash<int>{}(zone.offset_angle_mode));
signature_mix(std::hash<int>{}(zone.texture_mapping_mode));
signature_mix(std::hash<int>{}(zone.filament_color_mode));
signature_mix(std::hash<int>{}(zone.force_sequential_filaments ? 1 : 0));
signature_mix(std::hash<int>{}(zone.nonlinear_offset_adjustment ? 1 : 0));
signature_mix(std::hash<int>{}(zone.compact_offset_mode ? 1 : 0));
signature_mix(std::hash<int>{}(zone.use_legacy_fixed_color_mode ? 1 : 0));
signature_mix(std::hash<int>{}(zone.dithering_enabled ? 1 : 0));
signature_mix(std::hash<int>{}(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<int>{}(zone.minimum_visibility_offset_enabled ? 1 : 0));
signature_mix_float(zone.minimum_visibility_offset_pct, 100.f);
signature_mix(std::hash<int>{}(zone.generic_solver_lookup_mode));
signature_mix(std::hash<int>{}(zone.generic_solver_mode));
signature_mix(std::hash<int>{}(TextureMappingZone::DefaultGenericSolverMixModel));
signature_mix(std::hash<int>{}(zone.preview_simulate_colors ? 1 : 0));
signature_mix(std::hash<int>{}(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<std::string> physical_colors = physical_filament_colors_for_texture_preview(num_physical);
for (const std::string &color : physical_colors)
signature_mix(std::hash<std::string>{}(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<bool> *used_states)
{
if (texture_mgr == nullptr)
return texture_preview_settings_signature_impl(num_physical, texture_mgr, nullptr);
std::vector<unsigned int> 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<bool> *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<size_t>{}(num_physical));
if (texture_mgr == nullptr)
return signature;
const std::vector<unsigned int> 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<unsigned int>{}(zone.zone_id));
signature_mix(std::hash<int>{}(zone.enabled ? 1 : 0));
signature_mix(std::hash<int>{}(zone.deleted ? 1 : 0));
signature_mix(std::hash<int>{}(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<int>{}(halftone_model ? 1 : 0));
signature_mix(std::hash<int>{}(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<GUI::GLModel> &models,
const std::vector<ColorRGBA> &colors,

View File

@@ -80,6 +80,17 @@ bool texture_preview_simulation_enabled_for_all_filaments(const std::vector<unsi
size_t texture_preview_simulation_generation_signature();
size_t texture_preview_settings_signature(size_t num_physical, const TextureMappingManager *texture_mgr);
size_t texture_preview_settings_signature(size_t num_physical,
const TextureMappingManager *texture_mgr,
unsigned int base_filament_id,
const std::vector<bool> *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<bool> *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<GUI::GLModel> &models,

View File

@@ -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<const char *, 6> 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<const ConfigOptionInt *>(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<bool> &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()));